Keywords: ECMAScript 6 | JSON Import | Node.js | ES Modules | Import Assertions
Abstract: This article provides an in-depth exploration of various methods for importing JSON files in ECMAScript 6 modules, including the use of import assertions, manual reading with the fs module, the createRequire function, and solutions via Babel or TypeScript. It analyzes the implementation principles, applicable scenarios, and considerations for each method, accompanied by complete code examples. Additionally, the article covers the standardization process of JSON modules and future trends, assisting developers in selecting the most suitable approach based on project requirements.
With the stable support of ECMAScript 6 (ES6) modules in Node.js, developers face challenges in migrating from CommonJS to ES modules. Among these, importing JSON files is a common yet complex issue. In CommonJS, we can directly use require('./data.json') to load JSON files, but this straightforward approach is no longer applicable in ES modules. This article systematically introduces multiple methods for importing JSON files in ES6, analyzes their principles and applicability, and provides detailed code implementations.
Standardization Process of JSON Modules
The functionality for importing JSON modules has been submitted to the TC39 committee and is in the third stage (Stage 3) of the standardization process, which is the final stage before being accepted as an official specification. Once this proposal is formally adopted, developers will be able to use standard import syntax to directly import JSON files, for example: import config from './config.json'. This syntax parses JSON data into a JavaScript object and assigns it to the specified variable. It is important to note that this actually imports JavaScript objects from a JSON source, rather than directly "importing JSON".
Importing JSON with Import Assertions
In Node.js, import assertions offer an experimental way to import JSON files. This method involves adding an assertion to the import statement to specify the module type. For example:
import info from './package.json' assert { type: 'json' };
Or using dynamic import:
const { default: info } = await import('./package.json', {
assert: { type: 'json' }
});
However, it should be noted that in Node.js 18.12 LTS, import assertions are still marked as experimental and may have stability issues in production environments. Therefore, risks should be carefully assessed before use.
Manually Reading and Parsing JSON Files
For developers who prefer not to rely on experimental features, the Node.js official documentation recommends using the fs module to manually read JSON files and parse their content. Although this method involves more code, it offers the best compatibility and control. The specific implementation is as follows:
import { readFile } from 'fs/promises';
import { fileURLToPath } from 'url';
const filePath = new URL('./data.json', import.meta.url);
const fileContent = await readFile(filePath, 'utf-8');
const jsonData = JSON.parse(fileContent);
Here, we use import.meta.url to obtain the URL of the current module, then resolve the relative path via new URL(). The readFile method from fs/promises is used to asynchronously read the file content, and finally, JSON.parse() converts the JSON string into a JavaScript object. This method is compatible with all versions of Node.js and does not depend on any experimental features.
Leveraging the CommonJS Require Function
Node.js provides the createRequire function, which allows constructing a CommonJS-style require function within ES modules. This approach combines the modern syntax of ES modules with the mature functionality of CommonJS, offering a smooth migration path. The specific implementation is as follows:
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const data = require('./data.json');
The createRequire function takes import.meta.url as a parameter and returns a require function associated with the current module's context. This function can be used just like in CommonJS, including loading JSON files. This method strikes a good balance between compatibility and ease of use.
Implementation via Babel or TypeScript
For projects using Babel or TypeScript, JSON file import can be achieved by configuring相应的 plugins or compiler options. For example, in Babel, the @babel/plugin-transform-json-import plugin can be used to enable the following code to work correctly:
import * as data from './example.json';
const word = data.name;
console.log(word); // outputs 'testing'
In TypeScript, set "resolveJsonModule": true in tsconfig.json, and then JSON files can be directly imported. These tools convert JSON files into JavaScript modules during the build phase, thus avoiding runtime compatibility issues.
Converting JSON to JavaScript Modules
Another simple and effective method is to convert JSON files into JavaScript modules. For example, rename config.json to config.js and export the JSON data within it:
// config.js
export default {
// JSON data here
"name": "example",
"version": "1.0.0"
};
Then, standard ES6 import syntax can be used:
import config from '../config.js';
Although this method does not allow direct import of existing .json files, it is very practical for new projects or situations where file formats can be modified. It completely avoids any compatibility issues and the code is concise and clear.
Considerations in Browser Environments
In browser environments, ES6 module imports are restricted by HTML specifications and do not allow direct import of JSON files. Attempting to import will result in an error similar to the following:
Failed to load module script: The server responded with a non-JavaScript MIME type of "application/json". Strict MIME type checking is enforced for module scripts per HTML spec.
This is because browsers enforce strict MIME type checking for module scripts, and the MIME type of JSON files (application/json) is not permitted for module loading. In such cases, the method of converting JSON to JavaScript modules can be adopted, or the fetch API can be used to dynamically load JSON data.
Support from Build Tools
Modern build tools like Webpack, esbuild, etc., typically have built-in support for importing JSON files. For example, in Webpack 4 and above, import config from '../config.json' can be used directly, and Webpack will automatically handle JSON files during the build process. These tools implement this functionality through their respective loaders or plugins, greatly simplifying the development workflow.
Summary and Recommendations
There are multiple methods for importing JSON files in ES6 modules, each with its applicable scenarios, advantages, and disadvantages. For new projects, it is advisable to monitor the standardization process of JSON modules and use import assertions when conditions permit. For projects requiring high compatibility, manual reading and parsing or using createRequire are reliable choices. Projects using build tools can rely on the built-in support of these tools, while converting JSON to JavaScript modules is a simple and universal solution. Developers should choose the most appropriate method based on the specific needs of the project, target environment, and team preferences.