webpack
# 定义
静态模块打包工具
静态模块:指的是编写代码过程中的,html、css、js、图片等固定内容的文件
打包:把静态模块内容压缩,整合,转译等(前端工程化)
- 把 less/sass 转成 css 代码
- 把 ES6 + 降级成 ES5
- 支持多种模块标准语法
# 打包
- 准备一个要打包的 util 包
- 安装 webpack
npm i webpack webpack-cli --save-dev # -save-dev 仅开发时使用,对应到package.json的devDependencies
- package.json 配置打包命令
...
"scripts": {
"build": "webpack",
},
...
npm run build # 打包,生成dist文件
# 入口与出口
/webpack.config.js
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js', // 打包的入口:即源代码执行开始的文件(index.js)
output: {
path: path.resolve(__dirname, 'dist'), // 打包的出口:输出的目录,默认dist
filename: 'my-first-webpack.bundle.js', // 输出目录的入口文件(main.js)
clean: true, // 打包前清空输出目录
},
};
# 打包 HTML
HtmlWebpackPlugin | webpack 中文文档 (opens new window)
在打包时生成 html 文件
安装
npm install --save-dev html-webpack-plugin
/webpack.config.js
引入
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: 'index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index_bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public/login.html'), // 模板文件
filename: path.resolve(__dirname, 'dist/login/index.html'), 输出文件
})
]
};
# 打包 CSS 代码
Loaders | webpack 中文文档 (opens new window)
默认 webpack 只支持 js
- css-loader:css-loader 会对
@import
和url()
进行处理,就像 js 解析import/require()
一样 - style-loader:把 CSS 插入到 DOM 中
Install
npm install --save-dev css-loader style-loader # 默认最新版,需要与webpack版本一致
入口文件(index.js)
// bootstrap
import 'bootstrap/dist/css/bootstrap.min.css' // npm i bootstrap
import css from 'file.css'; // 引入样式
import './file.css'; // 当前文件没有使用到,也可以不设别名,这些import只是让webpack能识别到
/webpack.config.js
引入
module.exports = {
module: {
rules: [
{
test: /\.css$/i, // 匹配所有的css文件
use: ['style-loader', 'css-loader'], // 逆序执行,从后往前执行
},
],
},
};
# 优化 - 提取 CSS 代码
webpack-contrib/css-loader: CSS Loader (opens new window)
MiniCssExtractPlugin | webpack 中文文档 (opens new window)
上述操作后,css 样式是存储在 js 文件中的,不利于缓存;
使用 mini-css-extract-plugin
插件
Install
npm install --save-dev mini-css-extract-plugin
入口文件(index.js)
同上
/webpack.config.js
引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()], // 引入插件
module: {
rules: [
{
test: /\.css$/i,
// use: ['style-loader', 'css-loader'], // 不用和style-loader一起使用
use: [MiniCssExtractPlugin.loader, "css-loader"], // 配置规则,配合css-loader
},
],
},
};
最终打包时样式生成在 main.css
# 优化压缩
CssMinimizerWebpackPlugin | webpack 中文文档 (opens new window)
上一步生成的 main.css 并没有压缩
Install
npm install css-minimizer-webpack-plugin --save-dev
/webpack.config.js
import
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /.s?css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
optimization: {
minimizer: [
// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释(保证JS代码还能被压缩处理)
`...`, // 引入原有的压缩插件,否则原有的会失效,js变成不压缩的
new CssMinimizerPlugin(),
],
},
plugins: [new MiniCssExtractPlugin()],
};
# 打包 less 代码
less-loader | webpack 中文文档 (opens new window)
与 css 代码同理
# 打包图片
资源模块 | webpack 中文文档 (opens new window)
无需下载额外的加载器,webpack5 已内置。
默认情况下,当图片大于 8KB 时,打包图片到静态资源(dist/assets),反之使用 data URI(base64)
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
type: 'asset',
generator: {
filename: 'static/[hash][ext][query]' // hash 文件的哈希值;query查询参数 ?key=xxx
}
}
]
},
};
# 开发环境
开发环境 | webpack 中文文档 (opens new window)
启动 WEB 服务,自动检测代码,热更新
Install
npm install --save-dev webpack-dev-server
/webpack.config.js
import
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
+ mode: 'development', // 开发模式:调试代码、实时加载,模块热替换等
- mode: 'production', // 生产模式:压缩代码、资源优化、更轻量等
entry: {
index: './src/index.js',
print: './src/print.js',
},
devtool: 'inline-source-map',
+ devServer: {
+ static: './dist', // 放在内存,设不设置都无所谓
+ },
plugins: [
new HtmlWebpackPlugin({
title: 'Development',
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
+ optimization: {
+ runtimeChunk: 'single',
+ },
};
package.json
...
"scripts": {
"dev": "webpack serve --open", // --open自动打开默认浏览器
}
...
npm run dev
笔记
切换开发模式的两种方法:
/webpack.config.js
中修改mode
/package.json
的启动脚本中添加--mode=development
# 环境变量
# 打包场景应用
在打包 CSS 代码中提及 style-loader
和 MiniCssExtractPlugin.loader
两种加载器,并且两者是互斥的。在开发环境中使用 style-loader
加载器有更好的性能表现,而在生产环境则 MiniCssExtractPlugin.loader
更佳。
使用 cross-env
软件包可以灵活的在不同环境下切换两种加载器
Install
npm i cross-env --save-dev
package.json
...
"scripts": {
"build":"cross-env NODE_ENV=production webpack --mode=production",
"dev": "cross-env NODE_ENV=development webpack serve --open --mode=development", // --open自动打开默认浏览器
}
...
/webpack.config.js
引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()], // 引入插件
module: {
rules: [
{
test: /\.css$/i,
// use: ['style-loader', 'css-loader'], // 不用和style-loader一起使用
use: [process.env.NODE_ENV === 'development' ? 'style-loader': MiniCssExtractPlugin.loader, "css-loader"], // 配置规则,配合css-loader
},
],
},
};
# 前端注入环境变量
DefinePlugin | webpack 中文文档 (opens new window)
上面的 cross-env 只能在 node.js 环境下生效,前端代码无法访问 process.env.NODE_ENV
内置插件,无需安装
/webpack.config.js
引入
...
plugins: [
+ new webpack.DefinePlugin({
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
+ });
]
...
之后就可以在前端 js 中使用 process.env.NODE_ENV
index.js
if(process.env.NODE_ENV === 'production'){
console.log = function(){} // 生产模式下不打印log
}
# 开发环境调错
默认情况下,由于代码压缩,无法在控制台直观找到错误发生的行数。
/webpack.config.js
引入
const config = {...}
+ if(process.env.NODE_ENV === 'development'){
+ config.devtool = 'inline-source-map' // 仅开发模式使用
+ }
module.exports = config
# 解析别名
解析 (Resolve) | webpack 中文文档 (opens new window)
/webpack.config.js
引入
const config = {
...
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, 'src'),
+ },
+ },
...
}
module.exports = config
index.js
- import youAxios from '../src/utils/requst.js'
+ import youAxios from '@/utils/requst.js'
# 优化 CDN
以前的服务器带宽小,会有优势,现在意义不大,现在更主流的是用自己的 CDN 资源。
index.html
<% if(htmlWebpackPlugin,option.useCDN){} %>
<link hre="https://cdn.....min.css">
<% } %>
/webpack.config.js
import
const config = {
...
new HtmlWebpackPlugin({
...
useCdn: process.env.NODE_ENV === 'development'
...
})
...
}
if(process.env.NODE_ENV === 'production'){
config.externals = {
// key: import from 语句后面的字符串
// value: 留在原地的全局变量(最好和cdn在全局暴雷的变量一致)
// import 'bootstrap/dist/css/bootstrap.min.css'
'bootstrap/dist/css/bootstrap.min.css' : 'bootstrap'
// import 'axios'
'axios' : 'axios'
}
}
module.exports = config