metarhia/impress

Module loader is trying to load submodules that use optional dependencies

DmitryScaletta opened this issue · 0 comments

Describe the bug

By default the module loader loads all submodules in an exports field of a package.json file.
But some packages can have optional peer dependencies, and some of their submodules can use different optional dependencies.

For example drizzle-orm.

package.json
{
  "peerDependencies": {
    "@aws-sdk/client-rds-data": ">=3",
    "@cloudflare/workers-types": ">=3",
    "@libsql/client": "*",
    "@neondatabase/serverless": ">=0.1",
    "@opentelemetry/api": "^1.4.1",
    "@planetscale/database": ">=1",
    "@types/better-sqlite3": "*",
    "@types/pg": "*",
    "@types/sql.js": "*",
    "@vercel/postgres": "*",
    "better-sqlite3": ">=7",
    "bun-types": "*",
    "knex": "*",
    "kysely": "*",
    "mysql2": ">=2",
    "pg": ">=8",
    "postgres": ">=3",
    "sql.js": ">=1",
    "sqlite3": ">=5"
  },
  "peerDependenciesMeta": {
    "mysql2": {
      "optional": true
    },
    "@vercel/postgres": {
      "optional": true
    },
    "better-sqlite3": {
      "optional": true
    },
    "@types/better-sqlite3": {
      "optional": true
    },
    "sqlite3": {
      "optional": true
    },
    "sql.js": {
      "optional": true
    },
    "@types/sql.js": {
      "optional": true
    },
    "@cloudflare/workers-types": {
      "optional": true
    },
    "pg": {
      "optional": true
    },
    "@types/pg": {
      "optional": true
    },
    "postgres": {
      "optional": true
    },
    "@neondatabase/serverless": {
      "optional": true
    },
    "bun-types": {
      "optional": true
    },
    "@aws-sdk/client-rds-data": {
      "optional": true
    },
    "@planetscale/database": {
      "optional": true
    },
    "knex": {
      "optional": true
    },
    "kysely": {
      "optional": true
    },
    "@libsql/client": {
      "optional": true
    },
    "@opentelemetry/api": {
      "optional": true
    }
  },
}
Object.keys(pkg.exports)
[
  '.',
  './aws-data-api/pg',
  './aws-data-api/pg/migrator',
  './better-sqlite3',
  './better-sqlite3/migrator',
  './bun-sqlite',
  './bun-sqlite/migrator',
  './d1',
  './d1/migrator',
  './vercel-postgres/migrator',
  './vercel-postgres',
  './knex',
  './kysely',
  './libsql',
  './libsql/migrator',
  './mysql-core',
  './mysql2',
  './mysql2/migrator',
  './neon-serverless',
  './neon-serverless/migrator',
  './neon-http',
  './neon-http/migrator',
  './node-postgres',
  './node-postgres/migrator',
  './pg-core',
  './planetscale-serverless',
  './planetscale-serverless/migrator',
  './postgres-js',
  './postgres-js/migrator',
  './sql-js',
  './sql-js/migrator',
  './sqlite-core',
  './sqlite-proxy',
  './sqlite-proxy/migrator',
  './migrator',
  './version'
]

For postgres you only need submodules drizzle-orm/node-postgres and drizzle-orm/pg-core that require the pg package.

But the loader is trying to load all submodules, and the first of them uses an optional @aws-sdk/client-rds-data dependency, which is of course not installed if you plan to use only postgres, and it crashes.

impress/lib/deps.js

Lines 50 to 61 in 4cabe81

const loadModule = (name) => {
const lib = appRequire(name);
const pkg = require(`${CWD}/node_modules/${name}/package.json`);
if (!pkg.exports) return lib;
const subKeys = Object.keys(pkg.exports).map((key) => key.substring(2));
const subNames = subKeys.filter(validSubmodules);
for (const subName of subNames) {
const sub = appRequire(name + '/' + subName);
lib[subName] = sub;
}
return lib;
};

To Reproduce

  1. Run npm i drizzle-orm@0.28.6
  2. Run npm start
  3. See a module loading error
> node server.js

21:09:12  W1   error   Can not load modules: drizzle-orm
21:09:12  W0   info    Can not start Application server
 ELIFECYCLE  Command failed with exit code 1.

Additional context

The issue is not about the drizzle-orm itself or any other orm.
Some other packages may also use this pattern.