lang
lang/typescript/module/esm-only.md
medium
typescript-esm-only
TypeScript 项目纯 ESM 模块系统 — 禁 require / module.exports / CommonJS 混用。Use when 写 TS 业务代码 / 评审涉及 `esm-only` 的 PR。
esmcommonjsimportexport模块系统es modules
paths
frontend/**/*.tsfrontend/**/*.tsx
TypeScript · ESM only
规则
前端项目纯 ESM:
| 用 | 不用 |
|---|---|
import x from "y" / export ... |
require / module.exports |
import.meta.env / import.meta.url |
__dirname / __filename |
import.meta.glob(Vite) |
webpack-style require.context |
tsconfig
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Bundler",
"target": "ES2022",
"esModuleInterop": true,
"verbatimModuleSyntax": true
}
}
verbatimModuleSyntax: true 强制类型 import 显式:
// ✅
import type { Article } from "@/types/article";
import { fetchArticles } from "@/api/articles";
// ❌
import { Article, fetchArticles } from "@/api/articles"; // 类型混在值 import 里
路径别名
@/ → src/:
// ✅
import { Button } from "@/components/Button";
import { useTenant } from "@/stores/tenant";
// ❌ 相对路径深嵌套
import { Button } from "../../../components/Button";
副作用 import
// 仅副作用,无 export — 用 bare specifier
import "antd/dist/reset.css";
import "@/styles/global.css";
反例
// ❌ CommonJS
const x = require("lib");
module.exports = { x };
// ❌ __dirname(Node 全局,Vite 下不存在)
const path = __dirname + "/data.json";
// ✅ ESM 等价
import { fileURLToPath } from "node:url";
const here = fileURLToPath(new URL(".", import.meta.url));
自检
- [ ] 无
require/module.exports? - [ ] 类型 import 用
import type? - [ ] 路径别名
@/...不是相对深嵌套? - [ ] CSS 副作用 import 顺序:reset → tokens → global?