首页 > 解决方案 > 本机 node.js 和浏览器加密的同构代码

问题描述

有一个isomorphic-webcrypto假装这样做但没有:它为每个目标构建单独的构建。

有一种高贵的加密方式可以做到这一点,但它基于 if-else 条件,如果我想要一个同构的 mjs 代码,它就会失败。

最后,还有eval 的 require 方式来传递 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 和浏览器中以同构的方式使用本机加密,以便能够在节点和浏览器中透明地使用本机导入 mjs。

我怎样才能做到这一点?

标签: javascriptnode.jsisomorphic-javascriptwebcrypto-apimjs

解决方案


好吧。准备好迎接丑陋的事情了吗?:-) 看哪,我最近的 hackjob……IsomorphicCyrpto.js:

export default
  globalThis.crypto ||
  (await import('node:crypto')).default.webcrypto
;

这适用于 Node.js v16 的模块模式("type": "module"在 package.json或等效的 CLI args 中),并且可能也适用于您的捆绑程序……但谁知道呢。;-) 任何使用此代码片段的人都应该在他们想要使用它的任何平台上进行彻底的测试。

简而言之:

  • 对于大多数浏览器上下文,我们使用globalThis代表globalNode.js的 ,window甚至可能是 Worker 上下文。
  • 我们首先检查是否crypto是一个东西。如果是,我们可能在浏览器上,并且可以直接使用它。
  • 如果crypto不是,我们可能在 Node.js 上,我们需要导入模块。
  • 因为这是动态完成的,所以我们需要一个dynamicimport()而不是 true import
  • import()是异步的并返回一个 Promise。但是,嘿,这一切都很好,因为顶级await现在是 Node.js 中的东西!

然后使用该模块:

import crypto from './lib/IsomorphicCrypto.js';
console.log( crypto.randomUUID() );

Uggggly,但现在可以使用。希望有人提出更好的解决方案,或者 Node.js 和浏览器上下文在未来会集中在命名上。


推荐阅读