# 速度优化
减小文件搜索范围
- 配置
resolve.modules
:
Webpack 的
resolve.modules
配置模块库(即 node_modules)所在的位置,在 js 里出现import 'vue'
这样不是相对、也不是绝对路径的写法时,会去 node_modules 目录下找。但是默认的配置,会采用向上递归搜索的方式去寻找,但通常项目目录里只有一个 node_modules,且是在项目根目录,为了减少搜索范围,可以直接写明node_modules
的全路径;同样,对于别名(alias
)的配置,亦当如此:function resolve (dir) { return path.join(__dirname, '..', dir) } module.exports = { resolve: { extensions: ['.js', '.vue', '.json'], modules: [ resolve('src'), resolve('node_modules') ], alias: { 'vue$': 'vue/dist/vue.common.js', 'src': resolve('src'), 'assets': resolve('src/assets'), 'components': resolve('src/components'), // ... 'store': resolve('src/store') } }, ... }
需要额外补充一点的是,这是 Webpack2.* 以上的写法。在 1.* 版本中,使用的是
resolve.root
,如今已经被弃用为resolve.modules
;同时被弃用的还有resolve.fallback
、resolve.modulesDirectories
。- 设置 test & include & exclude
Webpack 的装载机(loaders),允许每个子项都可以有以下属性: + test:必须满足的条件(正则表达式,不要加引号,匹配要处理的文件) + exclude:不能满足的条件(排除不处理的目录) + include:导入的文件将由加载程序转换的路径或文件数组(把要处理的目录包括进来) + loader:一串“!”分隔的装载机(2.0版本以上,”-loader”不可以省略) + loaders:作为字符串的装载器阵列
对于
include
,更精确指定要处理的目录,这可以减少不必要的遍历,从而减少性能损失。同样,对于已经明确知道的,不需要处理的目录,则应该予以排除,从而进一步提升性能。假设你有一个第三方组件的引用,它肯定位于 node_modules,通常它将有一个 src 和一个 dist 目录。如果配置 Webpack 来排除 node_modules,那么它将从 dist 已经编译的目录中获取文件。否则会再次编译它们。故而,合理的设置 include & exclude,将会极大地提升 Webpack 打包优化速度,比如像这样:module: { preLoaders: [ { test: /\.js$/, loader: 'eslint', include: [resolve('src')], exclude: /node_modules/ }, { test: /\.svg$/, loader: 'svgo?' + JSON.stringify(svgoConfig), include: [resolve('src/assets/icons')], exclude: /node_modules/ } ], loaders: [ { test: /\.vue$/, loader: 'vue-loader', include: [resolve('src')], exclude: /node_modules\/(?!(autotrack|dom-utils))|vendor\.dll\.js/ }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url', exclude: /assets\/icons/, query: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') } } ] }
- 配置
设置 babel 的 cacheDirectory 为 true
babel-loader
is slow! 所以不仅要使用exclude
、include
,尽可能准确的指定要转化内容的范畴,而且要充分利用缓存,进一步提升性能。babel-loader
提供了cacheDirectory
特定选项(默认 false):设置时,给定的目录将用于缓存加载器的结果。未来的 Webpack 构建将尝试从缓存中读取,以避免在每次运行时运行潜在昂贵的 Babel 重新编译过程。如果值为空(loader: ‘babel-loader?cacheDirectory’)或true(loader: babel-loader?cacheDirectory=true),则 node_modules 在任何根目录中找不到任何文件夹时,加载程序将使用默认缓存目录(
node_modules/.cache/babel-loader
)或回退到默认的 OS 临时文件目录。实际使用中,效果显著;配置示例如下:rules: [ { test: /\.js$/, loader: 'babel-loader?cacheDirectory=true', exclude: /node_modules/, include: [resolve('src'), resolve('test')] }, ... ... ]
用 Happypack 来加速代码构建
设置 noParse
如果你确定一个模块中,没有其它新的依赖,就可以配置这项,Webpack 将不再扫描这个文件中的依赖,这对于比较大型类库,将能促进性能表现,具体可以参见以下配置:
module: { noParse: /node_modules\/(element-ui\.js)/, rules: [ { ... } ] }
拷贝静态文件
引入
DllPlugin
和DllReferencePlugin
提前构建一些第三方库,优化 Webpack 打包。而在生产环境时,就需要将提前构建好的包,同步到 dist 中;这里拷贝静态文件,你可以使用copy-webpack-plugin
插件:把指定文件夹下的文件复制到指定的目录;其配置如下:var CopyWebpackPlugin = require('copy-webpack-plugin') plugins: [ ... // copy custom static assets new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../static'), to: config.build.assetsSubDirectory, ignore: ['.*'] } ]) ]
# 体积优化
定位 webpack 体积大的原因
推荐使用
webpack-bundle-analyzer
—— Webpack 插件和 CLI 实用程序,它可以将内容束展示为方便交互的直观树状图,让你明白你所构建包中真正引入的内容;我们可以借助她,发现它大体有哪些模块组成,找到不合时宜的存在,然后优化它。我们可以在项目的 package.json 文件中注入命令"analyz": "NODE_ENV=production npm_config_report=true npm run build"
,以方便运行(npm run analyz),默认会打开 http://127.0.0.1:8888 作为展示。同类型的还有 webpack-chart (opens new window) 以及 webpack-analyse (opens new window),这两个站点也是以可视方式呈现构造的组件,可以让你清楚的看到模块的组成部分;不过稍显麻烦的是,你需要运行以下命令,生成工具分析所需要的 json 文件:
webpack --profile --json > stats.json // 如果,运行指定的 webpack 文件,可用此命令 webpack --config build/webpack.prod.conf.js --profile --json > stats.json
引入 DllPlugin 和 DllReferencePlugin
外部引入模块(CDN)
让每个第三包“引有所值”
- 确定引入的必要性
- 避免类库引而不用
- 尽量使用模块化引入
- 尽可能引入更合适的包
按需异步加载模块
生产环境,压缩混淆并移除 console
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, drop_console: true, pure_funcs: ['console.log'] }, sourceMap: false })
Webpack3 新功能: Scope Hoisting
Webpack在 3.0+ 版本,提供了一个新的功能:
Scope Hoisting
,又译作“作用域提升”。只需在配置文件中添加一个新的插件,就可以让 Webpack 打包出来的代码文件更小、运行的更快:module.exports = { plugins: [ new webpack.optimize.ModuleConcatenationPlugin() ] }