How to use 'require' for node-fetch in a function [duplicate] - javascript

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

Related

Error: require() of ES modules is not supported when importing node-fetch

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

Using an ES module in TailwindCSS config (Using React and Craco)

I've been trying for hours to import the package d3-colors into my tailwind.config.js. No solutions I have found on the internet have worked so far.
I have tried:
Converting it to tailwind.config.mjs, but then it doesn't get loaded. The configuration does not work.
Using the await import('colors-d3') but that doesn't work either because then I have to await the function that gets it, and that's not allowed either:
module.exports = await config();
SyntaxError: await is only valid in async functions and the top level bodies of modules
I've tried changing the package to type='module', but then I have all sorts of issues with Craco not being able to load it's config once I convert it to an ESM module because craco itself is commonjs.
I have tried modifying Craco's config...
I've tried using a postcss config file to pass the tailwind.config.mjs as the config file parameter, doesn't work either.
etc etc
I can't get it to work. How can I just import this module into my tailwind config?
According to the team, they won't be supporting ESM anytime soon.
https://github.com/tailwindlabs/tailwindcss/issues/8029#issuecomment-1086875656

require('node-fetch') gives ERR_REQUIRE_ESM

I just use
const fetch = require('node-fetch')
And I get
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\Alex\Desktop\rollbot\node_modules\node-fetch\src\index.js from C:\Users\Alex\Desktop\rollbot\index.js not supported.
Instead change the require of C:\Users\Alex\Desktop\rollbot\node_modules\node-fetch\src\index.js in C:\Users\Alex\Desktop\rollbot\index.js to a
dynamic import() which is available in all CommonJS modules.
{
code: 'ERR_REQUIRE_ESM'
}
All my other packages work, just node-fetch does this. What should I do in order to use node-fetch?
From the node-fetch package 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.
If you want to require it, then downgrade to v2.
The other option you have is to use async import('node-fetch').then(...)
What I found is that the latest version of node-fetch changed to ES modules by default. You can:
Uninstall the current version of node-fetch with npm uninstall node-fetch
Install the second version: npm install node-fetch#2
It has worked for me!
In my case, I personally found it easier to require ('cross-fetch') instead. The documentation is here: cross-fetch
It can be used in CommonJS as well as ES6 modules.
LATEST UPDATE MAY 2022
You may not needed node-fetch anymore.
In the latest version of Node.js (18.0.0), global fetch (experimental) is enabled by default.
const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
const data = await res.json();
console.log(data);
}
Through this addition, the following globals are made available: fetch, FormData, Headers, Request, Response.
You may disable this API with the --no-experimental-fetch
command-line flag.
You can use node-fetch#3 from CommonJS using dynamic imports. Since fetch is already an async API you can define a wrapper like this:
fetch.js
exports.fetch = async function (url, init) {
const {default: fetch} = await import("node-fetch");
return await fetch(url, init);
};
You can then use the wrapper like this:
const fetch = require("./fetch");
This trick doesn't work out of the box in TypeScript since TypeScript transforms the dynamic import to a regular require. To work around this just add the plain fetch.js to your project and also add a type declaration:
fetch.d.ts
/**
* #param { import("node-fetch").RequestInfo} url
* #param {import("node-fetch").RequestInit} init
* #returns {Promise<import("node-fetch").Response>}
*/
export function fetch(
url: import("node-fetch").RequestInfo,
init: import("node-fetch").RequestInit
): Promise<import("node-fetch").Response>;
cross-fetch is a nice alternative but it's wrapping a 2.x version of node-fetch so you won't get the latest version.
NodeJS supports two different module types:
the original CommonJS module that uses require() to load other modules
the newer ECMAScript modules (aka ESM) that use import to load other modules.
As mentioned in node-fetch changelog (28 Aug 2021):
This module 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. 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.
Alternatively, you can use the async import() function from CommonJS to load node-fetch asynchronously:
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
So, you can use this one-liner instead of const fetch = require('node-fetch').
Or instead of trying to load node-fetch, you can install and load the module node-fetch-commonjs instead. It's a CommonJS wrapper around node-fetch that should provide you compatibility:
const fetch = require('node-fetch-commonjs')
https://github.com/alex-kinokon/esm-hook worked nicely for me. Require it before you try to import node-fetch. Either via --require or at the top of your script.

