Keep

分析 Webpack import() 过程

发布:

在项目中遇到的问题是,使用 webpack 动态加载的模块代码没有执行,导致页面中出现空白。 在开发者工具里能够看到 news.js 文件确实是加载成功的,但在 .init() 代码执行失败,在 console.error 打印的日志中看到 “component 未定义”。代码如下:

import(/* webpackChunkName: 'news' */ `component/news`)
  .then(component => component.init())
  // 加载失败或者 init 失败 (ps: 一个 catch 接受两种情况,会让代码变复杂)
  .catch(console.error)

为了搞清楚 webpack 中 import 的工作过程,尝试去读 development 环境下打包后的代码,分析过程:

import() 做了什么

webpack 在打包时,会对 import() 做代码转换,根据下面转换后代码可以看到,__webpack_require__.e(chunkId) 返回 promise 对象,而业务中真实拿到的数据是 __webpack_require.bind(null, moduleId) 返回的结果。

var promise = __webpack_require_.e(0).then(__webpack_require.bind(null, 75))
promise.then(component => component.init())

__webpack_require__.e 函数辅助做什么事情

// 已加载过
installedChunks[chunkId] === 0
// 正在加载中
installedChunks[chunkId] = [resolve, reject, promise]
var installedChunkData = installedChunks[chunkid]
if (installedChunkDate === 0) return Promise.resolve()
    if (installedChunkData) {
      return installedChunks[chunkId][2]
    }
  var promise = new Promise((resolve, reject) => {
      installedChunkData = installedChunks[chunkId] = [resolve, reject]
  })
installedChunkData[2] = promise

下面到 webpackJsonp 函数

当脚本加载完成后,函数 webpackJsonp(chunkIds, moreModules, executeModules) 会自动执行,执行过程中会把所有 moreModules(它可能是 array 或 object 考虑到数组稀疏) 挂到全局 modules 上,以备 require/import(会被 webpack 转为 __webpack_require__ 函数) 时查找。

由于 chunkId 对应脚本已经加载并且执行完,此时针对 chunkId 更新标记 installedChunks[chunkId] === 0,同时把 installedChunks[chunkId] 中存储的 promise 状态置为 fullfilled,也就是说 import() 函数返回的 promise 对象状态更新。

看__webpack_require.bind(null, moduleId) 函数

__webpack_require 是相对重要的函数,负责模块本身引入其它公共模块,引入过程是:

  var module = installedModules[moduleId] = {
      i: moduleId,
      l: false, // loadedloaded
      exports: { }
  }

chunkId 和 moduleId 的关系?

webpack 约定在使用 import 语法时,需要指定 chunkName(chunkId) 和源文件模块 (moduleId) 对应关系如下,那么在 build 过程就很容易得到 chunkId 和 moduleId 对应关系。

import(/* webpackChunkName: "news" */ `component/news`)
  .then(component => component.init())

了解 import() 整个过程后,很容易找到问题所在了。component 未定义 说明 chunk 文件加载完后,在执行过程中 module.exports 对象异常。


avatar image

@read2025, 生活在北京(北漂),程序员,宅,马拉松[纯粹],喜欢动漫。"骑士总能救出公主,是因为恶龙从没伤害过她"