「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」
魔法注释
// 浏览器空闲时,再加载
import(/* webpackPrefetch: true */ 'LoginModal');
hash、chunkhash、contenthash
- hash:用hash命名文件
- chunkhash:多入口,多出口时。只会修改内容变动的文件名称(如果文件内引入了其他文件,则其他文件名称也被修改)
- contenthash:多入口,多出口时。只会修改内容变动的文件名称(其引入的文件若无变动,则不重命名)
mode生产环境和开发环境
mode: none | production | development
entry入口(三种类型的值)
// 1、设置一个入口
entry: "./src/index.js",
// 2、把两个文件打包进一个文件
entry: ["./src/index.js", "./src/other.js"],
// 3、多入口,同时需要多出口
entry: {
index: "./src/index.js",
other: "./src/other.js"
},
output: {
path: path.resolve(__dirname, "./build"),
filename: "[name]-[hash:6].js" // 利用hash去适应浏览器的缓存机制
}
output
output: {
path: path.resolve(__dirname, "./dist"),
filename: "[name].js",
publicPath: "./", // 可以写任意地址,补url前缀(可以配置成cdn),然后把打包后的文件传到cdn上
}
loader
webpack只支持js和json文件,需要loader对其进行编译
module: {
rules: [
{
test: /.css$/,
// loader执行顺序是从后向前
// css-loader 言简意赅 把css模块内容加到js模块
// css in js方式
// style-loader 从js中提取css的loader在html中创建
include: path.resolve(__dirname, "./src"), // 设置编译范围,构建更快
use: ["style-loader", "css-loader"]
},
{
test: /.less$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: true // 开启css模块化
}
},
{
loader: "postcss-loader", // 用来添加前缀,做css的浏览器兼容
},
"less-loader" // 解析less
]
},
{
test: /.(png|jpe?g|gif)$/,
use:{
loader: "file-loader",
options: {
name: "[name]_[hash:6].[ext]", // 打包后文件名————原名_6位hash.原后缀
outputPath: "images/" // 设置一个文件夹路径
}
}
},
// 推荐用url-loader 因为它支持limit
{ // url-loader有file-loader中所有的功能,完全可替代它,还增加了自己的功能
test: /.(png|jpe?g|gif)$/,
use:{
loader: "url-loader",
options: {
name: "[name]_[hash:6].[ext]", // 打包后文件名————原名_6位hash.原后缀
outputPath: "images/", // 设置一个文件夹路径
limit: 2 * 1024, // 小于2k的图片被转成Base64格式
}
}
},
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader", // 解析es6
options: {
// 语法转换插件 preset-env
presets: [
["@babel/preset-env", {
targets: { // 兼容浏览器版本
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
corejs: 2,
useBuiltIns: "usage"
}]
]
}
}
}
]
}
添加postcss-loader(用来添加前缀,做css的浏览器兼容)
// 可以单独建立一个文件postcss.config.js
const autoprefixer = require("autoprefixer");
module.exports = {
plugins: [
autoprefixer({
// 兼容最近两个版本
// 全球浏览器的市场份额大约1%的浏览器
overrideBrowserslist: ["last 2 versions", ">1%"]
})
]
}
babel可以单独文件配置babelrc(项目启动首先找自己的配置文件,找不到再去webpack配置中找)
{
"presets": [
[
"@babel/preset-env",
{
targets: { // 兼容浏览器版本
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
corejs: 2,
useBuiltIns: "usage"
}
],
"@babel/preset-react"
]
}
Polyfill是把es6用到的东西(如:promise),挂在window上,就可以用了。会造成全局污染
optimization js摇树
只在mode是production才会生效,development的tree shaking是不生效的,因为webpack为了方便你的调试,从打包后的代码注释可分辨是否生效
optimization: {
useExports: true, // 哪些导出的模块被使用了,再做打包
splitChunks: { // 代码分割
// 所有配置如下图
},
concatenateModules: true // 分析插件使用的地方,尽量插件和使用的地方放在一起
}
plugins插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MinCssExtractPlugin = require("min-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const webpack = require("webpack");
plugin: [
new CleanWebpackPlugin(), // 清除之前打包生产的文件
new MinCssExtractPlugin({ // 把css提取成独立的css文件,同时上面的style-loader要换成MinCssExtractPlugin.loader
filename: "[name].css"
}),
new HtmlWebpackPlugin({
// 常用配置
title: "首页", // 还需要在title标签中设置<title><%= htmlWebpackPlugin.options.title%></title>
template: "./src/index.html",
filename: "index.html",
// 压缩HTML文件
minify: {
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符和换行
minisyCSS: true // 压缩内联css
}
}),
// 压缩css,利用cssnano
new OptimizeCSSAssetsPlugin({
cssProcessor: require("cssnano"),
cssProcessorOptions: {
discardComments: {
removeAll: true
}
}
}),
// 需要注意:热更新要用style-loader,不能用MinCssExtractPlugin.loader
// 只针对css的修改,js部分vue-loader这些框架会帮我们解决
new webpack.HotModuleReplacementPlugin(), // 帮助热更新的插件
],
HtmlWebpackPlugin所有的配置
devtool
// 用于帮我们快速定位问题。开发环境默认开启,生成环境不开启。设置问none则关闭
// 浏览器的console能直接定位到问题文件代码位置
// 关闭后,浏览器报错会定位到打包后的文件。
devtool: "source-map"
推荐:开发环境用 cheap-module-eval-source-map 打包更快。生产用 cheap-module-source-map 防止代码泄露
WebpackDevServer
devServer: {
contentBase: path.resolve(__dirname, "./dist"), // 指定打开的路径
open: true, // 自动打开浏览器
hot: true, // 自动更新浏览器
hotOnly: true, // 更新改动,但不刷新浏览器
proxy: { // 跨域代理
"/api": {
target: "http://localhost:9092"
}
},
before(app, server) { // 使用mock数据
app.get("/api/mock.json", (req, res) => {
res.json({
hello: "express",
})
})
},
port: 8080,
}
resolve查找第三方依赖
resolve: {
// 查找第三方依赖
modules: [path.resolve(__dirname, "./node_modules")],
alias: {
// 减少查找过程
// 起别名
"@": path.resolve(__dirname, "./src/css"),
react: "./node_module... ...",
"react-dom": "./node_module... ...",
},
// 设置在加载模块时,可以不写后缀,按下面的顺序依次查找
// 会消耗一些性能,推荐写代码直接写上后缀名
ectensions: [".js", ".json", ".jsx"]
}
externals打包时排除一些包
// 场景:如果我们有自己的cdn,放在了index.html中。开发的时候为了方便又引入的插件
// 写法上保持一致
// 打包的时候就可以把包排除在外,避免引入两次(比较大的包用两次加载慢很多)
externals: {
"jquery": "jQuery"
}
sideEffects处理摇树副作用
sideEffects: ["*.css", "@babel/ployfill"]
//有些模块只需要被引入,不会调用(如:css、less)这样就不会被摇掉
多个配置文件
公共配置 webpack.config.base.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
module: {
rules: [
{
test: /.css$/,
// loader执行顺序是从后向前
// css-loader 言简意赅 把css模块内容加到js模块
// css in js方式
// style-loader 从js中提取css的loader在html中创建
include: path.resolve(__dirname, "./src"), // 设置编译范围,构建更快
use: ["style-loader", "css-loader"]
},
{
test: /.less$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: true // 开启css模块化
}
},
{
loader: "postcss-loader", // 用来添加前缀,做css的浏览器兼容
},
"less-loader" // 解析less
]
},
{
test: /.(png|jpe?g|gif)$/,
use:{
loader: "file-loader",
options: {
name: "[name]_[hash:6].[ext]", // 打包后文件名————原名_6位hash.原后缀
outputPath: "images/" // 设置一个文件夹路径
}
}
},
// 推荐用url-loader 因为它支持limit
{ // url-loader有file-loader中所有的功能,完全可替代它,还增加了自己的功能
test: /.(png|jpe?g|gif)$/,
use:{
loader: "url-loader",
options: {
name: "[name]_[hash:6].[ext]", // 打包后文件名————原名_6位hash.原后缀
outputPath: "images/", // 设置一个文件夹路径
limit: 2 * 1024, // 小于2k的图片被转成Base64格式
}
}
},
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader", // 解析es6
options: {
// 语法转换插件 preset-env
presets: [
["@babel/preset-env", {
targets: { // 兼容浏览器版本
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
corejs: 2,
useBuiltIns: "usage"
}]
]
}
}
}
]
},
resolve: {
// 查找第三方依赖
modules: [path.resolve(__dirname, "./node_modules")],
alias: {
// 减少查找过程
// 起别名
"@": path.resolve(__dirname, "./src/css"),
react: "./node_module... ...",
"react-dom": "./node_module... ...",
},
// 设置在加载模块时,可以不写后缀,按下面的顺序依次查找
// 会消耗一些性能,推荐写代码直接写上后缀名
extensions: [".js", ".json", ".jsx"]
},
plugins: [new CleanWebpackPlugin()]
}
开发配置 webpack.config.pro.js
"prod": "webpack --config ./webpack.config.pro.js",
const baseConfig = require("./webpack.config.base.js");
const { merge } = require("webpack-merge");
const MinCssExtractPlugin = require("min-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-plugin");
const proConfig = {
mode: "production",
output: {
path: path.resolve(__dirname, "./build"),
fileaname: "[name].js",
publicPath: "http://... ..."
},
module: {
rules: [
{
test: /.css$/,
// loader执行顺序是从后向前
// css-loader 言简意赅 把css模块内容加到js模块
// css in js方式
// style-loader 从js中提取css的loader在html中创建
include: path.resolve(__dirname, "./src"), // 设置编译范围,构建更快
use: ["style-loader", "css-loader"]
},
{
test: /.less$/,
use: [
MinCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true // 开启css模块化
}
},
{
loader: "postcss-loader", // 用来添加前缀,做css的浏览器兼容
},
"less-loader" // 解析less
]
},
{
test: /.(png|jpe?g|gif)$/,
use:{
loader: "file-loader",
options: {
name: "[name]_[hash:6].[ext]", // 打包后文件名————原名_6位hash.原后缀
outputPath: "images/" // 设置一个文件夹路径
}
}
},
// 推荐用url-loader 因为它支持limit
{ // url-loader有file-loader中所有的功能,完全可替代它,还增加了自己的功能
test: /.(png|jpe?g|gif)$/,
use:{
loader: "url-loader",
options: {
name: "[name]_[hash:6].[ext]", // 打包后文件名————原名_6位hash.原后缀
outputPath: "images/", // 设置一个文件夹路径
limit: 2 * 1024, // 小于2k的图片被转成Base64格式
}
}
},
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader", // 解析es6
options: {
// 语法转换插件 preset-env
presets: [
["@babel/preset-env", {
targets: { // 兼容浏览器版本
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
corejs: 2,
useBuiltIns: "usage"
}]
]
}
}
}
]
},
plugins: [
new MinCssExtractPlugin({ // 把css提取成独立的css文件,同时上面的style-loader要换成MinCssExtractPlugin.loader
filename: "[name].css"
}),
new HtmlWebpackPlugin({
// 常用配置
title: "首页", // 还需要在title标签中设置<title><%= htmlWebpackPlugin.options.title%></title>
template: "./src/index.html",
filename: "index.html",
// 压缩HTML文件
minify: {
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符和换行
minisyCSS: true // 压缩内联css
}
}),
// 压缩css,利用cssnano
new OptimizeCSSAssetsPlugin ({
cssProcessor: require("cssnano"),
cssProcessorOptions: {
discardComments: {
removeAll: true
}
}
}),
]
}
module.exports = merge(baseConfig, proConfig);
生产配置 webpack.config.dev.js
"dev": "webpack --config ./webpack.config.dev.js", // 开发环境打包
"dev": "webpack-dev-serve --config ./webpack.config.dev.js" // 开发环境启动项目
const baseConfig = require("./webpack.config.base.js");
const { merge } = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpacl-plugin");
const webpack = require("webpack");
const devConfig = {
mode: "development",
output: {
path: path.resolve(__dirname, "./dist"),
filname: "[name].js",
},
devtool: "cheap-inline-source-map",
module: {
rules: [
{
test: /.css$/,
// loader执行顺序是从后向前
// css-loader 言简意赅 把css模块内容加到js模块
// css in js方式
// style-loader 从js中提取css的loader在html中创建
include: path.resolve(__dirname, "./src"), // 设置编译范围,构建更快
use: ["style-loader", "css-loader"]
},
{
test: /.less$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: true // 开启css模块化
}
},
{
loader: "postcss-loader", // 用来添加前缀,做css的浏览器兼容
},
"less-loader" // 解析less
]
},
{
test: /.(png|jpe?g|gif)$/,
use:{
loader: "file-loader",
options: {
name: "[name]_[hash:6].[ext]", // 打包后文件名————原名_6位hash.原后缀
outputPath: "images/" // 设置一个文件夹路径
}
}
},
// 推荐用url-loader 因为它支持limit
{ // url-loader有file-loader中所有的功能,完全可替代它,还增加了自己的功能
test: /.(png|jpe?g|gif)$/,
use:{
loader: "url-loader",
options: {
name: "[name]_[hash:6].[ext]", // 打包后文件名————原名_6位hash.原后缀
outputPath: "images/", // 设置一个文件夹路径
limit: 2 * 1024, // 小于2k的图片被转成Base64格式
}
}
},
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader", // 解析es6
options: {
// 语法转换插件 preset-env
presets: [
["@babel/preset-env", {
targets: { // 兼容浏览器版本
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
corejs: 2,
useBuiltIns: "usage"
}]
]
}
}
}
]
},
devServer: {
contentBase: path.resolve(__dirname, "./dist"), // 指定打开的路径
open: true, // 自动打开浏览器
hot: true, // 自动更新浏览器
hotOnly: true, // 更新改动,但不刷新浏览器
proxy: { // 跨域代理
"/api": {
target: "http://localhost:9092"
}
},
before(app, server) { // 使用mock数据
app.get("/api/mock.json", (req, res) => {
res.json({
hello: "express",
})
})
},
port: 8080,
},
plugins: [
new HtmlWebpackPligin({
// 常用配置
title: "首页", // 还需要在title标签中设置<title><%= htmlWebpackPlugin.options.title%></title>
template: "./src/index.html",
filename: "index.html",
// 压缩HTML文件
minify: {
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符和换行
minisyCSS: true // 压缩内联css
}
}),
new webpack.HotModuleReplacementPlugin(), // 帮助热更新的插件
]
}
module.exports = merge(baseConfig, devConfig);
webpack返回一个函数时
"test:dev": "webpack --env.production --config webpack.config.test.js"
"test:build": "webpack-dev-server --config webpack.config.test.js"
// 用cross-env方式
"test:build": "cross-env NODE_ENV=test321312312312 --config webpack.config.test.js"
webpack.config.test.js
const baseConfig = require("./webpack.config.base.js");
const devConfig = require("./webpack.config.dev.js");
const proConfig = require("./webpack.config.pro.js");
const merge = require("webpack-merge");
console.log(provess.env.NODE_ENV) // 用cross-env方式
module.exports = (env) => {
if(env && env.production) {
return merger(baseConfig, proConfig);
} else {
return merger(baseConfig, devConfig);
}
}