Webpack 入门教程
webpack的简介和安装
为什么使用webpack
-
模块化打包:webpack可以帮我们把CommonJS和ES6语法模块化,转化为浏览器可以解释执行的语法。,我们既可以使用到模块化方案带飞我们的好处:避免代码变量命名等冲突,结构清晰,方便复用与管理,也可以通过webpack来满足浏览器的兼容!webpack可以帮我们解析模块间的依赖关系,并正确打包!
-
兼容更多的前端技术:前端技术和新的规范层出不穷
上面这是实际还是js和css,但是加入了一些增强语法,他们都可以提高前端开发效率和开发体验!但是这些语法都没有办法直接被浏览器执行,这就需要我们使用webpack,将这些代码进行编译,编写成浏览器可以执行的代码。
-
js规范:ES6、ES7、ES8
-
css预处理器:LESS、SASS
-
前端框架:vue、react、Angular
-
JS语言改进:CoffeScript和TypeScript
-
更多功能:webpack可以帮我们管理小素材图标、雪碧图等前端需求细节
webpack的安装
在安装 Webpack 前,你本地环境需要支持 node.js。nodejs
自带包管理工具npm.
NodeJS、webpack、npm、vue的关系
-
vue是学习js语言的新框架,新的框架有一部分不被浏览器兼容,如.vue文件,因此我们就需要webpack来帮我们做编译,将编译后的代码变为浏览器可执行的代码
-
npm工具可以帮我们管理各种js类库,打包工具webpack本身就是一个js的类库,因此需要使用npm帮助我们管理
-
webpack是一个js类库,不仅可以帮助我们编译,还可以帮助我们打包静态资源。
检查NodeJS版本
NodeJS安装完成以后,我们可以查看安装的版本,最其要求8.10+
node -v
安装webpack
全局安装webpack
npm install webpack -g
局部安装
npm install webpack --save-dev
-
局部安装和全局安装的区别:全局安装对所有版本生效,局部安装只对当前项目生效
-
局部版本的优先级高于全局安装版本
-
–save-dev表示该类库只在编译期间使用,打包结果中不包含该类库。webpack只是在开发阶段使用,浏览器运行期间不需要这部分代码。
webpack使用
项目初始化
使用npm init
,初始化前端项目
局部安装webpack
npm install webpack@3.6.0 --save-dev
webpack安装完成后,我们发现在package.json
文件中自动生成了一段配置代码。这段配置代码表示该项目使用webpack进行模块化静态资源打包,并且只在开发期间使用
项目创建
使用npm init
初始化项目以后,创建文件和目录如下
-
dist目录,手动创建,用于存放打包结果
-
src目录,手动创建,用于存放被打包的资源文件js、css、image等
-
index.html,手动创建,项目首页
-
node-modules目录,这个目录是自动生成的不需要手动新建,npm包管理工具引入的包都在这个目录下存放
furit.js代码
let apple ="苹果"
let watermelon="西瓜"
let pear= "梨"
module.exports ={
apple,
watermelon,
pear
}
main.js代码
let {apple,watermelon,pear} =require('./js/furit')
document.writeln(apple);
document.writeln(watermelon);
document.writeln(pear);
index.html代码
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript" src="./dist/bundle.js" charset="utf-8"></script>
</body>
</html>
使用webpack打包js模块
D:\software\file\typora\vue\webpack-demo\node_modules\.bin\webpack src/main.js dist/bundle.js
访问index.html结果如下
通过npm run build打包命令讲解webpack基础配置
创建webpack.config.js
作为wabpack的配置文件
const path = require('path')
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname,'dist'),
filename: "bundle.js"
}
};
-
引入NodeJS提供的模块path
-
path.resolve方法作用是完成路径拼接,__dirname是全局变量,代表当前文件所在路径
-
__dirname + ‘dist’ 就是bundle.js出口文件的完整的绝对路径
-
entry: 入口文件
-
output.filename:表示出口文件路径和文件名
使用如下命令打包
D:\software\file\typora\vue\webpack-demo\node_modules\.bin\webpack
也就是说,我们不用再使用命令行参数了,我们把入口、出口文件参数写在了配置文件里面。离我们使用npm run build
命令来实现打包操作还差一步,在项目配置管理文件package.json里面加入如下一行代码:
加入这一行代码的意义在于:当我们输入npm run build命令的时候,会自动查找package.json文件script.build脚本,从而执行webpack命令。并且这个webpack命令不是全局的,默认就是node_modules/.bin下面局部安装的webpack版本,所以我们就不用再加上前缀路径。至此,我们就可以使用npm run build命令来实现项目模块化资源文件打包,和vue-cli脚手架实现的原理一致。如下:
npm run build
css文件处理打包
在src文件夹下,创建css文件夹,在css文件夹中创建一个style.css
文件,文件内容是,设置背景为黄色
body {
background: yellow;
}
在main.js中将style.css
当作一个模块引入
require("!style-loader!css-loader!./css/style.css")
在webpack.config.js配置css
const path = require('path')
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname,'dist'),
filename: "bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" }
]
}
};
这时,我们调用npm run build
打包,就会出现如下错误:需要合适的loader去处理css文件类型
将npm镜像设置为阿里源镜像
npm config set registry http://registry.npmmirror.com
所以,我们安装css-loader。实际上是安装css-loader和style-loader。css-loader帮助我们加载css文件,style-loader帮我们把样式嵌入到文档中
npm install --save-dev css-loader@0.28.3 style-loader0.18.1
注不同版本的webpack对应的css-loader和style-loader版本不同,可以在
https://github.com/webpack/webpack/blob/webpack版本/package.json中查找对应版本。
再次运行项目
npm run build
结果如下
CSS中图片文件处理
在src文件夹中创建image文件夹,放入两种图片2.jpg
和1.png
大于10kb,修改style.css
文件
body {
background-color:yellow;
background: url(../image/1.png);
font-size:20px;
color: yellow;
}
div{
height: 100px;
width: 100px;
}
- 修改main.js,新添加一个jpg
import less10kb from './image/2.jpg';
require("./css/style.css");
let {apple,watermelon,pear} =require('./js/furit')
document.writeln(apple);
document.writeln(watermelon);
document.writeln(pear);
function component() {
const element = document.createElement('div');
// 将图像添加到我们已经存在的 div 中。
const myIcon = new Image();
myIcon.src = less10kb;
myIcon.style="width: 400px; height: 200px;";
element.appendChild(myIcon);
return element;
}
document.body.appendChild(component());
- 安装处理图片的url-loader,file-loader,使用如下命令:
npm install --save-dev@ url-loader@4.1.1 file-loader@file-loader
- 然后配置webpack.config.js,添加对css中图片的处理策略:
const path = require('path')
module.exports = {
entry: './src/main.js',
output:{
path: path.resolve(__dirname,'dist'),
filename: 'bundle.js',
publicPath:"dist/"
},
module: {
rules: [
{
test: /\.css$/,
use:[ "style-loader", "css-loader"]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use:[
{
loader : 'url-loader',
options:{
limit: 10240,
name: 'img/[name].[hash:8].[ext]'
}
}
]
}
]
}
}
-
test配置用于匹配处理图片的文件后缀名
-
use.options.limit:10240表示如果图片文件小于10kb,就把它打包到结果文件bundle.js
-
publicPath:"dist/"
表示可以被公开访问的独立资源文件存放的目录 -
file-loader
:假如图片小于10kb,我们就把图片转换为Base64编码打包到bundle.js文件中。那么,如果图片比较大,打包到js文件会比较臃肿,使用file-loader将图片文件独立于js文件存在并可以被使用
再次运行
npm run build
-
use.options.name:自定义图片名称
-
img:文件要打包到目标文件夹
-
name:图片原始文件名
-
hash:8:8位的hash值,保证一定的随机性
-
ext:使用图片原来的扩展名
js规范兼容babel
什么是ECMAScript
ECMAScript,简称ES,是由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)按照ECMA-262和ISO/IEC 16262标准制定的一种脚本语言规范。javascript是ECMAScript规范的实现,ECMAScript是javascript的标准。那么都有哪些常用的标准呢?
大名 | 小名 | 备注 |
---|---|---|
ECMAScript 5 | ES5 | 兼容绝大部分浏览器 |
ECMAScript 2015 | ES6 | 兼容绝大部分现代浏览器 |
ECMAScript 2016 | ES7 | 浏览器兼容性一般 |
ECMAScript 2017 | ES8 | 浏览器兼容性一般 |
ES5是我们目前前端js语言届的“普通话”,也就是说ES5可以被大部分浏览器兼容。但是ES5面向开发人员不够友好,语法繁琐并且难于理解,特别是原型、对象、集成;也没有一些新的js特性,如:Promise等的支持。
babel是什么
Babel 是一个javascript编译器,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。中文网站地址:https://www.babeljs.cn/
注意看下面的这个动图,左侧是转换钱的ES6+语法,右侧为转换之后ES5的语法
babel-loader
css打包转换我们使用css-loader,图片打包转码我们使用url-loader。我们将ES6+的语法转换为“普通话”ES5使用的是babel-loader。我们首先来安装它:
npm install --save-dev babel-loader@7.1.5 babel-core@6.26.3 babel-preset-env@1.7.0
可以看到除了 babel-loader,我们还安装了 babel-core,因为前者对后者有依赖关系。babel-preset用于识别语法规范,babel-preset有多项选择安装,比如es2015,es2016,es2017,env。但是一般用的比较多的是babel-preset-env,env表示兼容ES2015+的语法。配置webpack.config.js中的module.rules代码段:
{
test: /\.js$/,
exclude: /(node_modules)/,
use:{
loader: 'babel-loader',
options:{
presets:[
[
'env',
{
targets:{
browsers:['>1%', 'last 2 version' ,'not ie <=8']
}
}
]
]
}
}
},
-
test中正则表达式表示只针对js文件做处理
-
exclude表示不对node_modules目录下的文件做处理,这下面js文件不是我们写的
-
使用env设置:表示兼容ES2015+的语法
-
targets.browers表示兼容使用率大于1%,并且兼容浏览器最新2个版本,并且不兼容IE8及以下浏览器
然后我们使用npm run build
打包,打包之后结果如下。我们原始代码中定义变量使用的是let关键字,被转换为ES5规范的变量定义关键字var。
webpack整合vue
npm install vue --save
我们来写一个简单的例子来使用Vue,首先在main,js中使用Vue:
import Vue from 'vue'
new Vue({
el:'#app',
data:{
message:"springboot葵花宝典"
}
})
然后在index.html中,建一个id#app的div,使用插值表达式引用message变量
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id = 'app'>
{{message}}
</div>
</body>
<script type="text/javascript" src="./dist/bundle.js" charset="utf-8"></script>
</html>
webpack.config.js中添加resolve
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
注:resolve和module同级
页面访问
npm run build
vue单文件组件
在src文件夹下创建vue文件夹,然后创建test.vue
<template>
<div>
<input type="text" v-model="message">
<h2 style="color:blak">输入的内容是:{{message}}</h2></div>
</template>
<script>
export default {
name: 'test',
data(){
return {
message: 'springboot葵花宝典'
}
}
}
</script>
<style scoped>
</style>
-
template标签里面书写html视图层代码
-
script标签里面写模块化的Vuejs代码
-
style标签里面写针对该组件的视图样式
这种写法降低了视图、数据、样式之间的耦合度,对开发者更加友好。然后,我们可以在项目入口文件main,js这样使用该组件
import Vue from 'vue'
import test from './vue/test.vue'
new Vue({
// el:'#app',
// data:{
// message:"springboot葵花宝典"
// }
render: h=> h(test)
}).$mount("#app")
安装需要vue-loader等组件
npm install vue-loader@13.0.0 vue-template-compiler@2.6.10 --save-dev
在webpack.config.js中加入如下配置
{
test: /\.vue$/,
use:['vue-loader']
}
运行程序结果如下
什么是webpack插件
我们通常意义上,所说的软件应用的插件就是指对原有类库或者软件功能进行扩展,通常需要额外安装的类库或软件。所以从广义上讲css-loader、url-loader等都是webpack的插件。但是,我们一般不把它们叫做webpack的插件,而是称它们为转换器、加载器或者直接叫loader。还有一些对webpack功能进行扩展的类库或者程序,比如:htmlWebPackPlugin、uglifyJsPlugin,它们都对webpack的功能进行了扩展。而且不是完成转换加载之类的功能扩展,我们把这部分软件扩展程序,称为:webpack的插件。
htmlWebPackPlugin
我们之前通过浏览器访问的index.html是存放在项目根目录下面,而不是存放在dist目录下面。还有需要明白一点:dist目录下的文件才是我们真正做生产环境发布的程序文件。所以说,我们需要将index.html打包到dist文件夹里面。htmlWebPackPlugin帮我们做两件事:
-
帮我们把index.html(html模板)打包到dist文件夹下面
-
将最终的打包结果bundle.js,以script标签形式帮我们引入到html里面
所以,我们需要先把index,html里面手动引入的bundle.js代码删掉。从此以后就不需要手动引入bundle.js了。htmlWebPackPlugin会帮我们引入。
安装HtmlWebpackPlugin插件
npm install html-webpack-plugin@3.2.0 --save-dev
安装完成之后,在webpack.config.js里面做如下的配置:
plugins:[
new htmlWebpackPlugin({
template: 'index.html'
})
],
注:plugin和module同级
上面代码含义是使用和webpack.config.js同一目录下的index.html作为模板生成项目的访问入口。此外,我们之前为了正确的访问在css代码里面的图片文件,我们加上了publicPath的配置。我们将html打包到dist文件夹之后,这个配置就不需要了,删掉!
output:{
path: path.resolve(__dirname,'dist'),
filename: 'bundle.js',
//publicPath:"dist/"
},
npm run build
后查看dist文件

