Borewit/music-metadata

Can not import the library

janwirth opened this issue · 23 comments

Bug description
I can not import the package from node. I spent 10h.

Expected behavior
The package is imported and I can use the parseFile function.

Audio file demonstrating the problem
~/music-metadata
❯ npm i music-metadata

added 17 packages, and audited 18 packages in 1s

8 packages are looking for funding
run npm fund for details

found 0 vulnerabilities

~/music-metadata-test  
❯ node
Welcome to Node.js v18.4.0.
Type ".help" for more information.
> require('music-metadata')
Uncaught:
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/janwirth/music-metadata/node_modules/music-metadata/lib/index.js not supported.
Instead change the require of index.js in null to a dynamic import() which is available in all CommonJS modules.
    at __node_internal_captureLargerStackTrace (node:internal/errors:477:5)
    at new NodeError (node:internal/errors:388:5)
    at Module._extensions..js (node:internal/modules/cjs/loader:1139:19)
    at Module.load (node:internal/modules/cjs/loader:988:32)
    at Module._load (node:internal/modules/cjs/loader:834:12)
    at Module.require (node:internal/modules/cjs/loader:1012:19)
    at require (node:internal/modules/cjs/helpers:102:18) {
  code: 'ERR_REQUIRE_ESM'
}

Downgrading to version 7 solved it for me.

The problem seems to be that the module was changed to a pure ECMAScript Module (ESM) as you can read here: https://www.npmjs.com/package/music-metadata under "Compatibility".

Indeed, version 8 switched from CJS to ESM as mentioned in the v8 change log.
Duplicate of #1218.

Yes, I was really struggling to get it to work with various combinations of transpilation, typescript configurations etc. It would be useful to have a guide on how to set it up. I am running Node 16.15.0 on ts-node.

I was not using require before, but import. I am using this template here: https://github.com/electron-react-boilerplate/electron-react-boilerplate

I don't usually get stuck on stuff like this - I have several years of experience with JS and I'm familiar with all the .mjs, .cjs, type: module, --experimental-modules, magic webpack comments etc. you can do but here I was really out of my luck.

EDIT: I will revisit this with the ts-node guide that I saw in the link to the guide you sent. Thank you.

The lack of backward compatibility in ESM modules is a true nightmare @janwirth.

@Borewit Just faced the same issue, are you sure the ESM exports are matching the CJS exports from v7? It seems like parseFile is not exposed.

"parseFile" is not exported by "node_modules/music-metadata/lib/core.js", imported by "src/main/modules/ipc-library.ts".

content of import * as mmd:

[Object: null prototype] [Module] {
  parseStream: [Function: parseStream],
  parseBuffer: [AsyncFunction: parseBuffer],
  parseFromTokenizer: [Function: parseFromTokenizer],
  orderTags: [Function: orderTags],
  ratingToStars: [Function: ratingToStars],
  selectCover: [Function: selectCover],
  scanAppendingHeaders: [AsyncFunction: scanAppendingHeaders]
}

I am using Vite, not sure if it is related.

I'm building a project with Vite with Electron.

"Instead change the require of C:\Users\user\Documents\nodeProjs\musicplayer-electron\node_modules\music-metadata\lib\index.js in C:\Users\sambi\Documents\nodeProjs\musicplayer-electron\out\main\index.js to a dynamic import() which is available in all CommonJS modules."

I believe that while Electron doesn't support ESM , the Vite - Electron set up I ran does @create-electron

For now I'll downgrade to 7.13 , the Vite CJS -> ESM seems to be working for that version.

For now I'll downgrade to 7.13 , the Vite CJS -> ESM seems to be working for that version.

music-metadata 7.13 is CommonJS, not ESM as already discussed

Electron ES Module support is still an open issue at this point in time.

For now I'll downgrade to 7.13 , the Vite CJS -> ESM seems to be working for that version.

music-metadata 7.13 is CommonJS, not ESM as already discussed

