Webpack与小的初始脚本和异步加载所有其他脚本
Webpack with small initial script and async loading of all other scripts
我已经开始使用Webpack开发由多个页面和不同页面类型组成的普通网站。我习惯了RequireJs脚本加载器,它会在需要时按需加载所有依赖项。当页面加载时,只下载一小段javascript。
我想实现的是:
- 一个小的初始javascript文件,异步加载依赖项
- 每个页面类型都可以有自己的javascript,也可以有依赖关系。
- 通用模块、供应商脚本应该捆绑在通用脚本
我尝试了很多配置来达到这个目的,但是都没有成功。
entry: {
main: 'main.js', //Used on all pages, e.g. mobile menu
'standard-page': 'pages/standard-page.js',
'start-page': 'pages/start-page.js',
'vendor': ['jquery']
},
alias: {
jquery: 'jquery/dist/jquery.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js"),
new webpack.optimize.CommonsChunkPlugin('common.js')
]
在html中,我希望像这样加载javascript:
<script src="/Static/js/dist/common.js"></script>
<script src="/Static/js/dist/main.js" async></script>
在特定的页面类型(起始页)上
<script src="/Static/js/dist/start-page.js" async></script>
为了快速加载页面,common.js应该是一个很小的文件。Main.js加载async和require('jquery')。
Webpack的输出看起来很有希望,但是我不能让供应商的包异步加载。其他依赖项(我自己的模块和domReady)被加载到它们自动生成的块中,但不是jquery。
我可以找到很多这样做的例子,但不是异步加载供应商的重要部分。
webpack build输出:
Asset Size Chunks Chunk Names
main.js.map 570 bytes 0, 7 [emitted] main
main.js 399 bytes 0, 7 [emitted] main
standard-page.js 355 bytes 2, 7 [emitted] standard-page
c6ff6378688eba5a294f.js 348 bytes 3, 7 [emitted]
start-page.js 361 bytes 4, 7 [emitted] start-page
8986b3741c0dddb9c762.js 387 bytes 5, 7 [emitted]
vendor.js 257 kB 6, 7 [emitted] vendor
common.js 3.86 kB 7 [emitted] common.js
2876de041eaa501e23a2.js 1.3 kB 1, 7 [emitted]
这个问题的解决方案有两个方面:
- 首先你需要了解在webpack中代码分割是如何工作的。
- 其次,你需要使用
CommonsChunkPlugin
之类的东西来生成共享包。
在你开始使用webpack之前,你需要放弃对配置的依赖。Require.js都是关于配置文件的。这种心态使我很难过渡到webpack,它更接近于node.js中的CommonJS,它不依赖于配置。
考虑到这一点,请考虑以下内容。如果你有一个应用程序,你想让它异步加载javascript的其他部分,你需要使用以下范例之一:
Require.ensure
require.ensure
是在应用程序中创建"分离点"的一种方法。同样,您可能认为需要对配置执行此操作,但事实并非如此。在这个例子中,当我在我的文件中点击require.ensure
时,webpack将自动创建第二个bundle并按需加载它。在该分裂点内执行的任何代码都将被捆绑在一个单独的文件中。
require.ensure(['jquery'], function() {
var $ = require('jquery');
/* ... */
});
要求([])
您也可以使用amd版本的require()
实现相同的事情,该版本采用依赖项数组。这也将创建相同的分割点:
require(['jquery'], function($) {
/* ... */
});
共享包在上面的例子中,你使用entry
来创建一个vendor
包,它有jQuery。您不需要手动指定这些依赖包。相反,使用上面的拆分点,你的webpack会自动生成这个。
使用entry
仅为单独的<script>
标签,你想在你的页面。
现在您已经完成了所有这些,您可以使用CommonsChunkPlugin
来额外优化您的块,但是大多数魔术都是为您完成的,除了指定应该共享哪些依赖项之外,您不需要做任何其他事情。webpack
将自动拉入共享块,而不需要额外的<script>
标签或entry
配置。
您描述的场景(多个<script>
标签)可能实际上不是您想要的。有了webpack,所有的依赖和包都可以从一个单独的<script>
标签开始自动管理。在经历了从require.js到webpack的多次重构之后,我发现这通常是管理依赖的最简单和最好的方法。
这是我想到的解决方案。
首先,将这两个函数导出到window.*
——您需要在浏览器中使用它们。
export function requireAsync(module) {
return new Promise((resolve, reject) => require(`bundle!./pages/${module}`)(resolve));
}
export function runAsync(moduleName, data={}) {
return requireAsync(moduleName).then(module => {
if(module.__esModule) {
// if it's an es6 module, then the default function should be exported as module.default
if(_.isFunction(module.default)) {
return module.default(data);
}
} else if(_.isFunction(module)) {
// if it's not an es6 module, then the module itself should be the function
return module(data);
}
})
}
然后,当您想要在页面上包含一个脚本时,只需将此添加到HTML中:
<script>requireAsync('script_name.js')</script>
现在pages/
目录中的所有内容都将被预编译成一个单独的块,只有在需要时才能在运行时异步加载。
此外,使用上面的函数,您现在可以方便地将服务器端数据传递到客户端脚本:
<script>runAsync('script_that_needs_data', {my:'data',wow:'much excite'})</script>
现在你可以访问它了:
// script_that_needs_data.js
export default function({my,wow}) {
console.log(my,wow);
}
我最近走了同样的路,我正在优化我的Webpack输出,因为我认为捆绑包太大了,HTTP2可以并行加载js文件,缓存单独的文件会更好,我在捆绑包中复制了一些依赖项,等等。虽然我得到了Webpack 4 SplitChunksPlugin配置的解决方案,但我目前主要使用Webpack的动态import()语法,因为该语法会导致Webpack自动将动态导入的包捆绑在自己的文件中,我可以通过"魔法注释"命名:
import(/* webpackChunkName: "mymodule" */ "mymodule"); // I added an resolve.alias.mymodule entry in Webpack.config
前一段时间我做了这样一个小的"概念证明"来检查importlazy在IE11中的工作方式。我不得不承认它是有效的:)单击按钮后,负责更改页面背景颜色的代码将被加载-完整示例
Js:
// polyfils for IE11
import 'core-js/modules/es.array.iterator';
const button = document.getElementById('background');
button.addEventListener('click', async (event) => {
event.preventDefault();
try {
const background = await import(/* webpackChunkName: "background" */ `./${button.dataset.module}.js`);
background.default();
} catch (error) {
console.log(error);
}
})
Html: <button id="background" class="button-primary" data-module="background">change the background</button>
- Joomla异步脚本加载jdoc头
- 将自定义脚本加载到Vue.js组件中
- 延迟加载 脚本加载和/或执行
- 脚本加载问题
- I'当我试图将java脚本加载到web视图中时,我得到了一个空白屏幕
- 脚本加载脚本广告
- 当我有一个脚本数组时,如何等待脚本加载
- 将Dropbox API脚本加载到chrome扩展时出错
- 异步脚本加载
- 一旦第三方脚本加载失败,立即运行一段JavaScript
- 有没有办法阻止脚本加载两次?JavaScript
- 无法使用 AJAX 将脚本加载为纯文本
- 我怎样才能说服WebStorm我的用户脚本加载jQuery
- 需要JS脚本加载顺序
- 处理不同设备的页面中的脚本加载
- 显示加载 gif,直到脚本加载完毕
- jQuery Mobile pageinit,脚本加载和其他东西
- IE11 脚本加载不起作用(有时)
- 有条件地将内容脚本加载到 Safari 扩展中,就像在 FF/Chrome 中一样
- 如何在Chrome开发工具中找到以下脚本加载时间线