#### uglifyJsPlugin
生产环境中,我们通常会对js文件压缩,丑化。去掉空格、换行,变量替换为简单的字符。这样做有2点好处:
* 让代码更难以理解,黑客很难读懂压缩丑化之后的代码,从而一定程度上防止可以针对性的攻击。(但实际上对于有经验的web渗透人员,这个也起不到太大的效果,只能做到防君子不防小人)
* 压缩之后的代码体积更小,更有利于网络请求的性能优化
我们使用uglifyJsPlugin来完成对js文件压缩,丑化。首先安装:
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
我们安装1.1.1版本,与Vue-CLI2一致,避免兼容性问题!安装完成之后,在webpack.config.js里面做如下的配置:
const uglifyJsPlugIn = require(‘uglifyjs-webpack-plugin’)
plugins:[
new htmlWebpackPlugin({
template: 'index.html'
}),
new uglifyJsPlugIn()
],
```
#### 本地调试服务webpack-dev-server
我们在写代码的时候,希望我们改完代码之后,能够让浏览器自动感知到我们对代码的改动,也就是热部署,方便我们做代码的调试。在vue-cli脚手架中是使用npm run dev命令来实现的。现在我们就来实现这个功能。首先,要明确的说,这个热部署调试功能是webpack为我们实现的,webpack提供了一个本地开发服务器,依赖于NodeJS,内部使用express框架。它是一个单独的模块,我们先来安装它,在项目根目录执行命令:
```
npm install --save-dev webpack-dev-server@2.9.1
```
在webpack.config.js文件里面module.exports代码段下加入如下配置:
```
devServer:{
contentBase: './dist',
inline: true,
port: 8888
}
```
* contentBase:静态资源访问服务的根路径
* port:服务端口号
* inline:发生改变,实时热部署刷新浏览器页面
然后在package.json项目配置文件里面,加入如下配置:
```
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --open",
"test": "echo \"Error: no test specified\" && exit 1"
},
```
\--open表示,本地服务启动,自动打开浏览器,访问contentBase下面的index.html
使用`npm run dev`运行程序

### 环境配置分离
首先,我们回顾上一节中给大家介绍的内容:
* uglifyJsPlugin插件,用于对打包代码进行压缩,丑化。从而减少代码体积,提高网络传输效率。
* webpack-dev-server用于本地代码开发的时候,进行代码调试。实时的热部署更新。
大家可以看到,虽然上面两个都是webpack配置项目,但是我们通常希望uglifyJsPlugin只对生产环境的代码进行丑化,压缩。在我们平时开发过程中,我们还是希望代码是具有可读性、规范化的。而webpack-dev-server相反,我们希望实时热部署更新只在开发阶段生效,他并不需要在生产环境中生效。也就是说,配置项分为三种:
* 期望对生产环境和测试环境都生效的配置(如下图红色框和黄色框之外的配置)
* 期望只对测试环境生效的配置(黄色框的配置:本地调试服务设置)
* 期望只对生产环境生效的配置(红色框的配置:代码压缩丑化插件)
#### 建立基本文件结构
* webpack.base.conf.js:webpack基础配置,应该包含第二小节图中的红色框和黄色框之外的所有配置
* webpack.dev.conf.js:测试环境生效配置,应该包含第二小节图中的黄色框的配置
* webpack.prod.conf.js:测试环境生效配置,应该包含第二小节图中的红色框的配置
webpack.config.js(红色框)在以上三个文件配置完成之后,删除。

#### webpack-merge
通过前两个小节的说明,我相信大家能够明白,实际上:生产环境的完成配置 = base配置 + prod配置 测试环境的完整配置 = base配置 + dev配置
那么,现在我们就要一个问题,如何完成“+”加这个动作。也就是如何完成配置合并,我们需要使用到webpack-merge,先来安装它:
```
npm install webpack-merge@4.2.2
```
第一步:将webpack.config.js代码copy到webpack.base.conf.js,然后删除第二小节红色框和黄色框的部分。也就是去除生产环境和测试环境的个性化配置。
```
entry: './src/main.js',
output:{
path: path.resolve(__dirname,'../dist'),
filename: 'bundle.js',
},
```
第二步:调整webpack打包输出文件路径的配置,原来是dist换成'../dist',因为打包配置文件都放在了build目录下,它的上一级目录下的dist目录是文件打包输出路径。
第三步:在webpack.dev.conf.js中使用webpack-merge进行配置合并,同理需要将contentBase的dist换成‘../dist’,代码如下:
```
const path = require('path')
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.conf')
module.exports = merge(baseConfig,{
devServer:{
contentBase: path.resolve(__dirname,'../dist'),
inline: true,
port: 8888
}
});
```
第四步:需要调整package.json的`npm run dev`启动脚本,显式的指定配置文件的所在位置。否则,webpack还会默认使用根目录下面的webpack.config.js作为配置文件。
```
"scripts": {
"build": "webpack --config ./build/webpack.prod.conf.js",
"test": "webpack --config ./build/webpack.dev.conf.js",
"dev": "webpack-dev-server --open --config ./build/webpack.dev.conf.js"
},
```
至此,我们测试环境的配置文件就完成了!我相信大家可以按照测试环境的配置文件拆分方式,和代码配置webpack-merge,把生产环境的配置独立完成!
如果您觉得本文不错,欢迎关注,点赞,收藏支持,您的关注是我坚持的动力!
原创不易,转载请注明出处,感谢支持!如果本文对您有用,欢迎转发分享!