【问题标题】:Webpack - prevent font files (.woff, .eot, .ttf) in peer dependencies from being part of the buildWebpack - 防止对等依赖项中的字体文件(.woff、.eot、.ttf)成为构建的一部分
【发布时间】: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

我尝试过的事情:

  1. 按照以下问题中的建议向 webpack 配置添加一个外部密钥:Webpack to build without including peer dependencies

  2. 尝试从字体文件的规则中排除 node_modules。

  3. 删除字体文件本身的规则。

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

【问题讨论】:

    标签: javascript reactjs webpack webpack-4


    【解决方案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.

    中更详细地谈到了解决过程

    【讨论】:

      猜你喜欢
      • 2014-10-26
      • 2021-08-02
      • 2016-06-27
      • 2017-06-05
      • 2016-01-13
      • 2012-06-15
      • 2019-04-22
      • 1970-01-01
      相关资源
      最近更新 更多