返回介绍

六、webpack 实战场景

发布于 2024-09-07 12:28:44 字数 11382 浏览 0 评论 0 收藏 0

6.1 分析打包结果

http://blog.poetries.top/2018/11/20/webpack-bundleAnalyzer/

6.2 优化打包速度

6.2.1 方法一:分开 vendor 和 app

分开第三方代码和业务代码,借助 DllPluginDllReferencePlugin

之前的打包时间

现在我们来优化这个时间

第一步:新建 webpack.dll.conf.js

// build/webpack.dll.conf.js

const path = require('path')
const webpack = require('webpack')

module.exports = {
entry: {
// 把这些资源打包成 dll,提高编译速度
react: ['react','react-router-dom','redux','redux-immutable','immutable','react-redux','react-router','redux-logger','redux-thunk','styled-components'],
ui: ['antd-mobile','antd'],
others: ['react-icons','axios','clipboard','humps','lodash','md5','moment','normalizr']
},
output: {
path: path.resolve(__dirname, "../dll/"),
filename: '[name].dll.js',
library: '[name]'
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname,'../dll/','[name]-manifest.json'),
name: '[name]'
}),
new webpack.optimize.UglifyJsPlugin()
]
}

第二步:加一个命令

// package.json
"scripts": {
"dll": "webpack --config config/webpack.dll.conf.js"
}

执行 npm run dll

第三步: 在 plugins 中增加配置

// build/webpack.prod.conf.js
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: require('../dll/react-manifest.json')
}),
new webpack.DllReferencePlugin({
manifest: require('../dll/ui-manifest.json')
}),
new webpack.DllReferencePlugin({
manifest: require('../dll/others-manifest.json')
})
]
}

再次执行 npm run build

编译时间大大减少了

6.2.2 方法二:UglifyJsPlugin 并行处理

UglifyJsPlugin

  • parallel
  • cache
// build/webpack.prod.conf.js
module.exports = {
plugins: [
new UglifyJsPlugin({
parallel:true, //并行处理
cache: true
})
]
}

6.2.3 方法三:happyPack

happyPack 把所有串行的东西并行处理,使得 loader 并行处理,较少文件处理时间

https://www.npmjs.com/package/happypack

// build/webpack.prod.conf.js

// @file: webpack.config.js
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: [ /* ... */ ]
}
],
plugins: [
// 2) create the plugin:
new HappyPack({
// 3) re-add the loaders you replaced above in #1:
loaders: [ 'babel-loader?presets[]=es2015' ]
})
]
}

这时的编译时间也减小了一些

6.2.4 方法四:较少 babel-loader 编译时间

babel-loader

开启缓存,指定编译范围

  • options.cache
  • include
  • exclude

6.2.5 其他

  • 减少 resolve
  • Devtool 去除 sourcemap
  • cache-loader
  • 升级 node
  • 升级 webpack

6.3 长缓存优化

场景

改变 app 代码, vendor 变化

解决

  • 提取 vendor
  • hash –> chunkhash (把 hash 变为代码块的 hash ,而不是文件的 hash )
  • 提取 webpack runtime
output: {
path: path.resolve(__dirname, '../build/'),
filename: 'static/js/[name].[chunkhash:5].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
publicPath: '/' //浏览器中访问资源的路径
}

