如何在 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 无关,但与您使用的模块加载器有关。语法本身很好。 最简洁的方法是使用webpackjson-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 文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Jest 测试中导入 JSON 文件?

如何使用对象解构在 TypeScript 中导入 JSON?

如何在 TypeScript 中导入 package.json?

如何在three.js中导入json和渲染

如何在 Golang 中导入本地包

如何从 JSON 文件中导入字段?