webpack 5 基础学习
学习资料:前言 | 尚硅谷 Web 前端之 Webpack5 教程 (gitee.io)
概念 | webpack 中文文档 | webpack 中文文档 | webpack 中文网 (webpackjs.com)
用于打包资源和代码,打包静态文件 我们将webpack 打包的文件 称为 bundle
主要功能:压缩和加密代码文件 ,最后生成 用于上线 的代码
1.开发模式 仅能 编译 ES Moudle (解析 es6 语法)
2.生产模式 在上面的基础上还可以压缩 js 代码
开发模式:开发代码使用的模式
1.我们要加载配置这些资源,编译代码
- 代码检测树立代码规范
基本概念
命令行界面(CLI), 用于配置构建并与之交互。它在早期原型制作和性能分析的情况下特别有用。 大多数情况下, CLI 只是用于通过配置文件和一些标志(例如--env)来启动进程
使用 webpack 处理模块时, 最重要的是理解不同的模块语法 - 特别是受支持的方法和变量
Loaders 用于对模块的源代码进行转换。 它们被编写成一类将源代码作为参数传入, 并将编译转换后的新版本代码传出的函数体。
插件接口允许用户直接介入编译过程。 插件可以在不同时期运行的生命周期挂钩上注册回调函数。 在单个编译流程中,当每个钩子都被执行后,插件将拥有 当前编译流程的完整访问权限。
npx 会将 bin 目录添加为环境变量
快速使用 webpack (处理js 资源)
1.创建目录,src :用于存放原代码 在里面建立 文件main.js (打包的入口文件)
2 创建目标打包文件:src > js 文件夹 里面放一些js代码
3 . 在 main.js 中使用 js文件夹的代码
4 . 在src 目录同级建立 public 文件夹 放一些非代码的资源 icon html等 在public建立 html 文件,引用main.js 未经打包是无法识别 es6语法的 直接报错
5.快捷创建包描述 在根文件目录终端(webpack文件夹)下 输入指令 npm init -y 会生成一个 package.json 文件 (调整一下main 的路径)
6.安装 依赖 根文件目录终端输入 npm i webpack webpack-cli -D 就会生成 node mudle 文件夹 与 pakegae-lock
7 . 设置入口文件以及工作模式 npx webpack ./src/main.js --mode=development (production) production会对解析后代码进行压缩 这样就可以打包好一个编译后的mainjs在dist 目录下
8.修改一下 html 里的 js 代码引入,再运行就可以实现 效果
webpack 基本配置
五大核心概念
1.entry 入口
开始打包的文件
2.output
打包好的文件输出目录
3.loader
webpack 本身只能处理js,json 要借助 loader 才能处理其他资源
4.plugin 插件
拓展功能
5.model
1.开发模式 development 开发者模式
2.生产模式 production 用于上线的时候使用
配置文件
配置文件创建在根文件目录下
使用名称 webpack.config.js 默认条件下的使用
const path =require("path"); // nodejs 的路径模块
module.exports={
// 入口 entry 使用 main。js作为入口文件
entry:'./src/main.js',
// 输出 output
output:{
// path 是文件输出路径(全路径) filename 为输出的文件名字 是指在当前根文件夹下的 dist文件夹输出
path:path.resolve(__dirname,"dist"),
filename:'main.js'
},
// 加载器
module:{
rules:[
// loader 规则
]
},
// 插件 plugin
plugins:{
// plugin的配置
},
// 模式 model
mode:development,
};
处理样式资源css
直接去官方文档里找 loader Loaders | webpack 中文文档 | webpack 中文文档 | webpack 中文网 (webpackjs.com)
这里先在src 文件目录下建立好 css 文件夹用于存放 css 文件
在main文件里引用
import "./css/index.css";
1.下载包
无论什么样式都要下载如下两个包
npm install --save-dev css-loader
npm i style-loader -D
-
引入规则 在rules 规则里面写 规则
test: /.css$/i, use: ["style-loader", "css-loader"],less sass,scss,stylus 的引入和可以参考文档 lodars 引入方法大同小异
基本步骤都是 先在main文件里引入
import "./css/style.less"
下载 loader 包 (在文档里)
在loader 对象里面增加一条规则(文档里的)
处理图片资源
在文档里面搜索asset , base64 就是将图片变为字符串 (dataURL形式)可以减少加载 ,打包后的文件名会变为一个唯一hash值
1.这里先在css 加入图片样式
2.在rules 增加规则
{
test:/.(png|jpe?g|gif|webp|svg)$/,
type:"asset",
parser:{
dataUrlCondition:{
// 10k以下转为 base64
maxSize:10*1024,
}
}
}
修改输出的路径
输出的js去js 目录,输出的图片去图片目录
webpack.config.js
path 规定所有的打包的目录 一般写 dist
filename 是写入口文件的文件名 一般写为 “static/js/main.js”
图片资源的输出路径放在rules 里面规定,一般增加一个generator 在output增加资源路径
output里面
assetModuleFilename: 'static/images/[hash:10][ext][query]', 加入路径
clean:true // 打包自动删除以前的打包文件
// rules 里面不变
{
test:/.(png|jpe?g|gif|webp|svg)$/,
type:"asset/resource",
parser:{
dataUrlCondition:{
// 10k以下转为 base64
maxSize:10*1024,
}
},
}
使用 icon
在阿里图标库里选择图标导出 使用 Font class 模式 在css 文件中添加 iconfont.css 样式
1.src 下创建一个 fonts 文件夹
导入ttf woff woff2后缀的文件
注意 iconfont.css 的样式文件指向 进行修改
在入口 文件中引入 import iconfont.css 样式
这时候在rules 规则里修改规则,
{
test:/.(ttf|woff2?)$/,
type:"asset/resource",
generator: {
filename: 'static/media/[hash][ext][query]'
}
}
其他资源的使用
比如说使用 声音,或视频,只需要在上面的规则里添加后缀名
{
test:/.(ttf|woff2?|MP3|MP4|avi)$/,
type:"asset/resource",
generator: {
filename: 'static/media/[hash][ext][query]'
}
}
如何处理js资源
webpack 对 模块化里面的语言,对ES6 语法解析不充分
1.使用Bebel 来进一步解析 es6 语法
2.使用 eslint 来检查格式
一般先检查格式再去 做兼容
eslint
可以检查 js 和 jsx 语法 可以使用 eslint 拓展来辅助
eslint 里配置的规则就是检查的规则
配置文件由很多种写法:
:新建文件,位于项目根目录
.eslintrc.eslintrc.js.eslintrc.json- 区别在于配置格式不一样
package.json中eslintConfig:不需要创建文件,在原有文件基础上写 vue 就是使用这种方法
常见的规则
其他规则可以见规则 官网Configuring ESLint - ESLint中文
开发中一点点写 rules 规则太费劲了,所以有更好的办法,继承现有的规则。
现有以下较为有名的规则: 可以通过 extends 继承规则
- Eslint 官方的规则open in new window:
eslint:recommended - Vue Cli 官方的规则open in new window:
plugin:vue/essential - React Cli 官方的规则open in new window:
react-app
使用是是采用webpack plugin 插件 具体可见webpack 官网 搜 eslint
在 根目录下创建 配置文件 .eslintrc.js
module.exports = {
// 继承 Eslint 规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
parserOptions: {
ecmaVersion: 6, // es6 规则
sourceType: "module",
},
rules: {
"no-var": 2, // 不能使用 var 定义变量
},
};
同时可以创建 .eslintignore 用于忽略检查的文件
dist
eslint 的使用
-
npm install eslint-webpack-plugin --save-dev
在 webpack.config.js 的 plugins 中调用
在最上面调用
const ESLintPlugin = require('eslint-webpack-plugin');//引入文档调用
//在plugins 里面使用
// plugins: [new ESLintPlugin(options)],
plugins: [new ESLintPlugin(
{context:path.resolve(__dirname,"src")} //检测src下面的内容
)],
babel
将 ES6 语法转化为 commn 便于 兼容
-
babel.config.*:新建文件,位于项目根目录
babel.config.jsbabel.config.json
-
.babelrc.*:新建文件,位于项目根目录
.babelrc.babelrc.js.babelrc.json
-
package.json中babel:不需要创建文件,在原有文件基础上写
Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可
@ 简单理解:就是添加一组 Babel 插件 ,扩展Babel 的功能
这里创建一个 babel.config.js 配置文件
module.exports = {
// 预设
presets: [],
};
@babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。@babel/preset-react:一个用来编译 React jsx 语法的预设@babel/preset-typescript:一个用来编译 TypeScript 语法的预设
具体内容见官网 什么是 Babel? · Babel 中文文档 (docschina.org)
具体使用
可以查看webpack 搜索 babel
在根目录下 创建 babel.config.js
module.exports={
// 可以编译es6的语法
presets: ['@babel/preset-env'],
}
主要是在rules 里增加配置
{
test: /.m?js$/,
exclude: /(node_modules)/, //排除 ndoe_modules 在的js不处理
use: {
loader: 'babel-loader',
// 配置信息可以写在外面也可以写在里面
// options: {
// presets: ['@babel/preset-env'],
// plugins: ['@babel/plugin-proposal-object-rest-spread']
// }
}
}
处理html 资源
在打包后main.js 使用自动资源引入,这里采用 HtmlWebpackPlugin 在 webpack 文档里可以搜到,在开发中的html 就不要手动添加了
1.下载相关的包
npm install --save-dev html-webpack-plugin
- 在配置文件里的规则进行引用和使用,这样在就可以 template 设置的路径下得到一个自动引入入口文件的html
// 在顶部引入
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 插件 plugin
plugins: [new ESLintPlugin(
{context:path.resolve(__dirname,"src")} //检测src下面的内容
),new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建新的html
template:path.resolve(__dirname,"public/index.html")
})],
自动化更新
不用反复输入 npx webpack,改动刷新就会更新打包
只是在内存中打包资源,不会真实输出打包文件
下载包
npm i webpack-dev-server -D
在 webpack.config.js 里面配置文件
添加开发服务器,在plugins 后面添加配置
// 开发服务器
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
},
运行指令变为
npx webpack serve
ctrl +c 关闭终端
生产模式
用生产 上线代码的需要打包文件,开发摸手机可以只用开发服务器运行数据
为了区分生产模式和开发模式这里区分一下配置文件
1.在根目录下创建一个 config 文件
2.将 webpack.config,js 移动到该文件下,复制一份 将两个文件分别命名为 webpack.dev.js 和 webpack.prod.js 要将 调整绝对路径
__dirname,"../public/index.html" 提升一级
webpack.dev.js
const path =require("path"); // nodejs 的路径模块
const ESLintPlugin = require('eslint-webpack-plugin');//引入文档调用
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports={
// 入口 entry 使用 main.js作为入口文件
entry:'./src/main.js',
// 输出 output
output:{
// path 是文件输出路径(全路径) filename 为输出的文件名字 是指在当前根文件夹下的 dist文件夹输出
path:undefined,
filename:'static/js/main.js',
assetModuleFilename: 'static/images/[hash:10][ext][query]',
// clean:true // 打包自动删除以前的打包文件
},
// 加载器
module:{
rules:[
// loader 规则
{
test: /.css$/i, //检测 css文件
use: ["style-loader", "css-loader"], //从下到上 css资源编译成 commojs style标签放入到 html 文件中
},
{
test: /.less$/i,
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test:/.(png|jpe?g|gif|webp|svg)$/,
type:"asset/resource",
parser:{
dataUrlCondition:{
// 10k以下转为 base64
maxSize:10*1024,
}
},
// generator: {
// filename: 'static/images/[hash][ext][query]'
// }
},
{
test:/.(ttf|woff2?)$/,
type:"asset/resource",
generator: {
filename: 'static/media/[hash][ext][query]'
}
},
{
test: /.m?js$/,
exclude: /(node_modules)/, //排除 ndoe_modules 在的js不处理
use: {
loader: 'babel-loader',
// 配置信息可以写在外面也可以写在里面
// options: {
// presets: ['@babel/preset-env'],
// plugins: ['@babel/plugin-proposal-object-rest-spread']
// }
}
}
]
},
// 插件 plugin
plugins: [new ESLintPlugin(
{context:path.resolve(__dirname,"../src")} //检测src下面的内容
),new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建新的html
template:path.resolve(__dirname,"../public/index.html")
})],
// plugin的配置
// 开发服务器
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
},
// 模式 model
mode:"development",
};
webpack.prod.js
const path =require("path"); // nodejs 的路径模块
const ESLintPlugin = require('eslint-webpack-plugin');//引入文档调用
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports={
// 入口 entry 使用 main.js作为入口文件
entry:'./src/main.js',
// 输出 output
output:{
// path 是文件输出路径(全路径) filename 为输出的文件名字 是指在当前根文件夹下的 dist文件夹输出
path:path.resolve(__dirname,"../dist"),
filename:'static/js/main.js',
assetModuleFilename: 'static/images/[hash:10][ext][query]',
clean:true // 打包自动删除以前的打包文件
},
// 加载器
module:{
rules:[
// loader 规则
{
test: /.css$/i, //检测 css文件
use: ["style-loader", "css-loader"], //从下到上 css资源编译成 commojs style标签放入到 html 文件中
},
{
test: /.less$/i,
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test:/.(png|jpe?g|gif|webp|svg)$/,
type:"asset/resource",
parser:{
dataUrlCondition:{
// 10k以下转为 base64
maxSize:10*1024,
}
},
// generator: {
// filename: 'static/images/[hash][ext][query]'
// }
},
{
test:/.(ttf|woff2?)$/,
type:"asset/resource",
generator: {
filename: 'static/media/[hash][ext][query]'
}
},
{
test: /.m?js$/,
exclude: /(node_modules)/, //排除 ndoe_modules 在的js不处理
use: {
loader: 'babel-loader',
// 配置信息可以写在外面也可以写在里面
// options: {
// presets: ['@babel/preset-env'],
// plugins: ['@babel/plugin-proposal-object-rest-spread']
// }
}
}
]
},
// 插件 plugin
plugins: [new ESLintPlugin(
{context:path.resolve(__dirname,"../dist")} //检测src下面的内容
),new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建新的html
template:path.resolve(__dirname,"../public/index.html")
})],
// plugin的配置
// 不需要开发服务器
// 模式 model
mode:"production",
};
3.在pakage.json 配置快捷指令
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev": "webpack serve --config ./config/webpack.dev.js",
"build": "webpack --config ./config/webpack.prod.js",
"start":"npm run dev"
},
npm start 快捷打开 dev
npm run build 快捷打开production
CSS 单独处理
将Css单独变为单独文件,而不是嵌入在main.js 里面输出,设备解析js 需要时间
1.下载安装包
npm i mini-css-extract-plugin -D
在 webpack 官网搜索 MiniCssExtractPlugin
在生产环境下安装插件
config.dev.js
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //添加插件
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "../dist"), // 生产模式需要输出
filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
clean: true,
},
module: {
rules: [
{
// 用来匹配 .css 结尾的文件
test: /.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /.less$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"], //添加插件 换掉style-loader
},
{
test: /.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],//添加插件
},
{
test: /.styl$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"],//添加插件
},
{
test: /.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
},
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
},
},
{
test: /.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({ // new 一个路径
// 定义输出文件名和目录
filename: "static/css/main.css",
}),
],
// devServer: {
// host: "localhost", // 启动服务器域名
// port: "3000", // 启动服务器端口号
// open: true, // 是否自动打开浏览器
// },
mode: "production",
};
兼容处理
css 也会出现兼容性问题
npm i postcss-loader postcss postcss-preset-env -D
在css-loader后面添加
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
在packge.json 最后添加
"browserslist": ["last 2 version", "> 1%", "not dead"]
CSS 压缩
可以将css 样式变为 一行在webpack官方 搜索 cssminimizer 查看
安装包
npm install css-minimizer-webpack-plugin --save-dev
在 config.dev.js 中引用插件
html
html 和js 会默认压缩
总结
1.学习了两种开发模式
生产模式(编译语法和压缩文件)和开发模式(编译语法)
2.webpack 的核心
配置文件: config.dev.js 与 config.prod.js
3.快捷指令的配置
webpack 优化
提升开发体验
SourceMap
使用webpack 打包编译只能提示打包后文件的错误,不能提示源文件中的错误,source 可以映射原文件的错误 会生成一个 xxx.map 用于映射原代码和打包后代码的关系 在webpack.dev.js ,webpack.prod.js设置
可以先在 webpack 官方文档里搜索 devtool 查看
实际开发中:
在mode配置后面添加配置开发模式下使用: cheap-module-source-map (优点:打包编译速度快,只包含行映射,缺点:没有列映射)
// 模式 model
mode:"development",
devtool:"cheap-module-source-map",
生产者模式: source-map (优点:包含行/列映射 缺点:打包慢)
mode:"production",
devtool:"source-map"
提升打包速度
HotModuleReplacement
只能用于开发模式 ,传统的打包时候会从入口文件一个个的打包,HotModuleReplacement 对修改过的文件进行操作,在webpack 5 是默认配置 在 config.dev.js中进行 devServer:{hot:false// 关闭}
oneOf
在进行打包的时候所有的loader都会依次匹配 ,使用 on of只有匹配到了就会跳出匹配,把所有的loader oneOf 数组里
生产模式和开发模式都要写
排除文件
排除一些不必要的文件加快打包,使用 include 和exclude,这里是二选一 (生产和开发都需要)
在 rules 规则下 设置
include :path.resolve(__dirname."../src")
主要在 js loader 上面加和 eslint 插件里面添加
Cach
每次打包时 js 文件都要经过 Eslint 检查 和 Babel 编译,速度比较慢。
我们可以缓存之前的 Eslint 检查 和 Babel 编译结果,这样第二次打包时速度就会更快了。
在 js loader 后面加 option
options: {
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩
},
// 在 eslint 添加
cache: true, // 开启缓存
// 缓存目录
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
Thead
使用多线程打包可以加快打包,当项目越来越庞大时 打包速度就越慢,处理js 的 工具主要是 eslint,babel,Terser 三个工具
这个一般只是在生产模式中使用
npm i thread-loader -D
减少代码体积
Tree shaking
生产模式里的时候我们定义了一些工具函数库,或者引用 第三方函数库或者组件库
Tree shaking 是用到什么功能就打包什么功能,依赖于 es module
一个模块里有多个函数,因此打包只会打包调用过的函数,已经默认开启
babel
下载包
npm i @babel/plugin-transform-runtime -D
在js 规则里面添加
plugins: ["@babel/plugin-transform-runtime"],
babel 会使用引入一些比较小的代码,且会重复定义使用 ,需要禁用
imgage Minimizer
一般图片是静态链接,如果是本地的静态图片才会需要压缩 一般采用 image-minimizer-webpack-plugin 用来压缩图片
imge-minimizer-webpack-plugin 用来压缩图片的插件
下载包
npm i image-minimizer-webpack-plugin imagemin -D
下面还要用其他的包进行模式选择
无损压缩
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D
无损压缩
优化代码的运行性能
code Split
打包代码的时候会将 所有的js 打包到一个文件中,体积太大,如果分割成多个文件时运行起来就快了需要什么运行什么js文件
要分割的时候要对文件进行切分设定多个入口
npm i webpack webpack-cli html-webpack-plugin -D
这里会生成两个js 文件
console.log("hello app");
console.log("hello main");
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// 单入口
// entry: './src/main.js',
// 多入口
entry: {
main: "./src/main.js",
app: "./src/app.js",
},
output: {
path: path.resolve(__dirname, "./dist"),
// [name]是webpack命名规则,使用chunk的name作为输出的文件名。
// 什么是chunk?打包的资源就是chunk,输出出去叫bundle。
// chunk的name是啥呢? 比如: entry中xxx: "./src/xxx.js", name就是xxx。注意是前面的xxx,和文件名无关。
// 为什么需要这样命名呢?如果还是之前写法main.js,那么打包生成两个js文件都会叫做main.js会发生覆盖。(实际上会直接报错的)
filename: "js/[name].js",
clear: true,
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
mode: "production",
};
preload: 告诉浏览器加载资源
prefetch:浏览器空闲时加载资源