Webpack - 防止对等依赖项中的字体文件(.woff、.eot、.ttf)成为构建的一部分
Posted
技术标签:
【中文标题】Webpack - 防止对等依赖项中的字体文件(.woff、.eot、.ttf)成为构建的一部分【英文标题】:Webpack - prevent font files (.woff, .eot, .ttf) in peer dependencies from being part of the build 【发布时间】:2021-10-15 07:14:49 【问题描述】:我正在尝试修改我的 webpack 配置,以使来自对等依赖项的字体文件(.woff、.woff2 .eot、.ttf)不会包含在构建中。这是我的 Webpack 配置:
webpack.common.js
module.exports =
entry: './index.js',
output:
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js',
publicPath: '/',
libraryTarget: 'umd',
,
plugins: [
new CleanWebpackPlugin(),
new htmlWebpackPlugin(
template: path.resolve(__dirname, "public/index.html"),
),
new CopyPlugin(
patterns: [
from: path.resolve(__dirname, 'src/assets'), to: path.resolve(__dirname, 'dist/assets')
],
),
],
externals:
lodash: 'lodash',
'@scoped/scoped-ui': '@scoped/scoped-ui',
'@scoped/scoped-web-common': '@scoped/scoped-web-common',
'@scoped/scoped-rich-text-editor': '@scoped/scoped-rich-text-editor',
'@ckeditor/ckeditor5-react': '@ckeditor/ckeditor5-react',
bootstrap: 'bootstrap',
'react-bootstrap': 'react-bootstrap'
,
// also tried the array format
// externals: ['lodash', '@scoped/scoped-ui', '@scoped/scoped-web-common', '@ckeditor/ckeditor5-react', 'bootstrap', 'react-bootstrap'],
module:
rules: [
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
'babel-loader',
loader: 'eslint-loader',
options:
emitWarning: true,
formatter: 'table',
,
,
],
,
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
,
test: /\.(png|svg|jpg|gif)$/,
exclude: /node_modules/,
use: [
loader: 'file-loader',
options:
name: '[name].[ext]',
outputPath: 'static/img',
,
,
],
,
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
loader: 'file-loader',
options:
name: '[name].[ext]',
outputPath: '/assets/'
,
,
],
,
test: /\.ttf$/,
use: [
loader: 'ttf-loader',
options:
name: './font/[hash].[ext]',
outputPath: '/assets/'
,
,
],
,
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
'sass-loader',
],
,
],
,
;
Webpack(及相关)版本:
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.1.3"
package.json 中的对等依赖项:
"peerDependencies":
"@ckeditor/ckeditor5-react": "^2.1.0",
"@scoped/scoped-rich-text-editor": "0.0.1-56",
"@scoped/scoped-ui": "^1",
"@scoped/scoped-web-common": "^1",
"bootstrap": "^4.4.1",
"react-bootstrap": "^1.0.0-beta.17",
"lodash": "4.17.21"
,
我的构建脚本的结果是以下文件结构:
. ┠ 地区 ┠ 资产 ┠ [散列].ttf ┠ [散列].eot ┠ [散列].woff ┠ [散列].woff2 ┠ [someImage].jpg ┠ [someOtherImage].png ┠ 静态 ┠ index_bundle.js ┠ index_bundle.js.map ┠ index.html我尝试过的事情:
按照以下问题中的建议向 webpack 配置添加一个外部密钥:Webpack to build without including peer dependencies
尝试从字体文件的规则中排除 node_modules。
删除字体文件本身的规则。
2) 和 3) 都给我相同的结果,即构建脚本失败,错误如下所示:
ERROR in ./node_modules/@scoped/scoped-ui/build/assets/fonts/418e7417-47f3-40a1-8817-519a566f9d82.eot 1:1
Module parse failed: Unexpected character '@' (1:1)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
@ ./node_modules/@scoped/scoped-ui/build/styles/font.css (./node_modules/css-loader/dist/cjs.js!./node_modules/@scoped/scoped-ui/build/styles/font.css) 4:0-101 33:73-102
@ ./node_modules/css-loader/dist/cjs.js!./node_modules/@scoped/scoped-ui/build/styles/main.css
@ ./node_modules/@scoped/scoped-ui/build/styles/main.css
@ ./src/index.js
@ ./index.js
ERROR in ./node_modules/@scoped/scoped-ui/build/assets/fonts/4cc8f5da-4e24-4929-8efb-866ffcb1fe7e.eot 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
@ ./node_modules/@scoped/scoped-ui/build/styles/font.css (./node_modules/css-loader/dist/cjs.js!./node_modules/@scoped/scoped-ui/build/styles/font.css) 28:0-102 57:74-104
@ ./node_modules/css-loader/dist/cjs.js!./node_modules/@scoped/scoped-ui/build/styles/main.css
@ ./node_modules/@scoped/scoped-ui/build/styles/main.css
@ ./src/index.js
@ ./index.js
【问题讨论】:
【参考方案1】:我认为这可以通过使用自定义解析插件来解决:
webpack.config.js
const path = require('path');
const PreventFontsFromPeerDeps =
apply (resolver)
const beforeFinalFile = resolver.getHook('before-final-file');
let peerDepsFromMainRepo;
beforeFinalFile.tap("PreventFontsFromPeerDeps", (request, resolveContext) =>
if (!peerDepsFromMainRepo)
peerDepsFromMainRepo = request.descriptionFileData.peerDependencies;
return;
const path = request;
const isPathAFont = /* ... */;
const isFromPeerDeps = Object.keys(peerDepsFromMainRepo).some(k => path.includes(`node_modules/$k`));
if (isFromPeerDeps && isPathAFont)
// By returning this, this request will be ignored.
return path: false ;
);
,
;
/**
* @type import("webpack/types").Configuration
*/
const config =
/* ... */
resolve:
plugins: [PreventFontsFromPeerDeps]
,
/* ... */
;
module.exports = config;
这个自定义插件介入的捆绑过程部分可以被认为是解析过程。
这是解决资源的地方。这个解析过程由多个阶段组成,比如:判断所需模块的package.json
(也叫描述文件),判断路径是指路径还是到目录等
这些 stages 在内部用 webpack 的说法表示为 hooks。其中一个钩子是final-file
,它负责确定文件是否存在。通过使用before-final-file
,我们添加了某种优先级,这意味着我们的自定义逻辑将首先运行。
peerDepsFromMainRepo
指的是要解析的第一个文件。该文件很可能是存储库的一部分,因此与之关联的package.json
将是根目录之一,这意味着我们将能够从那里获取peerDependencies
对象。request
对象包含我们需要的所有信息,正如我们从这张图片中看到的那样:
插件本质上是从项目根目录的package.json
文件中获取对等依赖项,然后,对于每个传入的请求(请求=资源的路径),它检查该资源是否是对等依赖与否。
注意:在上图中,我举了一个更简单的例子,我添加了lodash
作为对等依赖项。您可以找到示例here。
我在this SO answer.
中更详细地谈到了解决过程【讨论】:
以上是关于Webpack - 防止对等依赖项中的字体文件(.woff、.eot、.ttf)成为构建的一部分的主要内容,如果未能解决你的问题,请参考以下文章
Vue 3 和 webpack 5 - 错误:“模块属性已从依赖项中删除”
冲突的对等依赖关系:webpack@4.46.0 npm ERR!节点模块/webpack
eslint 'html-webpack-plugin' 应该列在项目的依赖项中,而不是 devDependencies 中。 (导入/无外部依赖项)
一次性支持Webpack,Parcel和Rollup的最佳方法是什么?