了解了webpack的基本配置以后,接下来应该关注其优化策略。webpack
的优化策略对咱们的程序有着极大的性能提高。这是我记录学习webpack
优化的文章,纪录的同时也但愿分享给你们。css
在开发的过程当中,咱们会引入像react
、react-dom
这样的库,这样的库基本上每一次打包时它们的内容都不会改变,因此咱们引入动态连接库。将它们打包一次,在以后的构建过程当中它们就不会被打包,打包的模块也会使用动态连接库里面的代码而不是去node_modules
中取,这样咱们的构建速度就会大大提高。下面让咱们来看看webpack
中怎么构建动态连接库。html
咱们新建一个webpack.dll.config.js
的文件,配置以下node
const path = require('path')
const DllPlugin = require('webpack/lib/DllPlugin')
module.exports = {
entry:{
//将react、react-dom放到动态连接库中
react:['react','react-dom']
},
output:{
//输出的文件名称,[name]指的是当前动态连接库的名称,即react
filename:'[name].dll.js',
//输出到dist目录下
path:path.resolve(__dirname,'dist'),
//存动态连接库的全局变量名称,即_dll_react,加上_dll_防止全局变量冲突
library:'_dll_[name]',
},
plugins:[
new DllPlugin({
//动态连接库的全局变量名称,须要和library一致
name:'_dll_[name]',
path:path.join(__dirname,'dist','[name].manifest.json')
})
]
}
复制代码
下面执行命令npx webpack --config webpack.dll.config.js
,dist目录下多了两个文件,分别是react.dll.js
和react.manifest.json
react.dll.js
里面包含React
的基础运行环境,即react
、react-dom
模块。react.manifest. json
用于描述在动态连接库文件中包含哪些模块。react
而后再新建一个webpack.config.js
文件,在打包出来的chunk
块中声明须要引入的动态连接库,具体配置以下webpack
const path = require('path')
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin')
module.exports = {
entry: {
main: './main.js'
},
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'dist')
},
module:{
rules:[
]
},
plugins:[
new DllReferencePlugin({
manifest:require('./dist/react.manifest.json')
})
]
}
复制代码
执行命令npx webpack
,在dist
目录下生成bundle.js
。web
而后咱们在dist
目录下新建一个index.html
文件,引入打包构建出来的文件和动态连接库。json
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="./react.dll.js"></script>
<script src="./buncld.js"></script>
</body>
</html>
复制代码
当文件数量变多时,webpack
构建速度慢的问题会变得特别明显。可是运行在node
之上的webpack
是单线程的,不能同时处理多个任务。而HappyPack
可让webpack
作到这一点,它将任务分解成多个子进程去并发执行。因为JavaScript
是单线程模型,因此想要发挥多核CPU的做用只能经过多进程而不能经过多线程来实现。 接入HappyPack
的代码以下浏览器
const path = require('path')
const HappyPack = require('happypack');
module.exports = {
entry: {
main: './main.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.js$/,
//以babel为id,转交给happypack处理
use: ['happypack/loader?id=babel'],
},
{
test: /\.css$/,
//以css为id,转交给happypack处理
use: ['happypack/loader?id=css']
}
]
},
plugins: [
new HappyPack({
id: 'babel',
loaders: ['babel-loader']
}),
new HappyPack({
id: 'css',
loaders: ['style-loader','css-loader']
})
]
}
复制代码
执行构建命令 npx webpack
从命令行的输出能够看出HappyPack
已经生效bash
Happy[babel]: Version: 5.0.1. Threads: 3
Happy[babel]: All set; signaling webpack to proceed.
Happy[css]: Version: 5.0.1. Threads: 3
Happy[css]: All set; signaling webpack to proceed.
复制代码
为了提高网页的加载速度,能够对资源进行压缩。服务器
这里咱们会用到UglifyJS
,它经过去掉无效代码、去掉日志输出、缩短变量名,从而来优化咱们的代码。 简单的配置以下
const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin')
module.exports = {
//以上省略。。。
plugins: [
//压缩输出的 JavaScript 代码
new UglifyJSPlugin({
compress: {
//在 UglifyJS 删除没有用到的代码时不输出警告
warnings: false,
//删除全部 console 语句, 能够兼容IE浏览器
drop_console: true,
//内嵌己定义可是只用到一次 的变量
collapse_vars: true,
//提取出现了屡次可是没有定义成变量去 用的静态值
reduce_vars: true,
output: {
//最紧凑的输出
beautify: false,
//删除全部注释
comments: false,
}
}
})
]
复制代码
CSS
也能够向JavaScript
同样被压缩,这里用到的工具是cssnano
。cssnano
的意义不单单是删除空格,它能够理解CSS
代码。例如 margin:10px 20px 10px 20px
会被压缩为 margin:10px 20px
基本配置以下
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-plugin')
module.exports = {
//以上省略。。。。
module: {
rules: [{
test: /\.css$/,
use: [ExtractTextPlugin.extract({
use: ['style-loader', 'css-loader?minimize']
})]
}]
},
plugins:[
new HtmlWebpackPlugin({
template:'./index.html',
filename:'index.html'
}),
new ExtractTextPlugin({
filename: '[name]_[contenthash:8].css'
})
]
}
复制代码
若是将多个页面的公共代码抽离成单独的文件,就能优化一些问题。例如相同的资源被重复加载,浪费用户的流量和服务器的成本。每一个页面要加载的资源太大,致使网页首屏加载缓慢,影响用户体验。 基本配置以下,此配置主要针对多页面。单页就不存在于公共代码这一说法了。
import 'react'
import 'react-dom'
import './index.css' //每一个页面都用到的样式
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
module.exports = {
module: {
entry: './main.js',
rules: [{
test: /\.css$/,
use: [ExtractTextPlugin.extract({
use: ['style-loader', 'css-loader?minimize']
})]
}]
},
plugins: [
new CommonsChunkPlugin({
//从已有的common和base两个现成的chunks中提取公共部分
chunks: ['common', 'base'],
//将公共部分放到base中 这样配置以后 common会变小,由于公共部分都跑到了base里,而base不变
name: 'base'
})
]
}
复制代码
为了能使网页运行,以网页A为例,除了打包出来的A页面的JavaScrip
t代码还需引入公共部分代码
<script src= 'base.js'></script>
<script src='common.js'></script>
<script src='a.js'></script>
复制代码
单页应用首次渲染缓慢,一个很重要的缘由是一次性加载了全部功能对应的代码。这个时候若是采用按需加载,咱们网站的性能将会大大提高。 在webpac
k里,按需加载能够这样来写。例如咱们只打包出了一个bundle.js
。在bundle.js
中,有这么一段代码
window.document.getElementById('button').addEventListener('click',()=>{
import('./show').then(show=>{
show('webpack')
})
})
复制代码
在show.js
中
module.exports= function (content) {
window.aleat(`hello ${content}`)
}
复制代码
webpack
中内置了import
语句的支持,当遇到这样的语句时,首先会生成一个新的chunk
,而后触发import
的时候再去加载这个chunk
,返回的是一个Promise
对象,在加载成功时使用then
方法进行下面的操做,为了让webpack
正确打包chunk
,配置文件中需加入
output:{
//从entry打包生成的chunk
filename:'[name].js',
//动态加载生成的chunk
chunkFileName:'[name].js'
}
复制代码
webpack
的优化配置还有不少,这里只记录了我平时经常使用的,具体详情还请查阅官方文档。