javascript - 在 webpack 上,如何在不评估的情况下导入脚本?

标签 javascript webpack lazy-loading prefetch

我最近在做一些网站优化工作,我开始使用 webpack 中的代码拆分,使用如下 import 语句:
import(/* webpackChunkName: 'pageB-chunk' */ './pageB')
正确创建 pageB-chunk.js ,现在假设我想 预取 这个 block 在pageA中,我可以通过在pageA中添加这个语句来做到这一点:
import(/* webpackChunkName: 'pageB-chunk' */ /* webpackPrefetch: true */ './pageB')
这将导致
<link rel="prefetch" href="pageB-chunk.js">
被追加到 HTML 的头部,然后浏览器将预取它,到目前为止一切都很好。

问题是 进口 我在这里使用的语句不仅预取 js 文件,还评估 js 文件,意味着该 js 文件的代码被解析并编译为字节码,执行该 JS 的顶级代码。

在移动设备上这是一个非常耗时的操作,我想优化它,我只想要 预取 部分,我不想要 评估和执行部分,因为稍后当一些用户交互发生时,我会触发 解析和评估

enter image description here

↑↑↑↑↑↑↑↑我只想触发前两步,图片来自https://calendar.perfplanet.com/2011/lazy-evaluation-of-commonjs-modules/ ↑↑↑↑↑↑↑↑↑↑

当然我可以通过自己添加预取链接来做到这一点,但这意味着我需要知道我应该在预取链接中放入哪个 URL,webpack 肯定知道这个 URL,我如何从 webpack 中获取它?

webpack 有没有简单的方法来实现这一点?

最佳答案

更新

您可以使用preload-webpack-pluginhtml-webpack-plugin它会让你定义在配置中预加载的内容,它会自动插入标签来预加载你的 block

请注意,如果您现在使用 webpack v4,则必须使用 preload-webpack-plugin@next 安装此插件

例子

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    include: 'asyncChunks'
  })
]

For a project generating two async scripts with dynamically generated names, such as chunk.31132ae6680e598f8879.js and chunk.d15e7fdfc91b34bb78c4.js, the following preloads will be injected into the document head


<link rel="preload" as="script" href="chunk.31132ae6680e598f8879.js">
<link rel="preload" as="script" href="chunk.d15e7fdfc91b34bb78c4.js">

更新 2

如果您不想预加载所有异步 block ,但只指定一次,您也可以这样做

要么你可以使用migcoder's babel plugin或与 preload-webpack-plugin喜欢以下
  • 首先,您必须在 webpack magic comment 的帮助下命名该异步 block 。例子
    import(/* webpackChunkName: 'myAsyncPreloadChunk' */ './path/to/file')
    
  • 然后在插件配置中使用该名称,例如
    plugins: [
      new HtmlWebpackPlugin(),   
      new PreloadWebpackPlugin({
        rel: 'preload',
        include: ['myAsyncPreloadChunk']
      }) 
    ]
    


  • 首先让我们看看当我们指定 script 时浏览器的行为。标签或 link加载脚本的标签
  • 每当浏览器遇到 script标记它将加载它解析它
    并立即执行
  • 您只能在 async 的帮助下延迟解析和评估和defer标签 直到 DOMContentLoaded 事件
  • 如果您不插入脚本标签(仅使用 link 预加载它)
  • ,则可以延迟执行(评估)

    现在还有一些其他的不推荐 hackey 方式是您发送整个脚本和 stringcomment (因为评论或字符串的评估时间几乎可以忽略不计)当您需要执行时,您可以使用 Function() constructoreval两者都不推荐

    另一种方法服务 worker :(这将在页面重新加载后保留您的缓存事件,或者在加载缓存后用户下线)

    在现代浏览器中,您可以使用 service worker获取和缓存资源(JavaScript、图像、css 任何东西),当主线程请求该资源时,您可以拦截该请求并从缓存中返回资源,这样您在将脚本加载到缓存
    阅读更多关于服务人员的信息 here

    例子
    self.addEventListener('install', function(event) {
      event.waitUntil(
        caches.open('v1').then(function(cache) {
          return cache.addAll([
            '/sw-test/',
            '/sw-test/index.html',
            '/sw-test/style.css',
            '/sw-test/app.js',
            '/sw-test/image-list.js',
            '/sw-test/star-wars-logo.jpg',
            '/sw-test/gallery/bountyHunters.jpg',
            '/sw-test/gallery/myLittleVader.jpg',
            '/sw-test/gallery/snowTroopers.jpg'
          ]);
        })
      );
    });
    
    self.addEventListener('fetch', function(event) {
      event.respondWith(caches.match(event.request).then(function(response) {
        // caches.match() always resolves
        // but in case of success response will have value
        if (response !== undefined) {
          return response;
        } else {
          return fetch(event.request).then(function (response) {
            // response may be used only once
            // we need to save clone to put one copy in cache
            // and serve second one
            let responseClone = response.clone();
    
            caches.open('v1').then(function (cache) {
              cache.put(event.request, responseClone);
            });
            return response;
          }).catch(function () {
            // any fallback code here
          });
        }
      }));
    });
    
    

    如您所见,这不是 webpack 依赖 这超出了 webpack 的范围,但是在 webpack 的帮助下,你可以拆分你的包,这将有助于更好地利用 service worker

    关于javascript - 在 webpack 上,如何在不评估的情况下导入脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59838778/

    相关文章:

    entity-framework - IValidatableObject 的 Validate 方法期间出现延迟加载问题

    Angular Lazy 加载模块 - 子路由中的问题

    typescript - ES6 typescript 将所有导出的常量导入为数组

    javascript - 仅验证表单的可见部分

    javascript - 无法使用 javascript 或 jquery 获取 div 中数据集的更新值

    javascript - Chrome 扩展程序不工作

    javascript - 不正确的行号 - sourcemaps,Webpack 2 Typescript

    javascript - Vue 在用 webpack 编译时用注释替换 HTML

    javascript - 延迟加载 strip - 导致未定义的错误

    javascript - 当文本区域为空时如何禁用链接?