1.前言
webpack
是一个将前端资源模块化打包的工具。借助该工具,我们在项目开发的过程中,可以更便宜的处理模块间的依赖关系。而commonjs
的模块和ES6的处理代码必须在浏览器使用前,经过webpack的构建。
模块会随着项目的进展而逐渐增多,随之webpack打包的时间也会加长。最近开发的项目,经过基本的优化,打包的时间已经超过120s
, 而改动代码后,至少也要10s
页面才能重新刷新。如此,开阿发效率大大降低。
2. CommonsChunkPlugin
分析了下(这儿可以贴张图),主要占打包资源的是依赖的React
,axios
、semantic-react-ui
等等引入的包依赖,在执行node webpack.config.js
的时候,所有的依赖都会重新打包一遍。之前我采用的是CommonsChunkPlugin
来对相同的模块,单独提取出来打包,进而减小rebuild的性能。
var config = {
// 入口文件
entry: {
app: ['./index.js'],
lib: [
'react', 'react-dom', 'react-router',
'redux', 'react-redux', 'redux-thunk'
],
},
output: {
path: './',
filename: '[name].js',
},
plugins: [
// 提取共同模块
new webpack.optimize.CommonsChunkPlugin({
names: ['lib', 'app']
}),
]
}
然而CommonsChunkPlugin
只在rebuild
的时候有一点效果,初次运行的时间仍然没有变。
网上搜索加上实际操作,终于让我找到了解决方法。
3. DLL & DllReference
DLL
DLL 插件不执行任何模块的代码,只是引入模块。最终导出一个可以用于通过id(内部引入函数)来引入模块的函数和一个被写入特殊位置的
manifest.json
文件,该文件包含实际请求到模块id的映射。
详细参考 dllplugin
该插件结合output.library
选项,使dll方法可以在全局范围内使用。
webpack.dll.js
new DllPlugin({
path: path.join(__dirname, "manifest.json"),
name: "[name]_[hash]",
context: __dirname
})
path
: manifest文件生成的位置,绝对路径name
: dll 方法的名称(与 output.library 保持一致)context (可选)
: manifest文件中请求(对模块的引入请求)的上下文环境,默认与webpack环境保持一致
DllReference
用于引用可用的dll函数,可通过
manifest
文件将模块名称映射到模块的id
。
该插件可用于配置DllPlugin
创建的dll
包和Manifest
文件。并且可以通过以下两种方式访问:作用域模式
dll 的内容可以通过一个模块的前缀访问。例如:假设
scope="xyz"
, 在 dll 中的abc
文件就可以通过require("xyz/abc")
来访问。映射模式
dll 的内容被映射到当前路径。如果通过
require
引入的文件名和dll中文件名(解析后)相匹配,那么将使用dll中的文件来。注意:由于这个过程是发生在解析后,所以dll用户必须可以访问到同一路径下的所有dll文件。例如:如果dll文件包含jquery
和文件abc
,require("jquery")
和requier("./abc")
将从dll文件中去获取。
详细参考 dllreferenceplugin
webpack.config.js
new DllReferencePlugin({
context: __dirname,
scope: "xyz",
manifest: require("./manifest.json"),
name: "./my-dll.js",
sourceType: "commonsjs2",
content: { ... }
})
context
: (absolute path) context of requests in the manifest (or content property)scope
(optional): prefix which is used for accessing the content of the dll
manifest (object): an object containing content and namename
(optional): the name where the dll is exposed (defaults to manifest.name) (see also externals)sourceType
(optional): the type how the dll is exposed (defaults to “var”) (see also externals)content
(optional): the mappings from request to module id (defaults to manifest.content)
4. 实际操作
在根目录单独建立一个
webpack.dll.js
var webpack = require('webpack') module.exports = { output: { path: './dll', filename: '[name].js', /** * output.library * 将会定义为 window.${output.library} * 在这次的例子中,将会定义为`window.vendor_library` */ library: '[name]_library', libraryTarget: 'commonjs2' }, entry: { // 入口,依赖的外部模块 vendor: [ 'react', 'react-dom', 'react-router', 'redux', 'react-redux', 'redux-thunk', 'semantic-ui-react', 'lodash', 'echarts', 'axios' ] }, plugins: [ new webpack.DllPlugin({ /** * path * 定义 manifest 文件生成的位置 * [name]的部分由entry的名字替换 */ path: './dll/[name]-manifest.json', /** * name * dll bundle 输出到那个全局变量上 * 和 output.library 一样即可。 */ name: '[name]', context: __dirname }) ] }
生成dll文件
执行
./node_modules/.bin/webpack --config build/webpack.config.js
。请在每次依赖的模块更改时重新执行这个命令
在
index.html
中引入dll文件这一步必不可少,之前因为少了这一步,一直报 vendor_library not defined
//这个模块的引入必须在自定义文件的入口之前 <script src="dist/dll/vendor.dll.js"></script>
webpack.config.js
var webpack = require('webpack') module.exports = { output: { path: __dirname, filename: '[name].bundle.js', }, entry: { app: ['./app.js'] }, plugins: [ new webpack.DllReferencePlugin({ context: __dirname, manifest: require('./dll/test-manifest.json'), sourceType: 'commonjs2', name: './dll/test.js' }) ] }
BugFixed
配置中常可能会出现的问题:
vendor not defined : 模块没有在html中引入,在根目录文件夹中加入script标签引入dll文件。
打包时间没有变快: 检查下
webpack.config.js
的context
是否和webpack.config.js
的一致,不一致的话保持一致,一般这个context的默认值是开发项目的根路径。