0. 媒介
早在 2016 年我就宣布过一篇关于在多页面下运用 Webpack + Vue 的设置的文章,当时也是我在做本身一个个人项目时碰到的设置题目,想到他人也能够碰到跟我一样的题目,就把设置的思绪分享出来了,传送门在这里。
因为那份设置直到如今另有人在关注,同时近来公司协助项目晋级了 Webpack 4,乘隙也把之前的设置也晋级了一下,而且博客荒废了这么久,都快 9102 年了,不能比年均一篇博文都不到,所以有了下面的分享。
下面的设置主假如给在多页面下运用 Webpack 的同砚在晋级 Webpack 时供应一点思绪,多页面的设置思绪请点击上面的传送门。
下面代码的地点 https://github.com/cnu4/Webpack-Vue-MultiplePage
1. Webpack 晋级 4.x
1.1. 晋级和装置相干依靠
- webpack 晋级
- webpack-cli webapck4.x 须要新加的依靠
- mini-css-extract-plugin 庖代 extract-text-webpack-plugin
其他相干 loader 和 plugin
- css-loader
- file-loader
- url-loader
- vue-style-loader
- vue-template-compiler(注重要坚持与 vue 版本一向)
- html-webpack-plugin@next
1.2 修正设置
mode 构建形式
设置 mode 构建形式,比方 development 会将 process.env.NODE_ENV 的值设为 development
mini-css-extract-plugin
删除原 extract-text-webpack-plugin 设置,增添 mini-css-extract-plugin 设置
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].css'
}),
],
}
module.exports = {
module: {
rules: [
{
test:/\.vue$/,
loader: 'vue-loader',
},
{ test: /\.css$/,
use: [
// 开辟形式下运用 vue-style-loader,以便运用热重载
process.env.NODE_ENV !== 'production' ?
'vue-style-loader' : MiniCssExtractPlugin.loader,
'css-loader' ] },
]
}
}
optimization
这是 webpack 4 一个比较大的变动点,webpack 4 中删除了 webpack.optimize.CommonsChunkPlugin
,而且运用 optimization
中的splitChunk
来替换,下面的设置替代了之前的 CommonsChunkPlugin 设置,赞同能提取 JS 和 CSS 文件
module.exports = {
optimization: {
splitChunks: {
vendors: {
name: 'venders',
chunks: 'all',
minChunks: chunks.length
}
}
}
vue-loader 晋级
vue-loader 15 注重要合营一个 webpack 插件才准确运用
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
plugins: [ new VueLoaderPlugin() ]
}
html-webpack-plugin 晋级
晋级到 next
,不然开辟下没法一般注入资本文件
文件紧缩
- optimize-css-assets-webpack-plugin
- terser-webpack-plugin
紧缩的设置也挪动到了 optimization 选项下,值得注重的是紧缩东西换成了 terser-webpack-plugin,这是 webpack 官方也引荐运用的,预计在 webpack 5 中会变成默许的设置,实测打包速率确切变快了许多。
设置
module.exports = {
minimizer: [
new TerserPlugin({ // 紧缩js
cache: true,
parallel: true
}
}),
new OptimizeCSSAssetsPlugin({ // 紧缩css
cssProcessorOptions: {
safe: true
}
})
]
}
}
2. 打包速率优化
能够运用下面的插件看看打包时刻重要耗时在哪
2.1 相干 plugin 开启 parallel 选项
TerserPlugin 紧缩插件能够开启多线程,见上面设置
2.2 HappyPack 和 thread-loader 开启 Loader 多历程转换
github 的 Demo 中没有引入,有兴致的同砚能够尝试,在一些耗时的 Loader 确切能够进步速率
vue-loader 不支撑 HappyPack,官方发起用 thread-loader
const HappyPack = require('happypack');
exports.module = {
rules: [
{
test: /.js$/,
// 1) replace your original list of loaders with "happypack/loader":
// loaders: [ 'babel-loader?presets[]=es2015' ],
use: 'happypack/loader',
include: [ /* ... */ ],
exclude: [ /* ... */ ]
}
]
};
exports.plugins = [
// 2) create the plugin:
new HappyPack({
// 3) re-add the loaders you replaced above in #1:
loaders: [ 'babel-loader?presets[]=es2015' ]
})
];
2.3 提早打包大众代码
DllPlugin
运用 DllPlugn 将 node_modules 或许本身编写的不常变的依靠包打一个 dll 包,进步速率和充分利用缓存。相当于 splitChunks 提取了大众代码,但 DllPlugn 是手动指定了大众代码,提早打包好,免去了后续 webpack 构建时的从新打包。
起首须要增添一个 webpack 设置文件 webpack.dll.config.js
特地针对 dll 打包设置,个中用到 webpack.DllPlugin
。
实行 webpack --config build/webpack.dll.config.js
后,webpack会自动天生 2 个文件,个中vendor.dll.js 即兼并打包后第三方模块。别的一个 vendor-mainifest.json 存储各个模块和所需公用模块的对应关联。
接着修正我们的 webpack 设置文件,在 plugin 设置中增添 webpack.DllReferencePlugin
,设置中指定上一步天生的 json 文件,然后手动在 html 文件中援用上一步的 vendor.dll.js 文件。
背面假如增删 dll 中的依靠包时都须要手动实行上面打包敕令来更新 dll 包。下面插件能够自动完成这些操纵。
AutoDllPlugin
装置依靠 autodll-webpack-plugin
AutoDllPlugin 自动同时相当于完成了 DllReferencePlugin 和 DllPlugin 的事情,只须要在我们的 webpack 中增加设置。AutoDllPlugin 会在实行 npm install / remove / update package-name
或转变这个插件配件时从新打包 dll。须要注重的是转变 dll 中指定的依靠包不会触发自动从新打包 dll。
现实打包中天生环境是没题目的,但开辟形式下在有缓存的情况下,autodll 插件不会天生新的文件,致使 404,所以在 Demo 中临时关了这个插件。不过 dll 提早打包了大众文件,确切能够进步打包速率,有兴致的同砚能够研讨下开辟形式下的缓存题目,迎接在批评中分享。
module.exports.plugins.push(new AutoDllPlugin({
inject: true, // will inject the DLL bundles to html
context: path.join(__dirname, '.'),
filename: '[name].dll.js',
debug: true,
inherit: true,
// path: './',
plugins: [
new TerserPlugin({
cacheL true,
parallel: true
}),
new MiniCssExtractPlugin({
filename: '[name].css'
})
],
entry: {
vendor: ['vue/dist/vue.esm.js', 'axios', 'normalize.css']
}
}));
3. 增添 ES6+ 支撑
3.1 装置依靠
- @babel/core
- @babel/plugin-proposal-class-properties
- @babel/plugin-proposal-decorators
- @babel/plugin-syntax-dynamic-import
- @babel/plugin-transform-runtime
- @babel/preset-env
- @babel/runtime
- babel-loader
- @babel/polyfill
因为项目中是第一次设置 babel,一步到位直接运用新版 7,新版 babel 运用新的定名空间 @babel,假如是老项目晋级 babel 7,能够运用东西 babel-upgrade,读一下 晋级文档
这里说下上面依靠的作用和晋级 babel 7 的修改。
@babel/runtime, @babel/plugin-transform-runtime
新版中 @babel/runtime 只包含了一些 helpers,假如须要 core-js polyfill 浏览器不支撑的 API,能够用 transform 供应的选项 {"corejs": 2}
并装置依靠 @babel/runtime-corejs2
。纵然默许的 polyfill 没了,但 @babel/plugin-transform-runtime 依旧能够为我们星散辅佐函数,削减代码体积
@babel/polyfill
运用 @babel/runtime 的 polyfill 不会污染全局 API,因为不会修改原生对象的原型,它只是建立一个辅佐函数在当前作用于见效,所以诸如 [1, 2].includes(1)
如许的语法也没法被 polyfill。假如不是开辟第三方库,能够运用 @babel/polyfill,相反他的 polyfill 会影响到浏览器全局的对象原型
@babel/preset-env 供应了一个 useBuiltIns 选项来按需引入 polyfill,而不须要引入悉数。另一种方法是直接援用 core-js 包下的特定 polyfill。
stage presets
如今须要手动装置 @babel/plugin-proposal 开首的依靠是因为 babel 在新版中移除了 stage presets,为的是后续更好保护处于 proposal 阶段的语法。想要运用 proposal 阶段的语法须要零丁援用对应的 plugin, 上面的设置只加了几个处于 stage 3 阶段的 plugin,老项目发起运用 babel-upgrade 晋级,自动增加依靠
3.2 增加设置文件 .babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"targets": {
"browsers": [
"> 1%",
"last 2 versions",
"ie >= 11"
]
},
"useBuiltIns": "usage" // 按需引入 polyfill
}
]
],
"plugins": [
"@babel/plugin-transform-runtime",
"@babel/plugin-syntax-dynamic-import",
["@babel/plugin-proposal-class-properties", { "loose": false }],
["@babel/plugin-proposal-decorators", { "legacy": true }],
]
}
3.3 增添 webpack 设置
module.exports = {
modules: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
}
}
4. 其他题目
下面是我公司项目中碰到的题目,列位晋级过程当中假如碰到一样的题目能够参考一下处置惩罚思绪。
4.1 json-loader
webpack4 内置的json-loader 有点兼容性题目,装置 json-loader 依靠和变动设置
处置惩罚:
{
test: /\.json$/, //用于婚配loaders所处置惩罚文件拓展名的正则表达式
use: 'json-loader', //详细loader的称号
type: 'javascript/auto',
exclude: /node_modules/
}
4.2 vue-loader
vue-loader 晋级到 15.x 后,会致使旧的 commonjs 写法加载有题目,须要运用 require('com.vue').default
的体式格局援用组件
13的版本还能够设置 esModule,14 今后的版本不能设置了,vue 文件导出的模块一定是 esModule
处置惩罚:运用 require('com.vue').default
或许 import
的体式格局援用组件
esModule option stopped working in version 14 · Issue #1172 · vuejs/vue-loader · GitHub
尤大大发起能够本身写一个 babel 插件,碰到 require vue 文件的时刻自动加上 default 属性,如许就不必修改一切代码,我们在项目中也是如许处置惩罚的。
4.3 提取大众 css 代码
scss 中 import 的代码不能被提取到大众 css 中。scss 中的 @import 是运用 sass-loader 处置惩罚的,处置惩罚后已变成 css 文件,webpack 已不能推断是不是是同一个模块,所以不能提取到大众的 css 中,但多页面中我们照样愿望一些大众的 css 能被提取到大众的文件中。
处置惩罚:将须要提取到大众文件的 css 改到 js 中引入就能够,详见下面 issue
mini-css-extract-plugin + sass-loader + splitChunks · Issue #49
4.4 mini-css-extract-plugin filename 不支撑函数
mini-css-extract-plugin 的 filename 选项不支撑函数,但我们有时刻照样愿望能零丁掌握大众 css 文件的位置,而不是和其他进口文件的 css 运用一样的目次花样
处置惩罚:运用插件 FileManagerPlugin 在构建后挪动文件,等 filename 支撑函数后再优化