欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

動態(tài)引入DynamicImport實(shí)現(xiàn)原理

 更新時間:2023年01月08日 16:29:33   作者:情緒羊  
這篇文章主要為大家介紹了動態(tài)引入DynamicImport實(shí)現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

什么是動態(tài)引入(DynamicImport)?

本文介紹的動態(tài)引入實(shí)現(xiàn)方式基于 rollup 插件 @rollup/plugin-dynamic-import-vars

通常情況下,我們都是通過確定的字面量路徑來引用文件模塊的,例如:

import './a.js';
require('./a.js');
import('./a.js');

對于確定的文件路徑來說,構(gòu)建工具可以輕易的抓取文件并進(jìn)行相關(guān)的轉(zhuǎn)換。

但當(dāng)import或者require的目標(biāo)不是一個靜態(tài)字符串,而是一個動態(tài)表達(dá)式時,構(gòu)建工具其實(shí)也不確定用戶到底引用了什么,所以通常這種情況只能依靠 JavaScript 的運(yùn)行時來解析。

若動態(tài)表達(dá)式實(shí)際代表的路徑無法被解析,則運(yùn)行時會引起控制臺的錯誤。通常是因?yàn)樯傻奈募窂讲]有被納入打包體系,所以找不到文件。

下面列出了一些常見的動態(tài)引入表達(dá)式:

// TemplateLiteral 模板字符串
import(`./icons/arrow-${type}.svg`);
require(`./icons/arrow-${type}.svg`);
// BinaryExpression 二元表達(dá)式
import('./icon/arrow-' + type + '.svg');
// 直接引用一個變量
import(path);
require(path)

但經(jīng)過前人們的實(shí)踐發(fā)現(xiàn),當(dāng)動態(tài)表達(dá)式滿足一定的結(jié)構(gòu)時,構(gòu)建工具便可以通過一些特殊手段抓取并打包路徑匹配的相關(guān)文件,并自動注入一些 polyfill,從而實(shí)現(xiàn)動態(tài)引入(DynamicImport)的效果,也就是本文的主題。

動態(tài)引入的實(shí)現(xiàn)原理

本節(jié)內(nèi)容翻譯加工自 @rollup/plugin-dynamic-import-vars README.md 部分章節(jié)

當(dāng)動態(tài)導(dǎo)入的路徑中包含變量時,經(jīng)過 AST 分析可以生成對應(yīng)的通配符。在構(gòu)建的時候,這些通配符將被用于抓取匹配的文件。隨后這些文件會被添加進(jìn)構(gòu)建體系中,在運(yùn)行時,根據(jù)導(dǎo)入的實(shí)際路徑返回對應(yīng)的文件內(nèi)容。

下面是一些通配符的轉(zhuǎn)換示例:

`./locales/${locale}.js` -> './locales/*.js'
`./${folder}/${name}.js` -> './*/*.js'
`./module-${name}.js` -> './module-*.js'
`./modules-${name}/index.js` -> './modules-*/index.js'
'./locales/' + locale + '.js' -> './locales/*.js'
'./locales/' + locale + foo + bar '.js' -> './locales/*.js'
'./locales/' + `${locale}.js` -> './locales/*.js'
'./locales/' + `${foo + bar}.js` -> './locales/*.js'
'./locales/'.concat(locale, '.js') -> './locales/*.js'
'./'.concat(folder, '/').concat(name, '.js') -> './*/*.js'

待轉(zhuǎn)換的代碼可能是這樣的:

function importLocale(locale) {
  return import(`./locales/${locale}.js`);
}

經(jīng)過轉(zhuǎn)換后它會變成下面這樣:

function __variableDynamicImportRuntime__(path) {
  switch (path) {
    case './locales/en-GB.js':
      return import('./locales/en-GB.js');
    case './locales/en-US.js':
      return import('./locales/en-US.js');
    case './locales/nl-NL.js':
      return import('./locales/nl-NL.js');
    default:
      return new Promise(function (resolve, reject) {
        queueMicrotask(reject.bind(null, new Error('Unknown variable dynamic import: ' + path)));
      });
  }
}
function importLocale(locale) {
  return __variableDynamicImportRuntime__(`./locales/${locale}.js`);
}

