南通市文章资讯

Webpack在异步请求JS文件时如何获取JS Bundle的机制

2026-03-24 11:55:01 浏览次数:0
详细信息

Webpack 在处理异步 JS 文件请求时,主要通过以下几个机制来获取和加载 JS Bundle:

1. 代码分割与动态导入

Webpack 通过 import() 语法实现动态导入,将代码分割成多个 bundle:

// 动态导入 - Webpack 会自动分割代码
import('./module').then(module => {
  module.doSomething();
});

2. 运行时加载机制

JSONP 方式(Webpack 4 及之前)

// Webpack 生成的 runtime 代码示例
__webpack_require__.e = function requireEnsure(chunkId) {
  var promises = [];

  // 1. 通过 JSONP 加载 chunk
  var script = document.createElement('script');
  script.src = jsonpScriptSrc(chunkId);

  // 2. 设置回调函数
  window["webpackJsonp"] = window["webpackJsonp"] || [];
  window["webpackJsonp"].push = function(data) {
    // 处理加载的模块
  };
}

import() 方式(Webpack 5 优化)

Webpack 5 使用更现代的加载方式:

// 使用 promise-based 加载
__webpack_require__.f.j = function(chunkId, promises) {
  // 创建加载 promise
  var promise = new Promise(function(resolve, reject) {
    // 加载 chunk 文件
    var url = __webpack_require__.p + chunkId + ".js";
    loadScript(url, resolve, reject);
  });

  promises.push(promise);
};

3. 关键加载流程

步骤 1:解析模块依赖

// Webpack 编译时分析依赖
// 生成 chunk 映射表
{
  "src_utils_math_js": 0,
  "src_component_Modal_js": 1
}

步骤 2:生成 Manifest 文件

Webpack 生成包含 chunk 信息的 runtime:

// runtime 包含的 chunk 映射信息
(self["webpackChunk"] = self["webpackChunk"] || []).push([
  ["chunk-name"],
  {
    "./src/module.js": function(module, exports) {
      // 模块代码
    }
  }
]);

步骤 3:动态加载执行流程

// 1. 检查缓存
if(installedChunks[chunkId] !== undefined) {
  return Promise.resolve();
}

// 2. 创建加载 promise
installedChunks[chunkId] = [resolve, reject];

// 3. 创建 script 标签加载
var script = document.createElement('script');
script.src = chunkUrl;

// 4. 加载完成后执行
script.onload = function() {
  // 触发 webpackJsonp 回调
  // 解析模块并执行
};

4. 配置相关优化

Prefetch/Preload

import(/* webpackPrefetch: true */ './Modal');
import(/* webpackPreload: true */ './Chart');

魔法注释控制

// 指定 chunk 名称
import(/* webpackChunkName: "my-chunk" */ './module');

// 指定加载模式
import(/* webpackMode: "lazy" */ './module');

5. Webpack 配置示例

// webpack.config.js
module.exports = {
  output: {
    // 使用 [contenthash] 实现长效缓存
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].chunk.js',

    // 指定 chunk 加载路径
    publicPath: 'https://cdn.example.com/assets/',

    // Webpack 5 新增
    chunkLoadingGlobal: 'myCustomChunkLoadingFunction'
  },

  optimization: {
    // 分离 runtime 代码
    runtimeChunk: 'single',

    // 分割策略
    splitChunks: {
      chunks: 'all',
      minSize: 20000,
      maxSize: 244000
    }
  }
};

6. 实际加载示例

<!-- 初始加载的 HTML -->
<script src="runtime.bundle.js"></script>
<script src="main.bundle.js"></script>

<!-- 动态加载时 Webpack 注入 -->
<script src="1.chunk.js" async></script>

7. 调试技巧

// 查看 chunk 加载状态
console.log(__webpack_modules__);
console.log(__webpack_chunk_load__);

// 使用 webpack 的 stats 分析
npx webpack --profile --json > stats.json

总结

Webpack 的异步加载机制通过:

编译时分析依赖关系生成 chunk 映射 运行时动态加载通过 script 标签或 fetch 模块注册通过全局回调函数或 Promise 缓存优化避免重复加载

这种机制实现了按需加载,优化了首屏加载时间,同时保持了模块系统的完整性。

相关推荐