Electron ES Module support is still an open issue at this point in time.

I know and using the Electron-Vite template converts CJS to ESM. So I can use import {parseFile} from 'music-metadata' even though it is v7.13

I am having this same issue but with import - this is running through electron. I'm importing it like so:
import { parseFile } from 'music-metadata';

and yet I get this error:
Uncaught TypeError: Failed to resolve module specifier "music-metadata". Relative references must start with either "/", "./", or "../".
I have absolutely no clue what the problem is.

yeah, parseFile is not available from the default export in v8, when ES Modules are supported in Vite.

Gents, unfortunately I do not have the time to try and test every framework.

I do not mind you to create or contribute to issues here to solve integration challenges, and share recommendations, but in my opinion the issues you describe are not caused by music-metadata.

I offer both CJS (in version 7) and ESM support (in version 8) module at the moment, a time consuming compensation from my end for the poor backward compatibility and lack of ESM clearly taking over. Pick the one you need.

In the ESM module, parseFile() is only exported to Node, as it depends on Node specific API's. Client (browser) side typically follows the non-node path:

That distinction is made here, and is my opinion perfectly valid:

"exports": {
".": {
"node": "./lib/index.js",
"default": "./lib/core.js"
}
},

Regarding using music-metadata in Electron, after having almost the same discussion, see this post

Thanks @Borewit for the details! I'll look deeper into that see what is going wrong exactly for Node.js, thanks for the code pointers!

I'll open a PR if needed :)

csimpi commented

@Borewit
I use it from a very basic typescript project and the same is happening, I cannot use it and can't figure out what's going on.

Basic typescript project, running from the command line.


[INFO] 00:41:07 ts-node-dev ver. 2.0.0 (using ts-node ver. 10.9.1, typescript ver. 4.9.4)
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /music-match/node_modules/music-metadata/lib/index.js
require() of ES modules is not supported.
require() of /music-match/node_modules/music-metadata/lib/index.js from /music-match/src/music-match.ts 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 /music-match/node_modules/music-metadata/package.json.

    at new NodeError (internal/errors.js:322:7)
    at Module._extensions..js (internal/modules/cjs/loader.js:1102:13)
    at require.extensions..jsx.require.extensions..js (/tmp/ts-node-dev-hook-9363314290809173.js:114:20)
    at Object.nodeDevHook [as .js] (/music-match/node_modules/ts-node-dev/lib/hook.js:63:13)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:101:18)
    at Object.<anonymous> (/music-match/src/music-match.ts:8:1)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
[ERROR] 00:41:09 Error: Must use import to load ES Module: /music-match/node_modules/music-metadata/lib/index.js
require() of ES modules is not supported.
require() of /music-match/node_modules/music-metadata/lib/index.js from /music-match/src/music-match.ts 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.

@csimpi please have a look what ES Modules mean:

Looking to the error message, you are using CJS modules in your project. You have 2 options:

  1. Easy: Use music-metadata version 7, this is a CJS module
  2. Harder: Migrate your project to ESM
csimpi commented

@Borewit Thank you, I am using many many JS libraries with no requirement to upgrade. Can't you offer wider compatibility? Just asking, not complaining about.

I offer CJS & ESM, what other compatibility do you want?
There is no difference in functionality between 7 and 8.

csimpi commented

LOL, chill buddy.
The doc didn't mention that 7 and 8 are the same just different module systems, the doc says starting from v8 you drop CJS compatibility. Update your docs, answer less stupid questions after :)

Problem with the documentation or a reader who broadcasts first and then starts reading?

csimpi commented

@Borewit
In the case the documentation contains the information the problem with the reader, in the case the documentation doesn't contain a necessary information or it's not clear, it's the documentation :)

Friendly recommendation: While you are arguing with me and trying to prove something, you could update your doc and close this issue with an answer: I've updated the doc accordingly so this is not a question anymore.