┌──────────────────────────────────────────────────────────┐ │ 📄 shadcn/directory/udecode/plate/(guides)/typescript.cn │ └──────────────────────────────────────────────────────────┘
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
Plate 提供 ESM 格式的包,这需要特定的 TypeScript(和打包工具)配置来确保兼容性,特别是在导入子路径模块如 platejs/react 时。以下是几种解决方案和变通方法,以确保 TypeScript 正常工作。
tsconfig.json 中设置 "moduleResolution": "bundler"。"moduleResolution": "node" 并将路径映射到 dist/react(并可能在打包工具配置中添加别名)。depset 升级 Plate 依赖项。"moduleResolution": "bundler"对于现代打包工具(如 Vite、Next.js 14 等),最简单的方法是启用 TypeScript 新的 "bundler" 解析模式。示例:
// tsconfig.json
{
"compilerOptions": {
// ...
"module": "esnext",
"moduleResolution": "bundler",
// ...
}
}
这使 TypeScript 的解析逻辑更接近现代打包工具和 ESM 包的行为。以下是 Plate 模板 中的一个工作示例:
{
"compilerOptions": {
"strict": false,
"strictNullChecks": true,
"allowUnusedLabels": false,
"allowUnreachableCode": false,
"exactOptionalPropertyTypes": false,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": false,
"noPropertyAccessFromIndexSignature": false,
"noUncheckedIndexedAccess": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"isolatedModules": true,
"allowJs": true,
"checkJs": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"lib": ["dom", "dom.iterable", "esnext"],
"jsx": "preserve",
"module": "esnext",
"target": "es2022",
"moduleResolution": "bundler",
"moduleDetection": "force",
"resolveJsonModule": true,
"noEmit": true,
"incremental": true,
"sourceMap": true,
"baseUrl": "src",
"paths": {
"@/*": ["./*"]
}
},
"include": [
"next-env.d.ts",
".next/types/**/*.ts",
"src/**/*.ts",
"src/**/*.tsx"
],
"exclude": ["node_modules"]
}
"moduleResolution": "bundler" 是在 TypeScript 5.0 中引入的。"moduleResolution": "node" 并手动配置路径别名。// package.json
{
"devDependencies": {
"typescript": "^5.0.0"
}
}
如果看到类似 TS5023: Unknown compiler option 'moduleResolution' 的错误(针对 bundler),很可能是因为你的 TypeScript 版本低于 5.0。
"moduleResolution": "node" + 路径别名如果无法升级到 TS 5.0 或更改解析模式:
"moduleResolution": "node"。tsconfig.json 中使用 paths 将每个 Plate 子路径导入映射到其 dist/react 类型。tsconfig.json{
"compilerOptions": {
"moduleResolution": "node",
"paths": {
"platejs/react": [
"./node_modules/platejs/dist/react/index.d.ts"
],
"@platejs/core/react": [
"./node_modules/@platejs/core/dist/react/index.d.ts"
],
"@platejs/list/react": [
"./node_modules/@platejs/list/dist/react/index.d.ts"
]
// ...为所有 @platejs/*/react 包重复此操作
}
}
}
vite.config.tsimport { defineConfig } from 'vite';
import path from 'path';
export default defineConfig({
resolve: {
alias: {
'platejs/react': path.resolve(
__dirname,
'node_modules/platejs/dist/react'
),
'@platejs/core/react': path.resolve(
__dirname,
'node_modules/@platejs/core/dist/react'
),
'@platejs/list/react': path.resolve(
__dirname,
'node_modules/@platejs/list/dist/react'
),
// 非 /react 基础别名:
'platejs': path.resolve(
__dirname,
'node_modules/platejs'
),
'@platejs/core': path.resolve(
__dirname,
'node_modules/@platejs/core'
),
'@platejs/list': path.resolve(
__dirname,
'node_modules/@platejs/list'
)
}
}
});
注意:
@platejs/*/react 导入都进行此操作。moduleNameMapper 或类似方式复制这些别名。假设你正在升级一个包到 42.0.3,请确保所有 platejs* 包都升级到 最新版本(最高到 42.0.3)(如果某个包没有 42.0.3 版本,可以保持在 42.0.2)。版本混用通常会导致不兼容问题。
为了轻松管理和同步你的 platejs* 包版本,可以使用 depset CLI。例如,确保所有 @udecode 作用域的包都对齐到与 42.x.y 兼容的最新版本:
npx depset@latest @udecode 42
或者,指定特定版本如 42.0.3(如果可用,这将把所有包设置为 42.0.3,否则设置为之前的最新版本):
npx depset@latest @udecode 42.0.3
这有助于防止版本冲突,确保所有相关的 Plate 包都使用兼容的版本。
我将
moduleResolution改为bundler,但旧的导入出错了。
如果你的代码库有旧的 TypeScript 用法或依赖 node 解析,可以尝试路径别名方案,或者完全迁移到 TS 5+ / ESM 环境。
我看到
TS2305错误,提示缺少导出。这是解析错误还是真的缺少导出?
可能是两者之一:
moduleResolution: bundler需要的最低 TS 版本是多少?
TypeScript 5.0 或更高版本。
我们切换到 bundler 解析模式,但项目中的一些旧库出错了。
如果你的旧库不支持 ESM,可以继续使用 node 解析模式并手动配置路径别名。一些大型代码库会逐步升级或为遗留代码创建单独的构建管道。
在 Jest 中看到错误,但在 Vite 中没有。
你需要在 Jest 中复制别名/解析配置。例如:
// jest.config.js
module.exports = {
// ...
moduleNameMapper: {
'^platejs/react$': '<rootDir>/node_modules/platejs/dist/react',
'^@platejs/core/react$': '<rootDir>/node_modules/@platejs/core/dist/react',
// ...
}
};
║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
╚══════════════════════════════════════════════════════════════════════════════════════════════╝