持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
Webpack 系列专栏地址 进入
本文demo地址查看
本文主要写了 图片的处理、压缩,第三方字体处理,多页面打包的集成方案。
图片的处理
使用file-loader
或 url-loader
处理图片文件。
file-loader
使用图片的场景:
- js 操作 dom
- css
background
样式 - html img标签
新建 images
目录,用来存放图片。
js 操作 dom
index.js:
import pic from "./images/1.jpg";
const img = new Image();
img.src = pic;
console.log(pic); //图片路径
const tag = document.getElementById("app");
tag.append(img);
安装file-loader
npm i file-loader -D
webpack.config.js配置:
{
test: /\.(jpg|png|gif|webp)$/,
use: "file-loader",
},
执行npx webpack
或 npm run build
打包命令,dist
目录下多了我们引入的图片,运行html文件,图片也在页面中显示。不过图片的命名有点丑,下面通过配置改变命名的问题。
修改配置:
{
test: /\.(jpg|png|gif|webp)$/,
// use: "file-loader",
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "images", // 图片资源存放目录
},
},
},
使用[name]
名称占位符 和 [ext]
后缀名占位符优化,打包出来的图片名称和原名称保持一致。outputPath
参数为图片资源提供一个单独的目录。所有图片资源文件将被打包进images
目录下。
css 背景图
index.less 中添加代码:
// background-color: green;
background-image: url(../images/1.jpg);
执行打包命令,发现背景由原来的绿色变成了背景图片,没有任何问题。
对css文件做目录管理:
接下来,尝试把打包后的css文件也单独放到一个style文件夹下(之前的步骤,打包完成的css文件是直接存放在了dist根目录下),修改配置项:
plugins: [
new minicssPlugin({
// filename: "index.css",
// 将css文件放到style目录下
filename: "style/index.css",
}),
],
再次打包,就会发现问题,找不到背景图片了,打包后的css代码是 background-image: url(images/1.jpg);
。此时相当于在style目录下找这个图片,那肯定是找不到的。
此时正确的路径应该是 ../images/1.jpg
,给file-loader
添加 publicPath
字段,可以解决这个问题。
{
test: /\.(jpg|png|gif|webp)$/,
// use: "file-loader",
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "images", // 图片资源存放目录
publicPath: "../images", // 图片资源引入位置
},
},
},
打包后背景图的资源路径的值应该是 options.publicPath
+ options.name
的值,也就是 ../images/1.jpg
,即我们期望返回的路径。
此时查看页面,背景图已经正常显示,但是 js 创建的 img 标签的路径却无法找到,图片不能正常显示,因为html文件路径是在dist根目录的,在根目录下寻找图片../images/1.jpg
也是肯定找不到的。需要对html文件也做目录管理。
总结:当对css文件做目录管理的时候,会出现和图片资源路径对不上的情况,此时需要上面的特殊处理。
url-loader
url-loader
是基于 file-loader
的,不同的是 url-loader
可以将图片转换成 base64 形式,直接放在css中。
安装:
npm i url-loader -D
配置;
{
test: /\.(jpg|png|gif|webp)$/,
// use: "file-loader",
use: {
loader: "url-loader",
options: {
name: "[name].[ext]",
outputPath: "images", // 图片资源存放目录
publicPath: "../images", // 图片资源引入位置
limit: 3 * 1024, // 单位:字节
},
},
},
部分配置项和file-loader
是一致的,limit
参数可以过滤掉一些太大的图片,图片所占空间小于设定的值才会被编译成base64。一般情况下,让这个值为 3kb
是比较合理的。
图片压缩
使用 image-webpack-loader 进行图片压缩。
安装:
cnpm install image-webpack-loader
配置:
必须在 url-loader 或 file-loader之前使用,所以配置在后面。
{
test: /\.(jpg|png|gif|webp)$/,
// use: "file-loader",
use: [
{
loader: 'url-loader',
// ...
},
'image-webpack-loader',
],
},
字体处理
处理字体同样使用 file-loader
这个loader。
新建 src/font 目录,存放字体文件。index.less
中引入字体文件并使用:
@font-face {
font-family: "Alifont";
src: url("../font/Alibaba_PuHuiTi_2.0_105_Heavy_105_Heavy.ttf"),
url("../font/3tTvB4rcK7Bp5NvvbilQp.woff2") format("woff2"),
url("../font/3tTvB4rcK7Bp5NvvbilQp.woff") format("woff");
font-display: swap;
}
body {
font-family: "Alifont";
}
配置:
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'font',
publicPath: '../font', // 想要的正确路径
},
},
},
多页面实现方案
普通方式
普通的方式创建一个多页面:
新建 src/detail.js:
console.log('detail page')
新建 public/detail.html,当作详情页模板:
<div id="detail"></div>
修改 webpack.config.js配置:
// 新增detail入口
entry: {
index: './src/index.js',
detail: './src/detail.js',
},
plugins: [
// 增加
new htmlWebpackPlugin({
template: './public/detail.html',
filename: 'detail.html',
chunks: ['detail']
})
],
多页面应用新增一个页面,需要以上的步骤。感觉上述的步骤有些繁琐,不太友好,下面来实现一个多页面应用通用方案:
通用方案
新建 mpa.config.js 配置文件,主要负责生成 entry
实例化htmlWebapckPlugin
,使用自定义的 setSPA()
方法完成自动化的内容。一些基础配置可以和 webpack.config.js 保持一致。
将打包出口的目录由dist改为mpa:
output: {
path: resolve(__dirname, './mpa'),
filename: '[name].js',
},
需要遵守一些目录结构上的约定,src下直接创建目录命名即为页面的名称,目录下放index.html index.js文件,这样做主要是和images font 等目录做区分。如下图创建了三个页面 index login list:
安装 glob ,给下面的函数使用:
npm install glob -D
glob 是node的一个模块,用于匹配符合规则的文件路径,以数组形式返回
主要的 setSPA()
函数编写,要完成以下功能:
- 查询页面入口文件 及 相应的html模板
- 提取页面入口名称,用于entry及chunkName
- 实例化 htmlWebpackPlugin 存放在一个数组中
const setMPA = () => {
const entry = {}
const htmlwebpackplugins = []
// 查询页面入口文件 及 相应的html模板
// 提取页面入口名称,用于entry及chunkName
// new htmlWebpackPlugin
const entryPath = glob.sync('./src/*/index.js')
console.log('entryPath----', entryPath) // ['./src/index/index.js', './src/list/index.js' ...]
entryPath.map((item) => {
const entryName = item.match(/src\/(.*)\/index\.js$/)[1]
console.log(entryName) // index list login
entry[entryName] = item
// console.log('entry-----', entry)
htmlwebpackplugins.push(
// 在这里实例化是没有意义的,最终还要放在 plugins 中展开
new htmlWebpackPlugin({
template: join(__dirname, `./src/${entryName}/index.html`), // 使用 join 拼接成绝对路径
filename: `${entryName}.html`,
chunks: [entryName],
})
)
})
return {
entry,
htmlwebpackplugins,
}
}
解析出返回值:
const { entry, htmlwebpackplugins } = setMPA()
将 setMPA()
方法返回内容写进配置文件:
module.exports = {
mode: 'development',
entry,
plugins: [
new CleanWebpackPlugin(),
new minicssPlugin({
// filename: "index.css",
// 将css文件放到style目录下
filename: 'style/index.css',
}),
...htmlwebpackplugins
],
}
配置一个新的打包命令,指向 mpa.config.js 配置文件进行打包
package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
// ++
"mpa": "webpack --config ./mpa.config.js"
},
执行打包命令 npm run mpa
,正常输出bundle文件到mpa目录下。
setMPA()
动态的生成了 entry
入口配置和 html-webpack-plugin
插件的配置,如果想新增一个页面,直接在src下按约定好的目录规则新建目录及文件,再次打包就可以很方便的自动生成我们想要的结果。