可以看到,實(shí)際的 import 被替換成了注入的 __variableDynamicImportRuntime__ 函數(shù),該函數(shù)會根據(jù)運(yùn)行時拼接的具體字符串返回對應(yīng)的打包文件。

動態(tài)引入的限制

本節(jié)內(nèi)容翻譯加工自 @rollup/plugin-dynamic-import-vars README.md 部分章節(jié)

為了知道要在代碼中注入什么,我們必須能夠?qū)Υa進(jìn)行一些靜態(tài)分析,并對可能的導(dǎo)入做出一些假設(shè)。例如,如果只使用一個變量,理論上可以從整個文件系統(tǒng)中導(dǎo)入任何內(nèi)容。

function importModule(path) {
  return import(path); // 這根本無法推斷引入了什么
}

為了能夠?qū)崿F(xiàn)靜態(tài)分析,并避免可能出現(xiàn)的問題,動態(tài)引入的實(shí)現(xiàn)上限定了一些規(guī)則:

Import 路徑須為相對路徑

所有導(dǎo)入都必須相對于導(dǎo)入文件進(jìn)行。導(dǎo)入不應(yīng)該是純變量、絕對路徑或裸導(dǎo)入:

// Not allowed
import(bar); // 純變量
import(`/foo/${bar}.js`); // 絕對路徑
import(`${bar}.js`); // 裸導(dǎo)入
import(`some-library/${bar}.js`); // 裸導(dǎo)入

引用路徑需包含文件后綴

文件夾中可能包含你不打算導(dǎo)入的文件。因此,我們要求導(dǎo)入的靜態(tài)部分以文件擴(kuò)展名結(jié)束。

import(`./foo/${bar}`); // Not allowed
import(`./foo/${bar}.js`); // Allowed

導(dǎo)入當(dāng)前目錄的文件需要指定具體的文件匹配格式

如果你從當(dāng)前目錄導(dǎo)入文件,很可能會導(dǎo)入一些原本不打算導(dǎo)入的文件,包括書寫代碼的這個文件本身。因此這種情況下需要給出一個更具體的文件名匹配格式:

import(`./${foo}.js`); // not allowed
import(`./module-${foo}.js`); // allowed

通配符(Glob Pattern)僅有一層深度

在生成通配符時,字符串中的每個變量都會被轉(zhuǎn)換為通配符中的*,每個層級的目錄最多一個星號。這避免了無意中從更多的目錄中添加文件到導(dǎo)入中。

下面的例子中,最終將會生成 ./foo/*/.js 而非 ./foo/**/.js。

import(`./foo/${x}${y}/${z}.js`);

核心流程解讀

插件核心轉(zhuǎn)換代碼僅有 100 行,且非常易懂 —— plugins/index.js at master · rollup/plugins

整體流程分為以下幾步:

通過 AST 分析,拿到對應(yīng)的導(dǎo)入路徑,也就是 import 表達(dá)式括號中的源碼部分。

對這部分的源碼進(jìn)行處理,調(diào)用 dynamicImportToGlob 函數(shù)

執(zhí)行上述限制條件的判斷,嘗試獲取一個合法的通配符。

如果通配符不合法,將會引發(fā)錯誤,終止進(jìn)程。

執(zhí)行通配符,抓取相關(guān)文件。

替換 import 表達(dá)式,并注入 __variableDynamicImportRuntime__ 函數(shù)。

附上插件核心轉(zhuǎn)換代碼的截圖,代碼本身不長且非常容易理解,感興趣的同學(xué)可以自行跳轉(zhuǎn)研究。

以上就是動態(tài)引入DynamicImport實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于動態(tài)引入DynamicImport的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論