admin 管理员组

文章数量: 1086019


2024年4月13日发(作者:input not supported 怎么办)

webpack import动态加载原理

Webpack是一个模块打包工具,可以将多个模块打包成一个文件

以达到优化性能的目的。而import语法提供了在代码中动态引入模块

的方式,使得我们可以按需加载代码,减少页面加载时间,提高用户

体验。那么,Webpack是如何实现import动态加载的呢?

1. 实现动态导入的做法

在Webpack的内部实现中,动态导入语法会被编译成特定的代码

结构。当我们使用import()来引入一个模块时,Webpack会为我们自

动生成一个代码块(chunk),并在运行时动态的加载它。

import('./module').then(module => {

// do something with module

})

当我们执行这段代码时,Webpack会将./module单独打包成一个

代码块,并在需要的时候加载它。这种做法需要浏览器支持Promise,

因为动态导入返回的是一个Promise对象。

2. 代码生成原理

动态导入语法的原理是:Webpack通过执行一系列的转换,将代

码库转换成模块图(asset graph)。模块图是一个模块对象的集合,

包含了模块之间的依赖关系。

动态导入的关键在于打包的代码块创建和加载过程。当我们使用

import()引入一个模块时,Webpack会将该模块单独打包成一个代码块,

并在需要的时候动态加载它。这个代码块在Webpack中被称为

“jsonp”,它是通过XMLHttpRequest(XHR)实现动态加载的。

例如,当我们执行下面的代码时,Webpack会生成一个jsonp代

码块:

import('./module').then(module => {

// do something with module

})

jsonp代码块的内容通常和主代码块建立一种关系,其中包含了

实际的代码逻辑和依赖关系。

3. 实现原理

在Webpack内部,动态导入是通过json-p请求来实现的。

Webpack将动态导入语句转换成生成一个jsonp的函数调用,经过一系

列操作后,生成一个具有如下结构的代码:

// webpackBootstrap

(function(modules) {

// The module cache

var installedModules = {};

// The require function

function __webpack_require__(moduleId) {

// Check if module is in cache

if(installedModules[moduleId]) {

return installedModules[moduleId].exports;

}

// Create a new module (and put it into the cache)

var module = installedModules[moduleId] = {

i: moduleId,

l: false,

exports: {}

};

// Execute the module function

modules[moduleId].call(s, module,

s, __webpack_require__);

// Flag the module as loaded

module.l = true;

// Return the exports of the module

return s;

}

// expose the modules object (__webpack_modules__)

__webpack_require__.m = modules;

// expose the module cache

__webpack_require__.c = installedModules;

// define getter function for harmony exports

__webpack_require__.d = function(exports, name, getter) {

if(!__webpack_require__.o(exports, name)) {

Property(exports, name, { enumerable: true,

get: getter });

}

};

// define __esModule on exports

__webpack_require__.r = function(exports) {

if(typeof Symbol !== 'undefined' && ngTag) {

Property(exports, ngTag,

{ value: 'Module' });

}

Property(exports, '__esModule', { value:

true });

};

// create a fake namespace object

// mode & 1: value is a module id, require it

// mode & 2: merge all properties of value into the ns

// mode & 4: return value when already ns object

// mode & 8|1: behave like require

__webpack_require__.t = function(value, mode) {

if(mode & 1) value = __webpack_require__(value);

if(mode & 8) return value;

if((mode & 4) && typeof value === 'object' && value &&

value.__esModule) return value;

var ns = (null);

__webpack_require__.r(ns);

Property(ns, 'default', { enumerable: true,

value: value });

if(mode & 2 && typeof value != 'string') for(var key in

value) __webpack_require__.d(ns, key, function(key) { return

value[key]; }.bind(null, key));

return ns;

};

// getDefaultExport function for compatibility with non-

harmony modules

__webpack_require__.n = function(module) {

var getter = module && module.__esModule ?

function getDefault() { return module['default']; } :

function getModuleExports() { return module; };

__webpack_require__.d(getter, 'a', getter);

return getter;

};

//

__webpack_require__.o = function(object, property) { return

(object, property); };

// __webpack_public_path__

__webpack_require__.p = "";

})

/************************************************************

************/

([

/* 0 */

(function(module, exports) {

// Your

}),

/* 1 */

(function(module, exports, __webpack_require__) {

// Your dependency module

})

]);

在这个代码中,modules数组保存着所有需要打包的模块,

installedModules缓存所有已加载的模块,而__webpack_require__函

数则负责“请求”一个模块,返回该模块的exports。

4. 小结

Webpack通过jsonp来实现动态加载模块,它能够根据需要动态

生成chunk,而不是一次性将所有的代码都打包到一个文件中。因此,

能够大大提升页面初始化的速度,改善用户体验。基于Webpack的优

秀设计,动态导入已成为现代Web开发中的必备特性。


本文标签: 动态 代码 加载 模块 导入