deno.com
本页内容

动态导入

Deno Deploy 支持动态导入,但有一些限制。本页概述了这些限制。

说明符必须是静态确定的字符串字面量 跳到标题

在常规动态导入中,说明符不需要在构建时确定。因此,以下所有形式都是有效的

Deno CLI 中有效的动态导入
// 1. Statically determined string literal
await import("jsr:@std/assert");

// 2. Statically determined, but via variable
const specifier = "jsr:@std/assert";
await import(specifier);

// 3. Statically determined, but template literal
const stdModuleName = "path";
await import(`jsr:@std/${stdModuleName}`);

// 4. Dynamically determined
const rand = Math.random();
const mod = rand < 0.5 ? "npm:cowsay" : "npm:node-emoji";
await import(mod);

然而,在 Deno Deploy 中,说明符必须是字符串字面量,且不能有字符串插值。因此,在上面三个示例中,只有第一个在 Deno Deploy 中有效。

只有静态字符串字面量在 Deno Deploy 中有效
// 1. ✅ Works fine on Deno Deploy
await import("jsr:@std/assert");

// 2. ❌ Doesn't work on Deno Deploy
// because what's passed to `import` is a variable
const specifier = "jsr:@std/streams";
await import(specifier);

// 3. ❌ Doesn't work on Deno Deploy
// because this has an interpolation
const stdModuleName = "path";
await import(`jsr:@std/${stdModuleName}`);

// 4. ❌ Doesn't work on Deno Deploy
// because it's dynamic
const rand = Math.random();
const mod = rand < 0.5 ? "npm:cowsay" : "npm:node-emoji";
await import(mod);

一个例外——动态说明符适用于同一项目文件 跳到标题

如果目标文件(模块)包含在同一项目中,则支持动态确定的说明符。

动态说明符适用于同一项目中的文件
// ✅ Works fine on Deno Deploy
await import("./my_module1.ts");

// ✅ Works fine on Deno Deploy
const rand = Math.random();
const modPath = rand < 0.5 ? "dir1/moduleA.ts" : "dir2/dir3/moduleB.ts";
await import(`./${modPath}`);

请注意,以 ./ 开头的模板字面量会告诉模块解析器目标模块在同一项目中。相反,如果说明符不以 ./ 开头,则可能的模块将不会包含在生成的 eszip 中,导致动态导入在运行时失败,即使最终评估的说明符以 ./ 开头也是如此。

// ❌ Doesn't work because the analyzer can't statically determine if the
// specifier starts with `./` or not in this case.
// Compare this to the previous example. Only difference is whether to put
// `./` in the template literal or in the variable.
const rand = Math.random();
const modPath = rand < 0.5 ? "./dir1/moduleA.ts" : "./dir2/dir3/moduleB.ts";
await import(modPath);

我们将在未来考虑是否可以放宽此限制。

什么是 eszip?

当您在 Deno Deploy 上进行新部署时,系统会分析您的代码,通过递归遍历构建模块图,并将所有依赖项打包到一个文件中。我们称之为 eszip。由于其创建是完全静态的,因此 Deno Deploy 上的动态导入功能受到限制。

数据 URL 跳到标题

数据 URL 可以用作传递给动态导入的说明符。

静态数据 URL
// ✅ Works fine on Deno Deploy
const { val } = await import(
  "data:text/javascript,export const val = 42;"
);
console.log(val); // -> 42

对于数据 URL,支持完全动态的数据。

动态数据 URL
function generateDynamicDataUrl() {
  const moduleStr = `export const val = ${Math.random()};`;
  return `data:text/javascript,${moduleStr}`;
}

// ✅ Works fine on Deno Deploy
const { val } = await import(generateDynamicDataUrl());
console.log(val); // -> Random value is printed

将此技术应用于从网络获取的 JavaScript 代码,您甚至可以模拟真正的动态导入

external.js
export const name = "external.js";
从获取的源创建的动态数据 URL
import { assert } from "jsr:@std/assert/assert";
const res = await fetch(
  "https://gist.githubusercontent.com/magurotuna/1cacb136f9fd6b786eb8bbad92c8e6d6/raw/56a96fd0d246fd3feabbeecea6ea1155bdf5f50d/external.js",
);
assert(res.ok);
const src = await res.text();
const dataUrl = `data:application/javascript,${src}`;

// ✅ Works fine on Deno Deploy
const { name } = await import(dataUrl);
console.log(`Hello from ${name}`); // -> "Hello from external.js"

然而,请注意,提供给 import 的数据 URL 必须是 JavaScript;如果传递 TypeScript,会在运行时抛出 TypeError

您找到所需内容了吗?

隐私政策