microsoft / microsoft/playwright
[Feature]: Support Node.js subpath imports (`package.json` `imports` field)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 96.3k
- Forks
- 6.5k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 180
Description
### 🚀 Feature Request
Playwright's module resolver does not resolve Node.js [subpath imports](https://nodejs.org/api/packages.html#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](https://playwright.dev/docs/test-typescript#tsconfig-path-mapping).
### Example
Given the following `package.json`:
```json
{
"imports": {
"#utils/*": "./src/utils/*.ts"
}
}
```
And a test file or config using:
```ts
// 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](https://nodejs.org/api/packages.html#subpath-imports). TypeScript added [auto-import support for subpath imports in 5.4](https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/#auto-import-support-for-subpath-imports), and TypeScript 6.0 extended that further by [supporting the `#/` prefix syntax](https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/) 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 `paths` as well, which is redundant and diverges from the Node.js runtime semantics.
- Pre-compile tests with `tsc` before 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?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with Playwright's lib/transform/esmLoader.js, where the issue's stack trace places the failure, and compare its existing tsconfig.json paths resolution with Node.js package imports. Use the package.json and playwright.config.ts example to trace resolution of #utils/env. Done means the shown subpath import resolves when running npx playwright test without duplicating the alias in tsconfig.json.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- testing-qa, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100