webpack 学习一
1.Webpack 是什么?
webpack 是一个静态的模块化打包工具,为现代的 JavaScript 应用程序;
我们来对上面的解释进行拆解: 打包 bundler:webpack 可以将帮助我们进行打包,所以它是一个打包工具 静态的 static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器) 模块化 module:webpack 默认支持各种模块化开发,ES Module、CommonJS、AMD 等 现代的 modern:我们前端说过,正是因为现代前端开发面临各种各样的问题,才催生了 webpack 的出现和发展
Webpack 的依赖
Webpack 的运行是依赖 Node 环境的,所以我们电脑上必须有 Node 环境
Webpack 的安装
webpack 的安装目前分为两个:webpack、webpack-cli
那么它们是什么关系呢?
执行 webpack 命令,会执行 node_modules 下的.bin 目录下的 webpack;
webpack 在执行时是依赖 webpack-cli 的,如果没有安装就会报错;
Webpack-cli 中代码执行时,才是真正利用 webpack 进行编译和打包的过程;
所以在安装 webpack 时,我们需要同时安装 webpack-cli(第三方的脚手架事实上是没有使用 webpack-cli 的,而是类似于自己的 vue-service-cli 的东西)
webpack 默认打包
- 我们可以通过 webpack 进行打包,之后运行
打包之后
的代码 在目录下直接执行webpack
命令
webpack;
生成一个dist文件夹,里面存放一个 main.js 的文件,就是我们打包之后的文件:
- 这个文件中的代码被压缩和丑化了;
- 我们暂时不关心他是如何做到的,后续我讲 webpack 实现模块化原理时会再次讲到;
- 另外我们发现代码中依然存在 ES6 的语法,比如箭头函数、const 等,这是因为默认情况下 webpack 并不清楚 我们打包后的文件是否需要转成 ES5 之前的语法,后续我们需要通过 babel 来进行转换和设置;
我们发现是可以正常进行打包的,但是有一个问题,webpack 是如何确定我们的入口的呢?
- 事实上,当我们运行 webpack 时,webpack 会查找当前目录下的 src/index.js作为入口;
- 所以,如果当前项目中没有存在 src/index.js 文件,那么会报错;
Webpack 配置文件
- 在通常情况下,webpack 需要打包的项目是非常复杂的,并且我们需要一系列的配置来满足要求,默认配置必然 是不可以的。
- 我们可以在根目录下创建一个**webpack.config.js**文件,来作为 webpack 的配置文件:
入口(entry)
const config = {
entry: "./path/to/my/entry/file.js",
};
module.exports = config;
entry
属性的单个入口语法,是下面的简写:
const config = {
entry: {
main: "./path/to/my/entry/file.js",
},
};
输出(output)
在 webpack 中配置 output
属性的最低要求是,将它的值设置为一个对象,包括以下两点:
filename
用于输出文件的文件名。- 目标输出目录
path
的绝对路径。
const config = {
output: {
filename: "bundle.js",
path: "/home/proj/public/assets",
},
};
module.exports = config;
此配置将一个单独的 bundle.js
文件输出到 /home/proj/public/assets
目录中。
loader 和 plugins
loader
和plugins
单独分成模块去理解
指定配置文件
如果我们的配置文件并不是 webpack.config.js 的名字,而是其他的名字呢?
比如我们将 webpack.config.js 修改成了 wk.config.js;
这个时候我们可以通过 --config 来指定对应的配置文件;
jswebpack --config wk.config.js
但是每次这样执行命令来对源码进行编译,会非常繁琐,所以我们可以在 package.json 中增加一个新的脚本:
js{ "scripts": { "build": "webpack -- Webpack --config wk.config.js" } } //执行 yarn build || npm run build
2.loader
- webpack 到底是如何对我们的项目进行打包的呢?
- 事实上 webpack 在处理应用程序时,它会根据命令或者配置文件找到入口文件;
- 从入口开始,会生成一个 依赖关系图,这个依赖关系图会包含应用程序中所需的所有模块(比如.js 文件、css 文件、图片、字体等);
- 然后遍历图结构,打包一个个模块(根据文件的不同使用不同的 loader 来解析);
loader 的配置方式
配置方式表示的意思是在我们的 webpack.config.js 文件中写明配置信息:
module.rules 中允许我们配置多个 loader(因为我们也会继续使用其他的 loader,来完成其他文件的加载);
这种方式可以更好的表示 loader 的配置,也方便后期的维护,同时也让你对各个 Loader 有一个全局的概览;
module.rules 的配置如下:
rules 属性对应的值是一个数组:[Rule]
数组中存放的是一个个的 Rule,Rule 是一个对象,对象中可以设置多个属性:
test 属性:用于对 resource(资源)进行匹配的,通常会设置成正则表达式;
loader 属性: Rule.use: [ { loader } ] 的简写。
use 属性:对应的值时一个数组:[UseEntry]
- UseEntry 是一个对象,可以通过对象的属性来设置一些其他属性
- loader:必须有一个 loader 属性,对应的值 是一个字符串
options:可选的属性,值是一个字符串或者对象,值会被传入到 loader 中;
传递字符串(如:use: [ 'style-loader' ])是 loader 属性的简写方式(如:use: [ { loader: 'style-loader'} ]);
jsmodule.exports = { module: { rules: [ { test: /\.css$/, // 正则表达式匹配相应的资源 use: [ // 注意顺序(从下往上,从左往右,从后往前) { loader: "style-loader" }, { loader: "css-loader", options: { modules: true, }, }, { loader: "sass-loader" }, ], }, ], }, };
PostCSS 工具
什么是 PostCSS 呢?
- PostCSS 是一个通过 JavaScript 来转换样式的工具;
- 这个工具可以帮助我们进行一些CSS 的转换和适配,比如自动添加浏览器前缀、css 样式的重置;
- 但是实现这些工具,我们需要借助于 PostCSS 对应的插件;
如何使用 PostCSS 呢?主要就是两个步骤:
第一步:查找 PostCSS 在构建工具中的扩展,比如 webpack 中的 postcss-loader;
第二步:选择可以添加你需要的 PostCSS 相关的插件;
命令行使用 postcss
终端使用 PostCSS
- 也是可以的,但是我们需要单独安装一个工具 postcss-cli;
安装:postcss、postcss-cli
shellyarn add postcss postcss-cli -D
postcss-loader 的使用
借助于构建工具:
- 在 webpack 中使用 postcss 就是使用 postcss-loader 来处理的;
安装 postcss-loader:
shellyarn add postcss-loader -D我们修改加载css的loader
修改加载 css 的 loader
- 注意:因为 postcss 需要有对应的插件才会起效果,所以我们需要配置它的 plugin
单独的 postcss 配置文件
- 在根目录下创建 postcss.config.js,下入下面代码,将会自动加入 css 前缀
module.exports = {
plugins: [require("autoprefixer")],
};
postcss-preset-env(预设)
- postcss-preset-env 也是一个 postcss 的插件;
- 它可以帮助我们将一些现代的 CSS 特性,转成大多数浏览器认识的 CSS,并且会根据目标浏览器或者运行时环 境添加所需的 polyfill;
- 包括会自动帮助我们添加 autoprefixer(所以相当于已经内置了 autoprefixer)
安装 postcss-preset-env
yarn add postcss-preset-env -D
module.exports = {
plugins: ["postcss-preset-env"],
};
file-loader
要处理 jpg、png 等格式的图片,我们也需要有对应的 loader:file-loader
- file-loader 的作用就是帮助我们处理 import/require()方式引入的一个文件资源,并且会将它放到我们输出的 文件夹中;
安装 file-loader
shellyarn add file-loader -D
配置处理图片的 Rule
js{ test: /\.(png|jpe?g|gif|svg)$/, use: { loader: "file-loader" } }
有时候我们处理后的文件名称按照一定的规则进行显示:
比如保留原来的文件名、扩展名,同时为了防止重复,包含一个hash 值等
最常用的 placeholder
- [ext]: 处理文件的扩展名;
- [name]:处理文件的名称;
- [hash]:文件的内容,使用 MD4 的散列函数处理,生成的一个 128 位的 hash 值(32 个十六进制);
- [contentHash]:在 file-loader 中和[hash]结果是一致的(在 webpack 的一些其他地方不一样,后面会讲到);
- [hash:length]:截图 hash 的长度,默认 32 个字符太长了;
- [path]:文件相对于 webpack 配置文件的路径;
设置文件名称和存放路径
name 设置名称
outputPath 设置存放路径
js{ test: /\.(png|jpe?g|gif|svg)$/, use: { loader: "file-loader", options: { name: "[name].[hash:8].ext", outputPath: "img" } } }
url-loader
url-loader 和 file-loader 的工作方式是相似的,但是可以将较小的文件,转成 base64 的 URI。
安装 url-loader
shellyarn add url-loader -D
js{ test: /\.(png|jpe?g|gif|svg)$/, use: [ { loader: 'url-loader', options: { name: "img/[name].[hash:6].[ext]", outputPath: "img" } } ] }
url-loader 的 limit
开发中我们往往是小的图片需要转换,大的图片直接使用图片即可
- 小的图片转换 base64之后可以和页面一起被请求,减少不必要的请求过程
- 大的图片也进行转换,反而会影响页面的请求速度
限制哪些大小的图片转换和不转换
url-loader 有一个 options 属性 limit,可以用于设置转换的限制
js{ test: /\.(png|jpe?g|gif|svg)$/, use: [ { loader: 'url-loader', options: { name: "img/[name].[hash:6].[ext]", limit: 100 * 1024 } } ] }
asset module type 的介绍
我们当前使用的 webpack 版本是 webpack5
- 在 webpack5 之前,加载这些资源我们需要使用一些loader,比如 raw-loader 、url-loader、file-loader
- 在 webpack5 之后,我们可以直接使用资源模块类型(asset module type),来替代上面的这些 loader
资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader
asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现;
asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现;
asset/source 导出资源的源代码。之前通过使用 raw-loader 实现;
asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源 体积限制实现
js{ test: /\.(png|jpe?g|gif|svg)$/, type: "asset/resource", // file-loader的效果 }
自定义文件的输出路径和文件名
方式一:修改output,添加assetModuleFilename属性;
jsoutput: { filename: "bundle.js", // 必须是一个绝对路径 path: path.resolve(__dirname, "./build"), assetModuleFilename: "img/[name].[hash:6][ext]" }
方式二:在Rule中,添加一个generator属性,并且设置filename
js{ test: /\.(png|jpe?g|gif|svg)$/, type: "asset/resource", // file-loader的效果 generator: { filename: "img/[name].[hash:6][ext]" } }
url-loader 的 limit 的效果
步骤一:将 type 修改为 asset
步骤二:添加一个 parser 属性,并且制定 dataUrl 的条件,添加 maxSize 属性
js{ test: /\.(png|jpe?g|gif|svg)$/, type: "asset", generator: { filename: "img/[name].[hash:6][ext]" }, parser: { dataUrlCondition: { maxSize: 100 * 1024 } } }
加载字体文件
可以选择使用 file-loader 来处理,也可以选择直接使用 webpack5 的资源模块类型来处理
js{ test: /\.ttf|eot|woff2?$/i, type: "asset/resource", generator: { filename: "font/[name].[hash:6][ext]" } }
3.Plugin
- Webpack 的另一个核心是 Plugin
- Loader 是用于特定的模块类型进行转换
- Plugin 可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等
CleanWebpackPlugin
每次修改了一些配置,重新打包时,都需要手动删除 dist 文件夹
借助于一个插件来帮助我们完成,这个插件就是CleanWebpackPlugin
安装插件
shellyarn add clean-webpack-plugin -D
配置
jsconst { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = { plugins: [new CleanWebpackPlugin()], };
HtmlWebpackPlugin
- 生成对应的入口文件 index.html
- 我们的 HTML 文件是编写在根目录下的,而最终打包的 dist 文件夹中是没有 index.html 文件的。
- 在进行项目部署的时,必然也是需要有对应的入口文件 index.html;
- 所以需要对 index.html 进行打包处理
- 安装插件
yanr add html-webpack-plugin -D
配置
jsconst HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { plugins: [ new HtmlWebpackPlugin({ title: "title 测试", }), ], };
生成的 index.html 分析
该文件中也自动添加了我们打包的 bundle.js 文件
html<!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <link rel="icon" href="./favicon.ico" /> <title>title 测试</title> </head> <body> <script src="js/bundle.js"></script> </body> </html>
这个文件是如何生成的呢?
默认情况下是根据 ejs 的一个模板来生成的
在 html-webpack-plugin 的源码中,有一个 default_index.ejs 模块
自定义 HTML 模板
比如添加一个 noscript 标签,在用户的 JavaScript 被关闭时,给予响应的提示;
比如在开发 vue 或者 react 项目时,我们需要一个可以挂载后续组件的根标签;
这个我们需要一个属于自己的 index.html 模块
html<!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <noscript> <strong >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript> <div id="app"></div> </body> </html>
自定义模板数据填充
上面的代码中,会有一些类似这样的语法**
<% 变量 %>
,这个是EJS 模块填充数据的方式**在配置 HtmlWebpackPlugin 时,我们可以添加如下配置
template:指定我们要使用的模块所在的路径
title:在进行 htmlWebpackPlugin.options.title 读取时,就会读到该信息
jsconst HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { plugins: [ new HtmlWebpackPlugin({ title: "title 测试", template: "./public/index.html", }), ], };
DefinePlugin
模块中使用到一个 BASE_URL 的常量
html<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
- 并没有设置过这个常量值,所以会出现没有定义的错误, 这个时候我们可以使用 DefinePlugin 插件
DefinePlugin 允许在编译时创建配置的全局常量,是一个 webpack 内置的插件(不需要单独安装)
jsconst { DefinePlugin } = require("webpack"); module.exports = { plugins: [ new DefinePlugin({ BASE_URL: '"./"', }), ], };
CopyWebpackPlugin
在 vue 的打包过程中,如果我们将一些文件放到 public 的目录下,那么这个目录会被复制到 dist 文件夹中
- 这个复制的功能,可以使用 CopyWebpackPlugin 来完成
安装 CopyWebpackPlugin 插件
shellyarn add copy-webpack-plugin -D
配置 CopyWebpackPlugin
规则在patterns中设置;
from:设置从哪一个源中开始复制;
to:复制到的位置,可以省略,会默认复制到打包的目录下;
globOptions:设置一些额外的选项,其中可以编写需要忽略的文件:
- .DS_Store:mac 目录下回自动生成的一个文件;
- index.html:也不需要复制,因为我们已经通过 HtmlWebpackPlugin 完成了 index.html 的生成
- 其他...
jsconst CopyWebpackPlugin = require("copy-webpack-plugin"); module.exports = { plugins: [ new CopyWebpackPlugin({ patterns: [ { from: "public", globOptions: { ignore: ["**/index.html", "**/.DS_Store", "**/其他..."], }, }, ], }), ], };
总结
webpack 基本配置(一)
jsmodule.exports = { entry: "", // 入口,也可以配置成对象形式 output: { filename: "bundle.js", // 文件名 path: path.resolve(__dirname, "./dist"), // 打包后的路径, 必须是绝对路径 }, module: { rules: [], // loader }, plugins: [], // 插件 }; // 待补充...
常用的 loader(注意顺序(从下往上,从左往右,从后往前))
- css-loader、less-loader(sass-loader)、style-loader(会直接引入到 style 中)、MiniCssExtractPlugin.loader (生成独立文件引入)
- file-loader 处理 jpg、png 等格式的图片
- url-loader url-loader 和 file-loader 的工作方式是相似的,
但是可以将较小的文件
,转成 base64 的 URI - 待补充...
常用的 plugins
- CleanWebpackPlugin 重新打包, 自动删除 dist 文件夹
- HtmlWebpackPlugin 配置生成的 index.html
- DefinePlugin 模块中使用到一个 BASE_URL 的常量, 我们可以用这个插件配置这些常量
- 待补充...
⭐️⭐️⭐️ 好啦!!!本文章到这里就结束啦。⭐️⭐️⭐️
✿✿ ヽ(°▽°)ノ ✿
撒花 🌸🌸🌸🌸🌸🌸