有一个 isomorphic-webcrypto 假装这样做,但实际上并没有:它为每个目标构建单独的版本。
有 noble-crypto 方法可以做到这一点,但它基于 if-else 条件,如果我想要同构 mjs 代码,它会失败。
最后还有eval require way方式来传递bundler,但是node在mjs中无法使用它。
简而言之:
const crypto = require("crypto"); // work only in node.js but not in mjs file.
const crypto = eval(`require("crypto")`); // pass-thru bundler, then work only in node.js but not in mjs file.
window.crypto; // work only in browser
import * as crypto from "crypto"; // could work from both but must be at top level of a module, so it can't be a conditional import.
我想在node.js和浏览器中以同构的方式使用本机加密,以便能够在node和浏览器中透明地使用本机导入mjs。
我该怎么做?
好吧。准备好迎接丑陋的事情了吗? :-) 看哪,我最新的 hackjob...IsomorphicCyrpto.js:
export default
globalThis.crypto ||
(await import('node:crypto')).default.webcrypto
;
这适用于 Node.js v16 的模块模式(package.json 中的
"type": "module"
,或等效的 CLI 参数),并且可能也适用于您的捆绑器……但谁知道呢。 ;-) 任何使用此代码片段的人都应该在他们想要使用它的任何平台上进行彻底测试。
简而言之:
globalThis
,它代表 Node.js 下的 global
,代表大多数浏览器上下文的
window
,甚至可能是 Worker 上下文。
crypto
是否是一个东西。如果是,我们可能在浏览器上,并且可以直接使用它。
crypto
不是一个东西,我们可能在 Node.js 上,我们需要导入该模块。
import()
而不是真正的import
。
import()
是异步的并返回一个 Promise。但是,嘿,这一切都很好,因为top-level
await
现在已经是 Node.js 中的东西了!
import crypto from './lib/IsomorphicCrypto.js';
console.log( crypto.randomUUID() );
丑陋,但目前有效。希望有人能提出更好的解决方案,或者 Node.js 和浏览器上下文在未来会在命名上融合。
globalThis.crypto === require('node:crypto').webcrypto
所以代码:
globalThis.randomUUID()
在浏览器和 Node 中的工作方式相同,无需导入,也无需特殊工具。