【问题标题】:Single API to load JSON file in Browser and NodeJS?在浏览器和 NodeJS 中加载 JSON 文件的单一 API?
【发布时间】:2025-11-24 10:15:01
【问题描述】:

是否有现有的 API 或库可用于在浏览器和 Node 中加载 JSON 文件?

我正在开发一个模块,我打算通过 NodeJS 的命令行和浏览器运行该模块。我正在使用两者通用的最新语言特性(并且不需要支持旧版浏览器),包括类关键字和 ES6 导入语法。有问题的类需要加载一系列 JSON 文件(其中第一个文件标识需要加载的其他文件),我的偏好是按原样访问它们(它们是外部定义的并与其他工具共享)。

“导入”命令看起来可能适用于第一个 JSON 文件,但我没有看到使用该命令将一系列文件(由第一个文件确定)加载到变量中的方法。

一种选择是将辅助函数传递给类以加载文件,根脚本将根据 NodeJS 或浏览器的需要填充该函数。

另外,我目前的主要想法是定义一个单独的模块,其中包含一个可以导入的“异步函数 loadFile(fn)”函数,并设置路径以使不同版本的该文件为浏览器和 NodeJS 加载。

这似乎应该有一个原生选项,或者其他人已经为其编写了一个模块,但我还没有找到。

【问题讨论】:

  • axios 、 fetch 和 superagent 可以在两种环境中使用。在现代浏览器中,fetch 是内置的
  • 令人沮丧的是,并非如此。您最好的选择是 fetch 用于浏览器和 fetch polyfill 用于节点。 Fetch 是part of the web api,而不是节点必须为 ECMA 实现的东西。他们特定的网络接口是 http 模块。

标签: javascript node.js es6-modules


【解决方案1】:

对于节点,从 npm 安装 node-fetch 模块。

请注意,浏览器fetch 不能直接与您的文件系统对话——它需要请求另一端的 HTTP 服务器。 Node 可以与您的文件系统通信,也可以对服务器进行 HTTP 调用。

【讨论】:

  • 这看起来很有希望,但在这两种环境中都不能无缝工作(包括导入部分)。
  • 如果你想将一个代码库发送到两个平台,你必须使用像 Babel 这样的东西来设置一个编译过程。这在当今 JS 世界中几乎是标准的。
  • 我可能需要在某个时候进行转译,但到目前为止,我已经成功地避免了它(假设这只适用于最新的浏览器),并且只需要一个“cp”如果在 ExpressJS 之外托管。无需转译步骤即可刷新页面使开发更加容易。
  • 好吧,你会遇到节点不理解import而浏览器不理解require的问题。所以我怀疑你的运气已经用完了。 browserland 和 node 都没有共享 fetch API,我不会打赌在不久的将来会发生变化。
  • NodeJS 在 v14+ 中支持本地导入,只要您将 package.json 设置为“type”:“module”,尽管您不能在同一个包中混合 ES 和 commonjs 模块语法。跨度>
【解决方案2】:

现在听起来,这里没有完美的解决方案。 'fetch' API 是最有前途的,但前提是 Node 有一天会实现它。

与此同时,我已经选择了一个简单的解决方案,该解决方案可以无缝地以最少的依赖项工作,只需要对我的 ExpressJS 服务器路径进行一点魔法即可将服务的 Web 实例指向不同版本的 utils.js。

注意:要在 NodeJS (v14+) 中使用 ES 样式的导入语法,您必须在 package.json 中设置 "type":"module"。有关详细信息,请参阅https://nodejs.org/api/esm.html#esm_package_json_type_field。这对于真正的共享代码库是必要的。

使用它的模块(NodeJS + 浏览器运行相同的文件):

import * as utils from "../utils.js";
...
var data = await utils.loadJSON(filename);
...

浏览器的utils.js:

async function loadJSON(fn) { 
    return $.getJSON(fn); // Only because I'm using another JQuery-dependent lib
    /* Or natively something like
    let response = await fetch(fn);
    return response.json();
    */
}

export { loadJSON };

nodeJS 的 utils.js

import * as fs from 'fs';

async function loadJSON(fn) {
    return JSON.parse(await fs.promises.readFile(fn));
}

export { loadJSON };

【讨论】:

  • 这个解决方案的问题是代码注释“或本机,类似await fetch”)对于不使用jQuery的任何人来说都不是初学者。不使用 jQuery 的人不会通过将 'type' 设置为 'module' 得到帮助,因为它没有解决浏览器和 Node 没有共享用于发出 Internet 请求的 API 的基本事实。浏览器可以使用 fetch,但 Node 必须使用第三方模块,例如 node-fetch、axios 或类似的。共享代码库的最轻量级策略是在 Node 中使用 node-fetch 来镜像浏览器 API。
  • node-fetch 对浏览器和 nodejs 使用不同的导入语句。在这里,我只有两个版本的 util.js,服务器配置为为浏览器提供与节点导入不同的文件。无需其他修改或转译。正如你所说的 fetch 是浏览器的本机 API,我只是有 jquery 可用,所以我把该评论作为参考,因为我没有测试非 jquery 版本。如果这是一个 C 项目,两个目标将使用单个头文件,编译器将使用不同的源路径(处理多个平台的通用范例)。