Skip to content

getExports used for node v20, v18.19.0 doesn't handle reexports #29

@trentm

Description

@trentm

import-in-the-middle hooking of a CommonJS module that has reexports breaks usage of that module. For example:

% node --version v20.2.0 % cat foo.mjs import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3'; console.log('hi'); % node foo.mjs hi % node --experimental-loader=import-in-the-middle/hook.mjs foo.mjs (node:91931) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) file:///Users/trentm/tmp/iitm-node20-exports/foo.mjs:1 import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3'; ^^^^^^^^^^^^^^^^^^ SyntaxError: The requested module '@aws-sdk/client-s3' does not provide an export named 'ListBucketsCommand' at ModuleJob._instantiate (node:internal/modules/esm/module_job:122:21) at async ModuleJob.run (node:internal/modules/esm/module_job:188:5) Node.js v20.2.0 

Steps to Reproduce the Problem

  1. Save this "package.json":
{ "name": "iitm-node20-exports", "version": "1.0.0", "license": "MIT", "dependencies": { "@aws-sdk/client-s3": "^3.363.0", "import-in-the-middle": "^1.4.1" } }
  1. Save this "foo.mjs":
import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3'; console.log('hi');
  1. Run this (using node v20):
node --experimental-loader=import-in-the-middle/hook.mjs foo.js 

details

Adding this console.log to import-in-the-middle/lib/get-exports.js:

 if (format === 'commonjs') { console.log('XXX IITM getCjsExports of url %s\n-- source --\n%s\n-- parsed --\n%o\n--', url, source, getCjsExports(source)) return addDefault(getCjsExports(source).exports) }
and re-running:
% node --experimental-loader=import-in-the-middle/hook.mjs foo.mjs (node:96950) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) XXX IITM getCjsExports of url file:///Users/trentm/tmp/iitm-node20-exports/node_modules/@aws-sdk/client-s3/dist-cjs/index.js -- source -- "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.S3ServiceException = void 0; const tslib_1 = require("tslib"); tslib_1.__exportStar(require("./S3Client"), exports); tslib_1.__exportStar(require("./S3"), exports); tslib_1.__exportStar(require("./commands"), exports); tslib_1.__exportStar(require("./pagination"), exports); tslib_1.__exportStar(require("./waiters"), exports); tslib_1.__exportStar(require("./models"), exports); var S3ServiceException_1 = require("./models/S3ServiceException"); Object.defineProperty(exports, "S3ServiceException", { enumerable: true, get: function () { return S3ServiceException_1.S3ServiceException; } }); -- parsed -- { exports: [ '__esModule', 'S3ServiceException', [length]: 2 ], reexports: [ './S3Client', './S3', './commands', './pagination', './waiters', './models', [length]: 6 ] } -- XXX IITM getCjsExports of url file:///Users/trentm/tmp/iitm-node20-exports/node_modules/@aws-sdk/client-s3/dist-cjs/index.js -- source -- "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.S3ServiceException = void 0; const tslib_1 = require("tslib"); tslib_1.__exportStar(require("./S3Client"), exports); tslib_1.__exportStar(require("./S3"), exports); tslib_1.__exportStar(require("./commands"), exports); tslib_1.__exportStar(require("./pagination"), exports); tslib_1.__exportStar(require("./waiters"), exports); tslib_1.__exportStar(require("./models"), exports); var S3ServiceException_1 = require("./models/S3ServiceException"); Object.defineProperty(exports, "S3ServiceException", { enumerable: true, get: function () { return S3ServiceException_1.S3ServiceException; } }); -- parsed -- { exports: [ '__esModule', 'S3ServiceException', [length]: 2 ], reexports: [ './S3Client', './S3', './commands', './pagination', './waiters', './models', [length]: 6 ] } -- file:///Users/trentm/tmp/iitm-node20-exports/foo.mjs:1 import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3'; ^^^^^^^^^^^^^^^^^^ SyntaxError: The requested module '@aws-sdk/client-s3' does not provide an export named 'ListBucketsCommand' at ModuleJob._instantiate (node:internal/modules/esm/module_job:122:21) at async ModuleJob.run (node:internal/modules/esm/module_job:188:5) Node.js v20.2.0 

That shows the "reexports" I'm referring to.

I was kind of surprised that cjs-module-lexer recognized tslib_1.__exportStar(require("./S3Client"), exports); and similar as a "reexport". Does it have particular smarts about tslib or is it parsing and/or executing tslib?

Does import-in-the-middle want/need to get into recursively handling these "reexports"?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions