工程化 --- webpack
1. 简述
webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当webpack 处理应用程序时,会在内部从一个或多个入口点构建一个 依赖图 ,然后将项目中所需的每一个模块组合成一个或多个bundles,它们均为静态资源,用于展示你的内容
**静态模块: ** 指的是编写代码过程中的 html、css、js、图片等固定内容的文件
**打包: ** 把静态模块内容 压缩、整合、转译等(前端工程化)
2. 中文文档
https://www.webpackjs.com/concepts/entry-points/
3. 环境搭建
1. 安装
npm i webpack webpack-cli --save-dev # --save-dev 用来标记前面的这两个包只在当前项目的 dev 开发环境中使用
2. 配置自定义命令
package.json
{
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
# 配置自定义命令
"build": "webpack"
}
}
3. 运行自定义命令
会将代码打包整合到项目根目录下的 dist 文件夹中
# 真正执行的命令就是上面配置的 webpack
npm run build
4. 常用配置
1. 准备配置文件
在项目根目录下创建 wepack.config.js
2. 入口
const path = require('path')
module.exports = {
// 配置入口文件
entry: path.resolve(__dirname,'src/login/index.js'),
};
3. 出口
const path = require('path')
module.exports = {
entry: path.resolve(__dirname,'src/login/index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: './login/index.js',
clean: true // 生成打包后的内容前,先清空文件夹( 5.20.0 以上才能使用)
},
};
5. 打包HTML
webpack默认只能识别js代码或json格式,HtmlWebpackPlugin 插件可以让webpack拥有识别html代码并自动生成 html 文件的能力
1. 安装
npm install --save-dev html-webpack-plugin
2. 配置
const HtmlWebpackPlugin = require('html-webpack-plugin') // 导入插件
const path = require('path')
module.exports = {
entry: path.resolve(__dirname,'src/login/index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: './login/index.js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({ // 配置插件
filename: path.resolve(__dirname,'public/login.html'), // 以自己的网页为基础生成模版
template: path.resolve(__dirname,'dist/login/index.html') // 生成后的模版的输出路径
})
]
]
};
6. 打包 CSS 文件
6.1 css保存在js文件中
1.安装
css-loader
webpack默认只能识别js代码,css-loader 加载器可以让webpack拥有解析css代码的能力
style-loader
webpack默认只能识别js代码,style-loader 加载器可以让webpack拥有将解析后的 css代码 插入到 DOM 中的能力
npm i --save-dev css-loader
npm i --save-dev style-loader
2. 准备工作
1. 在js 文件中需要手动引入css文件
import './index.css'
3.配置
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
打包后的 css 会默认打包到 js 文件中,下面可以将css提取到单独的文件中,使浏览器并行的下载文件,提高页面加载速度
6.2 单独提取 css
css-loader 加载器 + mini-css-extract-plugin 插件
1. 安装
npm i --save-dev css-loader
npm i --save-dev mini-css-extract-plugin
npm i --save-dev css-minimizer-webpack-plugin
2. 准备工作
1. 在js 文件中需要手动引入css文件
import './index.css'
3. 配置
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
plugins: [new MiniCssExtractPlugin({
filename: "./login/index.css" // 文件保存目标位置
})],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
optimization: {
minimizer: [
`...`, // webpack5 会根据这个配置压缩 js
new CssMinimizerPlugin(), // 压缩 css
],
},
};
7. 打包 less
7.1 安装
npm i --save-dev css-loader
npm i --save-dev less less-loader
7.2 配置
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.less$/i,
use: [
'style-loader', // 这里可以选择使用 MiniCssExtractPlugin.loader 打包到独立的css文件
'css-loader',
'less-loader',
],
},
],
},
};
8. 打包图片
8.1 版本差异
在 webpack 5 之前,通常使用:
raw-loader将文件导入为字符串url-loader将文件作为 data URI 内联到 bundle 中file-loader将文件发送到输出目录
资源模块类型(asset module type),通过添加 4 种模式,来替换所有这些 loader:
asset/resource发送一个单独的文件并导出 URL。之前通过使用file-loader实现。asset/inline导出一个资源的 data URI(base64字符串)。之前通过使用url-loader实现。asset/source导出资源的源代码。之前通过使用raw-loader实现。asset在导出一个 data URI 和发送一个单独的文件之间自动选择,如果资源大于8kb则使用 asset/resource 模式,小于则使用 asset/inline 模式。之前通过使用url-loader,并且配置资源体积限制实现。
8.2 准备工作
1. 在js 文件中如果是本地图片资源需要手动引入图片文件,如果是网络图片,可以直接写
import imgObj from './assets/logo.png'
8.3 配置
webpack.config.js
自定义输出到指定目录,方式一
const path = require('path');
module.exports = {
output: {
// ...
assetModuleFilename: 'assets/[hash][ext][query]'
},
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset',
}
]
},
};
自定义输出到指定目录,方式二
webpack.config.js
const path = require('path');
module.exports = {
output: {
// ...
assetModuleFilename: 'images/[hash][ext][query]'
},
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset',
generator:{
filename: 'assets/[hash][ext][query]'
}
}
]
},
};
9. 搭建开发环境
借助了http模块创建了一个8080端口的web服务,默认以 webpack 配置的入口和出口 目录为服务器根目录,并且根据相关配置,打包相关代码在内存中,以output.path的值作为服务器根目录(所以可以直接自己拼接访问dist目录下的内容)
9.1 安装模块
npm i --save-dev webpack-dev-server
9.2 配置
package.json
{
"scripts": {
"dev": "webpack serve --open", // --open 表示自动打开默认浏览器
},
}
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development', // 设置开发环境
entry: {
index: './src/index.js',
print: './src/print.js',
},
plugins: [
new HtmlWebpackPlugin({
title: 'Output Management',
title: 'Development',
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
};
9.3 生产模式和开发模式的内置优化
开发模式: development 调试代码,实时加载,模块热替换等特点
**生产模式: production **压缩代码,资源优化,更轻量等特点
**配置方式一: **
webpack.config.js
module.exports = {
mode: 'production'
}
配置方式二: 优先级更高(推荐)
package.json
{
"scripts": {
"build": "webpack --mode=production"
"dev": "webpack --mode=development"
}
}
9.4 个性化配置
1. 需求
在开发模式下用 style-loader 将css 集成在js 文件中,生产模式下提取 css 代码到单独文件
1. 方案一
利用webpack.config,js 中配置导出函数,但是局限性大且只接收两种模式
module.exports = (env, argv) => {
if (argv.mode === 'development') {
config.devtool = 'source-map';
}
if (argv.mode === 'production') {
//...
}
return config;
};
2. 方案二:
借助 cross-env 包命令设置参数区分环境,(跨平台通用)
1. 安装
npm i --save-dev cross-env
2. 配置
package.json
{
"scripts": {
"build": "cross-env NODE_ENV=production webpack --mode=production",
"dev": "cross-env NODE_ENV=development webpack server --open --mode=development"
}
}
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
plugins: [new MiniCssExtractPlugin({
filename: "./login/index.css" // 文件保存目标位置
})],
module: {
rules: [
{
test: /\.css$/i,
use: [process.env.NODE_ENV === 'development' ? "style-loader" : MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
optimization: {
minimizer: [
`...`, // webpack5 会根据这个配置压缩 js
new CssMinimizerPlugin(), // 压缩 css
],
},
};
方案三: 配置不同的 webpack.config.js (适用于多种模式差异性较大的情况)
2. 需求
使用内置插件DefinePlugin,来实现在前端项目中,开发模式下打印函数生效,生产模式下打印函数失效
webpack.config.js
module.exports = {
plugins: [new webpack.DefinePlugin({
// key: 注入到打包后的前端js代码中作为全局变量
// value: 变量对应的值(在cross-env 注入在node.js 中的环境变量字符串)
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
})],
};
前端代码中使用
if (process.env.NODE_ENV === "production") {
console.log = function(){} // 将console.log 赋值为一个空函数
}
request.js
// 配置 开发环境/ 生产环境 的 URL根地址
axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://192.168.0.89:8888' : 'http://www.baidu.com'
9.5 开发环境调错
webpack.config.js
const config = {
plugins: [new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
})],
}
// 确保该功能只在开发环境中生效
if (process.env.NODE_ENV === "develoment"){
config.devtool = 'inline-source-map'
}
module.exports = config
9.6 路径别名 alias
在 webpack.config.js 中配置解析别名 @ 来代表 src 绝对路径
webpack.config.js
const config = {
resolve:{
alias:{
'@': path.resolve(__dirname,'src')
}
}
}
module.exports = config
index.js
import {checkPhone} from '@/utils/check.js'
9.7 CDN 加速
**作用: ** 将 静态资源文件 / 第三方库 放在 CDN 网络中的各个服务器中,供用户就近请求获取
1. 需求
开发模式使用本地第三方库, 生产模式下使用 CDN 加载引入
1. 在 html 中引入第三方库的 CDN 并用模版语法进行判断当前运行环境
<% if (htmlWebpackPlugin.options.useCdn) %>
<link href="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.11/dayjs.min.js" rel="stylesheet">
<% } %>
2. 配置 webpack.config.js 中 externals 外部扩展选项(防止某些import的包被打包)
webpack.config.js
const config = {
plugins: [new HtmlWebpackPlugin({
useCdn: process.env.NODE_ENV === "production"
})],
}
// 确保该功能只在开发环境中生效
if (process.env.NODE_ENV === "production"){
config.externals = {
// key: js代码导包时的 from 后面的标识字符串
// value: js代码导包时的 import 后面的变量名(要与 cdn 暴露在全局的变量名一致)
'dayjs': 'dayjs',
"bootstrap/dist/css/bootstrap.min.css": "bootstrap"
}
}
module.exports = config
10. 多页面打包
**单页面: ** 单个 html 文件,切换 DOM 的方式 实现不同业务逻辑展示,如Vue/React
**多页面: ** 多个html,切换页面实现不同业务逻辑展示
1. 准备源码.并改用模块化语法 导出 / 导入
2. 配置 webpack.config.js 的多入口和多页面设置
webpack.config.js
const config = {
entry: {
"模块名1": path.resolve(__dirname,'src/入口1.js'),
"模块名2": path.resolve(__dirname,'src/入口2.js')
},
output: {
path: path.resolve(__dirname,'dist'),
filename: './[name]/index.js'
},
plugins: [
new HtmlWebpackPlugin({
template: './public/页面1.html',
filename: './路径/index.html',
chunks:["模块名1"]
}),
new HtmlWebpackPlugin({
template: './public/页面2.html',
filename: './路径/index.html',
chunks:["模块名2"]
})
]
}
module.exports = config
11. 提取公共代码
1. 配置
webpack.config.js
const config = {
optimization: {
splitChunks: {
chunks: 'all', // 所有模块动态非动态引入的都分割分析
cacheGroups: { // 分割组
commons: { // 抽取公共模块
minSize: 0, // 抽取的chunk最小大小字节
minChunks: 2, // 最小引用数
reuseExitingChunk: true, // 当前 chunk 包含已从主 bundle 中拆分出的模块,则它江北重用
name(module,chunks,cacheGroupKEy) { // 分离出模块文件名
const allChunksNames = chunks.map((item) => item.name).join("~") // 模块名1~模块名2
return `./js/${allChunksNames}` // 输出到 dist 目录下的位置
}
}
}
}
}
}
module.exports = config

浙公网安备 33010602011771号