如何链接Webpack 4分割的块?

w8f9ii69  于 2022-11-24  发布在  Webpack
关注(0)|答案(2)|浏览(296)

问题是

我有一个使用Webpack 4的项目,想启用代码分割。我有这个配置来启用分割块。

optimization: {
    splitChunks: {
      chunks: 'all'
    },
  }

当我运行构建时,我得到一些文件名:

about-d434910cfbfb3b1f4f52.js
billing-d434910cfbfb3b1f4f52.js
login-d434910cfbfb3b1f4f52.js
vendors~about~billing~login~~97fa390a-d434910cfbfb3b1f4f52.js

about.jsbilling.jslogin.js是我的入口点。供应商文件包含这3个页面上使用的jQuery。我的理解是,我需要在我的模板中编写2个脚本标记,如:

<script type="text/javascript" src="http://0.0.0.0:8000/assets/bundles/vendors~about~billing~login~~97fa390a-d434910cfbfb3b1f4f52.js" ></script>
<script type="text/javascript" src="http://0.0.0.0:8000/assets/bundles/about-d434910cfbfb3b1f4f52.js" ></script>

这是有意义的,但我不清楚我应该如何知道如何连接哪个供应商文件和哪个入口点文件。在这种情况下,只有一个供应商文件,但我的项目有更多的依赖项,所以实际上可能有3个以上。更不用说这些将随着代码的变化而变化。

与Require.js的比较

在Require.js中,您将执行以下操作:

define(['jquery', 'my-module'], function($, myModule) {
  ...
});

和jQuery,在Webpack4中,这将是:

import $ from 'jquery';
import MyModule from 'my-module';

但是当你在Webpack中这样做的时候,你必须把依赖包作为一个脚本标记列出,导入的时候它不会下载jQuery。

Webpack动态导入

我知道Webpack有动态导入功能,它会返回一个承诺:

import('lodash').then(_ => {
    ...
});

这类似于Require.js,但是是为了分离应用程序功能。这不是我想要做的。如果import()可以接受多个模块名称,也许它可以工作,我只是用它来导入所有内容,但是根据文档,这绝对不是这个特性的使用方式。

那些问题

1)您如何通过编程方式知道哪些文件依赖于哪些文件,以便呈现正确的脚本标记?
2)有没有一种方法可以使用import来获得下载模块的行为,当模块还没有在页面中链接时,AMD会这样做?

swvgeqrz

swvgeqrz2#

如果由于某种原因您不能使用HtmlWebpackPlugin,例如,在我的例子中,我使用PHP并完全在后端生成HTML,您可以使用webpack-manifest-plugin并读取生成的清单,以编程方式仅链接所需的文件。
请注意,您将只加载一些初始JavaScript(在我的例子中,是由入口点生成的JavaScript),但是Webpack将负责链接由动态导入生成的文件。
要生成具有入口点的清单文件,您可以使用Create React App中当前使用的Webpack配置:顺便说一下,他们还在评论中给予了一些关于这个特定用例的提示:

// Generate an asset manifest file with the following content:
// - "files" key: Mapping of all asset filenames to their corresponding
//   output file so that tools can pick it up without having to parse
//   `index.html`
// - "entrypoints" key: Array of files which are included in `index.html`,
//   can be used to reconstruct the HTML if necessary```

以下是配置,以备将来更改:

const { WebpackManifestPlugin } = require('webpack-manifest-plugin');

然后在plugins数组中:

new WebpackManifestPlugin({
  fileName: 'asset-manifest.json',
  publicPath: paths.publicUrlOrPath,
  generate: (seed, files, entrypoints) => {
    const manifestFiles = files.reduce((manifest, file) => {
      manifest[file.name] = file.path;
      return manifest;
    }, seed);
    const entrypointFiles = entrypoints.main.filter(
      fileName => !fileName.endsWith('.map')
    );

    return {
      files: manifestFiles,
      entrypoints: entrypointFiles,
    };
  },
}),

请注意,如果您的入口点具有不同的名称,则entrypoints.main部分将不起作用,例如,在我的情况下,我不得不将其更改为entrypoints.app
生成的清单文件将具有以下结构:

{
  "files": {
    "app.js": "/js/app.9cdce93ada164d829885.js",
    // [more generated files, including the ones generated by dynamic imports]
  },
  "entrypoints": [
    "css/7741.bdbd58131904790cf1ce.css",
    "js/app.9cdce93ada164d829885.js"
    // [other files, for example the runtime file and/or the vendor file]
  ]
}

然后,您需要将这些资产与您正在使用的语言链接起来,您可能需要将css文件与js文件分开,以便以正确的方式链接它们。
在我的例子中,我已经在PHP中创建了一个app_assets()方法,它将扩展名作为参数并返回资产,因此,例如在我的刀片模板中,我可以对CSS执行如下操作:

@foreach(app_assets('css') as $link)
  <link rel="stylesheet" href="{{secure_asset($link)}}" type="text/css" />
@endforeach

对于JavaScript,请执行以下操作:

@foreach(app_assets('js') as $link)
  <script src="{{secure_asset($link)}}" type="module"></script>
@endforeach

相关问题