文章内容输出来源:拉勾大前端高薪训练营
- HMR
- 引入背景
- webpack-dev-server自动刷新的问题
- 自动刷新导致页面状态丢失
- 期望的结果
- 页面不刷新的前提下,模块也可以及时更新
- 计算机行业经常听到热拔插的名词
- 在一个正在运行的机器上随时插拔设备,机器运行状态不受影响,插上的设备可以立即开始工作
- 全称
- Hot Module Replacement
- 模块热替换
- 应用运行过程中实时替换某个模块,应用运行状态不收影响
- 是webpack中最强大的功能之一
- 极大程度提高了开发者的效率
- 使用HMR
- 开启HMR
- 已集成在webpack-dev-server中
- 两种方式
- 命令行开启
- webpack-dev-server --hot
- 文件配置
- const path = require ('path')
const webpack = require (‘webpack’)
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
const CopyWebpackPlugin = require (‘copy-webpack-plugin’)
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
//用于配置开发过程中的辅助工具。也就是与source-map功能相关的配置
devtool: ‘source-map’
// 专门用于webpack-dev-server做选项配置的
devServer: {
hot: true,
// 额外为开发服务器指定查找资源目录
contentBase: ‘./’,
proxy: {
‘/api’: {
// http://localhost:8080/api/users ⥤ https://api.github.com/api/users
target: ‘https://api.github.com’,
// http://localhost:8080/api/users ⥤ https://api.github.com/users
pathRewrite: {
‘^/api’: ‘’
},
// 不能使用localhost:8080 作为请求 GitHub的主机名
changeOrigin: true
}
}
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin(),
// 用于生成 index.html文件
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
},
// 指定自动生成的html的模板文件
template: ‘./src/index.html’,
}) ,
// 用于生成 about.html文件
new HtmlWebpackPlugin({
// 设置生成html的文件名称,默认为index.html
filename: ‘about.html’,
}) ,
// 用于拷贝资源文件。在开发阶段最好不要使用这个插件。
// 开发中会频繁执行打包任务,假设如果拷贝的文件较多或比较大。
// 每次执行开销较大,并且打包速度也会降低。建议打生产包时再放开使用
//new CopyWebpackPlugin([
// 支持通配符
// ‘public/**’,
// 也支持相对路径
// ‘public’,
//]) ,
]
}
- yarn webpack-dev-server --open
- js还是会导致自动刷新页面
- webpack HMR的疑问❓
- 为什么样式文件的热更新开箱即用❓
- 因为style-loader实现了热替换逻辑
- JS为啥不像css那样由某个Loader统一处理❓
- JS代码无规律可循
- 我的项目没有手动处理, JS照样可以热替换❓
- 你使用了框架。通过脚手架创建的项目内部都集成了HMR方案
- 总结
- 我们需要手动处理JS模块更新后的热替换
- HMR APIS
- JS模块的热替换
- main.js
- import createEditor from './editor'
import background from ‘./better.png’
import ‘./global.css’
const editor = createEditor()
document. body.appendchild(editor)
const img = new Image()
img.src = background
document.body. appendchild(img)
module.hot.accept(’./editor’, () ⥤ {
// console.log(‘editor 模块更新了,需要这里手动处理热替换’)
const value = lastEditor. innerHTML
document.body.removechild(lastEditor)
const newEditor = createEditor()
newEditor.innerHTML = value
document.body.appendchild(newEditor)
lastEditor = newEditor
})
- yarn webpack-dev-server
- OK~
- 图片模块的热替换
- import createEditor from './editor'
import background from ‘./better.png’
import ‘./global.css’
const editor = createEditor()
document. body.appendchild(editor)
const img = new Image()
img.src = background
document.body. appendchild(img)
module.hot.accept(’./editor’, () ⥤ {
// console.log(‘editor 模块更新了,需要这里手动处理热替换’)
const value = lastEditor. innerHTML
document.body.removechild(lastEditor)
const newEditor = createEditor()
newEditor.innerHTML = value
document.body.appendchild(newEditor)
lastEditor = newEditor
})
module.hot.accept(’./better.png’, () ⥤ {
img.src = background
console.log(background)
})
- yarn webpack-dev-server
- OK~
- HMR注意事项
- 1,处理HMR的代码报错会导致自动刷新
- 是因为使用了hot。可以考虑使用hotOnly,这样即使处理热替换的代码报错也不会自动刷新
- hot: true ⥤ hotOnly: true
- 2,没启用HMR的情况下,HMR APIS 会报错
- import createEditor from './editor'
import background from ‘./better.png’
import ‘./global.css’
const editor = createEditor()
document. body.appendchild(editor)
const img = new Image()
img.src = background
document.body. appendchild(img)
module.hot && module.hot.accept(’./editor’, () ⥤ {
// console.log(‘editor 模块更新了,需要这里手动处理热替换’)
const value = lastEditor. innerHTML
document.body.removechild(lastEditor)
const newEditor = createEditor()
newEditor.innerHTML = value
document.body.appendchild(newEditor)
lastEditor = newEditor
})
module.hot && module.hot.accept(’./better.png’, () ⥤ {
img.src = background
console.log(background)
})
- 3,代码中多了一些与业务无关的代码
- 去掉热替换配置
- yarn webpack
- 查看打包文件
- 发现: if(false){}
- 总结: 不会有任何影响
- 生产环境优化
- 生产环境跟开发环境有着很大的差异
- 生产环境注重运行效率
- 开发环境只注重开发效率
- webpack4推出了mode的用法
- none
- development
- production
- webpack也建议我们为不同的工作环境创建不同的配置
- 不同环境下的配置
- 配置文件根据环境不同导出不同配置
- const webpack = require( "webpack')
const CleanWebpackPlugin } = require("clean-webpack-plugin’)
const htmlWebpackPlugin = require(‘html-webpack-plugin’)
const CopywebpackPlugin = require(‘copy-webpack-plugin’)
module.exports = (env, argv) ⥤ {
const config = {
// 开发配置here
}
if (env =production") {
config.mode = 'production'
config.devtool =false
config.plugins =[
...config.plugins,
new CleanWebpackPlugin()
new CopywebpackPlugin(['public'])
]
}
return config
}
- 开发: yarn webpack --env development
- 生产: yarn webpack --env production
- 一个环境对应一个配置文件
- webpack.common.js
- webpack.dev.js
- webpack.prod.js
- const common = require('./webpack. common')
const merge = require(‘webpack-merge’)
const CleanWebpackPlugin = require( ‘clean-webpack-plugin’)
const CopyWebpackPlugin = require(’ copy-webpack-plugin’)
module. exports = merge(common, {
mode: ‘production’,
plugins: [
new CleanWebpackPlugin()
new CopyWebpackPlugin([‘public’])
]
})
- yarn add webpack-merge --dev
- yarn webpack --config webpack.prod.js
- DefinePlugin
- 在webpack新增的production模式下面,内部就开启了很多通用的优化功能
- 主要的优化配置之一
- 为代码注入全局成员
- 会注入:process.env.NODE_ENV
- 启用
- webpack.config.js
- const webpack = require('webpack')
module. exports ={
mode: ‘none’,
entry: ‘./src/main.js’,
output: {
filename: 'bundle. js
},
plugins: [
new webpack.DefinePlugin({
API_BASE_URL: ‘https://api.example.com’
})
]
}
- main.js
- console.Iog(API_BASE_URL)
- yarn webpack
- 打包后代码语法未通过
- webpack.config.js
- const webpack = require('webpack')
module. exports ={
mode: ‘none’,
entry: ‘./src/main.js’,
output: {
filename: 'bundle. js
},
plugins: [
new webpack.DefinePlugin({
API_BASE_URL: ‘“https://api.example.com”’
})
]
}
- const webpack = require(‘webpack’)
module. exports ={
mode: ‘none’,
entry: ‘./src/main.js’,
output: {
filename: 'bundle. js
},
plugins: [
new webpack.DefinePlugin({
API_BASE_URL:JSON.Stringify(‘https://api.example.com’)
})
]
}
- yarn webpack
- OK~
- Tree-shaking
- 摇树🌲
- 摇掉代码中未引用的部分
- 即未引用代码(dead code)
- webpack生产模式优化中就有这个功能
- 检测未引用的代码并移除它们
- 使用
- components.js
- export const Button =()⥤{
return document.createElement( 'button')
console. Log('dead-code')
}
export const Link =() ⥤{
return document.createELement(‘a’)
}
export const Heading = level ⥤ {
return document.createElement(‘h’ + level)
}
- index.js
- import { Button } from './components'
document.body.appendChild(Button())
- yarn webpack --mode production
- 经检查:未引用的代码被移除了
- 需要注意
- Tree Shaking不是指某个配置选项,而是一组功能搭配使用后的优化效果
- 这个功能会在production模式自动开启
- 非生产模式使用
- webpack.config.js
- module.exports = {
mode: 'none'
entry: './src/index.js',
output: {
filename: 'bundle.js'
},
optimization: {
// 表示在输出结果中只导出那些外部使用了的成员,负责标记枯树叶
usedExports: true,
// 负责摇掉那些枯树叶
minimize: true
}
}
- yarn webpack
- 合并模块函数(Scope Hoisting)
- concatenateModules
- module.exports = {
mode: 'none'
entry: './src/index.js',
output: {
filename: 'bundle.js'
},
optimization: {
// 表示在输出结果中只导出那些外部使用了的成员,负责标记枯树叶
usedExports: true,
// 尽可能的将所有模块合并输出到一个函数中,
// 这样既提升了运行效率,又减少了代码的体积
//又称为作用域提升。webpack3提出的特性
concatenateModules: true,
// 负责摇掉那些枯树叶
minimize: true
}
}
- Tree-shaking & Babel
- 传言如果使用Babel,Tree-shaking会失效
- Tree Shaking前提是ES Modules
- 也就是由webpack打包的代码必须使用ESM
- webpack在打包所有模块之前,先是将模块根据配置交给不同的Loader去处理。
- 最后再将所有Loader处理的结果打包到一起
- 为了转换代码中ECMAScript新特性
- 很多时候选择babel-loader进行处理
- babel-loader处理时可能产生这种转换
- ES Modules⥤ CommonJS
- webpack.config.js
- module. exports ={
mode: 'none,
entry: './src/index.js',
output: {
filename: 'bundle js
},
module: {
rules: [
{
test:/\.js$/,
use: {
loader: 'babel-loader',
options:{
presets: ['@babel/preset-env']
}
},
optimization: {
//模快只导出被使用的成员
usedExports: true
//尽可能合并每一个模块到一个函数中
// concatenateModules: true,
//压缩输出结果
// minimize: true
}
}
]
}
}
- yarn webpack
- Ok:Tree Shaking并未失效
- 因为在最新版本的babel-loader中已自动帮我们关闭了ES Modues转换的插件
- 强制使用ES Modules转换为CommonJS
- module. exports ={
mode: 'none,
entry: './src/index.js',
output: {
filename: 'bundle js
},
module: {
rules: [
{
test:/\.js$/,
use: {
loader: 'babel-loader',
options:{
presets: [
['@babel/preset-env', { modules: 'commonjs' }]
]
}
},
optimization: {
//模快只导出被使用的成员
usedExports: true
//尽可能合并每一个模块到一个函数中
// concatenateModules: true,
//压缩输出结果
// minimize: true
}
}
]
}
}
- yarn webpack
- OK: Tree Shaking失效了
- webpack 生产模式打包时自动开启
- sideEffects(副作用)
- webpack4中新增
- 允许通过配置的方式去标识代码是否有副作用,从而为tree Shaking提供更大的压缩空间
- 副作用是指模块执行时除了导出成员之外所作的事情
- 一般用于npm包标记是否有副作用
- Tree Shaking 跟 sideEffects并非因果关系,且二者并无什么关系
- webpack.config.js
- module. exports ={
mode: 'none,
entry: './src/index.js',
output: {
filename: 'bundle js
},
module: {
rules: [
{
test:/\.js$/,
use: {
loader: 'babel-loader',
options:{
presets: [
['@babel/preset-env', { modules: 'commonjs' }]
]
}
},
optimization: {
// 开启副作用特性
sideEffects: true
//模快只导出被使用的成员
// usedExports: true
//尽可能合并每一个模块到一个函数中
// concatenateModules: true,
//压缩输出结果
// minimize: true
}
}
]
}
}
- package.json
- 添加sideEffects属性并设置为false
- 标识当前package.json所影响的项目当中的所有代码都没有副作用
- yarn webpack
- Ok:成功去掉没有副作用的代码
- 注意
- 使用sideEffects的前提就是确保你的代码真的没有副作用
- package.json
- "sideEffects": false ⥤ "sideEffects": [
“./src/extend.js”,
“*.css”
]
- yarn webpack
- OK: 有副作用的代码正常被打包
- Code Splitting (代码分包,代码分割)
- webpack打包弊端
- 所有代码最终都被打包在一起
- 导致bundle体积过大
- 并非每个模块在启动时都是必要的
- HTTP1.1缺陷
- 同域并行请求限制
- 每次请求都有一定的延迟
- 请求的Header浪费带宽流量
- 解决:分包,按需加载
- 多入口打包(Multi Entry)
- 适用于多页应用程序
- 一个页面对应一个大包入口
- 不同页面的公共部分单独提取
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name].bundle. js’
},
module: {
rules: [
{
test: 八.csss/,
use: [
‘style-loader’,
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin()
new HtmlWebpackPlugin({
title: ‘Multi Entry’
template: ‘./src/index.html’,
filename: ‘index.html’
}),
new HtmlWebpackPlugin({
title: ‘Multi Entry’,
template: ‘./src/aibum. html’,
filename: 'album.html"
})
}
}
- yarn webpack
- OK: 但是两个打包生成的html都引用了所有的模块
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name].bundle. js’
},
module: {
rules: [
{
test: 八.csss/,
use: [
‘style-loader’,
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin()
new HtmlWebpackPlugin({
title: ‘Multi Entry’
template: ‘./src/index.html’,
filename: ‘index.html’,
chunks: [‘index’]
}),
new HtmlWebpackPlugin({
title: ‘Multi Entry’,
template: ‘./src/aibum. html’,
filename: 'album.html",
chunks: [‘album’]
})
}
}
- yarn webpack
- Ok~
- 提取公共模块(Split Chunks)
- 不同入口肯定会有公共模块
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name].bundle. js’
},
optimization: {
splitChunks: {
chunks: ‘all’
}
},
module: {
rules: [
{
test: 八.csss/,
use: [
‘style-loader’,
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin()
new HtmlWebpackPlugin({
title: ‘Multi Entry’
template: ‘./src/index.html’,
filename: ‘index.html’,
chunks: [‘index’]
}),
new HtmlWebpackPlugin({
title: ‘Multi Entry’,
template: ‘./src/aibum. html’,
filename: 'album.html",
chunks: [‘album’]
})
}
}
- yarn webpack
- Ok: 除了两个模块外也生成了公共模块
- 动态导入(Dynamic Imports)
- 按需加载
- 加载数据(不做描述)
- 加载模块
- 需要用到某个模块时,再去加载这个模块
- 动态导入的模块会被自动分包
- 相对多入口打包,更为灵活
- 使用
- index.js
- 静态导入
- import posts from './posts/posts'
import album from ‘./album/album’
const render = () ⥤ {
const hash = window.location.hash || ‘posts’
const mainElement = document.queryselector(’.main’)
mainElement.innerHTML = ‘’
if (hash === ‘posts’) {
mainElement.appendchild(posts())
} else if {
mainElement.appendchild(album())
}
}
render()
window. addEventListener(‘hashchange’, render)
- 问题: 无论何时两个模块都会加载
- 动态导入
- // import posts from './posts/posts'
// import album from ‘./album/album’
const render = () ⥤ {
const hash = window.location.hash || ‘posts’
const mainElement = document.queryselector(’.main’)
mainElement.innerHTML = ‘’
if (hash === ‘posts’) {
// mainElement.appendchild(posts())
import(’./posts/posts’).then(({ default: posts })⥤{
mainElement.appendChild(posts())
})
} else if {
// mainElement.appendchild(album())
import(’./album/album’).then(({ default: album })⥤{
mainElement.appendChild(album())
})
}
}
render()
window. addEventListener(‘hashchange’, render)
- yarn webpack
- OK: 打包后生成了三个包,一个主入口,一个按需加载的,一个公共的
- 魔法注释
- // import posts from './posts/posts'
// import album from ‘./album/album’
const render = () ⥤ {
const hash = window.location.hash || ‘posts’
const mainElement = document.queryselector(’.main’)
mainElement.innerHTML = ‘’
if (hash === ‘posts’) {
// mainElement.appendchild(posts())
import(/* webpackChunkName: ‘posts’ /’./posts/posts’).then(({ default: posts })⥤{
mainElement.appendChild(posts())
})
} else if {
// mainElement.appendchild(album())
import(/ webpackChunkName: ‘album’ */’./album/album’).then(({ default: album })⥤{
mainElement.appendChild(album())
})
}
}
render()
window. addEventListener(‘hashchange’, render)
- yarn webpack
- OK~
- 按需打包到同一个文件中
- // import posts from './posts/posts'
// import album from ‘./album/album’
const render = () ⥤ {
const hash = window.location.hash || ‘posts’
const mainElement = document.queryselector(’.main’)
mainElement.innerHTML = ‘’
if (hash === ‘posts’) {
// mainElement.appendchild(posts())
import(/* webpackChunkName: ‘components’ /’./posts/posts’).then(({ default: posts })⥤{
mainElement.appendChild(posts())
})
} else if {
// mainElement.appendchild(album())
import(/ webpackChunkName: ‘components’ */’./album/album’).then(({ default: album })⥤{
mainElement.appendChild(album())
})
}
}
render()
window. addEventListener(‘hashchange’, render)
- yarn webpack
- Ok: 生成components文件和一个公共模块文件
- 提取CSS到单个文件中
- MiniCssExtractPlugin
- 可以将css代码从打包结果中提取出来的插件
- 用它可以实现css模块的按需加载
- 使用
- yarn add mini-css-extract-plugin --dev
- webpack.config.js
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name].bundle. js’
},
module: {
rules: [
{
test: 八.csss/,
use: [
// ‘style-loader’, // 将样式通过style标签注入html中
MiniCssExtractPlugin.loader, //用于 将单独打包的css文件通过link方式注入
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: ‘Dynamic Import’
template: ‘./src/index.html’,
filename: ‘index.html’
})
new MiniCssExtractPlugin(),
}
}
- yarn webpack
- OK~
- OptimizeCssAssetsWebpackPlugin(压缩输出的CSS文件)
- yarn add optimize-css-assets-webpack-plugin --dev
- webpack.config.js
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name].bundle. js’
},
module: {
rules: [
{
test: 八.csss/,
use: [
// ‘style-loader’, // 将样式通过style标签注入html中
MiniCssExtractPlugin.loader, //用于 将单独打包的css文件通过link方式注入
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: ‘Dynamic Import’
template: ‘./src/index.html’,
filename: ‘index.html’
}),
new MiniCssExtractPlugin(),
new OptimizeCssAssetsWebpackPlugin(),
}
}
- yarn webpack
- OK~
- 推荐用法
- webpack.config.js
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name].bundle. js’
},
optimization: {
minimizer: [
new OptimizeCssAssetsWebpackPlugin()
]
},
module: {
rules: [
{
test: 八.csss/,
use: [
// ‘style-loader’, // 将样式通过style标签注入html中
MiniCssExtractPlugin.loader, //用于 将单独打包的css文件通过link方式注入
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: ‘Dynamic Import’
template: ‘./src/index.html’,
filename: ‘index.html’
}),
new MiniCssExtractPlugin(),
// new OptimizeCssAssetsWebpackPlugin(),
}
}
- yarn webpack
- OK: JS未自动压缩了:(
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’)
const TerserWebpackPlugin = require(‘terser-webpack-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name].bundle. js’
},
optimization: {
minimizer: [
new TerserWebpackPlugin(),
new OptimizeCssAssetsWebpackPlugin()
]
},
module: {
rules: [
{
test: 八.csss/,
use: [
// ‘style-loader’, // 将样式通过style标签注入html中
MiniCssExtractPlugin.loader, //用于 将单独打包的css文件通过link方式注入
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: ‘Dynamic Import’
template: ‘./src/index.html’,
filename: ‘index.html’
}),
new MiniCssExtractPlugin(),
// new OptimizeCssAssetsWebpackPlugin(),
}
}
- yarn add terser-webpack-plugin --dev
- 输出文件名Hash(substitution)
- 一般部署前端资源文件时,都会启用服务器的静态资源缓存
- 这样对于用户的浏览器而言,可以缓存住静态资源,后续不会再发起静态资源请求了
- 提高了应用响应速度
- 开启客户端静态资源缓存的问题
- 如果缓存策略中缓存失效时间过短,效果不太明显
- 过期时间设置比较长
- 应用更新后重新部署,没法及时看见更新效果
- 生产模式下,文件名使用Hash
- 生产模式下,文件名使用Hash
- 不用担心文件更新后的问题
- 几种hass
- 普通hash
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name]-[hash].bundle. js’
},
module: {
rules: [
{
test: 八.csss/,
use: [
// ‘style-loader’, // 将样式通过style标签注入html中
MiniCssExtractPlugin.loader, //用于 将单独打包的css文件通过link方式注入
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: ‘Dynamic Import’
template: ‘./src/index.html’,
filename: ‘index.html’
})
new MiniCssExtractPlugin({
filename: ‘[name]-[hash].bundle.css’
}),
}
}
- 整个项目级别的,项目中任何一个地方发生改动,hash值会发生变化
- chunk hash
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name]-[chunkhash].bundle. js’
},
module: {
rules: [
{
test: 八.csss/,
use: [
// ‘style-loader’, // 将样式通过style标签注入html中
MiniCssExtractPlugin.loader, //用于 将单独打包的css文件通过link方式注入
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: ‘Dynamic Import’
template: ‘./src/index.html’,
filename: ‘index.html’
})
new MiniCssExtractPlugin({
filename: ‘[name]-[chunkhash].bundle.css’
}),
}
}
- Chunck级别的hash,一旦chunk涉及内容改变,对应chunk的hash会发生变化
- 相对普通hash,chunk hash更精准一些。
- content hash
- 文件级别的hash,是根据文件内容生成的hash
- 相比普通hash 和 chunk hash,content hash是更优的hash方式
- 最适合解决缓存问题的
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,
album: ‘./src/album. js’
},
output: {
filename: ‘[name]-[contenthash].bundle. js’
},
module: {
rules: [
{
test: 八.csss/,
use: [
// ‘style-loader’, // 将样式通过style标签注入html中
MiniCssExtractPlugin.loader, //用于 将单独打包的css文件通过link方式注入
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: ‘Dynamic Import’
template: ‘./src/index.html’,
filename: ‘index.html’
})
new MiniCssExtractPlugin({
filename: ‘[name]-[contenthash].bundle.css’
}),
}
}
- 控制hash长度
- const { CleanWebpackPlugin } =require("clean-webpack-plugin')
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
module. exports ={
mode: ‘none’
entry: {
index:’./src/index. js’,$$
album: ‘./src/album. js’
},
output: {
filename: ‘[name]-[contenthash:8].bundle. js’
},
module: {
rules: [
{
test: 八.csss/,
use: [
// ‘style-loader’, // 将样式通过style标签注入html中
MiniCssExtractPlugin.loader, //用于 将单独打包的css文件通过link方式注入
‘css-loader’
]
}
]
},
plugins: {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: ‘Dynamic Import’
template: ‘./src/index.html’,
filename: ‘index.html’
})
new MiniCssExtractPlugin({
filename: ‘[name]-[contenthash:8].bundle.css’
}),
}
}