-
Notifications
You must be signed in to change notification settings - Fork 5.4k
[Feature]: Support Node.js subpath imports (package.json imports field) #40062
Description
🚀 Feature Request
Playwright's module resolver does not resolve Node.js subpath imports, i.e. specifiers starting with # that are mapped via the imports field of package.json. Only tsconfig.json paths aliases are currently supported, as documented here.
Example
Given the following package.json:
{
"imports": {
"#utils/*": "./src/utils/*.ts"
}
}And a test file or config using:
// playwright.config.ts
import { getEnvVar } from '#utils/env';Running npx playwright test fails with:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/project/internals/e2e-tests/src/utils/env'
imported from /project/internals/e2e-tests/playwright.config.ts
at finalizeResolution (node:internal/modules/esm/resolve:275:11)
at moduleResolve (node:internal/modules/esm/resolve:865:10)
at defaultResolve (node:internal/modules/esm/resolve:991:11)
at nextResolve (node:internal/modules/esm/hooks:785:28)
at resolve (.../playwright@1.59.1/node_modules/playwright/lib/transform/esmLoader.js:39:24)
...
code: 'ERR_MODULE_NOT_FOUND'
The stack trace shows the failure originates in Playwright's own esmLoader.js.
Motivation
Node.js subpath imports have been stable since Node.js 14.6.0. TypeScript added auto-import support for subpath imports in 5.4, and TypeScript 6.0 extended that further by supporting the #/ prefix syntax under nodenext and bundler moduleResolution. The TypeScript toolchain is clearly treating subpath imports as a first-class feature going forward.
Subpath imports are increasingly recommended over TSConfig paths for new projects, because they are handled natively by Node.js at runtime with no extra tooling or loader registration needed. They are also the only standard way to get import aliases in a plain JavaScript project, where TSConfig paths is not an option.
The current situation forces users into one of these workarounds:
- Duplicate all aliases in TSConfig
pathsas well, which is redundant and diverges from the Node.js runtime semantics. - Pre-compile tests with
tscbefore running Playwright, which adds overhead and friction to the dev loop.
Neither is acceptable when the whole point of subpath imports is to avoid that duplication and stay close to Node.js semantics. This is particularly painful in monorepos where subpath imports are defined at the package level and are expected to work consistently across the whole toolchain.
I think that this is not a Babel transform concern, it is a module resolution concern, which is where TSConfig paths support already lives?