javascript - 从运行时块加载生成的 webpack 块
问题描述
我正在使用新的(反应)代码部分更新现有的 Web 应用程序,并使用 webpack 将所有内容捆绑在一起以进行生产。index.html
因为现有的HTML 页面(实际上是 XML 转换为 HTML)已经存在,我无法使用HtmlWebpackPlugin
.
我想要实现的是 webpack 生成一个小的runtime.bundle.js
,它将动态加载其他生成的块(main.[contenthash]
和vendor.[contenthash]
),而不是将这些条目作为script
标签添加到index.html
. 这种方式runtime.bundle.js
可以设置为,nocache
而其他大块可以由浏览器缓存并在代码更改时正确获取。
例如,这里是生成的主体块index.html
,注意注释:
<html>
<head>...</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript" src="runtime.bundle.js"></script>
<!-- I want these two files below not injected as script tags,
but loaded from the runtime.bundle.js file above -->
<script type="text/javascript" src="vendors.31b8acd750477817012d.js"></script>
<script type="text/javascript" src="main.1e4a456d496cdd2e1771.js"></script>
</body>
</html>
运行时文件已经加载了一个不同的块,该块是从 JS 动态导入的,代码如下:
const App = React.lazy(() => import(/* webpackChunkName: "modulex" */ './App'));
这会在runtime.bundle.js
a = document.createElement('script');
(a.charset = 'utf-8'),
(a.timeout = 120),
i.nc && a.setAttribute('nonce', i.nc),
(a.src = (function(e) {
return (
i.p +
'' +
({ 1: 'modulex' }[e] || e) +
'.' +
{ 1: '0e0c4000d075e81c1e5b' }[e] +
'.js'
);
vendors
那么对于andmain
块也可以实现同样的效果吗?
我能想到的唯一其他替代解决方案是使用WebpackManifestPlugin
生成manifest.json
并使用它将块注入到已经存在的 HTML 文件中。
解决方案
我最终通过创建一个脚本来解决这个问题,该脚本使用manifest.json
(由 生成WebpackManifestPlugin
)生成一个runtime.js
脚本,该脚本将在页面加载时动态加载块并将其插入runtime.js
到index.html
. 这可以从npm scripts
使用tasksfile npm 包的部分调用。
在你的 webpack 配置中,将插件添加到插件数组中:
{
// your other webpack config
plugins: [
new ManifestPlugin(),
// other webpack plugins you need
],
}
我有以下外部 JS 文件,我可以npm scripts
使用 tasksfile npm 包调用它,该包配置为调用此函数:
// The path where webpack saves the built files to (this includes manifest.json)
const buildPath = './build';
// The URL prefix where the file should be loaded
const urlPrefix = 'https://www.yourdomain.com';
function buildRuntime() {
const manifest = require(`${buildPath}/manifest`);
// Loop through each js file in manifest file and append as script element to the head
// Execute within an IIFE such that we don't pollute global namespace
let scriptsToLoad = Object.keys(manifest)
.filter(key => key.endsWith('.js'))
.reduce((js, key) => {
return (
js +
`
script = document.createElement('script');
script.src = urlPrefix + "/js/${manifest[key]}";
document.head.appendChild(script);`
);
}, `(function(){var script;`);
scriptsToLoad += '})()';
// Write the result to a runtime file that can be included in the head of an index file
const filePath = `${buildPath}/runtime.js`;
fs.writeFile(filePath, scriptsToLoad, err => {
if (err) {
return console.log('Error writing runtime.js: ', err);
}
console.log(`\n${filePath} succesfully built\n`);
});
}
该函数基本上循环遍历manifest.json
.
然后使用这些条目作为src
属性创建脚本标记,然后将这些脚本标记添加到document.head
作为子项(触发条目的加载)。最后,这个脚本被保存到一个runtime.js
文件并存储在构建目录中。
您现在可以将此runtime.js
文件包含到您的 html 文件中,如果所有路径设置正确,您应该加载块。
推荐阅读
- python-3.x - 使用 CuDNNLSTM 预测 Y 标签
- python - 将 Pandas DataFrame 转换为 VALUES sql 语句
- c# - 无法将类型“System.Threading.Tasks.Task”隐式转换为“字符串”
- typescript - Prettier 不解析 Typescript 类型转换
- c - 在 C 中运行另一个文件
- django - 将大熊猫数据框下载为 CVS 文件
- r - 在 R 中使用 dplyr 将 csv 导入 SQLite 数据库时,我是否需要担心 SQL 注入?
- python - 如何编写函数将视频拆分成帧?
- c# - 光标图标不会在 Windows 窗体的构造函数内更改
- php - Python3 脚本在 shell 中运行良好,但在 PHP 中触发 UnicodeEncodeError