主要是打包优化方面
ignorePlugin
当不需要一个包的所有的功能的时候,可以忽略某些文件,手动引入对应的功能 安装
// 一个时间转换的插件,里面包含多种语言包的插件,导致插件很庞大
npm install moment
// index.js
import moment from 'moment'
moment.locale('zh-cn')
var r = moment().endOf('day').fromNow();
console.log(r)
可以查看打印效果,打印出来是中文
但尝试打包一下,整个index.js 500+kb,之前打包出来只有50+kb, 主要是因为把moment/locale
下所有的文件大欧
但我想只引入中文的文件,能不能不引入包里面所有的文件
配置
// webpack.config.js
let webpack = require('webpack')
module.exports = {
plugins: [
new webpack.ignorePlugin(/\.\/locale/, /moment/)
]
}
// index.js
import moment from 'moment'
// 手动引入
import 'moment/locale/zh-cn'
moment.locale('zh-cn')
var r = moment().endOf('day').fromNow();
console.log(r)
dllPlugin
动态链接库,能把某些大的库单独打包,单独用script引入,这样这些大的少变动的库,都不用在打包或者编译时重新打包编译
如,引用react
npm install react react-dom
// index.js
import React from 'react' // 引入react
import { render } from 'react-dom'
render(<h1>react</h1>, window.root)
新增webpack.react.congfig.js, 单独打包react
webpack.DllPlugin生成一个映射文件,与webpack.congfig.js的DllReferencePlugin形成关连,这样index.js引入react时,就会先去找manifest.json,有则不会再去打包进去
// webpack.react.congfig.js
let path = require('path')
let webpack = require('webpack')
module.exports = {
mode: 'development',
entry: {
react: ['react', 'react-dom'] // 要打包的第三方
},
output: {
filename: '_dll_[name].js', // 打包出来的文件名
path: path.resolve(__dirname, 'dist'),
library: '_dll_[name]', // 会承接(function(modules) {return XXX}) 返回的值
// libraryTarget: 'var' // umd var this commonjs
},
plugins: [
// 生成一个映射文件,与webpack.congfig.js的DllReferencePlugin形成关连,这样index.js引入react时,就会先去找manifest.json,有则不会再去打包进去
new webpack.DllPlugin({ // name == library
name: '_dll_[name]',
path: path.resolve(__dirname, 'dist', 'manifest.json')
})
]
}
配置好来后,执行
npx webpack --config webpack.react.config.js
打包后,会生成 _dll_react.js 以及manifest.json,
那怎么让主工程打包时,能用这个_dll_react.js,而不把react 打包到index.js 里面去呢
配置webpack.config.js 的 new webpack.DllReferencePlugin,与 webpack.DllPlugin形成关连
// webpack.config.js
module.exports = {
mode: "production",
// 多入口 单入口是字符串 ‘./src/index.js’
entry: {
index: './src/index.js',
},
devServer: {
open: true,
contentBase: './dist' // 启动服务时,文件去dist取得
},
output: {
filename: '[name].js', // 打包后的文件名
path: path.resolve(__dirname, 'dist')
},
plugins: [
...
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'manifest.json')
}),
],
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
}
]
}
}
重新打包主工程,你会发现index.js 很小,并不会把react都打包进去
最后在index.html 手动引入 打包出来的_dll_react.js
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document给对方</title>
</head>
<body>
<div id="root"></div>
<script src="/_dll_react.js"></script>
</body>
</html>
跑一下主工程
happypack
可以实现多线程打包,是第三方的包
npm install happypack
把之前写在rules的use的配置放到Happypack的use 中
// webpack.config.js
const Happypack = require('happypack')
module.exports = {
...
plugins: [
// css
new Happypack({
id: 'css',
use: ['style-loader', 'css-loader']
})
// js
new Happypack({
id: 'js',
use:[
{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
]
}),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'Happypack/loader?id=js' // 把之前
},
{
test: /\.css$/,
use: 'Happypack/loader?id=css'
}
]
}
}
打包,你会看到有3个进程进行打包,但是分配进程也会消耗性能,所以建议大的工程才采用这个方式,不然打包不快反而慢
noParse
不解析某个库的依赖库
module.exports = {
...
module: {
noParse: /jquery/
}
}
webpack 自带优化
1)import 在生产环境下 会自动的去掉没用的代码
别名tree-shaking
比如一个包export 出多个方法,但是实际项目里面只用到其中一个, 当打包模式是production, 它不会把没用的方法打包进去
2)如果用require,它不会去掉无用代码,而且会把导出的结果放到default 中去
let calc = require('./test')
console.log(calc.default.sum(1, 2))
3)scope hosting作用域提升
在webpack 中会自动省略一些可以简化的代码
抽离公共代码
多入口工程,抽离公共代码到一个模块 文件准备 新增common.js
function sum(a, b) {
return a + b
}
export default sum
other.js/index.js 都引入该模块
import sum from './common'
console.log(sum(3, 5))
配置多入口打包,此时打包,会发现,公共的用的代码都被打包到各自的文件中,整个项目来看是冗余了
那能不能,把公共的代码抽离成单独的文件出来
配置
module.exports = {
mode: "development",
optimization: {
splitChunks: { // 分割代码块
cacheGroups: { // 缓存组
common: {
chunks: 'initial', // 入口
minSize: 0, // 代码多大的时候就抽离
minChunks: 2, // 用过一次以上就抽离
},
}
}
},
}
打包完,则会发现多生成一个commonindexother.js,
里面有共用的sum 模块,
但,假如说,我会引用第三方的库,比如jquery,boostrap等,这些可以抽离成另一个库吗,
如果没有配置的话,默认也会打包到common~index~other.js
第三方库打包配置 other.js/index.js 都引入该模块
import sum from './common'
console.log(sum(3, 5))
import $ from 'jquery'
console.log($)
module.exports = {
mode: "development",
optimization: {
splitChunks: { // 分割代码块
cacheGroups: { // 缓存组
common: {
chunks: 'initial', // 从入口开始
minSize: 0, // 代码多大的时候就抽离
minChunks: 2, // 用过一次以上就抽离
},
vendor: {
priority: 1, // 权重,先抽离第三方,然后在去抽离common 公共代码块,不然会被全部都放到common
test: /node_modules/,
chunks: 'initial', // 入口
minSize: 0, // 代码多大的时候就抽离
minChunks: 2, // 用过一次以上就抽离
}
}
}
},
}
懒加载
可以控制某个点加载资源,而不是一开始全部都加载 文件准备 新建source.js
export default 'ZDFJ'
index.js,点击后加载source.js
let button = document.createElement('button')
button.addEventListener('click', function() {
// 草案中语法,通过jsonp实现动态加载文件
import('./source.js').then(function(data){
console.log(data)
})
})
document.body.append(button)
抛弃服务,点击按钮,则会发现加载0.js,打包后也会生成这个文件
热更新
不刷新页面,更新代码
文件准备
import str from './source'
if(module.hot) {
module.hot.accept('./source', ()=>{
console.log('文件更新了')
})
}
配置
module.exports = {
...
devServer: {
...
hot: true // 启动热更新
},
plugins: [
...
new webpack.HotModuleReplacementPlugin(), // 热更新插件
new webpack.NamedModulesPlugin(), // 打印热更新的路径
]
}
更改source的代码,你会看到页面没有刷新