项目准备

项目地址

项目结构

1
2
3
4
5
6
7
8
9
- src
- app
- App.vue
- img
- logo.png
- style
- app.scss
- index.html
- main.js

webpack基本概念

entry

即webpack打包的入口js文件,可以根据项目实际情况配置成但入口或者多入口,webpack会根据入口文件内的引入的文件绘制依赖图,将该模块和模块对应的依赖都打包到一个文件中。

1
2
3
4
5
6
7
8
9
10
11
//单入口
const config = {
entry:'a.js'
}
//多入口
const config = {
entry:{
a:'a.js',
b:['b1.js','b2.js'] //多个文件打包为一个文件
}
}

output

即webpack打包后的输出,即使此时的entry中存在多个入口,也只提供单一的输出配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//单一入口情况,一下将所有文件都打包到dist/bundle.js里
const config = {
output:{
filename:'bundle.js',
path:path.join(__dirname,'dist')
}
}
//多入口情况
const config ={
output:{
filename:'[name].js',
path:path.join(__dirname,'dist')
}
}

这里的输出文件名中可以使用[name],[hash],[chunkhash]等占位,这样输出的文件名中就有带有资源hash值。[hash]是本次打包所有资源的hash值,同义词打包的文件得到的hash是一样的,而[chunkhash]是单个文件打包的hash值,每个文件且每次打包都不相同。还可以使用[hash:8]来取hash值得位数

Loader

webpack是一个js bundler,如果需要它对非js得模块,例如typeScript,sass,less,vue等模块进行打包,则需要对应的loader进行转换。而且同一种资源有时需要使用不止一种loader。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const config ={
module:{
rules:[
{
test: /\.vue$/,
use: [{loader: 'vue-loader'}]
},
{
test:/\.scss/,
use:[
{loader:'style-loader'},
{
loader:'css-loader',
options: {
modules: true
}
},
{loader:'sass-loader'}
]
}
]
}
}

在rules数组中的每一项都是一种模块类型的转换规则,test参数匹配对应后缀的文件,use数组中配置对应使用的loader以及配置loader的其他参数。

官方推荐的loader

Plugins

plugins用于解决其他loader无法做到的事情,比如压缩资源,启动开发服务器等等。

1
2
3
4
5
6
7
8
9
10
11
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

const config ={
plugins:[
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({
template:path.join(__dirname,'src/index.html')
})
]
}

plugins数组的每一项就是一个插件

webpack自带的以及推荐使用的Plugins

webpack配置文件结构

webpack默认的配置文件名为webpack.config.js,当然也可以自定义其他文件名,只要在webpack –config filename命令中修改filename为当前的配置文件即可。

完整的webpack配置参数可以查看官方文档

开发模式和打包模式(Dev&Build)

可以通过命令行向webpack闯入参数,以判断使用开发模式还是打包。

在package.json中配置npm script:

1
2
3
4
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
"dev": "cross-env NODE_ENV=develement webpack-dev-server --config webpack.config.js"
}

命令行中使用了cross-env用于跨平台地设置及使用环境变量,具体的参照官方github说明

在build和dev中我们分别向webpack传入了不同的NODE_ENV参数值。在webpacl配置文件中,可以使用process.env.NODE_ENV来的到这个值,以便判断该运行那哪个模式。

webpack-dev-server

在webpack中用devServer参数来配置它,在此之前我们需要先判断是否运行在开发模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var WebpackDevServer = require('webpack-dev-server');

//获得NODE_ENV参数,用于判断处于开发模式还是打包模式
var isDev = process.env.NODE_ENV === 'develement';

const config = {
....
}

if(isDev){
//webpack-dev-server不能使用chunkhash,否则会报错
config.output.filename ='[name]-[hash].js';
config.devtool = '#cheap-module-eval-source-map';

config.plugins.push(
new webpack.HotModuleReplacementPlugin(), //热更新插件
new webpack.NoEmitOnErrorsPlugin() //防止错误信息导致webpack退出
)

//启动开发服务器
config.devServer={
contentBase:path.join(__dirname,'dist'),
compress:true, //启用gzip压缩
port:8080,
hot:true, //启用webpack热模块替换特性
open:true //是否在开始服务器后打开浏览器
}
}

在devServer中配置hot:true并不在代表已经启用了热模块替换,还需要使用webpack.HotModuleReplacementPlugin插件才能生效,hot仅仅是一个开关

单独打包css文件

想vue文件中的样式通常会被打包进js文件中,在该组件被加载时同时加载样式。而有一些公共的样式通常会写在单独的文件中,如果我们在多个组件中引用公共样式,那么公共样式会在多个js模块中被打包,这样会增加文件的体积。这是应该将这些公共样式提取出来单独打包。

这里我们使用extract-text-webpack-plugin插件来提取公共样式,所以此时我们的配置文件中就该改为这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var ExtracTextPlugin = require('extract-text-webpack-plugin');

const config ={
module:{
rules:[
{
test: /\.scss/,
use: ExtracTextPlugin.extract({
use: [{
loader: 'css-loader'
}, {
loader: 'sass-loader'
}]
})
}
]
},
plugins:[
new ExtracTextPlugin('style-[contentHash:8].css')
]
}

这样就能将scss文件单独打包了

提取公共模块

同理我们在项目中使用类库,也需要单独打包,以防止重复加载,节省流量。

这里使用的是webpack自带的插件CommonsChunkPlugin,在entry中添加vendor模块,然后在插件中配置单独打包vue。

1
2
3
4
5
6
7
8
9
10
11
var config = {
entry: {
app:path.join(__dirname, 'src/main.js'),
vendor:['vue']
},
plugins:[
new webpack.optimize.CommonsChunkPlugin({
name:'vendor'
})
]
}