每次打包 vendor 都不会变化,这样就达到了缓存的目的(服务端开启 cache-ctrol

场景:引入新模块,模块顺序变化,vendor hash 变化

解决: NamedChunksPlugin NamedModulesPlugin

对于动态模块引入需要给名称

6.4 多页面应用

6.4.1 多页面特点

  • 多入口
  • 多页面 HTML
  • 每个页面不同的 chunk
  • 每个页面不同的参数

6.4.2 多页面多配置

wepback 从 3.1.0 开始支持

优点

  • 可以使用 parallel-webpack (并行处理多份配置) 提高打包速度
    • 配置更独立、灵活

缺点

  • 不能多页面之间共享代码
//package.json

{
"name": "多页面配置",
"version": "0.1.0",
"private": true,
"dependencies": {
"clean-webpack-plugin": "^1.0.0",
"css-loader": "^1.0.1",
"ejs-loader": "^0.3.1",
"file-loader": "^2.0.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"react": "^16.3.1",
"style-loader": "^0.23.1",
"webpack": "^4.26.0",
"webpack-merge": "^4.1.4"
},
"scripts": {},
"devDependencies": {
"extract-text-webpack-plugin": "^4.0.0-beta.0"
}
}
/**
* 多页面多配置
* @type {[type]}
*/

const merge = require('webpack-merge')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpack = require('clean-webpack-plugin')
const ExtractTextwebpack = require('extract-text-webpack-plugin')

const path = require('path')

const baseConfig = {
mode: 'development',
entry: {
react: 'react'
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextwebpack.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[chunkhash].js'
},
plugins: [
new ExtractTextwebpack({
filename: 'css/[name].[hash].css'
}),
new CleanWebpack(['./dist'])
],
optimization: {
splitChunks: {
cacheGroups: {
commons: {
// commons 里面的 name 就是生成的共享模块 bundle 的名字
name: "react",
// chunks 有三个可选值,”initial”, “async” 和 “all”. 分别对应优化时只选择初始的 chunks,所需要的 chunks 还是所有 chunks
chunks: "initial",
minChunks: Infinity
}
}
}
}
}

//生成每个页面配置
const generatePage = function({
title = '',
entry = '',
template = './src/index.html',
name = '',
chunks = []
} = {}){
return {
entry,
plugins: [
new HtmlWebpackPlugin({
chunks,
template:`!!html-loader!${template}`,
filename: name + '.html'
})
]
}
}

const pages = [
generatePage({
title: 'page A',
entry: {
a: './src/pages/a'
},
name: 'a',
chunks: ['react','a']
}),
generatePage({
title: 'page B',
entry: {
b: './src/pages/b'
},
name: 'b',
chunks: ['react','b']
}),
generatePage({
title: 'page C',
entry: {
c: './src/pages/c'
},
name: 'c',
chunks: ['react','c']
})
]

module.exports = pages.map(page=>merge(baseConfig, page))

6.4.3 多页面单配置

多个页面共享一个配置

  • 优点:可以共享各个 entry 之间公用代码
  • 缺点:打包速度比较慢,输出的内容比较复杂
/**
* 多页面单配置
*/

const merge = require('webpack-merge')
const webpack = require('webpack')
const HtmlWbpackPlugin = require('html-webpack-plugin')
const CleanWebpack = require('clean-webpack-plugin')
const ExtractTextwebpack = require("extract-text-webpack-plugin")

const path = require('path')

const baseConfig = {
mode: 'development',
entry: {
react: 'react'
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextwebpack.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[chunkhash].js'
},
plugins: [
new ExtractTextwebpack({
filename: 'css/[name].[hash].css'
}),
new CleanWebpack(path.resolve(__dirname, 'dist'))
],
optimization: {
splitChunks: {
cacheGroups: {
commons: {
// commons 里面的 name 就是生成的共享模块 bundle 的名字
name: "react",
// chunks 有三个可选值,”initial”, “async” 和 “all”. 分别对应优化时只选择初始的 chunks,所需要的 chunks 还是所有 chunks
chunks: "initial",
minChunks: Infinity
}
}
}
}
}

//生成每个页面配置
const generatePage = function({
title = '',
entry = '',
template = './src/index.html',
name = '',
chunks = []
} = {}){
return {
entry,
plugins: [
new HtmlWbpackPlugin({
chunks,
template:`!!html-loader!${template}`,
title,
filename: name + '.html'
})
]
}
}

const pages = [
generatePage({
title: 'page A',
entry: {
a: './src/pages/a'
},
name: 'a',
chunks: ['react','a']
}),
generatePage({
title: 'page B',
entry: {
b: './src/pages/b'
},
name: 'b',
chunks: ['react','b']
}),
generatePage({
title: 'page C',
entry: {
c: './src/pages/c'
},
name: 'c',
chunks: ['react','c']
})
]

module.exports = merge([baseConfig].concat(pages))

完整例子 https://github.com/poetries/webpack-config-demo

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文