testdouble / quibble

Makes it easy to replace require'd dependencies.
94 stars 25 forks source link

Add support for import alias #69

Open Poyoman39 opened 2 years ago

Poyoman39 commented 2 years ago

Hi quibble team,

I've a feature request. On my project i'm using import alias defined in my package.json like that :

{
  // [ ... ]
  "type": "module",
  "imports": {
    "#src/*": "./*"
  },
  // [ ... ]
}

It looks like quibble loader fails at managing such import. In my .test.js file i tried to replace alias path with await td.replaceEsm('#src/dependencies'); this lead to the following error :

TypeError [ERR_PACKAGE_IMPORT_NOT_DEFINED]: Package import specifier "#src/dependencies" is not defined in package /.../node_modules/quibble/package.json imported from /.../node_modules/quibble/lib/esm-import-functions.js

Full call stack :

      at new NodeError (node:internal/errors:371:5)
      at throwImportNotDefined (node:internal/modules/esm/resolve:442:9)
      at packageImportsResolve (node:internal/modules/esm/resolve:819:3)
      at moduleResolve (node:internal/modules/esm/resolve:973:21)
      at defaultResolve (node:internal/modules/esm/resolve:1080:11)
      at resolve (file:///.../node_modules/quibble/lib/quibble.mjs:12:25)
      at resolve (file:///.../node_modules/quibble/lib/quibble.mjs:20:41)
      at ESMLoader.resolve (node:internal/modules/esm/loader:530:30)
      at ESMLoader.getModuleJob (node:internal/modules/esm/loader:251:18)
      at ESMLoader.import (node:internal/modules/esm/loader:332:22)
      at importModuleDynamically (node:internal/modules/cjs/loader:1042:29)
      at importModuleDynamicallyWrapper (node:internal/vm/module:437:21)
      at importModuleDynamically (node:vm:381:46)
      at importModuleDynamicallyCallback (node:internal/process/esm_loader:35:14)
      at Object.dummyImportModuleToGetAtPath (node_modules/quibble/lib/esm-import-functions.js:8:70)
      at Function.esmImportWithPath (node_modules/quibble/lib/quibble.js:117:35)
      at Object.replaceEsModule (node_modules/testdouble/lib/replace/module/index.js:39:50)
      at Module.replaceEsm (node_modules/testdouble/lib/replace/index.js:23:21)
      at Context.<anonymous> (file:///.../lib/cron/crons/common/utils/parseSalary.test.js:18:14)
      at processImmediate (node:internal/timers:466:21)

I remain available if you need more information

Poyoman39 commented 2 years ago

I don't know the exact way quibble is working internally. But it looks like the problem come from "dummyImportModuleToGetAtPath" function. When it try to "import", the original parentUrl context is lost, then package.json alias are lost too.

searls commented 2 years ago

Paging @giltayar for help! 🙏

giltayar commented 2 years ago

@Poyoman39 I'll look into it.

ghost commented 1 year ago

I'm not sure if this breaks anything, but there's a hacked out change here. It works for my case.

https://github.com/testdouble/quibble/compare/a620990753135cf0bc467968ea787e00bca74fa9...bojavou:quibble:3e92ad3767845c8db677bd86b48dc9ab18b5bc4a

It's like this: Detect private mappings which always start with # and resolve them against the calling package. Use import.meta.resolve to do it. This only runs from a module so it's exposed through a global symbol. It also needs the new CLI flag --experimental-import-meta-resolve.

node --experimental-import-meta-resolve --loader=quibble test.mjs