基于webpack自身配置的优化,不涉及到happypack和DLL.

总述

webpack自身是单进程的。优化的总思路是,时间上,小范围,扫描次数少;空间上,能分离即分离,能不打包不打包,在http请求数与文件大小之间找到平衡。

1.entry

根据指定目录下动态生成entry对象,可根据不同场景区分entry中的数量。间接提高开发效率。
或者遍历文件夹,生成entry对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let srcDir = path.resolve(process.cwd(), 'static/\$dev')
let componentsDir = path.resolve(process.cwd(), 'static/\$dev/components')
let entries = (() => {
let entryFiles = (process.env.NODE_ENV === 'production')
? glob.sync(srcDir+"/+(index|service|tryout|app|user|stat|knowledge|doc|plan|tech|example|semservice|semutterance)/*.js")
: glob.sync(srcDir+"/+(index|semservice|semutterance|knowledge|app)/*.js")
let map = {}
entryFiles.forEach(function(filepath){
let filename = filepath.substring(filepath.lastIndexOf('\/') + 1,filepath.lastIndexOf("."))
map[filename] = filepath;
});
return map
}())

2.resolve

modules默认只包括node_modules,如果需要添加其他的目录,需要保证node_modules在最后一位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
resolve:{
// 使用绝对路径,将只在给定目录中搜索。
modules: [path.resolve(__dirname, "src"), "node_modules"],
// 可省略文件后缀
extensions: ['.js', '.vue'],
// 减少webpack扫描时,每次查找相同包的时间。
alias:{
echarts:"components/echarts.min.js", // echarts
citySelector:"components/citySelector.js" // 城市选择
}
},
// 文件内引用时
import echarts from 'echarts';

3.module中的rules

总的来说就是,尽量添加include, exclude,限定范围。
在rules进行test时,尽量精准匹配,比如如果没有jsx的文件,只有js的,test就可以写为/.js$/,而不是/.jsx?$/。(具体正则匹配的效率上,没有实际验证过。。)

其中babel, babel对文件的编译时间是比较久的,里面东西比较多,这里简单说几点。
配置中可以开启cache,这样在文件没有修改的时候,babel不会重新编译,以节约时间。
另一个是,babel-pollyfilltransform-runtime

1
2
3
4
5
6
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory',
include: [path.resolve(__dirname, "src")],
exclude: [path.resolve(__dirname, "src", "assets"), /node_modules/]
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.babelrc
{
"presets": [
[
"es2015",
{
// 对modules语法不做转换,defaults to 'commonjs'
"modules": false
}],
// 0 -> n, 0打包后的代码量最大。
"stage-0"
],
// 动态对babel不能转换的新的API进行‘填补’
"plugins": ["transform-runtime"],
"comments": false
}

4.module中的noParse

1
2
3
4
5
6
7
8
module{
//忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制
// noParse:[componentsDir]
noParse:['jquery', 'lodash'],
rules: [
....
]
}

5.只在production环境下的,tree-shaking

实际验证现阶段(2017.7.27)tree-shaking之后,文件大小变化并不明显。主要受写法限制。尤其是引用大量第三方非ES6写法的库,其实作用不是很大。如果是从头自己写,在遵循ES6标准的基础上,控制性更好些。
同时uglify本身时间还比较长。用时间换空间的性价比不高。

因为tree-shaking必须配置一些压缩插件才能实现,默认是使用webpack-uglifyJS,但是由于是单进程的,处理比较慢。可选用webpack-parallel-uglify-plugin,多核处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
new UglifyJsparallelPlugin({
cacheDir: '.cache/',
workerCount: os.cpus().length,
uglifyJS: {
// 可以用uglifyJS自身的配置
// 这里用于支持低版本IE
supper_ie8: true,
compress: {
screw_ie8: false,
properties: false,
warnings: false
},
output: {
screw_ie8: false,
beautify: true,
quote_keys: true
},
mangle: {
screw_ie8: false
},
sourceMap: false
}
})

6. 只在dev环境下

module.exports.devtool = '#cheap-module-eval-source-map';

7. 编译成es3

关于在IE低版本下运行,这里会遇到一些坑,另开一篇具体说说。

1
const es3ifyPlugin = require('es3ify-webpack-plugin');

好了,做完上述优化,你会发现时间上变化并不明显。。。其实最主要的还是需要DLL,拆分,分步。

webpack.optimize.CommonsChunkPlugin

1
2
3
4
5
6
7
8
entry中,
//需要配合下面的CommonsChunkPlugin才能把库文件从index中分类出来
vendor: ["vue", "vue-router", "axios"]
new CommonsChunkPlugin({
name: 'vendor',
filename: "vendor.js"
})

其他一些常用配置

package.json

npm run build

1
2
3
4
"scripts": {
"dev": "webpack-dev-server --inline --hot --quiet --host 127.0.0.1 --port 8300",
"build": "../node_modules/.bin/cross-env NODE_ENV=production DEBUG_ENV=online webpack --progress --hide-modules --colors --profile"
},

查看打包后的文件大小

http://alexkuz.github.io/webpack-chart/
webpack –json –profile > stats.json

webpack-dev-server

与webpack -w 的区别
webpack -w 增量打包,在界面不会有任何体现,需要手动刷新。

webpack-dev-server,基于express的8080 Node服务器。可以设置代理等等。
具有HMR(热替换), LiveReload(自动刷新整个页面)。
实时编译,在内存中的。比webpack -w更快。
打包的静态资源路径相对于publicPath,如果不设置,相对于当前目录下。publicPath的优先级高于content-base的

这里面有个content-base, 还没弄清楚干啥的??。。
content-base是webpack-dev-server的HTTP服务启动后的根目录。最直接的就是如何访问到那个index.html的途径,与其物理存放位置的关系。