← 中文资源

简体中文版本

用于模块解析的导入映射

导入映射是一段 JSON 声明,告知浏览器如何解析模块标识符,无需打包器即可使用裸包名与带版本 URL。

阅读英文原文

概念概述

用于模块解析的导入映射(Import Maps for Module Resolution)指的是:导入映射是一段 JSON 声明,告知浏览器如何解析模块标识符,无需打包器即可使用裸包名与带版本 URL。

从更严格的定义看,An import map is a script of type importmap whose JSON body maps module specifiers used in imports to concrete URLs, letting the browser resolve bare names and remap paths. 该概念在工程实践中的价值,在于它能帮助团队用统一的语言描述一个具体的质量属性或设计约束,从而在评审与协作中减少歧义。

为什么需要它

It is used to run un-bundled modules in the browser, to swap implementations in tests, and to centralise dependency versions. 它与 CSS Cascade Layers、CSS Container Queries、Third-Party Cookies and Storage Partitioning 等概念经常一起出现,用于解决相近的工程问题。理解它的适用场景,有助于在多种备选方案之间做出有依据的取舍,而不是凭直觉选择技术方案。

常见误解

  • import maps can be added after modules have started loading
  • an import map rewrites the contents of a module file

需要避免的反模式

  • declaring multiple import maps or adding one late
  • mapping a specifier prefix without the required trailing slash

实践要点

  1. The map must appear before the first module load, and browsers allow only a single import map per document, so it belongs early in the head.
  2. Trailing slashes distinguish prefix mappings from exact specifier mappings; a prefix mapping rewrites any specifier that begins with the key plus a slash.
  3. The mechanism resolves URLs only and cannot polyfill module semantics, so it works alongside strict Content Security Policy rather than replacing a build step for older browsers.

参考来源

https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap

代码示例

// tsconfig.json 局部:
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@/features/*": ["features/*"],
      "@/shared/*": ["shared/*"],
      "@/config": ["config/index.ts"]
    }
  }
}

// src/config/index.ts —— 显式环境分层
export const config = {
  port: Number(process.env.PORT ?? 3000),
  logLevel: process.env.LOG_LEVEL ?? 'info',
} as const;

// src/features/orders/service.ts —— 别名导入取代 ../../../
import { config } from '@/config';
import { logger } from '@/shared/logger';

export async function listOrders(page: number) {
  logger.debug('listing orders page', page, 'port', config.port);
  return [{ id: 1, total: 42 }];
}

// 打包器(如 esbuild)注册解析器:
// esbuild src/index.ts --bundle //   --alias:@/features=./src/features //   --alias:@/shared=./src/shared //   --alias:@/config=./src/config/index.ts

const orders = await listOrders(1);
console.log('orders:', orders.length);