ECMAScript 提案:JSON 模块
为什么我们要像模块一样导入 JSON?
很长一段时间以来,各种捆绑器(例如 webpack)允许我们像导入 ECMAScript 模块一样导入 JSON 数据。JSON 模块将其转化为标准功能。
为什么这么有趣?它提供了一种方便的使用方式,例如在我们的应用程序中使用配置数据。例如,以下文件结构:
my-app/
src/
config-data.json
main.mjs
my-app/src/config-data.json
如下所示:
{
"appName": "My App"
}
这是my-app/src/main.mjs
:
import configData from './config-data.json' assert {type: 'json'};
console.log(`I am ${configData.appName}!`);
从assert
到结束的语法称为导入断言。JSON 模块是创建导入断言的用例之一。
JSON 模块的默认导出包含 JSON 数据。没有命名的导出。
通过获取 JSON 数据fetch()
如果没有 JSON 模块,我们将不得不使用fetch()
:
async function fetchConfigData(relativePath) {
const urlOfConfigData = new URL(
relativePath, import.meta.url); // (A)
const response = await fetch(urlOfConfigData.toString()); // (B)
const json = await response.json(); // (C)
return json;
}
const configData = await fetchConfigData('config-data.json');
console.log(`I am ${configData.appName}!`);
我们正在使用两个相对较新的功能:
- Fetch API,一种基于 Promises 的API,用于下载 JavaScript 代码中的文件(B 行和 C 行)。
- 模块元数据属性
import.meta.url
(A 行)。
fetch()
与 JSON 模块相比有两个缺点:
- 代码稍微复杂一些。
- Node.js 目前没有对
fetch()
. (而且我怀疑 JSON 模块将比fetch()
.更早得到支持。)
通过动态导入 JSON 模块import()
前面的import
语句是静态的(在运行时固定)。我们还可以动态导入 JSON 模块(在运行时可更改):
async function importConfigData(moduleSpec) {
const namespaceObj = await import( // (A)
moduleSpec, {assert: {type: 'json'}});
return namespaceObj.default; // (B)
}
const configData = await importConfigData('./config-data.json');
console.log(`I am ${configData.appName}!`);
注意,所述import()
操作者(A线)返回一个模块命名空间对象。这就是为什么我们.default
在 B 行返回 property 的值(包含默认导出)。
为什么要额外的语法?
您可能想知道为什么我们必须在重要语句的末尾使用额外的语法:
import configData from './config-data.json' assert {type: 'json'};
为什么 JavaScript 不能通过查看文件扩展名来检测这是 JSON?
import configData from './config-data.json';
这是不可能的,因为它会导致安全问题:浏览器从不查看文件扩展名,他们查看内容类型。服务器负责为文件提供内容类型。因此,导入.json
文件时可能会发生两件事:
- 我们自己的服务器可能会发送其他内容类型,
application/json
并且导入会以某种方式出错。 - 如果使用外部服务器,则风险更大:如果它发送内容类型为 的文件
text/javascript
,它可能会在我们的应用程序中执行代码。
因此,JavaScript 在导入 JSON 时不会依赖内容类型。
可用性
- Chrome 91 支持 JSON 模块(来源:Chrome 平台状态)。
文章链接:https://www.ooize.com/ecmascript-proposal-json-module.html