How to move to ESM

I am using Egg framework for my NodeJs(v14.15.4) application
I want to use latest version of p-debounce library, the package is now pure ESM, Instead of const pDebounce = require('p-debounce') I must use import pDebounce from 'p-debounce' that not works on EggJs
If I use import
(node:10636) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
test.js:5
import pDebounce from 'p-debounce'
^^^^^^
SyntaxError: Cannot use import statement outside a module
If I use require
internal/modules/cjs/loader.js:1080
throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
^
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: .\node_modules\p-debounce\index.js
require() of ES modules is not supported.
require() of .\node_modules\p-debounce\index.js from .\test.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 .\node_modules\p-debounce\package.json.
If I add "type": "module" in the package.json
const path = require('path');
^
ReferenceError: require is not defined
I have many require in my application and not want to change all to import at the moment
What is "type": "module" in the package.json ?
How can I fix the error?
You seem to be overlooking a particular point in the changelog you linked:
If you cannot move to ESM yet, don't upgrade to this version.
As you've pointed out, your application has already progressed significantly, and you have many require that you do not want to change at the moment. There is no need to upgrade to the latest version of p-debounce at this time, according to your needs.
When you do decide to migrate to ESM format, in order to upgrade individual files one at a time, you can use the .mjs extension to treat the code as an ECMAScript module.
ES modules are the future.
There is a way around in ES modules to require a common.js module. Using createRequire
WORKING EXEMPLE
axios-curlirize is ES module and axios support both.
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const axios = require('axios');
import curlirize from 'axios-curlirize';
curlirize(axios);
const { data } = await axios.get('https://jsonplaceholder.typicode.com/todos/1');
console.log(data)
Using ES modules you can use top-level await without function.

How to use npm module in DENO?

