ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

理解 Redux Toolkit 文档构建中的 `remark-typescript-tools`:TypeScript 7 时代的 vendored 插件移植

理解 Redux Toolkit 文档构建中的 `remark-typescript-tools`:TypeScript 7 时代的 vendored 插件移植 理解 Redux Toolkit 文档构建中的remark-typescript-toolsTypeScript 7 时代的 vendored 插件移植【免费下载链接】redux-toolkitThe official, opinionated, batteries-included toolset for efficient Redux development项目地址: https://gitcode.com/gh_mirrors/re/redux-toolkit本篇技术指南聚焦于 Redux Toolkit 仓库gh_mirrors/re/redux-toolkit中website/plugins/remark-typescript-tools这一 vendored内嵌复制插件它承担着 Docusaurus 文档站中代码块类型检查与 TS/JS 双 Tab 渲染和从源码 JSDoc 抽取文档块两大核心职责。读完本文你将掌握该插件在 TypeScript 7 原生编译器Go 内核下如何通过 overlay 文件系统、oxc-transform与oxfmt完成编译与格式化管线理解其与经典ts.*API 的差异以及仓库为何选择以 vendored 形式而不是 npm 依赖接入。背景Docusaurus 文档站为什么需要它Redux Toolkit 的官方文档位于 docs 目录由 Docusaurus 构建。文档中大量.mdx代码块需要在构建期被真实地当作 TypeScript 项目编译检查——这不仅包括语法检查还包括类型检查同时文档需要同时展示 TypeScript 与编译后的 JavaScript 两个版本形成 Tabs 切换。这两项能力分别由插件包内的两条 remark 管线提供最终统一从 index.ts 导出transpileCodeblocks将ts/tsx代码块编译、类型检查并替换为theme/Tabstheme/TabItem结构同时展示 TS 与 JSlinkDocblocks把形如docblock://的链接展开为源码中对应的 JSDoc/TSDoc 注释内容。在 website/docusaurus.config.ts 中两者被注册为 Docusaurus 的remarkPlugins。值得注意的细节是transpileCodeblocks只在 CI 环境启用process.env.CI判断注释明确说明因为它较慢// Only transpile codeblocks in CI, as its slow。为什么是 vendored 而不是发布版依赖README.md 明确解释了原因核心是 TypeScript 7 的破坏性变化TypeScript 7 的主导出只有{ version, versionMajorMinor }不再有typescript.js与typescript.d.ts。任何依赖经典ts.*API 的工具都会失效。上游remark-typescript-tools重度使用经典 API手写的LanguageServiceHost、getEmitOutput做转译、AST 遍历做 docblock 抽取因此在 TS 7 下无法运行。该移植唯一未完成的部分是声明文件输出rollup-plugin-dts仍然驱动经典 TypeScript API在 TS 7 下会崩溃因此上游包无法发布新版本。采用 vendored 方案后插件源码被 website/docusaurus.config.ts 直接以源码方式导入main: index.ts不再需要声明文件。此外README 特别强调这是一个桥梁bridge不是 fork不在该目录开发新功能上游 PR 承载同样的移植一旦上游发布新版本就删除本目录并重新依赖 npm 包。同时仓库在 .oxfmtrc.json 中将website/plugins/**列入ignorePatterns以便这份副本与上游保持格式化一致、易于 diff。从 package.json 可以看到完整依赖栈typescript^7.0.2、oxc-transform^0.144.0、oxfmt^0.63.0、make-synchronized^0.8.0、microsoft/tsdoc^0.15.0、unified^11.0.5、unist-util-visit^5.0.0、unist-util-flatmap^1.0.0、vfile^6.0.3以及mdast-util-mdx-jsx、mdast-util-mdxjs-esm。ESM 兼容桥ts7.cjs的作用TypeScript 7 是 ESM-only 的。Docusaurus 通过 jiti 加载docusaurus.config.ts而 jiti 会把沿途所有依赖转译成 CommonJS——但这一转译会保留 TypeScript 的import.meta导致加载时报错Cannot use import.meta outside a module。ts7.cjs 正是为解决这个兼容问题而生它是纯 CommonJS、不含任何 ESM 语法jiti 对它无可转译于是交给 Node 原生require(esm)处理Node 可以正确加载 TypeScript 7。该文件只导出运行时value导入API、SyntaxKind、getLeadingCommentRanges、getTrailingCommentRanges、isIdentifier、isVariableDeclaration、isVariableStatement。import type在运行时前即被擦除因此插件其余部分仍直接从typescript/unstable/ast导入类型。transpileCodeblocks代码块编译管线transpileCodeblocks的实现位于 transpileCodeblocks/plugin.ts核心是Compiler类compiler.ts。插件层处理流程插件的 transformer 对每个.mdx文件执行以下步骤跳过非目标文件仅处理fileExtensions中列出的扩展名默认[.mdx]。自动注入 Tabs 导入通过visit检查 AST 中是否已导入theme/Tabs与theme/TabItem若没有则在根节点插入对应的mdxjsEsm导入声明。遍历代码块对每个lang为ts或tsx的code节点递增codeBlock计数并跳过带no-transpilemeta 标签的代码块。拆分为虚拟文件splitFiles用正则^\/\/ file: ([\w\-./\[\]])(?: (.*))?\s*$将单个代码块按// file:标记拆分成多个虚拟文件存放到${virtualFilepath}/codeBlock_N/虚拟目录下默认文件名index.tsnoEmit标记对应skip标志用于只检查不展示的场景。编译并收集诊断调用compiler.compile()若存在line/character级别的诊断则通过file.fail()触发构建失败并附带诊断上下文行号与代码片段。组装替换节点defaultAssembleReplacementNodes将原代码块替换为TabsgroupId: language、defaultValue: tsvalues为[{ label: TypeScript, value: ts }, { label: JavaScript, value: js }]内含两个TabItemTS 版本展示postProcessTs的结果JS 版本展示postProcessTranspiledJs的结果并把meta中的.ts/.tsx标题改写为.js/.jsx。Compileroverlay 文件系统 单实例 APICompiler的核心设计是基于overlay覆盖层文件系统的虚拟文件模型// compiler.ts 中的 createOverlay() 核心片段 readFile: (fileName: string) this.virtual.get(slash(fileName)), fileExists: (fileName: string) this.virtual.has(slash(fileName)) ? true : undefined, directoryExists: (dirName: string) this.virtualDirs.has(slash(dirName)) ? true : undefined,关键点在于TS 7 的FileSystem回调返回undefined即回退到真实文件系统。因此虚拟代码块与真实的node_modules树可以共存而无需创建临时目录。代码块路径形如docs/api/createAction.mdx/codeBlock_2/所以addVirtualFile会为每个祖先目录注册到virtualDirs——即使磁盘上真实存在createAction.mdx这个文件在 overlay 中它也必须报告为目录。另一个关键点是externalResolutions的处理。注释说明TS 7 的 checker 运行在 Go 进程中无法回调 JavaScript 模块解析器因此externalResolutions不再通过resolveModuleNames生效而是注入paths条目到生成的 tsconfig 中packageId在 TS 7 中没有对应物被忽略。编译主流程compile()将每个虚拟文件的内容写入 overlay空行会被替换为//__NEWLINE__注释标记避免编译器删除空行emit 后再移除。生成一份与真实 tsconfig 相邻的__remark_typescript_tools.tsconfig.json其结构为{ extends: ./用户tsconfig文件名, compilerOptions: { noEmit: true, paths: { 模块名: [解析后的真实路径] } }, include: [], files: [所有虚拟文件绝对路径] }include: [] 显式files至关重要——用户的 tsconfig 没有files/include若不固定根文件编译器会对每个代码块拉取整个 docs 目录树。 3. 调用api.updateSnapshot({ openProjects: [configPath], fileChanges })增量更新项目快照fileChanges区分created/deleted/changed首次快照为undefined从快照中取出program。 4. 收集诊断getConfigFileParsingDiagnostics()getProgramDiagnostics() 每个文件的getSyntacticDiagnostics()getSemanticDiagnostics()通过flattenMessage展开messageChain并用SourceFile.getLineAndCharacterOfPosition换算行列号。 5. 最后emit()调用transformSync(fileName, source, { jsx: preserve })进行类型擦除与 JSX 转换——因为类型检查已完成这里只需语法级转换随后把//__NEWLINE__标记删除。Compiler实例通过WeakMapCompilerSettings, Compiler在多次调用间复用并提供dispose()关闭 API。后处理用 oxfmt 替代 PrettierpostProcessing.ts 实现了两个默认后处理器defaultPostProcessTs对每个虚拟文件调用formatCode并trim()。defaultPostProcessTranspiledJs先移除转译产物中的ts-ignore/ts-expect-error注释行正则/(\n\s*|)\/\/ (ts-ignore|ts-expect-error).*$/gm再格式化并将文件名后缀从.ts/.tsx改写为.js/.jsxname.replace(/.t(sx?)$/, .j$1)。格式化使用oxfmt而非 Prettier。oxfmt的format是异步的跨越 napi 边界而 remark 遍历管线是同步的因此通过make-synchronized在 worker 中运行并用Atomics.wait阻塞等待——这与旧版prettier/sync对 Prettier 的处理是同一技术。配置解析resolveFormatConfig从parentFile所在目录向上逐层查找.oxfmtrc.json、.oxfmtrc、oxfmt.json带缓存使代码块与所在仓库的格式化风格保持一致。仓库根目录的 .oxfmtrc.json 配置了semi: false、singleQuote: true、printWidth: 80等默认值并通过overrides对packages/rtk-query-codegen-openapi/**、packages/rtk-codemods/**等目录定制选项。与旧 Prettier 实现的关键行为差异README 与源码注释均明确缺少配置时不再跳过格式化而是回退到 oxfmt 默认配置——将未格式化的编译器输出直接放进文档比用默认配置格式化更糟且旧行为失败时仅输出一行日志、静默无效。linkDocblocks从源码抽取文档块linkDocblockslinkDocblocks/plugin.ts允许在 MDX 中写docblock://链接把源码注释渲染进文档。其 MDX 语法约定为链接的host pathname是相对basedir的源码文件query 参数token必填否则抛错token name must be provided as query parameter tokenoverload用于选择重载序号默认0。链接文字children[0].value为逗号分隔的 section 列表合法值为summary、remarks、overloadSummary、overloadRemarks、examples、params。sectionMapping定义了各 section 的渲染方式例如summary→ 渲染summarySection并移除summary标记params→ 用* **$1**将param x - desc改写为 Markdown 加粗列表examples→ 渲染examples自定义块。渲染后的结果会再次经过 MDX 解析器this.parse变为 AST 节点插入原位置。在 website/docusaurus.config.ts 中linkDocblocks的extractorSettings配置为tsconfig: ../docs/tsconfig.jsonbasedir: ../packages/toolkit/srcrootFiles: [index.ts, query/index.ts, query/createApi.ts, query/endpointDefinitions.ts, query/react/index.ts, query/react/ApiProvider.tsx, query/core/buildMiddleware/cacheCollection.ts]这意味着文档中的 docblock 链接全部指向packages/toolkit/src下的核心源码注释例如createApi、endpointDefinitions等。ExtractorAST 定位 TSDoc 解析extract.ts 中的Extractor类与Compiler共享同一套程序构造思路生成__remark_typescript_tools.docblocks.tsconfig.json覆盖层配置extends用户 tsconfig、noEmit: true、include: []、显式files通过 overlay 提供不落盘随后api.updateSnapshot({ openProjects: [configPath] })拿到program。findTokens递归遍历 AST 定位 token支持点号路径如createApi.something对VariableStatement、VariableDeclaration处理外部outside样式与内部inside样式两种注释挂载方式。getComment(token, fileName, overload)找到 AST 节点后用 utils.ts 中移植自编译器ts.getJSDocCommentRanges的getJSDocCommentRanges提取/**开头的注释区间对Parameter、TypeParameter、FunctionExpression、ArrowFunction、ParenthesizedExpression、VariableDeclaration、VariableStatement额外收集尾部注释排除/**/这种退化写法用microsoft/tsdoc的TSDocParser解析并注册自定义块标签overloadSummary、overloadRemarks返回的docComment额外附带了parserContext、buffer、overloadSummary、overloadRemarks、examples字段。renderDocNode把 TSDoc 节点渲染回 Markdown对DocFencedCode识别// codeblock-meta ...前缀提取代码块 meta对DocExcerpt输出其文本内容。两条管线的共同底层单例 API 与增量快照Compiler与Extractor均通过new API({ fs, cwd })构造 TypeScript 7 的同步 API 实例来自typescript/unstable/sync并用updateSnapshot({ openProjects })建立项目快照。两个插件分别用WeakMap缓存单例保证同一设置下只创建一个 API 实例。这种生成配置 overlay 文件系统 快照增量更新的架构直接对应 TypeScript 7 的 Go 内核架构编译器进程不再能回调 JS一切输入虚拟文件、生成配置、外部解析都通过 overlay 与paths注入检查结果以快照/诊断形式返回 JS 侧。版本基线README 记录的上游基线upstream 基于main5c375b1移植分支为feat/typescript-7-and-oxfmtb2ce7f2。在 Redux Toolkit 仓库中该插件以 website/plugins/remark-typescript-tools 目录存在依赖版本可从 package.json 查看根目录格式化约定见 .oxfmtrc.json接入方式见 website/docusaurus.config.ts。小结Redux Toolkit 文档站通过 vendored 的remark-typescript-tools实现了两条关键能力transpileCodeblocks在构建期真实编译、类型检查所有 TS/TSX 代码块并生成 TS/JS 双 Tab 展示linkDocblocks将源码 TSDoc 注释直接嵌入文档。移植的核心思路是在 TypeScript 7 的 Go 内核架构下用 overlay 文件系统替代LanguageServiceHost、用oxc-transform替代getEmitOutput、用oxfmt替代 Prettier并通过ts7.cjs解决 ESM-only 依赖在 jiti 转译链中的兼容问题。理解这条管线有助于你在阅读 Redux Toolkit 文档源码或为其他 Docusaurus 项目接入代码块类型检查 注释抽取能力时快速定位实现与配置。【免费下载链接】redux-toolkitThe official, opinionated, batteries-included toolset for efficient Redux development项目地址: https://gitcode.com/gh_mirrors/re/redux-toolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表