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

ilo*_*zcd 12 javascript lazy-loading prefetch webpack

我最近在做一些网站优化工作,我开始使用 webpack 中的代码拆分,使用 import 语句,如下所示:

import(/* webpackChunkName: 'pageB-chunk' */ './pageB')

哪个正确创建了pageB-chunk.js,现在假设我想在 pageA 中预取这个块,我可以通过在 pageA 中添加以下语句来实现:

import(/* webpackChunkName: 'pageB-chunk' */ /* webpackPrefetch: true */ './pageB')

这将导致

<link rel="prefetch" href="pageB-chunk.js">

附加到 HTML 的头部,然后浏览器将预取它,到目前为止一切顺利。

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

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

在此处输入图片说明

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

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

webpack 有什么简单的方法来实现这一点吗?

ilo*_*zcd 3

更新: 我将所有内容都包含在 npm 包中,请查看! https://www.npmjs.com/package/webpack-prefetcher


经过几天的研究,我最终编写了一个定制的 babel 插件......

简而言之,该插件的工作原理如下:

  • 收集代码中的所有import(args)语句
  • 如果import(args)包含 /* prefetch: true */ 注释
  • import()语句中查找chunkId
  • 将其替换为Prefetcher.fetch(chunkId)

Prefetcher 是一个帮助器类,包含 webpack 输出的清单,可以帮助我们插入预取链接:

export class Prefetcher {
  static manifest = {
    "pageA.js": "/pageA.hash.js",
    "app.js": "/app.hash.js",
    "index.html": "/index.html"
  }
  static function fetch(chunkId) {
    const link = document.createElement('link')
    link.rel = "prefetch"
    link.as = "script"
    link.href = Prefetcher.manifest[chunkId + '.js']
    document.head.appendChild(link)
  }
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

const pageAImporter = {
  prefetch: () => import(/* prefetch: true */ './pageA.js')
  load: () => import(/* webpackChunkName: 'pageA' */ './pageA.js')
}

a.onmousehover = () => pageAImporter.prefetch()

a.onclick = () => pageAImporter.load().then(...)
Run Code Online (Sandbox Code Playgroud)

该插件的详细信息可以在这里找到:

Prefetch - 从 webpack 获取控制权

再说一次,这是一种非常 hacky 的方式,我不喜欢它,如果你希望 webpack 团队实现这个,请在​​这里投票:

功能:按需预取动态导入