@swc-node/register — Files are not transpiled on Windows with tsconfig.json present
Describe the bug
I cannot reproduce this with the playground or CLI, only with @swc-node/register
node --import @swc-node/register/esm-register ./index.ts
file:///C:/New%20folder/index.ts:1
declare global {
^^^^^^
SyntaxError: Unexpected identifier 'global'
at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:167:18)
at callTranslator (node:internal/modules/esm/loader:285:14)
at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:291:30)
at async link (node:internal/modules/esm/module_job:76:21)
This issue ONLY occurs when a tsconfig.json is present. Even if it is completely blank (0 bytes; not even {}). Same issue occurs with recommended tsconfig.json compilerOptions. If tsconfig.json is deleted, this issue doesn't occur.
Steps to reproduce
pnpm initpnpm add -D @swc-node/register- Paste input code from below into
./index.ts. touch tsconfig.jsonnode --import @swc-node/register/esm-register ./index.ts
Input code
// Also happens with declare module 'xxx'
declare global {
namespace Express {
interface Locals {
cspNonce?: string
}
}
}
Config
No config.
Playground link (or link to the minimal reproduction)
https://play.swc.rs/?version=1.4.0&code=H4sIAAAAAAAAAz2OzQrCMBCE74W8w9yqr2ART97Ed4jrtgbyx24OQum7a5roZZaZD3bGhZykgN9ZWBWzpICxu3Eyg2v8xT5w6biZSs3wZPJWGItPD%2BuxmgGINrBmS4xrf7vHgIuFZa7glsj6fw6Q5nuKxJcTtIiLy9TIVs9XttpFKWqBzRnn3%2BDDcV%2FxAXF5lWHGAAAA&config=H4sIAAAAAAAAA1VPOw7DIAzdOQXy3KFi6NA79BCIOhERAYQdqSjK3QsJpM1mv4%2Ff8yqkhIkMPOVaxrJEnQjTuReEsmf9KQhwjkgm2chw6yxTpQbtCHdoOxhgnUbk6kJSd6WaA1wIhN3RsNl6O%2BT%2FTBPmmJDoKqxS7UeH10TRUmEO72Un2y%2B179HgAT9RDzsPg6VXd3JaUGxfBMLf3xcBAAA%3D
SWC Info output
Operating System:
Platform: win32
Arch: x64
Machine Type: x86_64
Version: Windows 11 Enterprise
CPU: (24 cores)
Models: AMD Ryzen 9 5900X 12-Core Processor
Binaries:
Node: 20.11.0
npm: N/A
Yarn: N/A
pnpm: N/A
Relevant Packages:
@swc/core: N/A
@swc/helpers: N/A
@swc/types: N/A
SWC Config:
output: N/A
.swcrc path: N/A
Next.js info:
output: N/A
Above output seems broken. pnpm --version: 18.15.2
pnpm list --depth Infinity
New [email protected] C:\New folder
devDependencies:
@swc-node/register 1.8.0
├─┬ @swc-node/core 1.12.0
│ ├─┬ @swc/core 1.4.1 peer
│ │ ├── @swc/core-darwin-arm64 1.4.1
│ │ ├── @swc/core-darwin-x64 1.4.1
│ │ ├── @swc/core-linux-arm-gnueabihf 1.4.1
│ │ ├── @swc/core-linux-arm64-gnu 1.4.1
│ │ ├── @swc/core-linux-arm64-musl 1.4.1
│ │ ├── @swc/core-linux-x64-gnu 1.4.1
│ │ ├── @swc/core-linux-x64-musl 1.4.1
│ │ ├── @swc/core-win32-arm64-msvc 1.4.1
│ │ ├── @swc/core-win32-ia32-msvc 1.4.1
│ │ ├── @swc/core-win32-x64-msvc 1.4.1
│ │ ├── @swc/counter 0.1.3
│ │ └── @swc/types 0.1.5
│ └── @swc/types 0.1.5 peer
├─┬ @swc-node/sourcemap-support 0.4.0
│ ├─┬ source-map-support 0.5.21
│ │ ├── buffer-from 1.1.2
│ │ └── source-map 0.6.1
│ └── tslib 2.6.2
├─┬ @swc/core 1.4.1 peer
│ ├── @swc/core-darwin-arm64 1.4.1
│ ├── @swc/core-darwin-x64 1.4.1
│ ├── @swc/core-linux-arm-gnueabihf 1.4.1
│ ├── @swc/core-linux-arm64-gnu 1.4.1
│ ├── @swc/core-linux-arm64-musl 1.4.1
│ ├── @swc/core-linux-x64-gnu 1.4.1
│ ├── @swc/core-linux-x64-musl 1.4.1
│ ├── @swc/core-win32-arm64-msvc 1.4.1
│ ├── @swc/core-win32-ia32-msvc 1.4.1
│ ├── @swc/core-win32-x64-msvc 1.4.1
│ ├── @swc/counter 0.1.3
│ └── @swc/types 0.1.5
├── colorette 2.0.20
├─┬ debug 4.3.4
│ └── ms 2.1.2
├── pirates 4.0.6
├── tslib 2.6.2
└── typescript 5.3.3 peer
Expected behavior
Node shouldn't throw a syntax error.
Actual behavior
No response
Version
See above.
Additional context
No response
cc @Brooooooklyn
I've narrowed the issue down.
TL;DR
compile function here checks to see if filename is contained in options.files to determine whether to transpile but that will always be true as the string passed by Node.JS to filename starts with file:/// while the string it checks against doesn't.
This issue isn't present without tsconfig.json because options.files is not set when tsconfig.json is not present.
Detailed Description
The string passed to the filename parameter of the compile function here starts with file:///. When a tsconfig is parsed, files is attached to options argument of compile here. When the files property is present, compile will check to see if filename is contained in files. However, on the PLATFORM === 'win32' branch, filename !== resolve(process.cwd(), file) will always be true as the right hand side of the conditional expression does not start with file:/// while the left hand side does. That means files will never be transpiled.
On a second note, the check on Windows will never work anyways because path.resolve converts the separators to the Windows version while filename uses POSIX-style separators. Maybe instead of filename !== resolve(process.cwd(), file), use !normalize(filename).endsWith(resolve(process.cwd(), file)).
Related: https://github.com/swc-project/swc-node/issues/710#issuecomment-1755713552
I've mentioned in my comment here, to fix the issue the protocol can be removed using fileUrlToPath