How do you resolve "Cannot use import statement outside a module" from a dependency when the dependency isn't declared as a module?
I want to use the validator in Svelte/kit to validate emails. However, when importing the ESM version, I get the "Cannot use import statement outside a module" error. I'm using pnpm instead of npm or yarn.
import isEmail from 'validator/es/lib/isEmail'
/node_modules/.pnpm/validator#13.6.0/node_modules/validator/es/lib/isEmail.js:1
import assertString from './util/assertString';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:355:18)
at wrapSafe (node:internal/modules/cjs/loader:1039:15)
at Module._compile (node:internal/modules/cjs/loader:1073:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1138:10)
at Module.load (node:internal/modules/cjs/loader:989:32)
at Function.Module._load (node:internal/modules/cjs/loader:829:14)
at Module.require (node:internal/modules/cjs/loader:1013:19)
at require (node:internal/modules/cjs/helpers:93:18)
at nodeRequire
It appears that validator is attempting to use the import statement, but it's package.json does not specify "type": "module". My guess is that this is the root cause of the error.
Debug steps
package.json has "type": "module"
Upgraded to latest version of node
Tried using the non-esm version of validator 'validator/lib/isEmail', but that causes other errors not related to this thread.
Related
SyntaxError: Cannot use import statement outside a module — this solution is for code you control, not for dependencies
"Uncaught SyntaxError: Cannot use import statement outside a module" when importing ECMAScript 6 — this seems to be very similar, but I'm getting this error in node, not in the browser
Metadata
Node: v16.2.0
Sveltekit: v1.0.0-next.115
Validator: 13.6.0
Have you tried importing like this?
import validator from 'validator'
I tried reproducing your issue with latest SvelteKit. This works fine:
// index.svelte
<script>
import validator from 'validator';
let result = validator.isEmail('foo#bar.com');
console.log(result);
</script>
When I changed the import statement to:
import validator from 'validator/es/lib/isEmail'
I got the error from your question (Cannot use import statement outside a module).
Importing validator/es/lib/isEmail supposedly only imports a subset of the library. I'm not sure how much difference it will make; it might not make any difference. A slightly larger build beats a build that doesn't work. I suggest getting it working first, then optimize the build size if you really need to.
For those that happen to have the same problem while deploying with nodejs using typescript.
"type":"module" was already set in my package.json in the main project. I put the build directory on the server (created by npm run build).
working-dir
|--build
|--index.js
|--...
I thought i had to just run node build/index.js, as I thought everything was packaged.
Turns out I need to add a package.json into the working directory (I think it also works by putting it into the build directory).
server
+ |--package.json
|--build
|--index.js
|--...
// package.json
{
"type": "module"
}
Without more information, if your problem solely lies in a problem with code you are dependent on, consider short term using something like patch-package to make the necessary adjustment, and long term, open up a PR over at the validator.js repo!
for patch-package, just go add the "type": "module" to the package.json at node_modules/validator, and then run npx patch-package validator. You can then version control the outputted diff file, and the changes are made automatically with npm hooks assuming patch-package is a (dev) dependency.
The behavior or defect of the library here is probably from the devs more keeping in mind things like webpack that do esm imports on their own terms, and not with the node module resolution patterns that it appears svelte is using. or at least how the problem has gotten this far.(might be wrong about this!).
After reading their docs: https://github.com/validatorjs/validator.js#es6, it looks like the es part in the import is, so it can be treeshakable. You can fix this error, by just importing it normally:
import isURL from 'validator/lib/isURL';
Try importing like this
import { isEmail } from "validator"
Try to import like below
const {isEmail} = require('validator');
Related
I am unsure whether I am supposed to use the require version or the import version.
It doesn't state that in the documentation and I found a statement in a Github issue that
Mixing import and require is definitely discouraged. The only way for Rollup to handle require statements is with rollup-plugin-commonjs, but that plugin will skip any files with import or export statements.
which could be interpreted as: "You need to still use require otherwise the common-js plugin will ignore your file and things will not work." or as "always use import everything else would constitute mixing". So that really confused me.
Context
I am trying to import a CommonJS library (Citation-js) into a javascript module (really typescript but I hope this is not relevant here). Now the documentation of common-js tells me to do
const Cite = require('common-js');
which tells me that it is a commonjs library (right?). Therefore I added
import commonjs from "rollup-plugin-commonjs";
import { nodeResolve } from "#rollup/plugin-node-resolve";
to my rollup config and put plugins: [commonjs(), typescript(), nodeResolve()] into the configuration.
Now vscode stops underlining everything and building the website with rollup works again. But the compiled javascript simply states require('common-js') and my browser complains that require is undefined.
Uncaught ReferenceError: require is not defined
So I tried
import Cite from 'common-js';
instead. But that resulted in the rollup build failing with
[!] Error: Unexpected token (Note that you need #rollup/plugin-json to import JSON files)
node_modules/#citation-js/core/package.json (2:8)
1: {
2: "name": "#citation-js/core",
^
Now I could of course install that plugin. But I am not sure that is right, since the whole point of a tool like rollup should be that dependencies of dependencies should be resolved automatically right?
I have also tried
Can't import npm modules in commonjs with rollup : "require is not defined"
This seemed like it would fix my problem: Using Older Require Module With Rollup
But:
the rollup-plugin-node-builtins is apparently not maintained (npm protested with security vulnerabilities and I found this: https://github.com/rollup/rollup/issues/2881). EDIT: There is a new package rollup-plugin-polyfill-node replacing that I guess.
resolve is no longer a member of #rollup/plugin-node-resolve so I assume that this has become nodeResolve which I am already using...
EDIT: installing #rollup/plugin-json actually lets me build the site again (with a bunch of warnings)
(!) Missing shims for Node.js built-ins (which is not fixed by the rollup-plugin-polyfill-node above)
(!) Missing global variable names
(!) Circular dependencies
(!) Unresolved dependencies
not sure what to do about these warnings
I am creating an app with Electron and Vue (using js not ts).
When I run the app using npm run electron:serve the app runs fine.
I now want to build a Windows exe so I can distribute my app. I have tried using electron-builder, electron-packager and electron-forge. Whenever I can get the build to finish, running the exe throws the cannot use import statement outside a module error (referring to the first import statement it finds, i.e. import { app, protocol, BrowserWindow } from 'electron').
I've tried adding "type":"module" to my package.json but (due a bug in Vue, according to this question), that throws Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]
I've also tried changing all my import statements to require but this doesn't work because some of the node modules I'm using use import and the error just throws for those instead.
I'm tearing my hair out over this. Where do I go from here?
UPDATE:
I have found a workaround for the Vue bug and posted my findings on the linked question. I can now add "type":"module" to my package.json.
However, I now get an error thrown when I run npm run electron:serve and from my built exe:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: <my_project_root>\dist_electron\index.js
require() of ES modules is not supported.
require() of <my_project_root>\dist_electron\index.js from <my_project_root>\node_modules\electron\dist\resources\default_app.asar\main.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.
To be clear, I'm not using require in any of my source code, but the compiled(?) version does?
What's going on here?
UPDATE 2:
As requested, here is a minimal reproducible example that maintains original folder structure, configs and package.json
As an exercise I decided to create a little vanilla JavaScript game using ES6 syntax that runs in the browser. The program works fine.
I'd like to test it using Jasmine. However, whenever I try to perform an import e.g.
import Deck from "../Deck.js";
Deck.js starts:
export default class Deck {
I get error SyntaxError: Cannot use import statement outside a module.
Things I've done:
Installed node v13.0.1 - I thought this version of node allowed es6 modules.
Installed jasmine and initialized node ./node_module/jasmine/bin/jasmine init
Run node ./node_module/jasmine/bin/jasmine - works fine without imports
Run node --experimental-modules ./node_module/jasmine/bin/jasmine - doesn't work with imports
Tried require instead of import: const Deck = require('../Deck.js'); - SyntaxError: Unexpected token 'export'
How do I get jasmine to work with imports? At the moment I cannot include any files to test !
I'm sure I've gone about this the wrong way, but i just want some cmd line tests.
Follow the offical guide from Babel at https://babeljs.io/setup#installation
Then choose one of the options from this solution: https://stackoverflow.com/a/59399717/673351
Personally, I have renamed my spec files to have the mjs extension becaue I would like ot use the LTS (currently 12) version of node.
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.
Besides going through the documentation of the package and trial/error attempts, how can I know for sure if an npm packaged can be imported with the ES6 import syntax?
Is there a file inside the package folder that I can check?
I constantly question myself about this.
For example:
The md5 package DOCS only mentions md5 = require('md5'); but I've just tested and it works with import md5 from 'md5'
How can I inspect the package and know for sure?
Since you are using Babel and webpack, you can always use import. Webpack is taking care of transpiling the import statements in your code to include the code from the npm packages. I can't think of any case where import would not work while require would.
You must check if the module/package has a dist or a src folder. If the package has a dist folder, Then it can be imported using es6's import statement. Otherwise if it has a src folder, Then it can't be imported using es6's import statement and you must use cjs's require function to import such modules. If you try to import a cjs module using the import statement, You will get the following error:
Syntax Error: Cannot use import statement outside a module