使用 Deno 如何将 Node.js 库转换为 Deno 库( 三 )

这里的关键部分是 resolveImportPath 函数,它实现了将 Node 类型的引入改为 Deno 类型的引入。首先,它检查路径是否对应于磁盘上的实际文件;如果失败了,它会尝试添加 .ts 后缀;如果失败,它尝试添加 /index.ts;如果失败,就会抛出一个错误 。
注入 Node.js 全局变量最后一步是处理 Node.js 全局变量 。首先,我们在项目目录中创建一个 global .deno.ts 文件 。这个文件应该导出包中使用的所有 Node.js 全局变量的兼容版本 。
export {Buffer} from "<https://deno.land/std@0.114.0/node/buffer.ts>";export {process} from "<https://deno.land/std@0.114.0/node/process.ts>";复制代码编译后的 AST 提供了一组源文件中使用的所有标识符 。我们将使用它在任何引用这些全局变量的文件中注入 import 语句 。
const sourceDir = "./src"; const destDir = "./edgedb-deno"; const pathRewriteRules = [{match: /^src/index.node.ts$/, replace: "mod.ts"},{match: /^src//, replace: "_src/"}, ];+ const injectImports = {+ imports: ["Buffer", "process"],+from: "src/globals.deno.ts",+ };// ... const rewrittenFile: string[] = []; let cursor = 0;+ let isFirstNode = true;parsedSource.forEachChild((node: any) => {+if (isFirstNode) {// only run once per file+isFirstNode = false;++const neededImports = injectImports.imports.filter((importName) =>+parsedSource.identifiers?.has(importName)+);++if (neededImports.length) {+const imports = neededImports.join(", ");+const importPath = resolveImportPath(+relative(dirname(sourcePath), injectImports.from),+sourcePath+);+const importDecl = `import {${imports}} from "${importPath}";nn`;+const injectPos = node.getLeadingTriviaWidth?.(parsedSource) ?? node.pos;+rewrittenFile.push(file.slice(cursor, injectPos));+rewrittenFile.push(importDecl);cursor = injectPos;}}复制代码写文件最后,我们准备将重写的源文件写入目标目录中的新主目录 。首先,我们删除所有现有的内容,然后依次写入每个文件 。
+ try {+await Deno.remove(destDir, {recursive: true});+ } catch {} const sourceFilePathMap = new Map<string, string>(); for (const [sourcePath, destPath] of sourceFilePathMap) {// rewrite file+await Deno.writeTextFile(destPath, rewrittenFile.join("")); }复制代码持续集成一个常见的模式是为包的 Deno 版本维护一个单独的自动生成的 repo 。在我们的例子中,每当一个新的提交合并到 master 中时,我们就在 GitHub Actions 中生成 edgedb-js 的 Deno 版本 。然后,生成的文件被发布到名为 edgedb-deno 的姊妹存储库 。下面是我们的工作流文件的简化版本 。
# .github/workflows/deno-release.ymlname: Deno Releaseon:push:branches:- masterjobs:release:runs-on: ubuntu-lateststeps:- name: Checkout edgedb-jsuses: actions/checkout@v2- name: Checkout edgedb-denouses: actions/checkout@v2with:token: ${{ secrets.GITHUB_TOKEN }}repository: edgedb/edgedb-denopath: edgedb-deno- uses: actions/setup-node@v2- uses: denoland/setup-deno@v1- name: Install depsrun: yarn install- name: Get version from package.jsonid: package-versionuses: martinbeentjes/npm-get-version-action@v1.1.0- name: Write version to filerun: echo "${{ steps.package-version.outputs.current-version}}" > edgedb-deno/version.txt- name: Compile for Denorun: deno run --unstable --allow-env --allow-read --allow-write tools/compileForDeno.ts- name: Push to edgedb-denorun: cd edgedb-deno && git add . -f && git commit -m "Build from $GITHUB_SHA" && git push复制代码edgedb-deno 内部的另一个工作流会创建一个 GitHub 发布,发布一个新版本到 deno.land/x 。这留给读者作为练习,尽管您可以使用我们的工作流作为起点 。
总结这是一个可广泛应用的模式,用于将现有的 Node.js 模块转换为 Deno 模块 。参考 edgedb-js repo获得完整的 Deno 编译脚本,跨工作流 。





推荐阅读