nodejs / import-in-the-middle

Like `require-in-the-middle`, but for ESM import
https://www.npmjs.com/package/import-in-the-middle
Apache License 2.0
52 stars 20 forks source link

SyntaxError on importing some packages when using register() #107

Open TheAsda opened 2 weeks ago

TheAsda commented 2 weeks ago

I'm using the ts-rest library. Without iitm it works just fine, but when i add iitm with register or --loader it throws SyntaxError: The requested module '@ts-rest/core' does not provide an export named 'initContract'.

Steps to Reproduce the Problem

Here is the reproduction repo. There are three scripts:

Specifications

Library version: 1.8.0 Node version: 20.11.1

TheAsda commented 2 weeks ago

If i remove "exports" section from ts-rest's package.json everything works fine

TheAsda commented 2 weeks ago

Looks like ts-rest has some weird bundling and "import" field in "exports" actually reexports cjs module as esm thus iitm fails to parse exported modules and proxies zero exports

TheAsda commented 2 weeks ago

I found a workaround:

import { createRequire } from 'module';

const require = createRequire(import.meta.url);
const core = require('@ts-rest/core');
const { initContract } = core;
TheAsda commented 2 weeks ago

Looks like the issue comes from parsing exported modules. If you launch without iitm hook it loads cjs version of package then mjs. iitm parses wrong export and produces wrong virtual proxy file for the library

TheAsda commented 2 weeks ago

Looks like for some reason iitm treats package as cjs even though it has esm export

timfish commented 2 weeks ago

for some reason iitm treats package as cjs even though it has esm export

Loader hooks (including iitm) load ESM and CJS loaded via ESM modules.

iitm v1.8.1 has been released. Have you tried that yet?

TheAsda commented 2 weeks ago

I'll try later today

TheAsda commented 2 weeks ago

Still error but this time with more details

Error ``` Error: 'import-in-the-middle' failed to wrap 'file:////temp/ts-rest-iitm-issue/node_modules/@ts-rest/core/index.cjs.mjs' at getSource (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:304:21) at async load (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:319:26) at async nextLoad (node:internal/modules/esm/hooks:865:22) at async Hooks.load (node:internal/modules/esm/hooks:448:20) at async MessagePort.handleMessage (node:internal/modules/esm/worker:196:18) { cause: TypeError: emitImportAssertionWarning is not a function at defaultLoad (node:internal/modules/esm/load:119:5) at nextLoad (node:internal/modules/esm/hooks:865:28) at getExports (\ts-rest-iitm-issue\node_modules\import-in-the-middle\lib\get-exports.js:80:27) at processModule (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:131:29) at getSource (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:269:31) at load (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:319:32) at nextLoad (node:internal/modules/esm/hooks:865:28) at Hooks.load (node:internal/modules/esm/hooks:448:26) at MessagePort.handleMessage (node:internal/modules/esm/worker:196:24) at [nodejs.internal.kHybridDispatch] (node:internal/event_target:826:20) } file:////temp/ts-rest-iitm-issue/app.js:1 import { initContract } from "@ts-rest/core"; ^^^^^^^^^^^^ SyntaxError: The requested module '@ts-rest/core' does not provide an export named 'initContract' 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 v20.11.1 ```

Here is the reproduction brand https://github.com/TheAsda/iitm-ts-rest-issue/tree/v1.8.1

TheAsda commented 2 weeks ago

The ".cjs.mjs" file reexports cjs module with export image image

TheAsda commented 2 weeks ago

If i replace "import" section with actual esm file different error occurs.

Error ``` Error: 'import-in-the-middle' failed to wrap 'file:////ts-rest-iitm-issue/node_modules/@ts-rest/core/index.esm.js' at getSource (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:304:21) at async load (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:319:26) at async nextLoad (node:internal/modules/esm/hooks:865:22) at async Hooks.load (node:internal/modules/esm/hooks:448:20) at async MessagePort.handleMessage (node:internal/modules/esm/worker:196:18) { cause: Error: Unexpected export statement in CJS module. at @:461:8 at esmSyntaxErr (\ts-rest-iitm-issue\node_modules\cjs-module-lexer\lexer.js:1153:24) at throwIfExportStatement (\ts-rest-iitm-issue\node_modules\cjs-module-lexer\lexer.js:1193:9) at parseSource (\ts-rest-iitm-issue\node_modules\cjs-module-lexer\lexer.js:155:13) at parseCJS (\ts-rest-iitm-issue\node_modules\cjs-module-lexer\lexer.js:43:5) at getCjsExports (\ts-rest-iitm-issue\node_modules\import-in-the-middle\lib\get-exports.js:37:20) at getExports (\ts-rest-iitm-issue\node_modules\import-in-the-middle\lib\get-exports.js:100:12) at async processModule (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:131:23) at async getSource (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:269:25) at async load (\ts-rest-iitm-issue\node_modules\import-in-the-middle\hook.js:319:26) at async nextLoad (node:internal/modules/esm/hooks:865:22) { code: 'ERR_LEXER_ESM_SYNTAX', loc: 15778 } } node:internal/modules/esm/translators:116 throw new ERR_INVALID_RETURN_PROPERTY_VALUE( ^ TypeError [ERR_INVALID_RETURN_PROPERTY_VALUE]: Expected string, array buffer, or typed array to be returned for the "source" from the "load" function but got undefined. at assertBufferSource (node:internal/modules/esm/translators:116:9) at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:163:3) at callTranslator (node:internal/modules/esm/loader:285:14) at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:291:30) { code: 'ERR_INVALID_RETURN_PROPERTY_VALUE' } Node.js v20.11.1 ```
TheAsda commented 2 weeks ago

So the ".esm.js" file is an actual esm module that exports a bunch of properties image But it's being treated as cjs module for some reason

TheAsda commented 2 weeks ago

And the behavior when i remove "exports" from the package's package.json and app works fine persists

TheAsda commented 2 weeks ago

Currently i found a "fix" what temporarily fixes. I'm patching @ts-rest/core package with yarn patch and put cjs entrypoint to the "import" and using dynamic import(). image It looks weird but works)