SIP.js icon indicating copy to clipboard operation
SIP.js copied to clipboard

ES Module not compliant with import statements missing file extensions

Open msaavedra-cirkelco opened this issue 5 years ago • 13 comments

Describe the bug ES Module not compliant with import statements missing file extensions.

Logs ERROR in ./node_modules/sip.js/lib/index.js 2:0-44 Module not found: Error: Can't resolve './version' in '/Users/msaavedra/cirkelco/gitlab/colabrie-desktop/node_modules/sip.js/lib' Did you mean 'version.js'? BREAKING CHANGE: The request './version' failed to resolve only because it was resolved as fully specified (probably because the origin is a '.mjs' file or a '.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request. @ dll renderer renderer[8]

ERROR in ./node_modules/sip.js/lib/index.js 7:0-22 Module not found: Error: Can't resolve './api' in '/Users/msaavedra/cirkelco/gitlab/colabrie-desktop/node_modules/sip.js/lib' Did you mean 'index.js'? BREAKING CHANGE: The request './api' failed to resolve only because it was resolved as fully specified (probably because the origin is a '.mjs' file or a '.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request. @ dll renderer renderer[8]

ERROR in ./node_modules/sip.js/lib/index.js 9:0-26 Module not found: Error: Can't resolve './grammar' in '/Users/msaavedra/cirkelco/gitlab/colabrie-desktop/node_modules/sip.js/lib' Did you mean 'index.js'? BREAKING CHANGE: The request './grammar' failed to resolve only because it was resolved as fully specified (probably because the origin is a '.mjs' file or a '.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request. @ dll renderer renderer[8]

ERROR in ./node_modules/sip.js/lib/index.js 11:0-31 Module not found: Error: Can't resolve './core' in '/Users/msaavedra/cirkelco/gitlab/colabrie-desktop/node_modules/sip.js/lib' Did you mean 'index.js'? BREAKING CHANGE: The request './core' failed to resolve only because it was resolved as fully specified (probably because the origin is a '.mjs' file or a '.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request. @ dll renderer renderer[8]

ERROR in ./node_modules/sip.js/lib/index.js 14:0-38 Module not found: Error: Can't resolve './platform/web' in '/Users/msaavedra/cirkelco/gitlab/colabrie-desktop/node_modules/sip.js/lib' Did you mean 'index.js'? BREAKING CHANGE: The request './platform/web' failed to resolve only because it was resolved as fully specified (probably because the origin is a '.mjs' file or a '.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request. @ dll renderer renderer[8]

To Reproduce (if possible) Steps to reproduce the behavior:

  1. added dependency to my project's package.json
  2. "dependencies": { ... "sip.js": "0.19.0", ... },
  3. yarn
  4. See error

Expected behavior Should compile without errors

Observed behavior Sip.js clearly uses ES Modules as of recently, but doesn't specify import file extensions

Environment Information

  • Node.js 15.8.0
  • Electron 11.2.3
  • React 17.0.1

Additional context https://nodejs.org/api/packages.html#packages_package_json_and_file_extensions

msaavedra-cirkelco avatar Feb 09 '21 17:02 msaavedra-cirkelco

Please note this is a webpack 5 specific issue due to a default value change: https://github.com/webpack/webpack/issues/11467

This then points to a typescript issue: https://github.com/microsoft/TypeScript/issues/16577

It appears typescript has made it possible, so we'll get this sorted, but using fullySpecified: false in webpack is the workaround for now.

james-criscuolo avatar Feb 09 '21 17:02 james-criscuolo

Thank you. That workaround did the trick.

msaavedra-cirkelco avatar Feb 09 '21 22:02 msaavedra-cirkelco

I disagree that it's a "webpack 5 specific issue". The files aren't built as compliant ESM files. They're built specifically to work with NodeJS. NodeJS will automatically try to resolve files by adding .js, .mjs or /index.js or /index.mjs. Chopping off the file extension leans heavily on NodeJS fixing improperly specified imports.

For example, if we were to copy and paste the raw files and open it in a browser as ESM modules (eg: Chrome), it'll also fail. The files end in .js, the imports do not. The solution is add the missing extensions or remove them, but they should be match.

In fact, it seems these aren't compatible as written in the NodeJS documentation either:

A file extension must be provided when using the import keyword to resolve relative or absolute specifiers. Directory indexes (e.g. './startup/index.js') must also be fully specified.

This behavior matches how import behaves in browser environments, assuming a typically configured server.

https://nodejs.org/api/esm.html#esm_mandatory_file_extensions

