什么webpack
webpack文档地址:概念 | webpack 中文文档
本质上,webpack是一个用于现代Javascript应用程序的静态模块打包工具,当webpack处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个bundles,他们均为静态资源,用于展示你的内容。
静态模块:指的是编写代码过程中的html、css、js、图片等固定内容的文件
打包:把静态模块内容,压缩,整合(把多个css文件、或js文件整合到一个文件中,减少浏览器http的请求次数,让用户更快的访问到页面),转译(把less、sass转成css代码;把ES6+降级成ES5;支持多种模块标准语法)等(前端工程化)
使用Webpack
需求:封装utils包,校验手机号长度和验证码长度,在src/index.js中使用并打包观察
步骤:
- 新建并初始化项目,编写业务源代码 npm init -y
- 下载webpack webpack-cli到当前项目中(版本独立),并配置局部自定义命令
npm i webpack webpack-cli --save-dev
配置局部自定义指令
"scripts":{
"buold":"webpack"
}
3 运行打包命令(npm run build),自动产生dist分发文件夹(压缩和优化后,用于最终运行的代码)
修改webpack的入口和出口
- 项目根目录,新建webpack.config.js配置文件
- 导出配置对象,配置入口,出口文件的路径
- 重新打包观察
注意:只有和入口产生直接/间接的引入关系,才会被打包
const path = require('path')
module.exports = {
//入口
entry: path.resolve(__dirname, 'src/login/index.js'),
// 出口
output: {
path: path.resolve(__dirname, 'dist'),
filename: './login/index.js',
clear: true //生成打包内容之前,清空输出目录,在版本5.2.0以上的版本
}
}
自动生成html文件
插件html-webpack-plugin 在webpack打包时生成html文件HtmlWebpackPlugin | webpack 中文文档
下载html-webpack-plugin本地软件包:
配置webpack.config.js让webpack拥有插件功能
npm install --save-dev html-webpack-plugin
webpack.config.js的文件内容
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
//入口
entry: path.resolve(__dirname, 'src/login/index.js'),
// 出口
output: {
path: path.resolve(__dirname, 'dist'),
filename: './login/index.js',
clean: true //生成打包内容之前,清空输出目录
},
// 插件:给webpack提供更多的功能
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public/login.html'), //模板文件
filename: path.resolve(__dirname, 'dist/login/index.html') //输出文件
})
]
}
生成后的html文件也会自动引入js文件
<script defer="defer" src=".././login/index.js"></script>
打包CSS代码
注意:Webpack默认只识别js代码
加载器:css-loader :解析css代码
加载器:style-loader:把解析后的css代码插入到DOM
安装 :npm install style-loader css-loader --save-dev
将CSS文件代码引入到src/login/index.js中(压缩转移处理等)
下载css-lader和style-loader本地软件包
配置webpack.config.js让webpack拥有该加载器功能
在webpack.config.js文件中添加如下代码
// 加载器(让webpack识别更多模块文件内容)
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
}
]
}
优化-提取css代码
好处:css文件可以被浏览器缓存,减少js文件体积
注意:不能和style-loader一起使用
文档:https://webpack.docschina.org/plugins/mini-css-extract-plugin/
npm install --save-dev mini-css-extract-plugin
配置webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public/login.html'), //模板文件
filename: path.resolve(__dirname, 'dist/login/index.html') //输出文件
}),
new MiniCssExtractPlugin() //生成css文件
],
// 加载器(让webpack识别更多模块文件内容)
module: {
rules: [
{
test: /\.css$/i,
// use: ['style-loader', 'css-loader']
use: [MiniCssExtractPlugin.loader, "css-loader"]
}
]
}
优化-压缩过程
使用 css-minimizer-webpack-plugin插件
浮动地方
为
npm i css-minimizer-webpack-plugin --save-dev
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
optimization: {
// 最小化
minimizer: [
// 对于 webpack@5 你可以使用 `...` 语法来扩展现有的 minimizers
// (i.e. `terser-webpack-plugin`),请将下一行注释掉,保证js代码还能被压缩处理
`...`, //不用这个,就需要用内置的插件terser-webpack-plugin
new CssMinimizerPlugin(),
],
},
打包less
npm install less less-loader --save-dev
module: {
rules: [
{
test: /\.css$/i,
// use: ['style-loader', 'css-loader']
use: [MiniCssExtractPlugin.loader, "css-loader"]
}, {
test: /\.less$/i,
use: [
// 'style-loader', 这个不能和MiniCssExtractPlugin.loader混用
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
]
},
打包图片
资源模块 | webpack 中文文档
资源模块:webpack5内置资源模块(字体、图片等)打包,无需额外loader
步骤:
配置webpack.config.js让webpack拥有图片打包功能
type:"asset" : 模式的判定方式,自己判断采用哪种方式
作用:
base64 =》减少http请求,让网页加载快一些,大于8KB,因为资源模块转为base64字符串的时候,可能会让这个文件真实的体积大于20%到30%之间,
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
type: 'asset', //让它自己判定是那种方式
generator:{
filename:"assets/[hash][ext][query]"
}
},
]
},
占位符[hash]对模块内容做算法计算,得到映射的数字字母组合的字符串
占位符[ext]使用当前模块原本的占位符,例如:.png,.jpg等字符串
占位符[query]保留引入文件时代码中查询参数(只有URL下生效)
注意:js中引入本地图片资源要用import方式(如果时网络图片http地址,字符串可以直接写)
搭建开发环境
问题:之前改代码,需要重新打包才能运行查看,效率很低,
开发环境:配置webpack-dev-server快速开发应用程序
作用:启动web服务,自动检测代码变化,热更新到网页
注意:dist目录和打包内容是在内存里(更新快)
步骤
下载 npm i webpack-dev-server --save-dev
设置模式位开发模式,并配置自定义命令
module.exports={ ... mode:'development'}
在pakage.json文件中修改
"scripts":{
"dev":"webpack serve --open"
}
使用npm run dev来启动开发服务器,试试热更新效果
注意1:webpack-dev-server 借助http模块创建8080默认web服务,
注意2:默认以public文件夹作为服务器根目录,访问该目录下的index.html
注意3:webpack-dev-server根据配置,打包相关代码在内存当中,以output.path的值作为服务器目录(所以可以直接拼接访问dist目录下的内容)
浏览器直接输入localhost:8080/login/index.html
location.href = '/login/index.html' 在public/index.html里面写如上代码,直接跳转到打包好的html文件内容
打包模式
打包模式:告知webpack使用相应模式的内置优化
分类
模式名称 | 模式名字 | 特点 | 场景 |
---|---|---|---|
开发模式 | development | 调试代码,实时加载,模块热替换等 | 本地开发 |
生产模式 | production | 压缩代码,资源优化,更轻量等 | 打包上线 |
设置:
方式一:在webpack.config.js配置文件设置mode选项
方式二:在package.json命令行设置mode参数
注意:命令行设置的优先级高于配置文件中的,推荐用命令行设置
推荐在package.json文件中进行修改
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode=production",
"dev": "webpack serve --open --mode=development"
},
打包模式的应用
需求:在开发模式下用style-loader内嵌更快,在生成模式下提取css代码
方案一:webpack.config.js配置导出函数,但是局限性大(只接收2中模式)
方案二:借助cross-env(跨平台通用)包命令,设置参数区分环境
步骤
下载cross-env软件包到当前项目 npm i cross-env --save-dev
配置自定义命令,传入参数名和值(会绑定到process.env对象下)
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "cross-env NODE_ENV=production webpack --mode=production",
"dev": "cross-env NODE_ENV=development webpack serve --open --mode=development"
},
在webpack.config.js区分不同环境使用不同配置
rules: [
{
test: /\.css$/i,
// use: ['style-loader', 'css-loader']
use: [process.env.NODE_ENV == 'production' ? MiniCssExtractPlugin.loader : 'style-loader', "css-loader"]
}, {
test: /\.less$/i,
use: [
// 'style-loader',
process.env.NODE_ENV == 'production' ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'less-loader'
]
},
....
]
方案3:配置不同的webpack.config.js(适用于多种模式差异较大情况)
前端-注入环境变量
需求:前端项目中,开发模式下打印语句生效,生产模式下打印语句失效
问题:cross-env设置的只在Node.js环境生效,前端代码无法访问process.env.NODE_ENV
解决:使用Webpack内置的DefinePlugin插件
DefinePlugin | webpack 中文文档
const webpack = require('webpack');
module.exports = {
new webpack.DefinePlugin({
// key是注入到打包后的前端js代码中作为全局变量
// value是变量对应的值在cross-env注入在node.js中的环境变量字符串
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV)
})
}
在index.js中设置console.log不起效
// 在这个后面的才会失效
if (process.env.NODE_ENV === 'production') {
console.log = function () { }
}
开发环境调错-source map
问题:代码被压缩和混淆,无法正确定位源代码位置(行数和列数)
source.map: 可以准确追踪error和warning在原始代码的位置
设置:webpack.config.js配置devtool选项
module.exports={
....
devtool:'inline-source-map'
}
inline-source-map选项:把源码的位置信息一起打包在js文件内
注意:source map仅适用于开发环境,不要再生产环境使用,(防止被轻易查看源码位置)
if (process.env.NODE_ENV === 'development') {
config.devtool = 'inline-source-map'
}
module.exports = config
解析别名 alias
解析别名:配置模块如何解析,创建import引入路径的别名,类确保模块引入变得更简单
解决:再webpack.config.js中配置解析别名@
//解析别名
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
优化-CDN使用
cdn定义:内容分发网络,指的是一组分布再各个地区的服务器
作用:把静态资源/第三方库放在CDN网络中各个服务器中,共用户就近请求获取
好处:减轻自己服务器请求压力,就近请求物理延迟低,配套缓存策略
需求:开发模式使用本地第三方库,生产模式下使用CDN加载引入
步骤:
在html中引入第三方库的CDN地址并用模板语法判断
配置webpack.config.js中externals外部扩展选项(防止某些import的包被打包)
步骤:
在html中引入cdn,并用模板语法判断
<% if(htmlWebpackPlugin.options.useCdn) { %>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet">
<% } %>
<% if(htmlWebpackPlugin.options.useCdn) { %>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6.axios.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/js/bootstrap.min.css"></script>
<% } %>
在webpack.config.js中配置useCdn的值和相关配置
const config={
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public/login.html'), //模板文件
filename: path.resolve(__dirname, 'dist/login/index.html'), //输出文件
useCdn: process.env.NODE_ENV === 'production' //生产模式下使用cdn引入的地址
}),
]
}
//生产环境下使用相关配置
if (process.env.NODE_ENV === 'production') {
config.externals = {
// key: import from 语句后面的字符串
// value:留在原地的全局变量(最好和cdn在全局暴露的变量一致)
'bootstrap/dist/css/bootstrap.min.css': 'bootstrap',
'axios': 'axios'
}
}
多页面打包
单页面:单个html文件,切换DOM的方式实现不同业务逻辑展示,
多页面:多个html文件,切换页面实现不同业务逻辑展示
const config = {
entry: {
"模块名1": path.resolve(__dirname, 'src/入口1.js'),
"模块名2": path.resolve(__dirname, 'src/入口2.js')
},
output: {
path: path.relative(__dirname, 'dist'),
filename: './[name]/index.js' // 多个模块自己选择到对应的文件夹下
},
plugins: [
new HtmlWebpackPlugin({
template: './public/页面2.html',//模板文件
filename: './路径/index.html', //输出文件,不能用[name]
chunks: ['模块名2']
}),
new HtmlWebpackPlugin({
template: './public/页面1.html',
filename: './路径/index.html', //输出到对应的文件夹下
chunks: ['模块名1'] // 引入那些打包后的模块(和entry的key一致)
}),
new MiniCssExtractPlugin({
filename: './[name]/index.css'
})
]
}
分割公共代码
需求:把2个以上页面引用的公共代码提取
步骤:
1 配置webpack.config.js的splitChunks分割功能
optimization: {
splitChunks: {
chunks: 'all', //所有模块动态非动态移入的都分割分析
cacheGroups: { //分隔组
commons: { //抽取公共模块
minSize: 0, // 抽取的chunk最小大小字节
minChunks: 2, //最小引用数
reuseExistingChunk: true, //当前chunk包含已从主bundle中拆分出的模块,则它将被重用
name(module, chunks, cacheGroupKey) { //分离出模块文件名
const allChunksNames = chunks.map((item) => item.name).join('~') //模块名1~模块名2
return `./js/${allChunksNames}` //输出到dist目录下位置
}
}
}
}
}