broofa / mime

Mime types for JavaScript

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

New package exports error with v4.0.0

brev opened this issue · comments

Hi,

Upon upgrading to v4.0.0, I started getting new errors when building my SvelteKit / Vite / TypeScript project:

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './lite.js' is not defined by "exports" in ROOT/node_modules/mime/package.json ...

I think somewhere during transpilation (out of my control), my import mime from 'mime/lite' is getting turned into import mime from 'mime/lite.js', which isn't covered by the current exports in package.json.

I'll submit a quick fix PR very soon.

Thanks for the great module.

Any chance you can put together a minimal, reproduceable test case?

I'd like to avoid defining multiple paths for a single resource in exports if at all possible.

With v4.0.0 I get the error
'getType' is not exported by node_modules/.pnpm/mime@4.0.0/node_modules/mime/dist/src/index_lite.js,

@MartinX3 that sounds like a different problem. Please open a separate issue for that.

Also, -> Be sure to include code demonstrating the issue <- , as it's working for me (see below).

$ node --version
v16.20.2

$ npm ls
foo@ /private/tmp/foo
-- mime@4.0.0

$ cat test.mjs
import mime from 'mime/lite';
console.log(mime.getType);

$ node test.mjs
[Function: getType]

@brev Can you file an issue with Vite/Svelte to get their take on this?

My understanding is that the current setup is consistent with how exports should work, so I'm inclined to argue that this is a bug in the bundler toolchain. That said, I could be wrong. Proper use of the exports field is a bit fuzzy due to the lack of any real Standard™ for it. I may be doing something wrong, but in re-reading the docs nothing's leaping out at me on this. And I'm pretty sure there are other modules with extension-less exports out there. If this is a toolchain issue, it'd be better to fix it at the source.

@broofa

$ node --version
v21.2.0

$ pnpm ls
Legend: production dependency, optional only, dev only

0@1.0.0 /tmp/0

dependencies:
mime 4.0.0

$ cat test.mjs
import { getType } from 'mime/lite';
console.log(getType);

$ node test.mjs
file:///tmp/0/test.mjs:1
import { getType } from 'mime/lite';
         ^^^^^^^
SyntaxError: The requested module 'mime/lite' does not provide an export named 'getType'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:132:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:214:5)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:113:12)

Node.js v21.2.0

It works if I replace { getType } by mime.
But it worked with { getType } in v3.0.0.

@MartinX3 I've created a new issue for your problem here. Please continue discussion there.

Hi @broofa, thanks for the help, sorry for the slow response.

Let me dig in a bit and see what I can find, I'll either post back here, or close this and open an issue elsewhere in the appropriate place. thanks.

Ok, the problem shows up when my current project uses mime@4, and one of my dependencies uses mime@3.

The problem is solved when making sure that my project, and all dependencies, are all upgraded to mime@4.

thanks.

@broofa I still get the error Module not found: Error: Package path ./dist/types/standard.js is not exported from package with dynamic imports in TypeScript:

const { Mime } = await import('mime');
const { default: standardTypes } = await import('mime/dist/types/standard.js');
const mime = new Mime(standardTypes);
mime.define({
    'application/vnd.oasis.opendocument.presentation': ['odp'],
    'application/vnd.oasis.opendocument.spreadsheet': ['ods'],
    'application/vnd.oasis.opendocument.text': ['odt'],
    'application/vnd.openxmlformats-officedocument.presentationml.presentation': ['pptx'],
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['xlsx'],
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['docx'],
});

Using the path without dist instead is not working either. The only way I can get this to work, is when I alter your package.json exports to include the dist path as well:

  "exports": {
    ...
    "./types/standard.js": "./dist/types/standard.js",
    "./dist/types/standard.js": "./dist/types/standard.js",
    ...
  },

Is it possible to export at least both paths? The "old" one and the actual "new" one?

@7freaks-otte 'mime/dist/types/standard.js' is not exposed by exports so that definitely won't work.

Using the [documented] mime/types/standard.js path works fine for me (see below). I'm guessing this is an issue somewhere in your build toolchain.

Maybe put together an MRE that demonstrates the problem and share that here? Not much I can do without being able to reproduce the issue.

$ node --version
v18.17.1

$ npm ls -a
foo@ /private/tmp/foo
`-- mime@4.0.0

$ cat test.mjs
const { Mime } = await import('mime');
const { default: standardTypes } = await import('mime/types/standard.js');

console.log("Types in standardTypes: ", Object.entries(standardTypes).length)

$ node test.mjs
Types in standardTypes:  326

Thanks for your feedback @broofa

I understand that mime/dist/types/standard.js is not supposed to work as you intentionally export mime/types/standard.js instead.

But this results in the TypeScript error error TS2307: Cannot find module 'mime/types/standard.js' or its corresponding type declarations. Somehow I can only get it to work, if I manually add the export entry with dist.

Your hint regarding the build toolchain seems right but is unfortunately beyond my control. I'm including your module in an Angular app and their toolchain @angular-devkit/build-angular includes webpack-dev-server which in turn includes express with send and serve-static => @types/send @types/serve-static => @types/mime.

This seems to be the source of the problem. Not that a submodule includes an old version of mime but that the old @types/mime types are included which seem to confuse module resolution at TypeScript compile time.

From my findings express v5 no longer includes mime, at least not the types, so I need to wait for webpack-dev-server and @angular-devkit/build-angular to upgrade. Thanks anyway.

error TS2307: Cannot find module 'mime/types/standard.js' or its corresponding type declarations.

@7freaks-otte This is why it's really helpful to provide an MRE. This is a different (and possibly valid?) issue that I'd like to understand further. But until I can reproduce it my hands are tied.

For example, here's a stackblitz I created to try to reproduce the issue, but I was only able to trigger a similar-but-not-identical error related to how the module and moduleResolution fields in tsconfig.json are set.

So, I have two "asks":

  1. Comment here and copy-paste the following:
  • Contents of tsconfig.json
  • Contents of package.json
  • Output of npm ls -a
  1. Fork that StackBlitz project and edit it to where it's reproducing your problem. Then share the link for that here.

[Edit: Actually, please create a new issue with the requested information, as this is different from the original issue above]

image

@broofa Thanks for digging into this. I was just about to tell you that I'm going to try to create an MRE as soon as I meet the deadline of an important project.

But I actually think that I just found the solution (though not the exact explanation why the error occurred):

Your stackblitz pretty much matches my configuration except for one entry: Angular projects typically have "moduleResolution": "node". This reproduces the exact error I'm experiencing. (See screenshot above)

As soon as I change moduleResolution to nodenext or bundler the error disappears. Maybe package.json exports are not respected in old node (= node10) module resolution.

Side note: bundler which would be the most appropriate option is not recognised before TypeScript 5. I'm currently on TypeScript 4.9.5 which only understands nodenext. Unfortunately nodenext requires file extensions to be specified on relative imports. So I either need to upgrade to TypeScript 5 or change each and every single import in my project from mime/types/standard to mime/types/standard.js. But that's a different story. 😉

@broofa thank you so much for the care you put on this, I read your explanation, but there is something I miss in it.
With ESM only package all dependency I used moved from main export to many exports, for three shakable, and reduce bundle size.
So I wonder why mine is going the other way than most libs we use, or did a missed something ?