Deno is super cool. I saw it in the morning and want to migrate to deno now. I was trying to move my existing nodejs script to deno. Can any one help me on how to use npm modules in deno. I need esprima module. This one has the package https://github.com/denoland/deno_third_party/tree/master/node_modules but i am not able to figure out how to use that.
Deno provides a Node Compatibility Library, that allows using some NPM packages that do not use non-polyfilled Node.js APIs.
As of Deno 1.25 there's an experimental NPM support by using npm: specifier
npm:<package-name>[#<version-requirement>][/<sub-path>]
import express from "npm:express";
const app = express();
app.get("/", function (req, res) {
res.send("Hello World");
});
app.listen(3000);
console.log("listening on http://localhost:3000/");
The --unstable flag is required.
When doing this, no npm install is necessary and no node_modules folder is created
You can also require and installed npm package by using https://deno.land/std/node/module.ts
The following works on deno >= 1.0.0
npm install esprima
import { createRequire } from "https://deno.land/std/node/module.ts";
const require = createRequire(import.meta.url);
const esprima = require("esprima");
const program = 'const answer = 42';
console.log(esprima.tokenize(program))
The above code will use esprima from node_modules/.
To run it, you'll need --allow-read && --allow-env flag
# you can also use --allow-all
deno run --allow-read --allow-env esprima.js
You can restrict it only to node_modules
deno run --allow-read=node_modules esprima.js
Which outputs:
[
{ type: "Keyword", value: "const" },
{ type: "Identifier", value: "answer" },
{ type: "Punctuator", value: "=" },
{ type: "Numeric", value: "42" }
]
Note: many APIs used by std/ are still unstable, so you may need to run it with --unstable flag.
Although since that whole project is written in TypeScript already, and it's not using any dependencies, it will be very easy for them to adapt it to Deno. All they need to do is use .ts extension on their imports.
You can also fork the project and do the changes.
// import { CommentHandler } from './comment-handler';
import { CommentHandler } from './comment-handler.ts';
// ...
Once they do, you'll be able to just do:
// Ideally they would issue a tagged release and you'll use that instead of master
import esprima from 'https://raw.githubusercontent.com/jquery/esprima/master/src/esprima.ts';
const program = 'const answer = 42';
console.log(esprima.tokenize(program))
Alternative
You can also use https://jspm.io/ which will convert NPM modules to ES Modules
All modules on npm are converted into ES modules handling full
CommonJS compatibility including strict mode conversions.
import esprima from "https://dev.jspm.io/esprima";
const program = 'const answer = 42';
console.log(esprima.tokenize(program))
For packages that use Node.js modules not supported by jspm it will throw an error:
Uncaught Error: Node.js fs module is not supported by jspm core.
Deno support here is tracking in
https://github.com/jspm/jspm-core/issues/4, +1's are appreciated!
To polyfill those Node.js APIs you'll have to include std/node.
// import so polyfilled Buffer is exposed
import "https://deno.land/std/node/module.ts";
import BJSON from 'https://dev.jspm.io/buffer-json';
const str = BJSON.stringify({ buf: Buffer.from('hello') })
console.log(str);
Issue
In general, there are two issues with npm packages in Deno:
ES Module (ESM) conformity is not given.
Bare imports like import _ from "lodash" don't work - no "magic" node_modules resolution
All import specifiers need to include the file extension - .ts,.js etc.
CommonJS module system is not usable in Deno
The npm package uses native Node.js builtins like fs or path.
Solutions to issue 1
1.1: Third party modules
The Third Party Modules section is the quickest way to discover compatible packages.
1.2: ESM CDN providers
Also take a look at CDN providers, that can auto-convert npm packages to ES Modules (ESM):
Skypack CDN
jspm.io
unpkg.com with ?module query parameter
Skypack CDN can deliver auto-converted packages, that e.g. have set a "module" entrypoint in package.json. For TypeScript users: It fetches .d.ts type definitions along with .js files (via X-TypeScript-Types HTTP headers used by Deno).
unpkg.com describes its ?module flag as follows: "Expands all 'bare' import specifiers in JavaScript modules to unpkg URLs. This feature is very experimental".
Esprima does not depend on Node.js builtins, so we can simplify its import by a CDN URL:
import esprima from "https://cdn.skypack.dev/esprima#^4.0.1"; // Option 1: Skypack
import esprima from "https://dev.jspm.io/esprima"; // Option 2: jspm
// your program
const tokens = esprima.tokenize("const foo = 'bar'"); // works
jspm would be a good choice here - Skypack TS types didn't work for me in this particular case.
1.3: Other approaches
You might also try to import an ESM compatible version directly from repository sources (e.g. an ESM branch). Though for Esprima it won't work because of missing file extensions in code.
Snowpack and jspm stand in for a more manual approach to convert CommonJS → ESM. The rollup plugin #rollup/plugin-commonjs (internally used by Snowpack) is even a more low-level tool.
Solution to issue 2
Deno provides a Node compatibility layer, see Marcos Casagrande's answer. However, not all native Node.js built-ins are fully supported.
As Esprima doesn't rely on Node builtins, you can go with the simpler CDN option.
As of version Deno 1.25 (released today) deno is now included with experimental npm support.
// main.ts
import express from "npm:express";
const app = express();
app.get("/", function (req, res) {
res.send("Hello World");
});
app.listen(3000);
console.log("listening on http://localhost:3000/");
You can now run deno run --unstable --A main.ts and express will be downloaded.
Starting with v1.15 Deno provides Node compatibility mode that makes it possible to run a subset of programs authored for Node.js directly in Deno. Compatibility mode can be activated by passing --compat flag in CLI.
deno run --compat --unstable --allow-read test.js
Currently, not all node.js built-in modules are supported and many are partially supported.
The following modules are not yet implemented:
cluster, dgram, http2, https, repl, tls, vm, lib

Categories