「译文」如何将 Node.js 库转换为 Deno 库(用到 Deno)
来源:安全 2025年03月21日 12:15
由于 Deno 规格托发放了 Node.js 兼容可选,这个勤务变得越发非常简单。这个可选在 Deno 的规格托上发放了一个打包装器,它力图如此一来众所周知地遵守 Node 的 API。
- import * as crypto from "crypto";+ import * as crypto from "";副本字符为了一般化处理操作过程,我们将所有过渡到的 Node.js API 打包装到 adapter.node.ts 档案中都,然后更进一步选取
// adapter.node.tsimport * as path from "path";import * as util from "util";import * as crypto from "crypto";export {path, net, crypto};副本字符举例来说 我们在 Deno 中都应使用相同的方式将 adapter.deno.ts
// adapter.deno.tsimport * as crypto from "";import path from "";import util from "";export {path, util, crypto};副本字符当我们所需 Node.js 特定的适应性时,我们这样一来从 adapter.node.ts 应运而生。通过这种方式将,我们可以通过非常简单地将所有 adapter.node.ts 应运而生表征为 adapter.deno.ts 来使 edgedb-js 兼容 deno。只要这些档案更进一步选取相同的适应性,一切都不应按预自已兼职。
基本上上,我们如何表征这些应运而生呢?我们所需编撰一个非常简单的 codemod 脚本。为了让它更有简练,我们将应使用 Deno 本身来编撰这个脚本。
写 Denoify 脚本首先我们所述下脚本所需意味着的适应性:
将 Node.js 式 import 匹配为更基本的 Deno 式过渡到。基本是将摘录档案都减少 .ts 后缀,给摘录附录都减少 /index.ts 档案。将 adapter.node 档案中都的摘录都匹配到 adapter.deno.ts将 Node.js 规格库 如 process 和 Buffer 注入到 Deno-ified code。虽然我们可以非常简单地从适配选取这些变量,但我们需表征 Node.js 档案以显式地应运而生它们。为了一般化,我们将检测在哪里应使用了 Node.js 规格库,并在所需时注入一个应运而生。将 src 附录一个大为 _src,对此它是 edgedb-js 的框架档案,不不应这样一来应运而生将 main 附录下的 src/index.node.ts 档案都漂移到项目根附录,并一个大为 mod.ts。警惕:这里的 index.node.ts 并不表明这是 node PDF的,只是为了区分 index.browser.ts创建一系列档案首先,我们所需计算源档案的列表。
import {walk} from "";const sourceDir = "./src";for await (const entry of walk(sourceDir, {includeDirs: false})) { // iterate through all Files}副本字符⚠️警惕:我们这里应使用的是 Deno 的 std/fs,而不是 Node 的 std/node/fs。
让我们道歉信各别表征游戏规则,并codice_一个 Map,它将从源档案逆时针等价到表征的目标逆时针。
const sourceDir = "./src";+ const destDir = "./edgedb-deno";+ const pathRewriteRules = [+ {match: /Andsrc/index.node.ts$/, replace: "mod.ts"},+ {match: /Andsrc//, replace: "_src/"},+];+ const sourceFilePathMap = new Mapstring>(); for await (const entry of walk(sourceDir, {includeDirs: false})) {+ const sourcePath = entry.path;+ sourceFilePathMap.set(sourcePath, resolveDestPath(sourcePath)); }+ function resolveDestPath(sourcePath: string) {+ let destPath = sourcePath;+ // apply all rewrite rules+ for (const rule of pathRewriteRules) {+ destPath = destPath.replace(rule.match, rule.replace);+ }+ return join(destDir, destPath);+}副本字符以上大多比较非常简单,下面开始重写源档案。
表征 imports 和 exports为了表征 import 逆时针,我们所需知道档案的存放方位。幸运的是 TypeScript 遮蔽了 载入 API,我们可以用来解出源档案到 AST,并查找 import 道歉信。
我们所需从 typescript 的 NPM 打包中都 import 载入 API。幸运的是,Deno 发放了摘录 CommonJS 准则的法则,所需在调试时 移除 ;还有unstable 参数
import {createRequire} from "";const require = createRequire(import.meta.url);const ts = require("typescript");副本字符让我们遍历这些档案并依序解出每个档案。
import {walk, ensureDir} from "";import {createRequire} from "";const require = createRequire(import.meta.url);const ts = require("typescript");for (const [sourcePath, destPath] of sourceFilePathMap) { compileFileForDeno(sourcePath, destPath);}async function compileFileForDeno(sourcePath: string, destPath: string) { const file = await Deno.readTextFile(sourcePath); await ensureDir(dirname(destPath)); // if file ends with '.deno.ts', copy the file unchanged if (destPath.endsWith(".deno.ts")) return Deno.writeTextFile(destPath, file); // if file ends with '.node.ts', skip file if (destPath.endsWith(".node.ts")) return; // parse the source file using the typescript Compiler API const parsedSource = ts.createSourceFile( basename(sourcePath), file, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS );}副本字符对于每个已解出的 AST,让我们遍历其顶层节点以查找 import 和 export 道歉信。我们不所需研究者,因为 import/export 总是 top-level 操作符(除了动态摘录 dynamic import(),但我们在 edgedb-js中都不应使用它们)。
从这些节点中都,我们提取源档案中都 import/export 逆时针的开始和告一段落x。然后,我们可以通过切片当前内容可并插入重写后的逆时针来表征应运而生。
const parsedSource = ts.createSourceFile(/*...*/);+ const rewrittenFile: string[] = [];+ let cursor = 0;+ parsedSource.forEachChild((node: any) => {+ if (+ (node.kind === ts.SyntaxKind.ImportDeclaration ||+ node.kind === ts.SyntaxKind.ExportDeclaration) &&+ node.moduleSpecifier+ ) {+ const pos = node.moduleSpecifier.pos + 2;+ const end = node.moduleSpecifier.end - 1;+ const importPath = file.slice(pos, end);++ rewrittenFile.push(file.slice(cursor, pos));+ cursor = end;++ // replace the adapter import with Deno version+ let resolvedImportPath = resolveImportPath(importPath, sourcePath);+ if (resolvedImportPath.endsWith("/adapter.node.ts")) {+ resolvedImportPath = resolvedImportPath.replace(+ "/adapter.node.ts",+ "/adapter.deno.ts"+ );+ }++ rewrittenFile.push(resolvedImportPath); }});rewrittenFile.push(file.slice(cursor));副本字符这里的更为重要大多是 resolveImportPath 函数,它意味着了将 Node 型式的过渡到改称 Deno 型式的过渡到 。首先,它核查逆时针不应并不相同于磁盘上的基本上档案;如果受挫了,它会想法移除 .ts 后缀;如果受挫,它想法移除 /index.ts;如果受挫,就会抛出一个误解。
注入 Node.js 规格库最后一步是处理 Node.js 规格库。首先,我们在项目附录中都创建一个 global .deno.ts 档案。这个档案不应选取打包中都应使用的所有 Node.js 规格库的兼容发行版。
export {Buffer} from "";export {process} from "";副本字符载入后的 AST 发放了各别源档案中都应使用的所有前缀。我们将应使用它在任何摘录这些规格库的档案中都注入 import 操作符。
const sourceDir = "./src"; const destDir = "./edgedb-deno"; const pathRewriteRules = [ {match: /Andsrc/index.node.ts$/, replace: "mod.ts"}, {match: /Andsrc//, 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 = MLT-import {${imports}} from "${importPath}";MLT-;+ 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(); 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-latest steps: - name: Checkout edgedb-js uses: actions/checkout@v2 - name: Checkout edgedb-deno uses: actions/checkout@v2 with: token: ${{ secrets.GITHUB_TOKEN }} repository: edgedb/edgedb-deno path: edgedb-deno - uses: actions/setup-node@v2 - uses: denoland/setup-deno@v1 - name: Install deps run: yarn install - name: Get version from package.json id: package-version uses: martinbeentjes/npm-get-version-action@v1.1.0 - name: Write version to file run: echo "${{ steps.package-version.outputs.current-version}}"> edgedb-deno/version.txt - name: Compile for Deno run: deno run ;还有unstable ;还有allow-env ;还有allow-read ;还有allow-write tools/compileForDeno.ts - name: Push to edgedb-deno run: 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 载入脚本,跨兼职漂。
。三维互动系统沈阳看白癜风哪里好
天津看男科哪家比较好
贵阳看风湿去哪个医院好
天津看白癜风哪间医院好
金奥康和艾司奥美拉唑的区别
哪种血糖仪家用比较准好
金笛复方鱼腥草合剂
瑞特和罗氏血糖仪哪个好
血糖仪什么型号的准确度高
下一篇: 爱情,没有不吵架的,但底线是不相恋
-
立夏过后,给孩子多吃这5道蒸菜,个子长得快!别错过长高黄金季中
导语:天和天后,给女儿多吃掉这5道煮菜,合在一起样子太快!别错过长颇高黄金11集 天和天后,天气越来越波了,在烹饪上我们要多调至节,特别是有女儿的中产阶级在做菜时并不需要十分得意。