vue项目的webpack构建优化
vue项目的webpack构建优化值得一提的是,在说webpack的速度优化之前,按需加载和按需引入,是你先要做好的,之后再说速度优化的问题。按需加载,参考:https://segmentfault.com/a/1190000011519350对参考博客中的一些问题的补充,当前router.js中代码为const Index = () => import('@/compo...
vue项目的webpack构建优化
值得一提的是,在说webpack的速度优化之前,按需加载和按需引入,是你先要做好的,之后再说速度优化的问题。
按需加载,参考:https://segmentfault.com/a/1190000011519350
对参考博客中的一些问题的补充,
当前router.js中代码为
const Index = () => import('@/components/Index')时,
路由比较多,一个个修改太费劲,这个时候可以试一下,sublime有个很强大的功能,可以根据正则替换匹配的代码。
^const\s+(\w+)\s+.*@(.*)'\)
const $1 = () => import(/* webpackChunkName: "$1" */ '@$2')
还有一个有趣的功能,正常情况下你npm run build 编译好的js是这样的:
在本地测试的时候,我想知道js具体对应那些模块,调试的时候会更得心应手,这个时候,只需要改一下 .babelrc和 webpack.prod.conf.js这两个文件。
在.babelrc中,
{
"presets": [
["env", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime"],
"comments": false, // 此项设置为true
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}
在 webpack.prod.conf.js中
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
修改为
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[name].js')
},
修改这两项之后,重新npm run build编译,js则会显示为
js文件的名称是对应模块的名称。
一. webpack-parallel-uglify-plugin插件
1. webpack提供的UglifyJS插件由于采用单线程压缩,速度很慢 , webpack-parallel-uglify-plugin插件可以并行运行UglifyJS插件,这可以有效减少构建时间。
2. 修改webpack.prod.conf.js文件
var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')// 删掉webpack提供的UglifyJS插件
// new webpack.optimize.UglifyJsPlugin({
// compress: {
// warnings: false
// },
// output: {
// comments: false,
// },
// sourceMap: true
// }),
// 增加 webpack-parallel-uglify-plugin来替换
new ParallelUglifyPlugin({ cacheDir: '.cache/', uglifyJS:{ output: { comments: false }, compress: { warnings: false } }})
二. 换用happypack多进程构建
webpack的构建毕竟还是单进程的。采用happypack可以改为多进程构建。而对于小文件而言,happypack效果并不明显。而对于babel-loader编译的庞大的js文件群来说,则是一大利器。
首先安装:npm install happypack --save-dev或者yarn add happypack
然后修改webpack.base.conf.js的配置如下:
module.exports = {
plugins: [
new HappyPack({
id: 'js',
cache: true,
loaders: ['babel-loader?cacheDirectory=true'],
threadPool: happThreadPool
})
],
... // 其他配置
module: {
... // 其他配置
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
js: 'happypack/loader?id=js' // 将loader换成happypack
}
}
},
{
test: /\.js$/,
loader: ['happypack/loader?id=js'], // 将loader换成happypack
include: [resolve('src'), resolve('node_modules/jsdom')], // src是项目开发的目录
}
]
}
}
三. webpack 3.x webpack3新特性一览 https://juejin.im/entry/5971483951882552681c4a30
1. webpack 3.x 提供了一个新的功能:Scope Hoisting,又译作“作用域提升”。只需在配置文件中添加一个新的插件,就可以让 Webpack 打包出来的代码文件更小、运行的更快。
注意:使用这个方法的前提是webpack版本必须是3.x
2. 修改webpack.prod.conf.js
......plugins: [ // 往plugins添加一个配置 // ps 只针对es6的模块化有效 new webpack.optimize.ModuleConcatenationPlugin(),]
再次需要注意的地方,升级webpack,需要把一些附属插件也升级到相对应的版本
四.DllPlugin和DllReferencePlugin
对于文件大小有很高要求的话,不推荐用dll,但dll对于速度的提升还是很明显的。
Dll打包以后是独立存在的,只要其包含的库没有增减、升级,hash也不会变化,因此线上的dll代码不需要随着版本发布频繁更新。使用Dll打包的基本上都是独立库文件,这类文件有一个特性就是变化不大。只要包含的库没有升级, 增减,就不需要重新打包。这样也提高了构建速度。而且也具有可移植性,如果其他项目需要相同的库,可以直接copy过去。
1.在build文件夹下新建webpack.dll.conf.js文件
var path = require('path')
var webpack = require('webpack')
var AssetsPlugin = require('assets-webpack-plugin')
var CleanWebpackPlugin = require('clean-webpack-plugin')
var config = require('../config')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var env = config.build.env
module.exports = {
entry: {
libs: [
'vue/dist/vue.esm.js',
'vue-router',
'vuex',
'iview',
"fabric",
"echarts",
"moment",
"numeral",
"lodash"
],
},
output: {
path: path.resolve(__dirname, '../libs'),
filename: '[name].[chunkhash:7].js',
library: '[name]_library',
},
plugins: [
new webpack.DefinePlugin({
'process.env': env,
}),
new webpack.DllPlugin({
path: path.resolve(__dirname, '../libs/[name]-mainfest.json'),
name: '[name]_library',
context: __dirname, // 执行的上下文环境,对之后DllReferencePlugin有用
}),
new ExtractTextPlugin('[name].[contenthash:7].css'),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
}),
new AssetsPlugin({
filename: 'bundle-config.json',
path: './libs',
}),
new CleanWebpackPlugin(['libs'], {
root: path.join(__dirname, '../'), // 绝对路径
verbose: true,
dry: false,
}),
],
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
},
],
},
}
2.在build文件夹下新建build-dll.js文件
var path = require("path")
var webpack = require("webpack")
var dllConfig = require("./webpack.dll.conf")
var chalk = require("chalk")
var rm = require("rimraf")
var ora = require("ora")
var spinner = ora({
color: "green",
text: "building for Dll..."
})
spinner.start()
rm(path.resolve(__dirname, "../libs"), err => {
if (err) throw err
webpack(dllConfig, function(err, stats) {
spinner.stop()
if (err) throw err
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + "\n\n"
)
console.log(chalk.cyan(" build dll succeed !.\n"))
})
})
3.修改webpack.prod.conf.js文件(忽略其他配置)
var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var bundleConfig = require("../libs/bundle-config.json")
plugins: [
// 增加DllReferencePlugin配置
// new webpack.DllReferencePlugin({
// context: __dirname,
// manifest: require("../libs/libs-mainfest.json") // 指向生成的manifest.json
// }),
new HtmlWebpackPlugin({
// 增加两个变量
// libJsName: bundleConfig.libs.js,
// libCssName: bundleConfig.libs.css,
},
}),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// copy custom static assets
new CopyWebpackPlugin([
// 添加
// {
// from: path.resolve(__dirname, "../libs"),
// to: config.build.assetsSubDirectory,
// ignore: ["*.json"]
// }
])
]
})
4.修改模版文件index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<% if (htmlWebpackPlugin.options.libCssName){ %>
<link rel="stylesheet" href="./static/<%=htmlWebpackPlugin.options.libCssName %>"><% } %>
<title>善贾</title>
<% if (htmlWebpackPlugin.options.libJsName){ %>
<script src="./static/<%= htmlWebpackPlugin.options.libJsName %>"></script>
<% } %>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
5.修改package.json,增加scripts
"scripts": {
// 添加
"build:dll": "node build/build-dll.js"
}
6.执行,先执行npm run build:dll ,之后在执行npm run build
五.HardSourceWebpackPlugin(模块缓存)rebuild +++
这也算是webpack中的一个神器,官方给出的编译速度提升率大概在70%,但实际效果远远高于此,
1.修改webpack.prod.conf.js文件(忽略其他配置)
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
plugins: [
// 添加
new HardSourceWebpackPlugin({
// Either an absolute path or relative to webpack's options.context.
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
// Either an absolute path or relative to webpack's options.context.
// Sets webpack's recordsPath if not already set.
recordsPath: 'node_modules/.cache/hard-source/[confighash]/records.json',
// Either a string of object hash function given a webpack config.
configHash: function(webpackConfig) {
// node-object-hash on npm can be used to build this.
return require('node-object-hash')({sort: false}).hash(webpackConfig);
},
// Either false, a string, an object, or a project hashing function.
environmentHash: {
root: process.cwd(),
directories: [],
files: ['package-lock.json', 'yarn.lock'],
}
})
]
六.css-loader的版本 (build++,rebuild++)
css-loader是webpack中对css模块的处理。
降低css-loader的版本,虽然简单,但是对于速度的提升确是很多的。
对于css-loader来说,版本超过0.15.*,编译的速度会慢很多,所以一般推荐0.14.*,不要超过0.15.*,速度会提升50%左右,具体速度提升,看项目代码情况。
七.cache(缓存)
当代码不曾改变时,webpack会优先从缓存中读取所需数据,若查询不到相关数据,才会再次编译。
1.webpack的cache默认为false,在webpack.base.conf.js中
module.exports = {
cache: true
// 其他配置
}
2.设置 babel 的 cacheDirectory 为true,在webpack.base.conf.js中
module: {
exprContextCritical: false,
rules: [
... // 其他配置
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory=true',
include: [resolve('src'), resolve('test')]
}
]
}
八.happypack
相对于node的单线程执行,无疑,多线程并行执行,速度会有所提升,而happypack就是webpack中的一个插件,目的是通过多进程模型,来加速代码构建。
1.在webpack.base.conf.js中
// 添加
var os = require('os')
var HappyPack = require('happypack')
// 根据电脑的cpu判断线程数
var happThreadPool = HappyPack.ThreadPool({size: os.cpus().length})
module.exports = {
plugins: [
// 线程池初始化
new HappyPack({
id: 'js',
cache: true,
loaders: ['babel-loader?cacheDirectory=true'],
threadPool: happThreadPool
})
],
}
// 修改
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/jsdom')]
}
// 为
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
js: 'happypack/loader?id=js' // 将loader换成happypack
}
}
},
{
test: /\.js$/,
loader: ['happypack/loader?id=js'], // 将loader换成happypack
include: [resolve('src'), resolve('node_modules/jsdom')], // src是项目开发的目录
},
九.使用resolve=> alias
在webpack.base.conf.js中
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'assets': path.resolve(__dirname, '../src/assets')
}
}
在alias中尽量使用别名,
resolve: { alias: { jquery: "./scripts/jquery.min.js"}}
在模块中使用 。 import 。jquery from 'jquery',这样也是可以缩短编译时间,
而且要善于利用alias中定义的别名,尽量使用这些别名,
例如:@
import Utils from '@/tool/Utils'
这些别名的使用,对于编译时间是有所缩短的。
既然说到这了,在这里也提一下,在css中使用@别名的方法。
当在css中直接使用定义的别名时,会报错,
原因是 css 文件会被用 css-loader 处理,这里 css @import 后的字符串会被 css-loader 视为绝对路径解析,因为我们并没有添加 css-loader 的 alias,所以会报找不到 @ 目录。
解决方式:(引用这种加~的路径时,必须使用了css预处理器。例如sass,less等,是否可用,并未实测)
在 Webpack 中 css import 使用 alias 相对路径的解决办法有两种(推荐第二种方法)
一是直接为 css-loader 添加 ailas 的路径,但是在 vue-webpack 给的模板中,单独针对这个插件添加配置就显得麻烦冗余了;
二是在引用路径的字符串最前面添加上 ~ 符号,如 @import "~@/style/theme";Webpack 会将以 ~ 符号作为前缀的路径视作依赖模块而去解析,这样 @ 的 alias 配置就能生效了。
以上是我在项目中遇到的一些问题,通过参考一些博客,和在项目中的测试,总结出来的一些方法。
更多推荐
所有评论(0)