I have a file, test.js with these lines of code inside:
import {blabla} from "./bla";
async function dataGenerator() {
..........
}
(async() => {
console.log('1')
await dataGenerator()
console.log('2')
})()
Note: Ignore the import structure. It is just fictive for the question. In my file the imports are auto.
When I'm trying to run from terminal with node test.js it returns error:
Cannot find module 'D:\bla' imported from D:\test.js
I have added into package.json the line: "type": "module". Without this it returns:
Cannot use import statement outside a module
I'm using node v14. How can I run the test.js without adding to all the imports ".js". There are functions in functions in functions and is complicated to add .js extension. Is there any npm to run it?
Node.js by default does not attempt to guess the file extension when using import for ES modules. This is different from CommonJS modules with require.
In the documentation for the ES module loader you can read how files are found on disk.
The heading 'Customizing ESM specifier resolution algorithm' states:
The --experimental-specifier-resolution=[mode] flag can be used to customize the extension resolution algorithm. The default mode is explicit, which requires the full path to a module be provided to the loader. To enable the automatic extension resolution and importing from directories that include an index file use the node mode.
I'm creating a program to analyze security camera streams and got stuck on the very first line. At the moment my .js file has nothing but the import of node-fetch and it gives me an error message. What am I doing wrong?
Running Ubuntu 20.04.2 LTS in Windows Subsystem for Linux.
Node version:
user#MYLLYTIN:~/CAMSERVER$ node -v
v14.17.6
node-fetch package version:
user#MYLLYTIN:~/CAMSERVER$ npm v node-fetch
node-fetch#3.0.0 | MIT | deps: 2 | versions: 63
A light-weight module that brings Fetch API to node.js
https://github.com/node-fetch/node-fetch
keywords: fetch, http, promise, request, curl, wget, xhr, whatwg
dist
.tarball: https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0.tgz
.shasum: 79da7146a520036f2c5f644e4a26095f17e411ea
.integrity: sha512-bKMI+C7/T/SPU1lKnbQbwxptpCrG9ashG+VkytmXCPZyuM9jB6VU+hY0oi4lC8LxTtAeWdckNCTa3nrGsAdA3Q==
.unpackedSize: 75.9 kB
dependencies:
data-uri-to-buffer: ^3.0.1 fetch-blob: ^3.1.2
maintainers:
- endless <jimmy#warting.se>
- bitinn <bitinn#gmail.com>
- timothygu <timothygu99#gmail.com>
- akepinski <npm#kepinski.ch>
dist-tags:
latest: 3.0.0 next: 3.0.0-beta.10
published 3 days ago by endless <jimmy#warting.se>
esm package version:
user#MYLLYTIN:~/CAMSERVER$ npm v esm
esm#3.2.25 | MIT | deps: none | versions: 140
Tomorrow's ECMAScript modules today!
https://github.com/standard-things/esm#readme
keywords: commonjs, ecmascript, export, import, modules, node, require
dist
.tarball: https://registry.npmjs.org/esm/-/esm-3.2.25.tgz
.shasum: 342c18c29d56157688ba5ce31f8431fbb795cc10
.integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
.unpackedSize: 308.6 kB
maintainers:
- jdalton <john.david.dalton#gmail.com>
dist-tags:
latest: 3.2.25
published over a year ago by jdalton <john.david.dalton#gmail.com>
Contents of the .js file (literally nothing but the import):
user#MYLLYTIN:~/CAMSERVER$ cat server.js
import fetch from "node-fetch";
Result:
user#MYLLYTIN:~/CAMSERVER$ node -r esm server.js
/home/user/CAMSERVER/node_modules/node-fetch/src/index.js:1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/user/CAMSERVER/node_modules/node-fetch/src/index.js
require() of ES modules is not supported.
require() of /home/user/CAMSERVER/node_modules/node-fetch/src/index.js from /home/user/CAMSERVER/server.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/user/CAMSERVER/node_modules/node-fetch/package.json.
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1089:13) {
code: 'ERR_REQUIRE_ESM'
}
user#MYLLYTIN:~/CAMSERVER$
From the Upgrade Guide
node-fetch was converted to be a ESM only package in version 3.0.0-beta.10. node-fetch is an ESM-only module - you are not able to import it with require.
Alternatively, you can use the async import() function from CommonJS to load node-fetch asynchronously:
// mod.cjs
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
or you stay on v2 as they say in the README
node-fetch is an ESM-only module - you are not able to import it with require. We recommend you stay on v2 which is built with CommonJS unless you use ESM yourself. We will continue to publish critical bug fixes for it.
EDIT
I saw that in the doc, used it, and the script crashes with :
error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
Since you are using typescript you should do something like this
import { RequestInfo, RequestInit } from "node-fetch";
const fetch = (url: RequestInfo, init?: RequestInit) => import("node-fetch").then(({ default: fetch }) => fetch(url, init));
To fix this, I downgraded node-fetch to the latest version 2, which right now is 2.6.6. This is the script I ran:
yarn add node-fetch#^2.6.6
or
npm install node-fetch#^2.6.6
I also added these compiler options:
{
"compilerOptions": { "allowJs": true, "outDir": "./dist" },
}
node-fetch v3 is ESM-only: https://github.com/node-fetch/node-fetch#loading-and-configuring-the-module. The esm module you’re adding is for adding ESM compatibility, but it’s unnecessary now that Node 12+ supports ESM natively; and it doesn’t work with ESM-only packages like node-fetch 3+.
To fix your issue:
Remove the esm package.
Add "type": "module" to your package.json.
And that’s it. Then when you run node server.js it should work.
I always had errors with previous solutions, this is what worked every single time for me
npm i -D node-fetch
const _importDynamic = new Function('modulePath', 'return import(modulePath)');
export const fetch = async function (...args: any) {
const {default: fetch} = await _importDynamic('node-fetch');
return fetch(...args);
}
Use ESM syntax, also use one of these methods before running the file.
specify "type":"module" in package.json
Or use this flag --input-type=module when running the file
Or use .mjs file extension
Many times that error happens through the current version of fetch what we can do to solve it, is to install a previous version I tried it and it worked for me.
to install the previous version:
npm i node-fetch#2.6.1 or whatever you prefer.
Since the question was really about requiring node-fetch and there are definitely reasons that a developer might need to use require vs import, the answer to import the module using import() is somewhat accurate but isn't complete, because it ignores the fact that using import is async and if you're using node-fetch in your code in multiple places you're going to have a bit of an async mess all over the place whenever you want to use node-fetch, so the answer is very incomplete IMHO. A more complete answer would include a better how-to. Something like the following:
You need to use import() rather than require because this is an ES module. To avoid an async mess, you'll want to await the importing of this module once and then be able to use it wherever else you need it. To do that, create a module that imports any of your ES-only modules something like this:
"use strict";
let got;
let fetch;
module.exports.load = async function() {
queueMicrotask(function() {
// any ESM-only module that needs to be loaded can be loaded here, just add import for each using specific structure of each
import("got").then(({default: Got}) => got = Got );
fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
});
while(
// check each module to see if it's been loaded here
!got || !got.get || !fetch || typeof fetch !== "function"
) {
// waiting for modules to load
console.log("Waiting for ES-Only modules to load...");
await new Promise((resolve)=>setTimeout(resolve, 1000));
}
module.exports.got = got;
module.exports.fetch = fetch;
console.log("ES-Only modules finished loading!");
}
This then allows you to call the await the loading of the ES-Only modules once and then use the module later by grabbing it from your intermediary module like this:
"use strict";
const esmModules = require("esm_modules"); // or whatever you called the intermiary module
async function doMyFetching(url, options) {
const fetch = esmModules.fetch;
const result = await fetch(url, options)
}
The nice part of doing it this way is that you know that your ES-Only modules are loaded and you know that once they're loaded you can use them at will throughout the rest of your code in a simple and clean way that doesn't force you to add additional async logic all over the place whenever you need the module.
Here is in Typescript, this will install to the global scope, just import the file and fetch ready to use:
/* filename: fetch.ts */
if (!globalThis.fetch) {
import('node-fetch').then(({ default: fetch, Headers, Request, Response }) => {
Object.assign(globalThis, { fetch, Headers, Request, Response })
})
}
In case someone is solving this issue in 2022:
Recent versions of nodejs already includes global fetch api. It is still an experimental feature and may be not ready to be used in production, but if you are writing some basic script or doing some sandbox project, you should definitely try it. Works without issues for me.
This is an official announcement and some examples here and here
I think this link is a comprehensive explanation about Error [ERR_REQUIRE_ESM]: require() of ES [node-fetch Module ] not supported.
node-fetch Error [ERR_REQUIRE_ESM]: require() of ES Module not supported
I'm trying to get webpack to ignore an import, so that its imported by the browser using a native ES6 import statement, not webpack. I'm trying to get ffmpeg.js to import directly as it crashes webpack when it tries to bundle it, as the files are too large.
Following the answer here (How to exclude a module from webpack, and instead import it using es6), I have my code in the local tree as /ffmpeg/ffmpeg-mpeg.js and verified my dev server can access as http://localhost:8080/ffmpeg/ffmpeg-webm.js
I then import via:
import ffmpeg from '/ffmpeg/ffmpeg-webm.js';
And add that to the externals section of my webpack config:
externals: {
'/ffmpeg/ffmpeg-webm.js': 'ffmpeg',
},
The result is an link that looks like this
webpack:///external "ffmpeg"
containing:
module.exports = ffmpeg;
Which then fails with "Uncaught Error: Cannot find module ?" (In fact that error is hardcoded in the generated file)
So that seems to assume there is a global ffmpeg option and then maps that module to that, but instead I want it leave the line completely untouched by webpack and leave it to the browser.
Whats the correct way to do that? The exclude rule thats downvoted on that page doesn't work either.
Edit:
You can use this:
import(/* webpackIgnore: true */'/ffmpeg/ffmpeg-webm.js').then(({default: ffmpeg}) => {
//Do what you want to do with ffmpeg
});
Which will prevent webpack from compiling the import (so it will be a regular ES6 import)
Original answer:
You forgot to include the external script in your page.
Also since you pointed out that your file is very big, I'd recommend to include it defered
So you need to add
<script src="/ffmpeg/ffmpeg-webm.js" defer></script>
To the head of your app and you would then import it slightly differently using the import function with a callback
import('/ffmpeg/ffmpeg-webm.js').then(ffmpeg => {
//Do what you want to do with ffmpeg
});
Small note: the externals key does not need to be the path of your file, it's just the name you will use when importing, so rename it if you are getting confused with the path
module.export = {
//...
externals: {
"ffmpeg-webm": "ffmpeg"
}
}
//Then import
import('ffmpeg-webm').then(ffmpeg => {
//Do what you want to do with ffmpeg
});
Alternatively for node js, instead of using externals you could use
const ffmpeg = __non_webpack_require__('/ffmpeg/ffmpeg-webm.js')
Just keep in mind that this will transform it as a normal require that only works with node js
Although I am able to start the npm project using npm start without any issues with webpack or babel, once I run npm test, I find the following error related to testing App.js using App.test.js (where App.js imports ApolloClient):
TypeError: Cannot assign to read only property '__esModule' of object '[object Object]'
| import ApolloClient from 'apollo-boost';
| ^
at node_modules/apollo-boost/lib/bundle.cjs.js:127:74
at Array.forEach (<anonymous>)
at Object.<anonymous> (node_modules/apollo-boost/lib/bundle.cjs.js:127:36)
Essentially, I'm confused as to why I get an error when running the test but not when starting the project.
I've tried adding in a number of babel plugins to both .babelrc and in my webpack config file:
#babel/plugin-transform-object-assign
#babel/plugin-transform-modules-commonjs
babel-plugin-transform-es2015-modules-commonjs
However, I haven't been able to resolve the issue. My thinking was that this is related to the fact that the file that fails to compile was originally CommonJS.
I was only able to find something relatively similar here, https://github.com/ReactTraining/react-router/pull/6758, but I didn't find a solution.
Is there something that I'm missing specifically related to running tests? I should also mention I've tried frameworks other than Jest and ran into the same issue.
EDIT:
I removed everything from App.test.js except the imports to isolate the issue so it just contains the following:
import React from 'react';
import { shallow } from 'enzyme/build';
import App from './App';
UPDATE:
I was able to resolve the initial error by upgrading apollo-boost from version 0.3.1 to 0.4.2. However, I now have a different error that is similarly frustrating. I am using Babel 7 and have added the plugin #babel/plugin-syntax-dynamic-import to both my .babelrc and to my webpack.config.js files. Despite this, I get the following error related to the use of a dynamic import in App.js when running the Jest to test App.test.js:
SyntaxError: Support for the experimental syntax 'dynamicImport' isn't currently enabled
Add #babel/plugin-syntax-dynamic-import (https://git.io/vb4Sv) to the 'plugins' section of your Babel config to enable parsing.
I'm not sure if there is a parsing error or something else, but I've tried numerous things that have not worked. The closest discussion I could find related to this problem is, https://github.com/facebook/jest/issues/5920, however, the proposed solutions don't work for me.
UPDATE:
One thing that I'm trying is to avoid duplication of the babel options as right now they're both in .babelrc and in the babel-loader options within webpack.config.js. From what I found online (Whats the difference when configuring webpack babel-loader vs configuring it within package.json?), the way to make webpack use the settings in .babelrc is to not specify options. However, doing so results in the same error described above showing up only this time when running npm start. I will add that the project that was originally created using create-react-app, however, in order to support multiple pages, I needed to customize webpack's configuration and so ejected from it. I'm not sure why this is so convoluted.
its probably a babel configuration issue, I'm pretty sure jest needs to be compiled to work with create-react-app...
did you specify a setup file in package.json:
"jest": {
"setupFiles": [
"/setupTests.js"
]
}
and in setupTests.js:
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
It turns out that one of the components in the project's src directory had its own local package.json file even though it wasn't being used and was not installed as a local dependency in the top level package.json (instead imports were done using relative urls). For some reason, the existence of this file changed the behavior of webpack and other tools when starting and testing the project such that none of the top level configurations were used for files within directories with separate package.json files. Once I removed these local package.json files from the components sub-directory, all the prior issues were resolved. One hallmark of this problem is that compilation errors were not showing up for JavaScript files that weren't nested under an alternate package.json file.
Hopefully this is useful for anyone that encounters similar errors as I don't think the cause can be directly determined from the compiler messages alone.
I am trying to use video.js via webpack.
I installed video.js via npm - npm install video.js --save-dev
In webpack I read that video.js should be loaded via script loader else it throws an error.
This is how I am loading video.js through the babel loader
module:
loaders: [
{
test: /video\.js/,
loader: 'script'
}
]
I got this solution from here https://github.com/videojs/video.js/issues/2750
This is my import statement
import videojs from 'video.js';
The issue that I now face is the import is returning an empty object, so when I try to do this:
var vidTag = ReactDOM.findDOMNode(this.refs.html5Video);
this.videojs = videojs(vidTag);
I get this error:
renderer-0.js:8031 Uncaught (in promise) TypeError: (0 , _video2.default) is not a function(…)
Any help will be much appreciated. I am new to ES6 / React / Webpack
Please take a look at the loader's README before copy&pasting some random code. The script-loader is not appropiate here, because it imports scripts into the global scope while skipping the whole module system.
So, if you wanted to use the script-loader, you would just write:
import "script-loader!video.js";
console.log(videojs); // should be an object now
Usually I would not recommend the use of the script-loader because it neglects the whole point of a module system where you import stuff explicitly into the local scope. In the example above, the import happens as a side-effect into the global scope which is effectively the same as just using a <script> tag with all its downsides like name clashes, etc.
There are often better alternatives to it, like the exports-loader, which appends a module.exports at the end of the module, thus turning an old-school global script into a CommonJS module.
In this particular case, however, you don't need a loader at all because video.js is already aware of a CommonJS module system. Just write import videojs from "video.js";.
There is another minor problem, however. If you compile this with webpack, it will print a warning to the console:
WARNING in ../~/video.js/dist/video.js
Critical dependencies:
13:480-487 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
# ../~/video.js/dist/video.js 13:480-487
This is because webpack detects that this file has already been bundled somehow. Often it's better to include the actual src with all its tiny modules instead of one large dist because this way webpack is able to optimize the bundle in a better way. I've written down an exhaustive explanation about how to import legacy scripts with webpack.
Unfortunately, video.js does not include its src in the version deployed at npm, so you're forced to use the dist. In order to get rid of the error message and to improve webpack's build time, you can instruct webpack to skip video.js when parsing the code for require() statements by setting the module.noParse option in your webpack.config.js:
module: {
noParse: [
/node_modules[\\/]video\.js/
]
}
Usually it's safe to flag all pre-bundled modules (typically those with a dist folder) as noParse because they are already self-contained.
include SDN
<script src="//vjs.zencdn.net/5.11/video.min.js"></script>
webpack config:
config.externals = {
'video.js': 'videojs'
};