diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 0bfd30ef..ada3e1c2 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -59,6 +59,10 @@ export default defineConfig({ text: 'Nodejs', link: '/front-end/05-Node.js/' }, + { + text: 'Webpack', + link: '/front-end/08-webpack/' + }, { text: 'React', link: '/front-end/' @@ -159,6 +163,7 @@ sidebar: { "/front-end/05-Node.js/": set_sidebar("/docs/front-end/05-Node.js/"), "/front-end/06-mongoDB/": set_sidebar("/docs/front-end/06-mongoDB/"), "/front-end/07-ajax/": set_sidebar("/docs/front-end/07-ajax/"), + "/front-end/08-Webpack/": set_sidebar("/docs/front-end/08-webpack/"), "/blogs/01-technology/": set_sidebar("/docs/blogs/01-technology/"), "/devops/git/": set_sidebar("/docs/devops/git/"), }, diff --git a/docs/front-end/08-webpack/01-webpack.md b/docs/front-end/08-webpack/01-webpack.md new file mode 100644 index 00000000..227dad3f --- /dev/null +++ b/docs/front-end/08-webpack/01-webpack.md @@ -0,0 +1,1108 @@ +# webpack + +## 1 webpack 概述 + +### 1.1 什么是 webpack + +**webpack** 是一个用于现代 JavaScript 应用程序的 **打包工具**。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图,然后将项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,可以在浏览器上直接运行。 + +打包工具:把很多细分的功能合成一个,让浏览器支持。 + +在 webpack 看来, 前端的所有资源文件(js、json、css、img 、html...)都会作为模块处理。 + +**官方网站:** https://webpack.js.org/ + +**中文网站:** https://www.webpackjs.com/ 或者 https://webpack.docschina.org/guides/ + +### 1.2 为什么需要打包工具 + +开发时,我们会使用框架(React、Vue 等),ES6 模块化语法,less、sass 这种 css 预处理器等语法进行开发。这样的代码要想在浏览器运行必须经过编译成浏览器能识别的 js、css 等语法,才能运行。所以我们需要打包工具帮我们做完这些事。除此之外,打包工具还能压缩代码、做兼容性处理、提升代码性能等。 + +常见的打包工具有 Grunt、Gulp、Parcel、Webpack、Rollup、Vite 等, 目前最流行的打包工具是 webpack。 + +### 1.3 webpack 五大核心概念 + +* Entry: 指示 webpack 从哪个文件开始打包 。 + * Output: 指示 webpack 打包完的文件输出到哪里去,如何命名等 。 +* Loader: webpack 本身只能处理 js、json 等资源,其他资源需要借助 loader,Webpack 才能解析 。 + * Plugins: 扩展 webpack 的功能 ,如打包优化、压缩等。 +* Mode:模式,有生产模式 production 和开发模式 development 两种。 + +### 1.4 开发模式和生产模式 + +#### 开发模式: + +开发模式顾名思义就是我们开发代码时使用的模式。这个模式下我们主要做两件事: + +1. 编译代码,使浏览器能识别运行,开发时我们有样式资源、字体图标、图片资源、html 资源等,webpack 默认都不能处理这些资源,所以我们要加载配置来编译这些资源。 +2. 代码质量检查,树立代码规范,提前检查代码的一些隐患,让代码运行时能更加健壮。提前检查代码规范和格式,统一团队编码风格,让代码更优雅美观。 + +#### 生产模式: + +生产模式是开发完成代码后,我们需要得到代码将来部署上线。这个模式下我们主要对代码进行优化,让其运行性能更好。优化主要从两个角度出发: + +1. 优化代码运行性能。 +2. 优化代码打包速度。 + + + +## 2 安装 webpack + +**全局安装:** + +```shell +# 安装 +npm install webpack webpack-cli -g + +# 使用 +webpack -v +``` + +**本地安装(推荐):** + +```bash +# 安装 +npm install webpack webpack-cli -D + +# 使用 +npx webpack -v +``` + +> ① wepback 是核心内容,webpack-cli 是在运行 webpack命令时,所依赖的一个工具。 +> +> ② 使用 npx 可以执行安装在本地的命令行可执行命令。 + + + + + +## 3 零配置使用 webpack 命令 + +### 3.1 webpack 命令 + +顾名思义,零配置指的是可以在无配置的情况下使用 wepack 命令对代码进行打包操作。 + +```js +# 将 src/index.js 打包至 dist/main.js 模式默认值:production +npx webpack + +# 将 src/index.js 打包至 dist/main.js 模式指定为:development +npx webpack --mode development + +# 将 src/one.js 打包至 dist/main.js +npx webpack ./src/one.js --mode development + +# 将 src/one.js、two.js 打包至 dist/main.js +npx webpack ./src/one.js ./src/two.js --mode development + +# 将 src/one.js 打包至 build/main.js +npx webpack ./src/one.js --output-path build --mode development + +# 将 src/two.js 打包至 dist/index.js +npx webpack ./src/two.js --output-filename index.js --mode development + +# 将 src/one.js 和 src/two.js 打包至 build/index.js +npx webpack ./src/one.js ./src/two.js --output-path build --output-filename index.js --mode development +``` + +eavl全局函数:字符串当作代码进行执行。目的是为了方便统计代码的长度,优化的建议。 + +### 3.2 配置 npm 执行命令 + +可以通过配置 `package.json` 来保存命令: + +```json +{ + "scripts": { + "build": "npx webpack ./src/index.js --output-path build --output-filename ./dist/app.js --mode development", + "start": "npx webpack ./src/index.js --output-path start --output-filename ./dist/app.js --mode development" + } +} + +``` + +可以通过`npm run build` 或者 `npm start` 运行命令 (如果名字为 `start` 可以省略 `run`) + +### 3.3 演示:编译打包应用 + +**创建 js 文件** + +```javascript + src/app.js + src/js/one.js + src/js/two.js + src/js/three.js +``` + +**创建 json 文件** + +```javascript +src/json/data.json +``` + +**src/app.js 文件:** + +```js +// 导入模块 +import one from './js/one'; // 扩展名可以省略 +import two from './js/two'; // 扩展名可以省略 +import three from './js/three'; // 扩展名可以省略 + +// 导入json +import users from './json/data'; // 扩展名可以省略 + +one(); +two(); +three(); +console.log(users); +``` + +**运行指令:** + +```bash +npx webpack ./src/app.js --output-path dist --output-filename index.js --mode development +``` + +**总结:** + +```javascript +webpack实现的功能: +- 能够编译打包 js 和 json 文件 +- 能将 es6 的模块化语法转换成浏览器能识别的语法 +- 能压缩代码(生产模式) + +webpack不能实现的功能: +- 不能编译打包 css、img 等文件 +- 不能将实现 js 兼容性处理 +``` + + + +## 4 webpack 配置文件 + +在项目的根目录创建一个名字为 `webpack.config.js` 的文件。 + +```js +const path = require('path'); + +module.exports = { + /********* 入口 **********/ + // 字符串指定单一入口 + entry: "./src/app.js", + // 数组指定多入口 + //entry: ['./src/js/one.js', './src/js/two.js'], + // 对象指定多入口 + // entry: { + // frist: './src/js/one.js', + // second: './src/js/two.js', + // }, + + /********* 出口 **********/ + output: { + path: path.resolve(__dirname, './dist'), + // 固定的输出文件名 + // filename: 'index.js', + // filename: '[name].js', //默认name是main + // filename: '[name][hash:8].js', + filename: 'index-[hash:12].js', + clean: true // 每次打包会把清空原来的输出目录 + }, + + /********* loader **********/ + /********* 插件 **********/ + /********* 模式 **********/ + mode: "development" +} +``` + +```javascript +运行命令:按照 webpack配置文件 执行 +npx webpack +``` + +**情况一:单入口单出口** + +```js +const path = require("path"); +module.exports = { + /**************** 入口 ***********************************/ + entry:"./src/app.js", + + /**************** 出口 *************************************/ + output:{ + filename: "index.js", + path:path.join(__dirname,"/build"), + clean:true + }, +} +``` + +**情况二:多入口单出口** + +```js +const path = require("path"); +module.exports = { + /**************** 入口 ***********************************/ + entry:['./src/js/one.js', './src/js/two.js'], + + /**************** 出口 *************************************/ + output:{ + filename: "index.js", + path:path.join(__dirname,"/build"), + clean:true + }, +} +``` + +**情况三:多入口多出口** + +```js +const path = require("path"); +module.exports = { + /**************** 入口 ***********************************/ + entry: { + frist: './src/js/one.js', + second: './src/js/two.js', + }, + + /**************** 出口 *************************************/ + output:{ + // filename: '[name].js', 这里[name] name是入口对象的名称 + // hash是为了浏览器刷缓存 + filename: '[name][hash:8].js', + path:path.join(__dirname,"/build"), + clean:true + }, +} +``` + + + +## 5 处理样式资源 + +Webpack 本身是不能识别样式资源的,所以我们需要借助 Loader 来帮助 Webpack 解析样式资源,我们找 Loader 都应该去官方文档中找到对应的 Loader,然后使用,如果官方文档找不到的话,可以从社区 Github 中搜索查询。 + +### 5.1 处理 Css 资源 + +**下载包** + +```bash +npm i css-loader style-loader -D +-D 代表开发依赖 +``` + +注意:需要下载两个 loader + +**功能介绍** + +- `css-loader`:负责将 Css 文件编译成 Webpack 能识别的模块(js文件) +- `style-loader`:会动态创建一个 Style 标签,添加到html结构中(Dom操作),里面放置 Webpack 中 Css 模块内容 + +此时样式就会以 Style 标签的形式在页面上生效 + +**配置** + +```js +module: { + rules: [ + { + // 用来匹配 .css 结尾的文件 使用正则 /\.css$/ + test: /\.css$/, + // use 数组里面 Loader 执行顺序是从右到左 + use: ["style-loader", "css-loader"], + }, + ], +}, +``` + +**添加 Css 资源** + +- src/css/index.css + +```css +.box1 { + width: 100px; + height: 100px; + background-color: pink; +} +``` + +**在 JS 入口文件 app.js 中奖将CSS 作为模块导入** + +```js +// 引入 Css 资源,Webpack才会对其打包 +import "./css/index.css"; +``` + +**运行指令** + +```javascript +npx webpack +``` + +### 5.2 处理 Less 资源 + +**下载包** + +```javascript +npm i less less-loader -D +``` + +**功能介绍** + +* `less`:负责编译 less 文件,命令行工具 + +- `less-loader`:负责导入 less 文件 + +**配置** + +```js +module: { + rules: [ + { + test: /\.less$/, + use: ["style-loader", "css-loader", "less-loader"], + }, + ], +}, +``` + +**添加 Less 资源** + +- src/less/index.less + +```css +.box2 { + width: 100px; + height: 100px; + background-color: deeppink; +} +``` + +**在 JS 入口文件中奖将CSS 作为模块导入** + +```js +// 引入资源,Webpack才会对其打包 +import "./less/index.less"; +``` + +**运行指令** + +```javascript +npx webpack +``` + + + +## 6 处理样式中的图片资源 + +### 6.1 打包图片资源 + +过去在 Webpack4 时,我们处理图片资源通过 `file-loader` 和 `url-loader` 进行处理,现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了,我们不需要即可处理图片资源。 + +**样式文件中使用图片资源** + +```css +.box{ + background-image: url("../images/1.jpeg"); +} +``` + +**运行指令** + +```javascript +npx webpack +``` + +此时如果查看 dist 目录的话,会发现多出几张图片资源,因为 Webpack 会将所有打包好的资源输出到 dist 目录下。 + +### 6.2 输出 base64 格式图片 + +配置将小于某个值的图片转化成 data URI 形式(Base64 格式) + +```js +module: { + rules: [ + { + test: /\.(png|jpe?g|gif|webp)$/, + type: "asset", + parser: { + dataUrlCondition: { + maxSize: 10 * 1024 // 小于10kb的图片会被base64处理 + } + } + }, + ], +}, +``` + +- 优点:减少请求数量 +- 缺点:体积变得更大 + +### 6.3 修改输出图片资源的名称和路径 + +```js +module: { + rules: [ + { + test: /\.(png|jpe?g|gif|webp)$/, + type: "asset", + parser: { + dataUrlCondition: { + maxSize: 10 * 1024, // 小于10kb的图片会被base64处理 + }, + }, + generator: { + // 将图片文件输出到 static/images 目录中 + // 将图片文件命名 [hash:8][ext][query] + // [hash:8]: hash值取8位 + // [ext]: 使用之前的文件扩展名 + // [query]: 添加之前的query参数 对应less文件图片url ?="query参数" 打包的时候不会变 + filename: "static/images/[hash:8][ext][query]", + }, + }, + ], +}, +``` + +src/less/app.less入口文件 + +```less +@len: 1000px; +@color: #f90; + +@font-face { + font-family: "FZSJ"; + src: url("../fonts/FZSJ-WSMQSJW.woff2") format("woff2"), + url("../fonts/FZSJ-WSMQSJW.woff") format("woff"), + url("../fonts/FZSJ-WSMQSJW.ttf") format("truetype"), + url("../fonts/FZSJ-WSMQSJW.eot") format("embedded-opentype"), + url("../fonts/FZSJ-WSMQSJW.svg") format("svg"); + font-weight: normal; + font-style: normal; + } + +.box { + width: @len; + height: (@len/5); + background: @color; + padding: 20px; + font-family: FZSJ; +} + +p { + width: 400px; + height: 200px; +} + +.p1 {background: url(../images/101.webp?n=123123123123)} +.p2 {background: url(../images/bg01.jpg)} +.p3 {background: url(../images/bg02.jpg)} +.p4 {background: url(../images/db01.jpeg)} +.p5 {background: url(../images/db02.png)} +.p6 {background: url(../images/db03.gif)} +``` + + + +## 7 处理样式中的字体文件资源 + +**Webpack5 可以自动导入样式中需要的所有文件资源**, 如需要设置输出目录,需要进行配置: + +```js +module: { + rules: [ + ... + { + test: /\.(ttf|woff2?|woff|svg|eot)$/ + type: "asset/resource", + generator: { + filename: "static/fonts/[hash:8][ext][query]", + }, + }, + ... + ], +}, +``` + +**`asset/resource` 和 `asset` 的区别:** + +```javascript +1. `asset/resource` 发送一个单独的文件并导出 URL。之前通过使用 `file-loader` 实现。 +2. `asset` 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 `url-loader`,并且配置资源体积限制实现。 +``` + +**样式中使用字体文件资源** + +```css +@font-face { + font-family: "FZSJ"; + src: url("../fonts/FZSJ-WSMQSJW.woff2") format("woff2"), + url("../fonts/FZSJ-WSMQSJW.woff") format("woff"), + url("../fonts/FZSJ-WSMQSJW.ttf") format("truetype"), + url("../fonts/FZSJ-WSMQSJW.eot") format("embedded-opentype"), + url("../fonts/FZSJ-WSMQSJW.svg") format("svg"); + font-weight: normal; + font-style: normal; +} +``` + +**运行指令** + +```bash +npx wepback +``` + + + +## 8 处理样式中的其他文件资源 音视频 + +与处理字体文件资源的配置类似,**无需配置即可导入**,如果需要配置输出目录,可进行如下配置: + +```js +module: { + rules: [ + { + test: /\.(mp3|mp4|avi)$/, + type: "asset/resource", + generator: { + filename: "static/media/[hash:8][ext][query]", + }, + }, + ] +} +``` + + + +## 9 处理 HTML 文件本身 + +HTML 文件不能直接被 webpack 解析,需要借助 `HtmlWebpackPlugin` 插件编译解析。 + +**下载包** + +```bash +npm i html-webpack-plugin -D +``` + +**配置** + +```js +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + plugins: [ + ... + new HtmlWebpackPlugin({ + // 以 public/index.html 为模板创建文件 + template: path.resolve(__dirname, "public/index.html"), + + // 目标文件地址,目标文件会在输出目录的里面 + filename: 'page/[index]-[hash].html' + + // 注意:输出的模板页面会默认引入打包后的JS文件 + // inject:false,// 不会引入JS文件 + inject: "body",// 在body尾部引入JS文件 + hash:true,// 为JS文件增加后缀,可以去除缓存 + + minify: { + removeAttributeQuotes:true,// 移除双引号 + removeComments:true,// 移除注释 + collapseWhitespace:true// 代码进行折叠 + } + }), + ... + ], +} + +``` + +**HTML 文件注意事项** + +注意不要在 HTML 中引入 JS 文件, `HtmlWebpackPlugin` 会自动引入 + +**运行命令** + +```js +npx webpack +``` + +js的加载默认会阻塞页面 + +```javascript +