fileTypeFromFile not found
kenn opened this issue · 16 comments
Description
import { fileTypeFromFile } from 'file-type'
'"file-type"' has no exported member named 'fileTypeFromFile'. Did you mean 'fileTypeFromBlob'?ts(2724)Existing Issue Check
- I have searched the existing issues and could not find any related to my problem.
ESM (ECMAScript Module) Requirement Acknowledgment
- My project is an ESM project and my
package.jsoncontains the following entry:"type": "module".
File-Type Scope Acknowledgment
- I understand that file-type detects binary file types and not text or other formats.
Can you describe your environment @kenn ?
Which JavaScript engine are you using? Node.js (which version?), browser?
What value is "type" in your package.json?
fileTypeFromFile is a Node.js (back-end) specific function. This Node.js engine only function is only exported via the Node.js entry point:
Lines 14 to 24 in 8dfed93
Ref: https://nodejs.org/api/packages.html#conditional-exports
The error message indicates that fileTypeFromBlob can be resolved, so something on your end has decided the typings should not be loaded as a Node.js engine, but seems to take the "default" (front-end) route, which is lacking the Node.js functions.
Ah I see, setting override in tsconfig.json fixed the problem. Thanks!
"paths": {
"~/*": ["./app/*"],
"file-type": ["./node_modules/file-type/index.d.ts"] // Added override for file-type types
},Um, didn't work. Do you need more information to figure out the issue?
SyntaxError: The requested module 'file-type' does not provide an export named 'fileTypeFromFile'
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)This probably comes down to the fact that the "moduleResolution": "bundler" setting in tsconfig.json (e.g. default in create-next-app setups) instructs TS to not pick up the node conditional export.
Another "solution" would be to add "customConditions": ["node"] to the tsconfig.json, but I suspect this will cause trouble down the line when using modules client-side (in the browser) and suddenly their node exports are being used.
Interestingly, file-type is the first module with which I ran into this problem. Would love to hear about a better fix for this.
Good suggestions @soulchild, stating the Node API dependency somehow in Typescript configuration, is in imho the way to go.
Interestingly, file-type is the first module with which I ran into this problem.
Not so many ECMAScript modules have a Node specific entry point defined I guess.
It looks like that the result of TypeScript compiler option moduleResolution set to bundler is causing the Node entry point not being imported. Not much we can change about that.
To workaround, you now have the following options:
Option #1
Set the node condition in the TypeScript compiler option:
{
"compilerOptions": {
"target": "es2022",
"moduleResolution": "bundler",
"customConditions": ["node"] // Set this condition
}
}Option #2
Import the Node entry point via a subpath import:
import { fileTypeFromFile } from 'file-type/node'Do you mind trying out both options, and let us know the result @kenn ?
Option 1 didn't work
import { fileTypeFromFile } from 'file-type'
^
SyntaxError: The requested module 'file-type' does not provide an export named 'fileTypeFromFile'But Option 2 worked! Thank you @Borewit !
Maybe we should just update README?
Option 1 didn't work
Weird that the Custom Conditions (option 1) does not work, that is literately the use case provided by the TypeScript documentation, how the Custom Conditions can be used.
But Option 2 worked! Thank you @Borewit !
Great, good to have that confirmed!
Maybe we should just update README?
I agree, I think this is worth mentioning in the README, that if for some reason the import conditions do not work, users can force importing the Node entry point via the subpath.
The core.js literally does not export this funtion
Correct, and it should not, as this is the default entry point. Node specific function should not be exposed via the default entry point, they should only be exposed via the node entry point (./index.js).
Please read the full discussion and it will start to make sense.
If a function is only available in a specific context (e.g., Node), this should be reflected in the import itself. eg.
import { fileTypeFromFile } from 'file-type/node'IMHO, export resolution should only be used to switch between different formats (ESM/CJS).
IMHO, export resolution should only be used to switch between different formats (ESM/CJS).
You aren’t a big fan of automatic transmissions in cars either, I suppose?
Setting node statically in the customConditions (option 1) works as well.
{
"moduleResolution": "bundler",
"customConditions": ["node"], // Set this condition
}Using music-metadata with the same conditional export:
Evidence: lowvisiondave/music-metadata-typescript-repro#1

