webpack 常见应用场景
CSS 处理
解析 CSS 文件
在前面的例子也能看到,我们解析css需要用到的loader有css-loader和style-loader。css-loader主要用来解析css文件,而style-loader是将css渲染到DOM节点上。
首先我们来安装一下:
# css-loader -> 6.2.0; style-loader -> 3.2.1
yarn add css-loader style-loader -D然后我们新建一个css文件。
/* style.css */
body {
background: #222;
color: #fff;
}然后在index.js引入一下:
import './style.css';紧接着我们配置一下webpack:
module.exports = {
...
module: {
rules: [
{
test: /\.css$/, // 识别css文件
use: ['style-loader', 'css-loader'] // 先使用css-loader,再使用style-loader
}
]
},
...
};这时候我们打包一下,会发现dist路径下只有main.js和index.html。但打开一下index.html会发现css是生效的。
这是因为style-loader是将css代码插入到了main.js当中去了。
打包 css 文件
如果我们不想将css代码放进js中,而是直接导出一份css文件的话,就得使用另一个插件——mini-css-extract-plugin。
# 2.1.0
yarn add mini-css-extract-plugin -D然后将其引入到配置文件,并且在plugins引入。
const miniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
...
plugins: [
// 使用miniCssExtractPlugin插件
new miniCssExtractPlugin({
filename: "[name].css" // 设置导出css名称,[name]占位符对应chunkName
})
]
};紧接着,我们还需要更改一下loader,我们不再使用style-loader,而是使用miniCssExtractPlugin提供的loader。
const miniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
...
module: {
rules: [
{
test: /\.css$/,
// 使用miniCssExtractPlugin.loader替换style-loader
use: [miniCssExtractPlugin.loader,'css-loader']
}
]
},
plugins: [
new miniCssExtractPlugin({
filename: "[name].css"
})
]
};接下来打包一下,dist路径下就会多出一个main.css文件,并且在index.html中也会自动引入。
<!DOCTYPE html>
<html lang="en">
<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" />
<title>Document</title>
<script defer src="main.js"></script>
<link href="main.css" rel="stylesheet" />
</head>
<body>
HelloWorld!
</body>
</html>css 添加浏览器前缀
当我们使用一下css新特性的时候,可能需要考虑到浏览器兼容的问题,这时候可能需要对一些css属性添加浏览器前缀。而这类工作,其实可以交给webpack去实现。准确来说,是交给postcss去实现。
postcss对于css犹如babel对于JavaScript,它专注于对转换css,比如添加前缀兼容、压缩css代码等等。
首先我们需要先安装一下postcss和post-css-loader。
# postcss -> 8.3.6,postcss-loader -> 6.1.1
yarn add postcss postcss-loader -D接下来,我们在webpack配置文件先引入postcss-loader,它的顺序是在css-loader之前执行的。
rules: [
{
test: /\.css$/,
// 引入postcss-loader
use: [miniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
},
];接下来配置postcss的工作,就不在webpack的配置文件里面了。postcss自身也是有配置文件的,我们需要在项目根路径下新建一个postcss,config.js。然后里面也有一个配置项,为plugins。
module.exports = {
plugins: [],
};这也意味着,postcss自身也支持很多第三方插件使用。
现在我们想实现的添加前缀的功能,需要安装的插件叫autoprefixer。
# 1.22.10
yarn add autoprefixer -D然后我们只需要引入到postcss的配置文件中,并且它里面会有一个配置选项,叫overrideBrowserslist,是用来填写适用浏览器的版本。
module.exports = {
plugins: [
// 将css编译为适应于多版本浏览器
require('autoprefixer')({
// 覆盖浏览器版本
// last 2 versions: 兼容各个浏览器最新的两个版本
// > 1%: 浏览器全球使用占有率大于1%
overrideBrowserslist: ['last 2 versions', '> 1%'],
}),
],
};关于overrideBrowserslist的选项填写,我们可以去参考一下browserslist,这里就不多讲。
当然,我们其实可以在package.json中填写兼容浏览器信息,或者使用browserslist配置文件.browserslistrc来填写,这样子如果我们以后使用其他插件也需要考虑到兼容浏览器的时候,就可以统一用到,比如说babel。
// package.json 文件
{
...
"browserslist": ['last 2 versions', '> 1%']
}
# .browserslsetrc 文件
last 2 versions
> 1%但如果你多个地方都配置的话,overrideBrowserslist的优先级是最高的。
接下来,我们修改一下style.css,使用一下比较新的特性。
body {
display: flex;
}然后打包一下,看看打包出来后的main.css。
body {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}压缩 css 代码
当我们需要压缩css代码的时候,可以使用postcss另一个插件——cssnano。
# 5.0.7
yarn add cssnano -D然后还是在postcss配置文件中引入:
module.exports = {
plugins: [
... ,
require('cssnano')
]
}打包一下,看看main.css。
body {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}解析 CSS 预处理器
在现在我们实际开发中,我们会更多使用Sass、Less或者stylus这类css预处理器。而其实html是无法直接解析这类文件的,因此我们需要使用对应的loader将其转换成css。
接下来,我就以sass为例,来讲一下如何使用webpack解析sass。
首先我们需要安装一下sass和sass-loader。
# sass -> 1.36.0, sass-loader -> 12.1.0
yarn add sass sass-loader -D然后我们在module加上sass的匹配规则,sass-loader的执行顺序应该是排第一,我们需要先将其转换成css,然后才能执行后续的操作。
rules: [
...{
test: /\.(scss|sass)$/,
use: [miniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'],
},
];然后我们在项目中新建一个style.scss。
$color-white: #fff;
$color-black: #222;
body {
background: $color-black;
div {
color: $color-white;
}
}然后在index.js引入。
import './style.css';
import './style.scss';然后执行打包,再看看打包出来的main.css,scss文件内容被解析到里面,同时如果我们引入多个css或css预处理器文件的话,miniCssExtractPlugin也会将其打包成一个bundle文件里面。
body {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
body {
background: #222;
}
body div {
color: #fff;
}HTML 模板
当我们是Web项目的时候,我们必然会存在html文件去实现页面。
而对于其他类型的文件,比如css、图片、文件等等,我们是可以通过引入入口js文件,然后通过loader进行解析打包。而对于html文件,我们不可能将其引入到入口文件然后解析打包,反而我们还需要将打包出来的bundle文件引入html文件去使用,
因此,其实我们需要实现的操作只有两个,一个是复制一份html文件到打包路径下,另一个就是将打包出来的bundle文件自动引入到html文件中去。
这时候我们需要使用一个插件来实现这些功能——html-webpack-plugin。
# 5.3.2
yarn add html-webpack-plugin -D安装插件后,我们先在src文件下新建一下index.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Webpack Demo</title>
</head>
<body>
<div>Hello World</div>
</body>
</html>这里面我们暂时不需要引入任何模块。
接下来配置一下webpack。一般plugin插件都是一个类,而我们需要在plugins选项中需要创建一个插件实例。
对于htmlWebpackPlugin插件,我们需要传入一些配置:html模板地址template和打包出来的文件名filename。
const path = require('path');
// 引入htmlWebpackPlugin
const htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
plugins: [
// 使用htmlWebpackPlugin插件
new htmlWebpackPlugin({
// 指定html模板
template: './src/index.html',
// 自定义打包的文件名
filename: 'index.html',
}),
],
};接下来执行一下打包,就会发现dist文件下会生成一个index.html。打开会发现,webpack会自动将bundle文件引入:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Webpack Demo</title>
<script defer src="main.js"></script>
</head>
<body>
<div>Hello World</div>
</body>
</html>如果我们有多个chunk的时候,我们可以指定该html要引入哪些chunk。在htmlWebpackPlugin配置中有一个chunks选项,是一个数组,你只需要加入你想引入的chunkName即可。
const path = require('path');
// 引入htmlWebpackPlugin
const htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
main: './src/main.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
plugins: [
new htmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['index'], // 只引入index chunk
}),
],
};打包完成后,dist文件下会出现index.html、index.js和main.js,但是index.html只会引入index.js。
<!DOCTYPE html>
<html lang="en">
<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" />
<title>Document</title>
<script defer src="index.js"></script>
</head>
<body>
HelloWorld!
</body>
</html>如果我们需要实现多页面的话,只需要再new一个htmlWebpackPlugin实例即可,这里就不再多说。
JavaScript 转义
不仅仅css需要转义,JavaScript也要为了兼容多浏览器进行转义,因此我们需要用到babel。
# 8.2.2
yarn add babel-loader -D同时,我们需要使用babel中用于JavaScript兼容的插件:
# @babel/preset-env -> 7.14.9; @babel/core -> 7.14.8; @core-js -> 3.16.0
yarn add @babel/preset-env @babel/core core-js -D接下来,我们需要配置一下webpack的配置文件。
{
test: /\.js$/,
use: ['babel-loader']
}然后我们需要配置一下babel。当然我们可以直接在webpack.config.js里面配置,但是babel同样也提供了配置文件.babelrc,因此我们就直接在这边进行配置。
在根路径新建一个.babelrc。
{
"presets": [
[
"@babel/preset-env",
{
// 浏览器版本
"targets": {
"edge": "17",
"chrome": "67"
},
// 配置corejs版本,但需要额外安装corejs
"corejs": 3,
// 加载情况
// entry: 需要在入口文件进入@babel/polyfill,然后babel根据使用情况按需载入
// usage: 无需引入,自动按需加载
// false: 入口文件引入,全部载入
"useBuiltIns": "usage"
}
]
]
}接下来,我们来测试一下,先修改一下index.js。
new Promise((resolve) => {
resolve('HelloWorld');
}).then((res) => {
console.log(res);
});然后执行yarn build进行打包。
在使用babel之前,打包出来的main.js如下。
!(function () {
'use strict';
new Promise((o) => {
o('HelloWorld');
}).then((o) => {
console.log(o);
});
})();上面打包代码是直接使用了Promise,而没有考虑到低版本浏览器的兼容。然后我们打开babel后,执行一下打包命令,会发现代码多出了很多。
而在打包代码中,可以看到webpack使用了polyfill实现promise类,然后再去调用,从而兼容了低版本浏览器没有promise属性问题。
Webpack 本地服务
当我们使用webpack的时候,不仅仅只是用于打包文件,大部分我们还会依赖webpack来搭建本地服务,同时利用其热更新的功能,让我们更好的开发和调试代码。
接下来我们来安装一下webpack-dev-server:
# 版本为3.11.2
yarn add webpack-dev-server -D然后执行下列代码开启服务:
npx webpack serve或者在 package.json 配置一下:
"scripts": {
"serve": "webpack serve --mode development"
}然后通过yarn serve运行。
这时,webpack 会默认开启http://localhost:8080/服务(具体看你们运行返回的代码),而该服务指向的是dist/index.html。
但你会发现,你的dist中其实是没有任何文件的,这是因为webpack将实时编译后的文件都保存到了内存当中。
webpack-dev-server 的好处
其实webpack自带提供了--watch命令,可以实现动态监听文件的改变并实时打包,输出新的打包文件。
但这种方案存在着几个缺点,一就是每次你一修改代码,webpack 就会全部文件进行重新打包,这时候每次更新打包的速度就会慢了很多;其次,这样的监听方式做不到热更新,即每次你修改代码后,webpack 重新编译打包后,你就得手动刷新浏览器,才能看到最新的页面结果。
而webpack-dev-server,却有效了弥补这两个问题。它的实现,是使用了express启动了一个http服务器,来伺候资源文件。然后这个http服务器和客户端使用了websocket通讯协议,当原始文件作出改动后,webpack-dev-server就会实时编译,然后将最后编译文件实时渲染到页面上。
webpack-dev-server 配置
在webpack.config.js中,有一个devServer选项是用来配置webpack-dev-server,这里简单讲几个比较常用的配置。
port
我们可以通过 port 来设置服务器端口号。
module.exports = {
...
// 配置webpack-dev-server
devServer: {
port: 8888, // 自定义端口号
},
};open
在devServer中有一个open选项,默认是为false,当你设置为true的时候,你每次运行webpack-dev-server就会自动帮你打开浏览器。
module.exports = {
...
// 配置webpack-dev-server
devServer: {
open: true, // 自动打开浏览器窗口
},
};proxy
这个选项是用来设置本地开发的跨域代理的,关于跨域的知识就不多在这说了,这里就说说如何去配置。
proxy的值必须是一个对象,在里面我们可以配置一个或多个跨域代理。最简单的配置写法就是地址配上api地址。
module.exports = {
...
devServer: {
// 跨域代理
proxy: {
'/api': 'http://localhost:3000'
},
},
};这时候,当你请求/api/users的时候,就会代理到http://localhost:3000/api/users。
如果你不需要传递/api的话,你就需要使用对象的写法,从而增加一些配置选项:
module.exports = {
//...
devServer: {
// 跨域代理
proxy: {
'/api': {
target: 'http://localhost:3000', // 代理地址
pathRewrite: { '^/api': '' }, // 重写路径
},
},
},
};这时候,当你请求/api/users的时候,就会代理到http://localhost:3000/users。
在 proxy 中的选项,还有两个比较常用的,一个就是changeOrigin,默认情况下,代理时会保留主机头的来源,当我们将其设置为true可以覆盖这种行为;还有一个是secure选项,当你的接口使用了https的时候,需要将其设置为false。
module.exports = {
//...
devServer: {
// 跨域代理
proxy: {
'/api': {
target: 'http://localhost:3000', // 代理地址
pathRewrite: { '^/api': '' }, // 重写路径
secure: false, // 使用https
changeOrigin: true, // 覆盖主机源
},
},
},
};多个打包配置
通常我们项目都会有开发环境和生产环境。
前面我们也看到了webpack提供了一个mode选项,但我们开发中不太可能说开发的时候mode设置为development,然后等到要打包才设置为production。当然,前面我们也说了,我们可以通过命令--mode来对应匹配mode选项。
但如果开发环境和生产环境的webpack配置差异不仅仅只有mode选项的话,我们可能需要考虑多份打包配置了。
多个 webpack 配置文件
我们默认的webpack配置文件名为webpack.config.js,而webpack执行的时候,也默认会找该配置文件。
但如果我们不使用该文件名,而改成webpack.conf.js的话,webpack正常执行是会使用默认配置的,因此我们需要使用一个--config选项,来指定配置文件。
webpack --config webpack.conf.js因此,我们就可以分别配置一个开发环境的配置webpack.dev.js和生成环境的配置webpack.prod.js,然后通过指令进行执行不同配置文件:
// package.json
"scripts": {
"dev": "webpack --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
}单个配置文件
如果说,你不想创建那么多配置文件的话,我们也可以只只用webpack.config.js来实现多份打包配置。
按照前面说的使用--mode配置mode选项,其实我们可以在webpack.config.js中拿到这个变量,因此我们就可以通过这个变量去返回不同的配置文件。
// argv.mode可以获取到配置的mode选项
module.exports = (env, argv) => {
if (argv.mode === 'development') {
// 返回开发环境的配置选项
return { ... }
}else if (argv.mode === 'production') {
// 返回生产环境的配置选项
return { ... }
}
};静态资源处理
当我们使用了图片、视频或字体等等其他静态资源的话,我们需要用到url-loader和file-loader。
# url-loader -> 4.1.1; file-loader -> 6.2.0
yarn add url-loader file-loader -D首先我们在项目中引入一张图片,然后在引入到index.js中。
import pic from './image.png';
const img = new Image();
img.src = pic;
document.querySelector('body').append(img);然后我先使用url-loader。
module.exports = {
...
module: {
rules: [
{
test: /\.(png|je?pg|gif|webp)$/,
use: ['url-loader']
}
]
}
};然后执行一下打包。
你会发现,dist路径下没有图片文件,但是你打开页面是可以看到图片的,且通过调试工具,我们可以看到其实url-loader默认会将静态资源转成base64。
当然,url-loader选项有提供一个属性,叫limit,就是我们可以设置一个文件大小阈值,当文件大小超过这个值的时候,url-loader就不会转成base64,而是直接打包成文件。
module.exports = {
...
module: {
rules: [
{
test: /\.(png|je?pg|gif|webp)$/,
use: [{
loader: 'url-loader',
options: {
name: '[name].[ext]', // 使用占位符设置导出名称
limit: 1024 * 10 // 设置转成base64阈值,大于10k不转成base64
}
}]
}
]
}
};这时候我们再打包一下,dist文件夹下就会出现了图片文件。
而file-loader其实跟url-loader差不多,但它默认就是导出文件,而不会导出base64的。
module.exports = {
...
module: {
rules: [
{
test: /\.(png|je?pg|gif|webp)$/,
use: ['file-loader']
}
]
}
};打包一下,会发现dist文件夹下依旧会打包成一个图片文件,但是它的名称会被改成哈希值,我们可以通过options选项来设置导出的名称。
module.exports = {
...
module: {
rules: [
{
test: /\.(png|je?pg|gif|webp)$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]', // 使用占位符设置导出名称
}
}]
}
]
}
};而对于视频文件、字体文件,也是用相同的方法,只不过是修改test。
module.exports = {
...
module: {
rules: [
// 图片
{
test: /\.(png|je?pg|gif|webp)$/,
use: {
loader: 'url-loader',
options: {
esModule: false,
name: '[name].[ext]',
limit: 1024 * 10
}
}
},
// 字体
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 1024 * 10
}
}
},
// 媒体文件
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 1024 * 10
}
}
}
]
}
};但现在有个问题,就是如果直接在index.html引入图片的话,可以顺利打包吗?
答案是不会的,我们可以测试一下。首先将图片引入index.html。
<!DOCTYPE html>
<html lang="en">
<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" />
<title>Document</title>
</head>
<body>
<img src="./image.png" />
</body>
</html>然后执行打包后,打包出来的index.html照样是<img src="./image.png">,但是我们并没有解析和打包出来image.png出来。
这时候我们需要借助另一个插件——html-withimg-loader。
# 0.1.16yarn add html-withimg-loader -D然后我们再添加一条rules。
{ test: /\.html$/,loader: 'html-withimg-loader' }这时候打包成功后,dist文件成功将图片打包出来了,但是打开页面的时候,图片还是展示不出来。然后通过调试工具看的话,会发现
<img src="{"default":"image.png"}">这是因为html-loader使用的是commonjs进行解析的,而url-loader默认是使用esmodule解析的。因此我们需要设置一下url-loader。
{ test: /\.(png|je?pg|gif|webp)$/, use: { loader: 'url-loader', options: { esModule: false, // 不适用esmodule解析 name: '[name].[ext]', limit: 1024 * 10 } }}这时候重新打包一下,页面就能成功展示图片了。
Webpack5 资源模块
在webpack5中,新添了一个资源模块,它允许使用资源文件(字体,图标等)而无需配置额外 loader,具体的内容大家可以看看文档,这里简单讲一下如何操作。
前面的例子,我们对静态资源都使用了url-loader或者file-loader,而在webpack5,我们甚至可以需要手动去安装和使用这两个loader,而直接设置一个type属性。
{ test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i, type: "asset/resource",}然后打包测试后,静态文件都会直接打包成文件并自动引入,效果跟file-loader一致。
type值提供了四个选项:
asset/resource: 发送一个单独的文件并导出 URL。之前通过使用file-loader实现。asset/inline: 导出一个资源的 data URI。之前通过使用url-loader实现。- **
asset/source:**导出资源的源代码。之前通过使用raw-loader实现。 asset: 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用url-loader,并且配置资源体积限制实现。
同时,我们可以在output设置输出bundle静态文件的名称:
output: { path: path.resolve(__dirname, 'dist/'), filename: '[name].js', // 设置静态bundle文件的名称 assetModuleFilename: '[name][ext]'}清理打包路径
在每次打包前,我们其实都需要去清空一下打包路径的文件。
如果文件重名的话,webpack还会自动覆盖,但是实际中我们都会在打包文件名称中加入哈希值,因此清空的操作不得不实现。
这时候我们需要使用一个插件——clean-webpack-plugin。
yarn add clean-webpack-plugin -D然后只需引入到配置文件且在plugins配置就可以使用了。
const path = require('path');
// 引入CleanWebpackPlugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist/'),
filename: '[name].js',
publicPath: '',
},
plugins: [
// 使用CleanWebpackPlugin
new CleanWebpackPlugin(),
],
};有些情况下,我们不需要完全清空打包路径,这时候我们可以使用到一个选项,叫cleanOnceBeforeBuildPatterns,它是一个数组,默认是[**/*],也就是清理output.path路径下所有东西。而你可以在里面输入只想删除的文件,同时我们可以输入不想删除的文件,只需要在前面加上一个!。
需要注意的是,
cleanOnceBeforeBuildPatterns这个选项是可以删除打包路径下之外的文件,只需要你配上绝对路径的话。因此CleanWebpackPlugin还提供了一个选项供测试——dry,默认是为false,当你设置为true后,它就不会真正的执行删除,而是只会在命令行打印出被删除的文件,这样子更好的避免测试过程中误删。
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist/'),
filename: '[name].js',
publicPath: '',
},
plugins: [
new CleanWebpackPlugin({
// dry: true // 打开可测试,不会真正执行删除动作
cleanOnceBeforeBuildPatterns: [
'**/*', // 删除dist路径下所有文件
`!package.json`, // 不删除dist/package.json文件
],
}),
],
};文件归类
在目前我们的测试代码中,我们的src文件夹如下:
├── src
│ ├── Alata-Regular.ttf
│ ├── image.png
│ ├── index.html
│ ├── index.js
│ ├── style.css
│ └── style.scss而正常项目的话,我们会使用文件夹将其分好类,这并不难,我们先简单归类一下。
├── src
│ ├── index.html
│ ├── js
│ │ └── index.js
│ ├── static
│ │ └── image.png
│ │ └── Alata-Regular.ttf
│ └── style
│ ├── style.css
│ └── style.scss接下来,我们需要打包出来的文件也是归类好的,这里就不太复杂,直接用一个assets文件夹将所有静态文件放进去,然后index.html放外面。
├── dist
│ ├── assets
│ │ ├── Alata-Regular.ttf
│ │ ├── image.png
│ │ ├── main.css
│ │ └── main.js
│ └── index.html这里先补充一下style.css引入字体的代码:
@font-face {
font-family: 'test-font';
src: url('../static/Alata-Regular.ttf') format('truetype');
}
body {
display: flex;
font-family: 'test-font';
}首先,我们先将打包出来的JavaScript文件放入assets文件夹下,我们只需要修改output.filename即可。
output: {
path: path.resolve(__dirname, 'dist/'),
filename: 'assets/[name].js'
}其次,我们将打包出来的css文件也放入assets路径下,因为我们打包css是使用miniCssExtractPlugin,因此我们只需要配置一下miniCssExtractPlugin的filename即可:
plugins: [
...new miniCssExtractPlugin({
filename: 'assets/[name].css',
}),
];最后就是静态资源了,这里我们使用静态模块方案,所以直接修改output.assetModuleFilename即可:
output: {
path: path.resolve(__dirname, 'dist/'),
filename: 'assets/[name].js',
assetModuleFilename: 'assets/[name][ext]'
},这时候打包一下,预览一下页面,发现都正常引入和使用。