I'm not 100% sure where the issue is, but I believe the .ts files should be importing with the .ts extension. Without it, then the transcompilation will be just as "blind" as the Typescript runtime, depending on the compiler's custom module resolution instead of it being a proper ESM import. I think tsc just passes the bucket and leaves it as in improper as it is in the source code.


Edit: It's also broken in normal NodeJS meaning the ESM modules are invalid. It doesn't run.

node node_modules/sip.js/lib/index.js

internal/process/esm_loader.js:74
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/carlos/projects/test/node_modules/sip.js/lib/version' imported from /home/carlos/projects/test/node_modules/sip.js/lib/index.js
    at new NodeError (internal/errors.js:322:7)
    at finalizeResolution (internal/modules/esm/resolve.js:308:11)
    at moduleResolve (internal/modules/esm/resolve.js:731:10)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:842:11)
    at Loader.resolve (internal/modules/esm/loader.js:89:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:242:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:76:40)
    at link (internal/modules/esm/module_job.js:75:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

That's because lib/index.js tries to import version, not version.js

clshortfuse avatar Dec 02 '21 19:12 clshortfuse

Sorry, did not mean this only impacts webpack 5, but most people hitting this problem at the time would be hitting it due to webpack 5. As time goes on everything will transition to the standard webpack 5 (and others before it) have set, and we should eventually adjust, but for most users, classifying this as a "webpack 5 issue" is likely accurate.

The way to fix it is clear, as you've mentioned, but adding extensions (particularly non-ts extensions in ts files) feels wrong. Maybe since the issue was opened the tools have grown to accommodate this better, but at the time we were looking into a tsc transform, and it did not work so well.

james-criscuolo avatar Dec 02 '21 19:12 james-criscuolo

Sorry, I am still not sure on how is this a webpack issue index.js

import { UserAgent, Web, SessionDescriptionHandlerModifier } from 'sip.js';
console.log(UserAgent);

package.json

{
  "name": "sipjs-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "sip.js": "^0.20.0",
  }
}

node index.js Just this simple file with a normal import gives the same issue

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/yatingera/Desktop/Ringcentral/webphone-helper/node_modules/sip.js/lib/version' imported from /Users/yatingera/Desktop/Ringcentral/webphone-helper/node_modules/sip.js/lib/index.js

Unless, you always run with node --experimental-specifier-resolution=node index.js

nerdchacha avatar Jan 19 '22 10:01 nerdchacha

Got same issues a while ago.

package.json

{
  "name": "scripts",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "build": "webpack ./index.js --output-path ../../wwwroot/js --output-filename index.bundle.js --config webpack.dev.config.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "sip.js": "^0.20.0",
    "webpack": "^5.55.1"
  },
  "devDependencies": {
    "@types/node": "^16.7.10",
    "webpack-cli": "^4.8.0",
    "source-map-loader": "^1.0.0"
  }
}

webpack.dev.config.js

const { SourceMapDevToolPlugin } = require("webpack");
plugins: [
    new SourceMapDevToolPlugin({
        filename: "[file].map"
    }),
]
module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.m?jsx?$/,
                use: ['source-map-loader'],
                resolve: {
                    fullySpecified: false
                },
            }
        ]
    },
    output: {
        sourceMapFilename: "[name].js.map"
    },
    devtool: "source-map"

};

index.js import { UserAgent, Web, SessionDescriptionHandlerModifier } from 'sip.js';

then I pack everything with command npm run build

ErikKalstrom avatar Jan 19 '22 12:01 ErikKalstrom

While we could wait for nodenext module resolution in Typescript, which should launch with v4.6, all that's going to do is force you to use .js extension anyway. Typescript team says they will not remap your import statements in .ts files to automatically append a .js extension.

That is explained here: https://github.com/microsoft/TypeScript/issues/42151

That means, the solution is start adding the .js extensions files now. I will say: it's VERY ugly and feels weird. That said, it'll allow for better tree-shaking, resulting in smaller package sizes.

The other alternative is to move to pure Javascript with JSDoc syntax and use TypeScript for type checking. Basically Typescript is added onto your code, not part of it. That's my preferred method of development, but I understand that would be a larger task.

clshortfuse avatar Jan 19 '22 15:01 clshortfuse

Anyone have a hint on how you'd set this up using craco or something in a React app?

At the moment the library is unusable in a React app.

I tried adding to craco.config.js:

    webpack: {
        configure: (webpackConfig, { env, paths }) => {

            webpackConfig.output = {
                fullySpecified: false
            };
            return webpackConfig;
        }
    },

