webpack 之 DefinePlugin 插件
DefinePlugin是webpack 自带插件。可以使用webpack.DefinePlugin()获取。并且它有一个参数,是一个对象。对象的键是代码的中的变量。
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.examle.com')
})
]
}
// 注释: 代码中所有使用API_BASE_URL的地方都会被替换。注意:输出的是代码片段。所有如果想输出字符串需要使用:JSON.stringify()
webpack 之 Tree-shaking
未引用的代码(dead-code)就是在打包之后将未引用的代码剔除掉保留有用的代码。也是去除冗余代码有效方法。会在生产功能自动启用。yarn webpack --mode production
optimization: {
usedExports: true, // 负责标记【枯树叶】
minimize: true // 代码压缩,负责【摇掉】它们
}
webpack 之代码合并 Scope Hoisting
// babel-loader: 配置参数:
use: {
loader: 'babel-loader',
options: {
presets: [ // @babel/preset-env 传递参数需要数组里在创建一个数组。第一个元素为'@babel/preset-env', 第二个元素为一个对象来配置参数。
['@babel/preset-env', {modules: 'commonjs'}]
]
}
}
webpack tree shaking 与 Babel 同时使用失效的传说
网上说babel 和 tree shaking 一起使用会导致去除不了冗余代码。 是因为当执行@babel/preset-env这个组合插件的时候里面有一个可以将esm代码转换为commonjs的语法。而tree shaking 只能转换esm 的规则。所以导致失效。
- 但是最新的babel 已经默认禁用转换为commonjs的插件。默认使用esm的语法。所以不会出现以上问题。
- 不管这个插件可以强制将babel使用commonjs转换的插件。
- 这个时候tree shaking 去除冗余代码就没有效果了。
webpack 之 sideEffects
optimization: {
/**
* sideEffects: true 开启副作用检查。
* 在package.json里面添加一个字段。sideEffects: false表示代码没有副作用。
* usedExports: true 将没有引入的代码不进行导出
* minimize: true 压缩代码
* {
* "name": "your-project",
* "sideEffects": [
* "./src/some-side-effectful-file.js" // 如果有副作用的话package.json里面sideEffects数组表示。
* ]
* }
*/
sideEffects: true,
usedExports: true,
minimize: true
},
webpack 代码分割
- 多入口打包
- 动态导入
- 多入口打包 使用与多页面打包程序。
/**
* 使用多入口打包。
* 1. 需要 entry 为对象,
* 健是html-webpack-plugin参数一个chunks
* 属性的一个元素可以任意组合,
* 我们在html-webpack-plugin配置多个页面。配置完多个页面
* 但是webpack不知道我们这个几个html到底加载那几个js文件
* 这个时候就需要我们去指定js了
* 我们需要根据entry对象健名去配置html-webpack-plugin chunks:Array<entry.key>
*
*/
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'none',
// entry: './src/index.js', //多入口是对象。
entry: {
index: './src/index.js', // 对象的健跟html-webpack-plugin参数配置的chunks名字保持一致。
album: './src/album.js'
},
output: {
filename: '[name].bundle.js' // 因为需要输出多个入口文件所以使用[name]占位符。生成多个文件。
},
module: {
rules:[
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
}
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Multi Entry',
template: './src/index.html',
chunks: ['index'] // 决定使用哪个打包完的js文件
// 如果有一些公共的js文件也可以配追在这个数组里面。
}),
new HtmlWebpackPlugin({
title: 'Multi Entry',
template: './src/album.html',
filename: 'album.html',
chunks: ['album']
})
]
}
webpack 公共模块提取
optimization: { // 优化
splitChunks: { // 将所有公共模块提取出来。
chunks: 'all',
}
},
webpack 动态导入
- 按需加载。
- 需要到某个模块时再去加载某个模块。
- 动态导入的模块被自动分包。
使用import()动态加载文件,import()返回的是promise()。then()可以接收该模块的内容。可以根据页面判断是否加载。 避免使用import * from * 必须先于模块执行。 因为import()是esm模块化语法。所以webpack可以直接处理这些。只加载用户访问的页面。 大大增加在加载效率。
webpack 魔法注释
if (hash === '#posts') {
// /* webpackChunkName: 'components' */ 根据这个webpackChunkName来决定这个文件合并后的名字,如何同一个项目有类似的名字的话也会合并一起。
import(/* webpackChunkName: 'components' */'./posts/posts').then(({ default: posts }) => {
mainElement.appendChild(posts())
})
} else if (hash === '#album') {
// mainElement.appendChild(album())
import(/* webpackChunkName: 'components' */'./album/album').then(({ default: album }) => {
mainElement.appendChild(album())
})
}
webpack 之 mini-css-extract-plugin
- 将样式提取出来单独的css文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module: {
rules: [
{
test: /\.css$/,
use: [
// 'style-loader', // 将样式通过style标签的方式注入
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin()
]
webpack 之 optimize-css-assets-webpack-plugin
- webpack 只是在生产环境对js文件使用压缩。其他文件需要自行压缩。
- 所以有这样一款插件来压缩css文件。
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('optimize-css-assets-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
module.exports = {
mode: 'none',
entry: {
main: './src/index.js'
},
output: {
filename: '[name].bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 'style-loader', // 将样式通过style标签的方式注入
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
optimization: {
minimize: true,
minimizer: [// 配置这个数组就被认定需要自定义插件
new CssMinimizerPlugin(),
new TerserWebpackPlugin()
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Dynamic import',
template: './src/index.html',
filename: 'index.html'
}),
new MiniCssExtractPlugin(),
]
}
webpack 输出文件名 Hash
- 指定hash值的长度 filename: '[name]-[contenthash: 8].bundle.js'
- hash // 整体hash
输出文件的filename 和插件输出的filename都支持hash.并且是全局的哈希。
- chunkhash // 分组哈希
输出文件的filename 和插件输出的filename都支持chunkhash.并且是分组的哈希
- contenthash根据不同的文件生成的hash。文件级别的
splitChunks webpack 优化
splitChunks实现分包机制。