如何在 ECMAScript 6 中导入 JSON 文件?
Posted
技术标签:
【中文标题】如何在 ECMAScript 6 中导入 JSON 文件?【英文标题】:How to import a JSON file in ECMAScript 6? 【发布时间】:2016-04-28 21:35:13 【问题描述】:如何在 ECMAScript 6 中访问 JSON 文件?
以下不起作用:
import config from '../config.json'
如果我尝试导入 javascript 文件,这会很好。
【问题讨论】:
这与 ES6 无关,但与您使用的模块加载器有关。语法本身很好。 最简洁的方法是使用webpack
和json-loader
。
ES6 支持 JSON 导入,语法如下: import * as data from './example.json';
@williamli 这在当今(2020 年)的浏览器中不起作用,除非有更多的事情发生(例如,像 Babel 这样重写代码的构建步骤):例如在 Chrome 中获得 “加载模块脚本失败:服务器以非 JavaScript MIME 类型“application/json”响应。根据 html 规范对模块脚本强制执行严格的 MIME 类型检查。”(参见规范讨论 here 和 this proposal repo 上的讨论。)到目前为止,需要使用以下答案之一。
【参考方案1】:
更优雅的解决方案是使用 CommonJS 的 require 函数
createRequire 构造一个 CommonJS 的 require 函数,以便您可以使用典型的 CommonJS 功能,例如读取 JSON
import createRequire from "module";
const require = createRequire(import.meta.url);
const data = require("./data.json");
【讨论】:
【参考方案2】:正如 Azad 所说,正确的答案是使用 fs.readFileSync() 加载文件(或任何异步变体,例如带有回调的 fs.readFile 或带有 promises/await 的 fs.promises.readFile,然后解析JSON 与 JSON.parse()
const packageJsonRaw = fs.readFileSync('location/to/package.json' )
const packageJson = JSON.parse(packageJsonRaw )
Webpack/Babel 选项不实用,除非您已经在使用该设置。
【讨论】:
【参考方案3】:使用 ES 模块导入 JSON 作为功能于 2020 年中期提交给 TC39,并且(在本次编辑时)处于第 3 阶段,这是规范接受之前的最后一个阶段(请参阅 https://github.com/tc39/proposal-json-modules更多细节)。登陆后,您可以将其用作:
import someName from "./some/path/to/your/file.json";
someName
实际上是 JSON 数据描述的 JS 对象的变量名称。 (当然,请注意,这会从 JSON 源导入 JavaScript,而不是“导入 JSON”)。
如果您使用的是足够现代的捆绑程序(如esbuild
或类似的),或者您使用的是最新的转译器(如babel
),那么您已经可以使用此语法而无需担心支持。
或者,如果您拥有 JSON 文件的所有权,您还可以使用最少的额外代码将您的 JSON 转换为有效的 JS 文件:
config.js
export default
// my json here...
那么……
import config from '../config.js'
不允许导入现有的 .json 文件,但可以完成工作。
【讨论】:
这实际上并没有回答问题。例如,您不能简单地将 package.json 转换为 package.js。有时您想真正导入 JSON 而不是 JS。 根本不是解决方案,您正在导出一个恰好与 JSON 具有相同语法的 javascript 对象。 更新了问题文本;尽量避免进一步的语义辩论。 “将其转换为 JS”不是如何导入 JSON 文件的解决方案。那不再是 JSON 文件了。这是关于如何导入 JSON 的排名第一的谷歌结果,主要答案是不导入 JSON。 在.js
文件里有配置更方便,因为你可以在里面有cmets。 JSON 文件不支持这个。【参考方案4】:
感谢所有提出和实施JSON modules 和Import Assertions 的人。从 Chrome 91 开始,可以直接导入 JSON,例如:
// test.json
"hello": "world"
// Static Import
import json from "./test.json" assert type: "json" ;
console.log(json.hello);
// Dynamic Import
const default: json = await import("./test.json", assert: type: "json" );
console.log(json.hello);
// Dynamic Import
import("./test.json", assert: type: "json" )
.then(module => console.log(module.default.hello));
注意:其他浏览器目前可能尚未实现此功能。
【讨论】:
【参考方案5】:从“./resource.json”导入数据 在 Chrome 91 中是可能的。 现在支持 JSON 模块。这允许开发人员静态导入 JSON,而不是依赖动态检索它的 fetch() 函数。
https://www.stefanjudis.com/snippets/how-to-import-json-files-in-es-modules/
【讨论】:
【参考方案6】:如果你使用节点,你可以:
const fs = require('fs');
const config = JSON.parse(fs.readFileSync('../config.json'));
或
const evaluation = require('../config.json');
// evaluation will then contain all props, so evaluation.config
// or you could use:
const config = require('../config.json');
其他:
// config.js
// json object here
// script.js
import config from '../config.js';
或
import * from '../config.json'
【讨论】:
const config = JSON.parse(fs.readFileSync('../config.json'));
为我工作。节点一团糟。
我认为这里const config = JSON.parse(fs.readFileSync('../config.json'));
错过了参数'utf8',所以它应该是这样的:JSON.parse(fs.readFileSync('../package.json', 'utf8'));
【参考方案7】:
我正在使用
vuejs,版本:2.6.12 vuex,版本:3.6.0 vuex-i18n,版本:1.13.1。我的解决办法是:
messages.js:
import Vue from 'vue'
import Vuex from 'vuex';
import vuexI18n from 'vuex-i18n';
import translationsPl from './messages_pl'
import translationsEn from './messages_en'
Vue.use(Vuex);
export const messages = new Vuex.Store();
Vue.use(vuexI18n.plugin, messages);
Vue.i18n.add('en', translationsEn);
Vue.i18n.add('pl', translationsPl);
Vue.i18n.set('pl');
messages_pl.json:
"loadingSpinner.text:"Ładowanie..."
messages_en.json:
"loadingSpinner.default.text":"Loading..."
majn.js
import messages from './i18n/messages'
Vue.use(messages);
【讨论】:
【参考方案8】:导入 JSON 文件仍处于试验阶段。它可以通过下面的标志来支持。
--experimental-json-modules
否则,您可以直接使用fs
加载相对于import.meta.url
的JSON 文件:-
import readFile from 'fs/promises';
const config = JSON.parse(await readFile(new URL('../config.json', import.meta.url)));
你也可以使用module.createRequire()
import createRequire from 'module';
const require = createRequire(import.meta.url);
const config = require('../config.json');
【讨论】:
【参考方案9】:我使用它安装插件“babel-plugin-inline-json-import”,然后在 .balberc 中添加插件。
安装插件
npm install --save-dev babel-plugin-inline-json-import
babelrc 中的配置插件
“插件”:[ “内联 json 导入” ]
这是我使用它的代码
import es from './es.json'
import en from './en.json'
export const dictionary = es, en
【讨论】:
【参考方案10】:除了其他答案之外,在 Node.js 中,甚至可以在 ES 模块中使用 require
来读取 JSON 文件。我发现这在读取其他包中的文件时特别有用,因为它利用 Node 自己的 module resolution strategy 来定位文件。
ES 模块中的require
必须首先使用createRequire
创建。
这是一个完整的例子:
import createRequire from 'module';
const require = createRequire(import.meta.url);
const packageJson = require('typescript/package.json');
console.log(`You have TypeScript version $packageJson.version installed.`);
在安装了 TypeScript 的项目中,上面的代码将从 package.json 读取并打印 TypeScript 版本号。
【讨论】:
【参考方案11】:对于 NodeJS v12 及更高版本,--experimental-json-modules
可以解决问题,无需 babel 的任何帮助。
https://nodejs.org/docs/latest-v14.x/api/esm.html#esm_experimental_json_modules
但是是以commonjs形式导入的,所以import a, b from 'c.json'
还不支持。
但你可以这样做:
import c from 'c.json';
const a, b = c;
【讨论】:
【参考方案12】:只需这样做:
import * as importedConfig from '../config.json';
然后像下面这样使用它:
const config = importedConfig.default;
【讨论】:
这在浏览器中本身并不适用,尽管它可能与您似乎正在使用的任何构建系统(Babel 或其他)结合使用。【参考方案13】:在带有 fetch 的浏览器中(现在基本上全部):
目前,我们不能import
具有 JSON mime 类型的文件,只能使用 JavaScript mime 类型的文件。这可能是将来添加的功能 (official discussion)。
fetch('./file.json')
.then(response => response.json())
.then(obj => console.log(obj))
在 Node.js v13.2+ 中:
目前需要--experimental-json-modules
flag,否则默认不支持。
尝试运行
node --input-type module --experimental-json-modules --eval "import obj from './file.json'; console.log(obj)"
并查看输出到控制台的 obj 内容。
【讨论】:
我在浏览器中做了第一个,它成功了【参考方案14】:在 TypeScript 或使用 Babel 中,您可以在代码中导入 json 文件。
// Babel
import * as data from './example.json';
const word = data.name;
console.log(word); // output 'testing'
参考: https://hackernoon.com/import-json-into-typescript-8d465beded79
【讨论】:
只是添加到这个(typescript json import)你现在可以简单地将它添加到你的 tsconfig... "compilerOptions": "resolveJsonModule": true 有浏览器支持吗?我在当前的 FF 上试过这个并得到错误Loading failed for the module with source "example.json"
;在 Chrome 上,我得到“加载模块脚本失败:服务器以“application/json”的非 JavaScript MIME 类型响应。对每个 HTML 规范的模块脚本强制执行严格的 MIME 类型检查。”
我突然想到,当你说“在 ES6 中”时,你实际上是指“在 TS 中”——我以为你在谈论 tsc
的代码 emitted但事实并非如此。我正在尝试在浏览器 (<script type="module">
) 上本地运行 ES6 模块,如果直接运行 import
行,就会出现上述错误。如果我错了,请纠正我,实际上你的意思是在实际的 ES6 中可以从 JSON 导入。
当我说“任何浏览器都支持这个”时,我的意思不是“在你通过 Babel 转换它之后”。您链接的第一篇文章有 TS 将 import
语句转换为节点 require()
(试试看!),第二个链接没有说明 JSON 导入。这里的问题不在于解析器或模块系统,而是 loader —— 浏览器的加载器不会解析除 Javascript 之外的任何内容的导入。在幕后,您总是必须使用 AJAX 调用(fetch / XHR)并解析结果,即使您的构建工具链将其抽象出来。
这样我们就不会在兴奋时忘记,转译器所做的只是将 json 内容内联到输出文件的常量中,因为在 javascript 的世界中,这确实是唯一安全的方式(除了 ajaxing 这是一个不同的故事)【参考方案15】:
根据您的构建工具和 JSON 文件中的数据结构,可能需要导入 default
。
import default as config from '../config.json';
例如在Next.js
中使用
【讨论】:
为 TypeScript 添加了注释,以确保resolveJsonModule
在您 tsconfig.json
中是 true
。【参考方案16】:
很遗憾,ES6/ES2015 不支持通过模块导入语法加载 JSON。 但是...
有很多方法可以做到这一点。根据您的需要,您可以研究如何在 JavaScript 中读取文件(如果您在浏览器中运行,window.FileReader
可能是一个选项)或使用other questions 中描述的其他一些加载器(假设您使用的是 NodeJS) .
IMO 最简单的方法可能是将 JSON 作为 JS 对象放入 ES6 模块并导出。这样你就可以在需要的地方导入它。
如果您使用 Webpack,导入 JSON 文件 will work by default(自 webpack >= v2.0.0
)也值得注意。
import config from '../config.json';
【讨论】:
没有必要把它放在一个字符串中。毕竟它叫 JSON,而不是 JSSN。 另外,torazaburo 在之前删除的答案中解释说:没有 ES6“模块系统”;有一个由特定加载器实现的 API。任何加载器都可以做它想做的任何事情,包括支持 JSON 文件的导入。例如,加载器可能会选择支持 import foo from './directory 作为 import directory/index.js 的意思 事实上 ES6/ES2015 确实支持通过导入语法加载 JSON:import * as data from './example.json'; +1 用于提醒 webpack 自动执行此操作。不过要小心,如果你有“test: /.js/”,webpack 会尝试将你的 json 文件编译为 JavaScript。 #失败。要修复它,请将其更改为“test: /.js$/” webpack 是基于 nodejs 的,不是吗?【参考方案17】:有点晚了,但我在尝试为我的网络应用提供分析时偶然发现了同样的问题,该分析涉及基于 package.json 版本发送应用版本。
配置如下:React + Redux,Webpack 3.5.6
json-loader 自从 Webpack 2+ 以来并没有做太多事情,所以在摆弄了一些之后,我最终将它删除了。
实际上对我有用的解决方案就是使用 fetch。 虽然这很可能会强制执行一些代码更改以适应异步方法,但它运行良好,特别是考虑到 fetch 将提供动态 json 解码这一事实。
原来是这样:
fetch('../../package.json')
.then(resp => resp.json())
.then((packageJson) =>
console.log(packageJson.version);
);
请记住,由于我们在这里专门讨论 package.json,因此该文件通常不会捆绑在您的生产构建中(甚至是开发版本),因此您必须使用 CopyWebpackPlugin 来使用 fetch 时可以访问它。
【讨论】:
不能。 Fetch 不支持本地文件...您可能正在使用 polyfill 或其他东西。 @sapy 迟了几个月的回复,但 fetch API 绝对确实 支持从路径加载而不指定服务器的主机名,以及从相对路径加载。您正在考虑的是从file:///
URL 加载,这不是这里发生的情况。
这是一个非常有用的答案,非常简单,对我来说适用于本地文件【参考方案18】:
我正在使用 babel+browserify,并且我在目录 ./i18n/locale-en.json 中有一个 JSON 文件,带有翻译命名空间(与 ngTranslate 一起使用)。
无需从 JSON 文件中导出任何内容(顺便说一句,这是不可能的),我可以使用以下语法对其内容进行默认导入:
import translationsJSON from './i18n/locale-en';
【讨论】:
以上是关于如何在 ECMAScript 6 中导入 JSON 文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用对象解构在 TypeScript 中导入 JSON?