Didn't seem to change anything though.

MattRiddell avatar Jan 21 '22 14:01 MattRiddell

This is still an issue for anyone trying to install and use sip.js in a default React app created by CRA with TS template.

For now, the workaround for me was npm run eject and then apply this patch:

diff --git a/config/webpack.config.js b/config/webpack.config.js
index 6b4a4cd..3b29fe5 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -343,6 +343,9 @@ module.exports = function (webpackEnv) {
           exclude: /@babel(?:\/|\\{1,2})runtime/,
           test: /\.(js|mjs|jsx|ts|tsx|css)$/,
           loader: require.resolve('source-map-loader'),
+          resolve: {
+            fullySpecified: false,
+          }
         },
         {
           // "oneOf" will traverse all following loaders until one will

(And this is the first time I needed to eject CRA in 4 years.)

Mazuh avatar Jan 27 '22 10:01 Mazuh

Workaround for CRA: Downgrade react-scripts to 4.0.3.

snilek avatar Apr 08 '22 14:04 snilek

How can I use this on backend, I tried to install using NPM and tried to import in one of the JS file and ran node filename.

I got errors, Cannot use import statement outside a module I added type = module in package.json still did not work

got this error Cannot find module '/Users/username/poc/node_modules/sip.js/lib/version' imported from /Users/username/poc/node_modules/sip.js/lib/index.js

saiteja-raikou avatar Jun 20 '22 08:06 saiteja-raikou

I have the same issue. Sorry, I do not understand the solution.

resolve: {
  fullySpecified: false,
}

I will check.

I resolve the issue by hacking sip.js package.json. I remove the line "type": "module",. And It starts working.

The project utilizes Typescript compiler. So it can compile into any type of code. So "type": "module", is redundant. This feature is good for pure written JS libraries. I've been looking over Javascript module systems. It still looks unclear.

victor-shelepen avatar Aug 02 '22 07:08 victor-shelepen

Unfortunately, it also makes the packace unusable for us that you cannot import it in a vanilla Node.js project without workarounds. To me, it sounds like a pretty urgent problem for an npm package. Hopefully there is a neat solution!

Thaigun avatar Aug 09 '22 12:08 Thaigun

Pushed fix to main branch here 930462fbf3bbbc7f04202ff00645672dfdbb912f

Would welcome any feedback and/or testing.

  1. Using TypeScript 4.8 for development
  2. With "type": "module" in package.json
  3. Using NodeNext for TypeScript compiler options module and moduleResolution
  4. Added .js extensions to all imports
  5. Only index.js files now import index.js files
  6. Replaced all imports of index.js in general files with imports of the exact file required
  7. Removed double import of the grammar directory (was imported by index.js and core/messages/index.js)
  8. Tested importing into node.js application
  9. Tested importing into HTML page with script tag specifying type="module"
  10. Tested packing with webpack without using the resolve: { fullySpecified: false }

I think it's backward compatible with 0.20.x (I've dropped it into a few existing projects without any issues), but imagine there are custom build setups with workarounds related to this issue which now might break? I know the idea is addressing this issue will make the need for that kind of thing go away, but suppose I can imagine not being able to drop this in for some setups?

Again, any feedback and/or testing welcome - I'd like to get this right this time around and put it behind us.

john-e-riordan avatar Oct 02 '22 17:10 john-e-riordan

Added to main branch and queued up to go out soon in next release - 0.21.0.

john-e-riordan avatar Oct 21 '22 14:10 john-e-riordan

Module not found: Error: Can't resolve './platform/web' in 'E:\WorkStation\Test\node_modules\sip.js\lib'
Did you mean 'index.js'?
BREAKING CHANGE: The request './platform/web' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

How can I solve this issue?

k-star-229 avatar Oct 24 '22 07:10 k-star-229

You didn't provide any context with regard how to reproduce that message, just reading the error message however, adding index.js to whatever import you have in your Test program will likely fix the issue - import "sip.js/platform/web/index.js";

john-e-riordan avatar Oct 24 '22 13:10 john-e-riordan

Are you using webpack? Just a guess, but if you are you may be able to add fullSpecified: false to workaround the issue - current webpack now wants fully specified paths...

               module: {
                    rules: [
                        {
                            test: /\.m?js$/,
                            resolve: {
                                fullySpecified: false
                            }
                        }
                    ]
                },

john-e-riordan avatar Oct 24 '22 14:10 john-e-riordan