Hi i'm currently learning nodejs and I try to import a json file like this :
'use strict'
import data from 'users.json'
console.log(data)
Each time I get this error "Cannot find package 'users.json'"
But if I read the file with fs it worked so can you explain me how to do please
try :
import data from './users'
which is the es6 method of doing things or if you want an older syntax method you can try
const data = require('./users')
Okay so the explanation just is this, those fullstops and forward slash are used to indicate relative paths to the file the import is being called from, which means somethings you'd see something like for example ../file/help. The ./ means go up one directory ../ means go up two directories and so on. The name after the slash just tells your program the folder to go in to look for the file to import from so ./folder means go up one directory and enter into the folder directory and so on.
Almost forgot to mention, you should not import from a json file or a text file or any other file that does not have a .js extention(of which you do not actually have to specify) unless absolutely neccessary. To deal with files in node you have to use the fs library.
const fs =require('fs')
....
fs.readFile('./users.json','utf-8',(err,jsonString)=>{
const data = JSON.parse(jsonString);
//whatever other code you may fanacy
}
take a look at the fs module for a list of awesome features you can use to play with files
While the selected answer is correct, here's an explanation that I hope might add some clarity:
import MyModule from 'some-module'
is ES6 import syntax, as opposed to the older CommonJS syntax, which uses require.
CommonJS's require can be used to import files generally; ES6's import statement is more specific, and is generally used for importing js files which meet the criteria for being a module (having an export statement), or specific assets such as CSS sheets. Unlike require, it won't generally work for reading in files that are not modules.
You can't mix CommonJS require and ES6 import in the same file (at least not easily), so if you're using ES6 import and wish to read a file, do so with fs.readFileSync or a similar method. If the file is a json string, you'll need to parse it with JSON.parse().
If you want to use ES6 (NOT CommonJS) module system but want to use the Node.js version which is less than V18 (supports direct json import) then use the below approach.
import { createRequire } from "module";
const require = createRequire(import.meta.url); // construct the require method
const data = require("users.json"); // Now you can use require method in ES6
console.log(data)
Related
This question is not whether Node.js supports the ES Module system.
That question has been answered previously, eg:
How can I use an ES6 import in Node.js?
Node.js - SyntaxError: Unexpected token import
And these answers are supported by the official Node.js docs:
ECMAScript modules are the official standard format to package JavaScript code for reuse...Node.js fully supports ECMAScript modules as they are currently specified and provides interoperability between them and its original module format, CommonJS. Node.js has two module systems: CommonJS modules and ECMAScript modules. Authors can tell Node.js to use the ECMAScript modules loader via the .mjs file extension, the package.json "type" field, or the --input-type flag.
Source
So it is clear that Node.js supports the ES Module system.
This question is:
When using the ES Module system in Node.js, can all Node packages be imported using the same import syntax?
The reason I ask is that a lot of packages' documentation does not specify how to import them using ES Module style, eg:
https://expressjs.com/en/starter/hello-world.html
https://github.com/expressjs/session
I want to avoid the situation where I am trying to figure out the correct syntax to use each time I want to import a library.
This answer seems to suggest this syntax:
import * as [ whatever_was_previously_used_as_the_variable_name ] from [ whatever_was_previously_between_the_quotes_in_the_parenthesis ]
So, using the examples above, this:
const express = require('express');
const app = express();
const session = require('express-session');
could safely be converted to:
import * as express from 'express';
const app = express();
import * as session from 'express-session';
Is that the 'universal' syntax that should be used to import all Node packages?
(Update: that session import above doesn't work, at app.use(session(sessionConfig)); it caused the error TypeError: session is not a function - I needed to define the import like this: import session from 'express-session'. I also had to import axios like this: import axios from 'axios', or i got a similar error. However, to use msal-node i had to use import * as msal from '#azure/msal-node').
Just to confuse things, I have come across other syntax examples, such as these in the Node docs (which includes node:):
import * as fs from 'node:fs/promises';
// OR:
import * as fs from 'node:fs';
Source
I am hoping a definitive answer can be provided that covers the different scenarios that may exist, eg: Node packages that live in the node_modules directory as well as one's own custom JavaScript modules that live outside of node_modules.
In this way, if I ever come across a package that does not specify installation instructions using the ES Modules style, I will still know the correct way to import it.
The import statement is indeed universal and can be used to import a module of either system, whether inside node_modules or out, or built-in to Node. When importing a CommonJS module this way, the value it would normally expose to require becomes its default export, so import name from 'url';, or any other form of import statement that retrieves the default export, will get you what you need.
The import * as name from 'url'; form you mentioned is for retrieving all of a module's named exports. This creates a module namespace object, never a function, though the function or other value that a CommonJS module exposes to require is available on the default property. There's generally no need to use import * with a CommonJS module, since everything that Node detects as a named export will be properties on the default export anyways.
You can also create a require from inside an ES module; this will work exactly the same way as require in CommonJS, but that includes the limitation of importing only CommonJS and built-in modules, not ES modules.
I have a require statement in my script.
const packageJsonVersion = require('../package.json').version;
If I try and run the script I get an error saying I need to convert it to an import statement.
I changed the code to import { version as packageJsonVersion } from '../package.json' but when I run the script I get the following error.
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".json" for /home/alex/_code/connect/package.json
I'm not sure how to get around this.
It depends on what environment you're doing this in.
Right now, browsers don't natively support JSON modules (though it's coming).
If you're doing this with a bundler, you need to be sure to tell the bundler how to handle the .json extension.
If you're doing this in Node.js, you need the JSON module notation (assert {type: "json"}).
Separately, though, JSON modules won't support named exports (this is mentioned by both links above). You'll have to import the default and then use the version property on it:
import data from "../package.json" assert { type: "json" };
const packageJsonVersion = data.version;
I have a NodeJS app with a lot of routes, functions, etc. I have a lot of files with const xxx = require('yyy').
I now want to use this: https://www.npmjs.com/package/simple-ldap-search
I thought my journey would be as peaceful as it has been for now, but I can't use it, let me explain: instead of the usual require, I have to use import, as described in the documentation:
import SimpleLDAP from 'simple-ldap-search';
I searched on StackOverflow, and I saw I could put "type": "module" in the top package.json file, but then if I do I can't use require... It seems unsolvable.
Does it mean I have to choose between using ES6 or CommonJS? I read this question: Using Node.js require vs. ES6 import/export
I have the impression the import is more efficient, am I right?
Is it possible to use simple-ldap-search in my current node app without making big changes?
Is it possible to "convert" (I know it's not the precise term but I think you'll understand) the use of require to import and vice-versa?
Thanks for your answers.
As this project issue states, it isn't possible to use require in a project that switched to type: "module" in its package.json. For these use cases one would need to use a loader like Babel, etc.
It is worth considering switching over to ES modules, i.e to add type: "module" to your top-level package.json. It is still possible to import a CommonJS module with import but it does not work the other way around.
Alternatively, you can switch back to a 2.x version of that package, from what I see they made the switch to ES modules from 3.0.0 onwards.
While you can't use import in a commonjs file, you can use import()
This will make it more annoying when having to deal with the async loading, but is probably easier than converting your entire project to ESModules.
const simpleLDAPLoader = import('simple-ldap-search');
// later
async function () {
const {default: SimpleLDAP} = await simpleLDAPLoader;
const simpleLDAP = new SimpleLDAP();
}
Adn this will use the cached version every time you await the exisiting promise
Source: https://nodejs.org/api/esm.html#esm_interoperability_with_commonjs
Using require to load an ES module is not supported because ES modules have asynchronous execution. Instead, use import() to load an ES module from a CommonJS module.
I am not sure if it is going to help you in your case but I have found this solution for myself and I can use ES6 import and "require" at the same time.
In package.json:
"type": "module"
And in your file:
import { createRequire } from "module";
const require = createRequire(import.meta.url);
Works for my projects!
I have a typescript file in which some functions have been added.
The following shows the actual address of the typescript file :
../myproject/src/util/validation/user-validation
All the functions are exported from the file. For instance,
export function validateSignUpData(userDetail:UserDetail):Array<String>{
let errorMessages = new Array<String>();
/* Some Code */
Now I am trying to use the exported function in Node server, though it throws an error which I do not comprehend.
Error: Cannot find module '../myproject/src/util/validation/user-validation'
This is how I tried to get the functions inside my Node server file:
app.post('/users',(req,res)=>{
let validator = require('../myproject/src/util/validation/user-validation');
let errorMessages = validator.validateSignUpData(req.body);
I googled require function, and it seemed that my code must work properly. Some forums suggests that typescript must be installed to resolve the issue, though I have already installed typescript!
I will be glad, if you help me!
Thank you.
The export keyword is used for ES6 modules (Related article also covering node.js). This is a new language feature that was shipped in 2015.
It uses export function name() {...} to export a function and import {name} from './path/to/file'; to import it somewhere else.
Node uses the CommonJs syntax (which is still largely popular).
The idea behind it is that any module (i.e. js-file) can export an object like this: module.exports = {key: "value"}. This object can then be imported using require('./path/to/file').
You can use es6 modules in node like this: How can I use an es6 import in node?.
There are 2 methods of modules in node js, es6 modules and requrejs
require is used together with module.exports
add this to your module
module.exports.validateSignUpData=validateSignUpData
and then the require function will export it.
The other way is to use es6 modules but it doesn't work under all circumstances
https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enabling
Is there is a performance or behavioural difference between importing from an index file or importing individual modules?
For example, with an index file (#/modules/user) of...
import routes from './routes'
import controller from './controller'
const user = {
routes,
controller
}
export default user
If I import just the routes from that file...
import user from '#/modules/user'
const routes = Router()
routes.use('/user', user.routes)
Is this any different to just importing the routes individually from their own file (#/modules/user/routes)? Does the controller get imported as it's in the user object?
import userRoutes from '#/modules/user/routes'
const routes = Router()
routes.use('/user', userRoutes)
There are currently no native ES modules in Node.js. The actual difference depends on the toolchain. When the application is built with Webpack/Rollup (a minifier is potentially needed too) and configured to use ES modules internally, tree-shaking can be applied. This is best case scenario.
This would be a case for tree-shaking if there were a reexporting module:
import routes from './routes'
import controller from './controller'
export {
routes,
controller
}
And it was imported like
import { routes } from '#/modules/user'
However, the cases in the original post are different. In one case, once user constant is imported, it's impossible to remove unused controllers property from it with tree-shaking. In another case, #/modules/user/controller module remains unused and doesn't need tree-shaking. It will be ignored even if the application is configured to use CommonJS modules.
So yes, it's possible for ES modules to import only modules that are in use, and this heavily depends on actual code and project configuration.
Client-side applications primarily benefit from tree-shaking because it affects bundle size. This concern shouldn't be taken into account in server-side Node.js application - unless unused module imports massive amount of third-party modules that aren't used anywhere else.
Currently you can only use the import syntax using transpilers(converters from one syntax to another) as it is not yet natively supported by engines. Lets take babel for example.
Babel converts the import to CommonJS style code that can work within Node.js. While the syntax is conformant to ES6, the implementation is not.
Babel converts the syntax into CommonJS, evaluating the imported code before determining what is being imported. With ES6, the imports and exports are determined before the code is evaluated.
With future support of es6 imports inside node, importing a specific function inside the code will only return that exported function, without evaluating the whole script in the targeted file.
Currently they work the same since transpilers convert them to traditional node require syntax.
However, you can use webpack Treeshaking to remove unused code from the output file, this way they are almost identical in behavior.
The # syntax
The # syntax depends on the module loader or module bundler. The module loader is not part of the ECMAScript spec. You most likely have something like babel-plugin-root-import in your webpack/babel config.
Basically it means from the root of the project.. it avoids having to write things like import Component from '../../../../components/component'. in this case, it has nothing to do with partial imports.