Webpack具有小的初始脚本和所有其他脚本的异步加载

时间:2015-10-07 20:35:41

标签: javascript jquery asynchronous webpack

我开始使用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中我想加载像这样的javascripts:

<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]  

3 个答案:

答案 0 :(得分:1)

这是我提出的解决方案。

首先,将这两个功能导出到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);
}

答案 1 :(得分:1)

我最近也走过这条路,我正在优化Webpack输出,因为我认为捆绑包太大,HTTP2可以并行加载js文件,并且使用单独的文件进行缓存会更好,我得到了一些依赖当我得到一个使用Webpack 4 SplitChunksPlugin配置的解决方案时,我目前正朝着主要使用Webpack的dynamic import()语法的方向发展,因为仅此语法将导致Webpack自动将动态导入的bundle捆绑在其自己的文件中,我可以通过“魔术评论”来命名:

import(/* webpackChunkName: "mymodule" */ "mymodule"); // I added an resolve.alias.mymodule entry in Webpack.config

答案 2 :(得分:0)

前一段时间,我做了一个很小的“概念证明”来检查importlazy在IE11中的工作方式。我必须承认它有效:) 点击按钮后,负责更改页面背景颜色的代码已加载-full example

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>