Webpack 打包其他资源
file-loader
-
要处理 jpg、png 等格式的图片,需要有对应的 loader :file-loader;
- file-loader 的作用就是帮助我们处理 import/require() 方式引入的一个文件资源,并且会将它放到我们 输出的文件夹中;
-
安装 file-loader:
npm install file-loader -D
-
配置处理图片的 Rule:
{ test: /.(jpe?g|png|gif|svg)$/, use: { loader: 'file-loader', } }
文件的命名规则
-
我们处理后的文件名称需要按照一定的规则进行显示:
- 比如保留原来的文件名、拓展名,同时为了防止重复,包含一个 hash 值等;
- 可以使用 PlaceHolders 来完成, webpack 给我们提供了大量的 PlaceHolder 来显示不同的内容:
-
常用的 PlaceHolder:
- [ext] : 处理文件的拓展名;
- [name] : 处理文件的名称;
- [hash] : 文件的内容,使用 MD4 的散列函数处理,生成一个 128 位的 hash (32 个十六进制);
- [contentHash] :在 file-loader 中和 [hash] 结果一致;
- [hash: < length >] : 截取 hash 的长度,默认 32个 字符太长了;
- [path] : 文件相对于 webpack 配置文件的路径;
设置文件的名称与路径
{
test: /.(jpe?g|png|gif|svg)$/,
use: {
loader: 'file-loader',
options: {
// 此处前面加 img/ 已经设置了路径,也可通过 outputPath 来设置输出的文件夹;
name: 'img/[name].[hash:8].[ext]',
// outputPath:'img',
}
}
}
url-loader
- url-loader 和 file-loader 的工作方式是相似的,但可以将较小的文件,转成 base64 的 URI。
-
安装 url-loader:
npm install url-loader -D
{ test: /.(jpe?g|png|gif|svg)$/, use: { loader: 'url-loader', options: { name: 'img/[name].[hash:8].[ext]', } } }
url-loader 的 limit
-
开发中往往需要将小的图片进行转换,大的图片直接使用;
- 因为小的图片转换 base64 之后可以和页面一起被请求,减少不必要的请求过程;
- 而大的图片也进行转换反而会影响页面的请求速度;
-
限制大小用于判断图片需不需要进行转换:
- url-loader 的 options 属性 limit,可以用于设置转换的限制;
{
test: /.(jpe?g|png|gif|svg)$/,
use: {
loader: 'url-loader',
options: {
limit: 100*1024,
name: 'img/[name].[hash:8].[ext]',
}
}
}
认识 asset module type(资源模块类型)
- 从 Webpack5 开始,我们可以直接使用资源模块类型,来代替一些 loader;
-
通过添加 4 种新的模块类型,来替换这些 loader:
- asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现;
- asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现;
- asset/source 导出资源的源代码。之前使用 raw-loader 实现;
- asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现;
加载字体文件
- 如果我们需要使用某些特殊的字体或者字体图标,那么我们会引入很多字体相关的文件;
- 在 component 中引入,使用 i 元素显示字体图标:
// i元素
const iEl = document.createElement("i");
iEl.className = "iconfont icon-ashbin";
document.body.appendChild(iEl);
字体的打包
使用 webpack5 的资源模块类型来处理;
{
test: /.(eot|ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "font/[name]_[hash:6][ext]",
},
},
认识 Plugin
- Loader 适用于特定的模块类型进行转换;
- Plugin 可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等;
CleanWebpackPlugin
-
之前每次修改配置重新打包时,都需要手动删除 dist 文件夹;
- 我们可以借助于一个插件来帮助我们完成,即 CleanWebpackPlugin;
-
安装插件:
npm install clean-webpack-plugin
-
在插件中配置
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.export = { plugins: [ new CleanWebpackPlugin(), ] }
HtmlWebpackPlugin
对 HTML 进行打包处理:
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.export = {
plugins: [
new HtmlWebpackPlugin(),
]
}
自定义模板数据填充
-
在配置 HtmlWebpackPlugin 时,可以添加如下配置:
- template:指定我们要使用的模块所在路径;
- title:在进行 HtmlWebpackPlugin.options.title 读取时,会读到该信息;
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.export = {
plugins: [
new HtmlWebpackPlugin({
title: 'webpack项目',
template: './public/index.html'
}),
]
}
CopyWebpckPlugin
-
在 Vue 打包过程中,如果我们将一些文件放到 public 的目录下,这个目录会被赋值到 dist 文件夹中,这个功能可以使用 CopyWebpackPlugin 来完成;
-
安装 CopyWebpackPlugin 插件:
npm install copy-webpack-plugin -D
-
配置 CopyWebpackPlugin :
- 复制的规则在 patterns 中设置;
- from:设置从哪一个源中开始复制;
- to:复制到的位置,可省略,会默认复制到打包目录下;
- gloOptions:设置一些额外的选项,其中可以编写需要忽略的文件;
new CopyWebpackPlugin({
patterns: [
{
from: "public",
gloOptions: {
ignore: ["**/index.html"],
},
},
],
}),
Mode 和 Devtool 配置
module.exports = {
// 设置模式
// 开发阶段,会设置development
// production 准备打包上线的时候,设置prodution
mode: "development",
// 设置source-map,建立js映射文件,方便调试代码和错误
devtool: "source-map",
}
为什么需要babel
-
在开发中很少直接去使用 babel,但是 babel 对于前端开发来说是不可或缺的一部分:
- 使用 ES6+ 的语法, TypeScript和开发 React 项目,它们都是离不开 babel 的;
- babel 可以让我们理解代码从编写到线上的转变;
-
babel 的含义
- babel 是一个工具链,主要用于旧浏览器或者环境中将 ECMAScript + 代码转换为向后兼容版本的 JavaScript;
- 包括:语法转换、源代码转换等;
[1,2,3].map((n) => n + 1);
[1,2,3].map(function(n)) {
return n + 1;
}
babel 命令行使用
-
babel 本身可以作为一个独立的工具(和 postcss 一样),不和 webpack 等构建工具配置来单独使用。
-
需要安装如下库:
- @babel/core:babel 的核心代码,必须安装;
- @babel/cli:可以让我们在命令行使用 babel;
安装指令: npm install @babel/cli @babel/core -D
-
使用 babel 来处理源代码:
- src:源文件的目录;
- --out-dir:指定要输出的文件夹 dist;
指令: npx babel src --out-dir dist
插件的使用
- 若需要转换箭头函数,可以使用相关插件来完成;
指令: npm install @babel/plugin-transform-arrow-functions -D
npx babel src --out-dir dist --plugins=@babel/plugin-transform-arrow-functions
-
使用后 const 并没有转换成 var;
- 因为 plugin-transform-arrow-functions,并没有提供这样的功能;
- 需要使用 plugin-transform-block-scoping 来完成这样的功能;
指令: npm install @babel/plugin-transform-block-scoping -D
npx babel src --out-dir dist --plugins=babel/plugin-transform-block-scoping,@babel/plugin- transform-arrow-functions
babel 的预设 preset
-
如果需要转换的内容过多,可以使用预设(preset);
-
安装 @babel/preset-env 预设:
npm inatall @babel/preset-env -D
-
执行如下命令:
npx babel src --out-dir dist --persets=@babel/preset-env
babel 的底层原理
-
本质上来说,babel 就是一个编译器,将一种源代码转换为另一种源代码;
-
工作流程:
- 解析阶段(Parsing);
- 转换阶段(Transformation);
- 生成阶段(Code Generation);
babel-loader
-
在实际开发中,通常会在构建工具中通过配置 babel 来对其进行使用,如 webpack ;
-
需要安装相关的依赖:
-
如果之前已经安装了 @babel/core, 那么不需要再次安装;
npm install babel-loader @babel/core
-
-
可以设置一个规则,在加载 js 文件时,使用 babel;
module: {
rules: [
{
test: /.m?js$/,
use: {
loader: 'babel-loader',
}
}
]
}
指定使用的插件
{
test: /.m?js$/,
use: {
loader: 'babel-loader',
options: {
plugins: [
'@babel/plugin-transform-block-scoping',
'@babel/plugin-transform-arrow-functions'
]
}
}
}
babel 的配置文件
-
可以将 babel 的配置信息放到一个独立的文件中,babel 给我们提供了两种配置文件的编写:
- babel.confih.json(或 .js, .cjs, .mjs)文件;
- .babelrc.json(或 .babelrc, .js, .cjs, .mjs)文件; (更加推荐)
搭建本地服务器
-
目前开发的代码,为了运行需要有两个操作:
- 操作一:npm run build;
- 操作二:通过 live server 或者直接通过浏览器,打开 index.html 代码,查看效果;
-
这个过程会影响我们开发效率,我们希望当文件发生变化时,可以自动地完成编译和展示;
-
为了完成自动编译,webpack 提供了几种可选的方式:
- webpack watch mode;
- webpack-dev-server(常用);
- webpack-dev-middleware;
Webpck watch
-
webpack 给我们提供了 watch 模式:
- 在该模式下,webpack 依赖所有文件,只要有一个发生了更新,代码将被重新编译;
- 不需要手动运行 npm run build 指令了;
-
开启 watch 的方式:
- 方式一:在导出的配置中,添加 watch:true;
- 方式二:在启动 webpack 命令中,添加 --watch 的标识;
-
方式二:在 packag.json 的 scripts 中添加一个 watch 的脚本:
"scripts": {
"build": "webpack --config wk.config.js",
"watch": "webpack --watch",
"type-check": "tsc --noEmit",
"type-check-watch": "npm run type-check -- --watch"
},
webpack-dev-server
-
watch 方式可以监听到文件的变化,但是事实上它本身是没有自动刷新浏览器功能的:
- 是通过z在 VSCode 中使用 live-server 来完成这样的功能的;
- 我们希望在不使用 live-server 的情况下,可以具备 live reloading (实时重新加载) 的功能;
-
安装 webpack-dev-server
npm install webpack-dev-server -D
-
修改配置文件,告知 dev server,从什么位置查找文件:
devServer: {
contentBase: "./build"
},
target: "web",
"serve": "webpack serve --config wk.config.js"
-
webpack-dev-server 在编译之后不会写入到任何输出文件,而是将 bundle 文件保留在内存中:
- 事实上 webpack-dev-server 使用了一个库叫 memfs(memory-fs webpack 自己写的)
模块热替换(HMR)
-
HMR 的定义
- HMR 的全称是 Hot Module Replacement;
- 模块热替换是指在应用程序运行过程中,替换、添加、删除模块。而无需重新刷新整个页面;
-
HMR 通过如下几种方式,来提高开发的速度:
- 不重新加载整个页面,可以保留某些应用程序的状态不丢失;
- 只需要更新变化的内容,节省开发的时间;
- 修改了 css、js 源代码,会立即在浏览器更新,相当于直接在浏览器的 devtools 中直接修改样式;
-
使用 HMR
- 默认情况下,webpack-dev-server 已经支持 HMR,我们只需要开启即可;
- 在不开启 HMR 的情况下,当我们修改了源代码之后,整个页面会自动刷新,使用的是 live reloading;
HMR 的原理
HMR Socket Server,是一个 socket 的长连接:
- 长连接建立后双方可以通信(服务器可以直接发送文件到客户端);
- 当服务器监听到对应的模块发生变化时,会生成两个文件:.json(mainifest 文件)和 .js 文件(update chunk);'
- 通过长连接,可以直接将这两个文件主动发送给客户端(浏览器);
- 浏览器拿到两个新的文件后,通过 HMR runtime 机制,加载这两个文件,并且针对修改的模块进行更新; \