Skip to content

Commit cb7fa00

Browse files
authored
fix: use tsx instead of swc as default bin script transpiler, as swc errors when it encounters 'next/cache' (#7681)
Fixes #7677 - Payload bin scripts were not properly working on windows - Use tsx by default instead of swc, as swc does not handle next/cache imports without the .js at the end - Support other node runtimes through --disable-transpile flag
1 parent a212cde commit cb7fa00

File tree

9 files changed

+107
-54
lines changed

9 files changed

+107
-54
lines changed

docs/admin/components.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ Instead, we utilize component paths to reference React Components. This method e
145145

146146
When constructing the `ClientConfig`, Payload uses the component paths as keys to fetch the corresponding React Component imports from the Import Map. It then substitutes the `PayloadComponent` with a `MappedComponent`. A `MappedComponent` includes the React Component and additional metadata, such as whether it's a server or a client component and which props it should receive. These components are then rendered through the `<RenderComponent />` component within the Payload Admin Panel.
147147

148-
Import maps are regenerated whenever you modify any element related to component paths. This regeneration occurs at startup and whenever Hot Module Replacement (HMR) runs. If the import maps fail to regenerate during HMR, you can restart your application and execute the `payload generate:importmap` command to manually create a new import map.
148+
Import maps are regenerated whenever you modify any element related to component paths. This regeneration occurs at startup and whenever Hot Module Replacement (HMR) runs. If the import maps fail to regenerate during HMR, you can restart your application and execute the `payload generate:importmap` command to manually create a new import map. If you encounter any errors running this command, see the [Troubleshooting](/docs/beta/local-api/outside-nextjs#troubleshooting) section.
149149

150150
### Component paths in external packages
151151

docs/local-api/outside-nextjs.mdx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,27 @@ payload run src/seed.ts
6161
The `payload run` command does two things for you:
6262

6363
1. It loads the environment variables the same way Next.js loads them, eliminating the need for additional dependencies like `dotenv`. The usage of `dotenv` is not recommended, as Next.js loads environment variables differently. By using `payload run`, you ensure consistent environment variable handling across your Payload and Next.js setup.
64-
2. It initializes swc, allowing direct execution of TypeScript files without requiring tools like tsx or ts-node.
64+
2. It initializes tsx, allowing direct execution of TypeScript files manually installing tools like tsx or ts-node.
6565

6666
### Troubleshooting
6767

68-
If you encounter import-related errors, try running the script in TSX mode:
68+
If you encounter import-related errors, you have 2 options:
69+
70+
#### Option 1: enable swc mode by appending `--use-swc` to the `payload` command:
71+
72+
Example:
73+
```sh
74+
payload run src/seed.ts --use-swc
75+
```
76+
77+
Note: Install @swc-node/register in your project first. While swc mode is faster than the default tsx mode, it might break for some imports.
78+
79+
#### Option 2: use an alternative runtime like bun
80+
81+
While we do not guarantee support for alternative runtimes, you are free to use them and disable payloads own transpilation by appending the `--disable-transpilation` flag to the `payload` command:
6982

7083
```sh
71-
payload run src/seed.ts --use-tsx
84+
bunx --bun payload run src/seed.ts --disable-transpile
7285
```
7386

74-
Note: Install tsx in your project first. Be aware that TSX mode is slower than the default swc mode, so only use it if necessary.
87+
You will need to have bun installed on your system for this to work.

packages/graphql/bin.js

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,54 @@
1-
#!/usr/bin/env node
1+
#!/usr/bin/env node --no-deprecation
22

3-
import { register } from 'node:module'
43
import path from 'node:path'
54
import { fileURLToPath, pathToFileURL } from 'node:url'
65

7-
// Allow disabling SWC for debugging
8-
if (process.env.DISABLE_SWC !== 'true') {
6+
const useSwc = process.argv.includes('--use-swc')
7+
const disableTranspile = process.argv.includes('--disable-transpile')
8+
9+
if (disableTranspile) {
10+
// Remove --disable-transpile from arguments
11+
process.argv = process.argv.filter((arg) => arg !== '--disable-transpile')
12+
13+
const start = async () => {
14+
const { bin } = await import('./dist/bin/index.js')
15+
await bin()
16+
}
17+
18+
void start()
19+
} else {
920
const filename = fileURLToPath(import.meta.url)
1021
const dirname = path.dirname(filename)
1122
const url = pathToFileURL(dirname).toString() + '/'
1223

13-
register('@swc-node/register/esm', url)
14-
}
24+
if (!useSwc) {
25+
const start = async () => {
26+
// Use tsx
27+
let tsImport = (await import('tsx/esm/api')).tsImport
1528

16-
const start = async () => {
17-
const { bin } = await import('./dist/bin/index.js')
18-
await bin()
19-
}
29+
const { bin } = await tsImport('./dist/bin/index.js', url)
30+
await bin()
31+
}
2032

21-
void start()
33+
void start()
34+
} else if (useSwc) {
35+
const { register } = await import('node:module')
36+
// Remove --use-swc from arguments
37+
process.argv = process.argv.filter((arg) => arg !== '--use-swc')
38+
39+
try {
40+
register('@swc-node/register/esm', url)
41+
} catch (_) {
42+
console.error(
43+
'@swc-node/register is not installed. Please install @swc-node/register in your project, if you want to use swc in payload run.',
44+
)
45+
}
46+
47+
const start = async () => {
48+
const { bin } = await import('./dist/bin/index.js')
49+
await bin()
50+
}
51+
52+
void start()
53+
}
54+
}

packages/graphql/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"dependencies": {
4444
"graphql-scalars": "1.22.2",
4545
"pluralize": "8.0.0",
46-
"@swc-node/register": "1.10.9",
46+
"tsx": "4.17.0",
4747
"ts-essentials": "7.0.3"
4848
},
4949
"devDependencies": {

packages/payload/bin.js

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,54 @@
11
#!/usr/bin/env node --no-deprecation
22

3-
import { register } from 'node:module'
43
import path from 'node:path'
54
import { fileURLToPath, pathToFileURL } from 'node:url'
65

7-
const useTsx = process.argv.includes('--use-tsx')
6+
const useSwc = process.argv.includes('--use-swc')
7+
const disableTranspile = process.argv.includes('--disable-transpile')
88

9-
// Allow disabling SWC/TSX for debugging
10-
if (process.env.DISABLE_SWC !== 'true' && !useTsx) {
11-
const filename = fileURLToPath(import.meta.url)
12-
const dirname = path.dirname(filename)
13-
const url = pathToFileURL(dirname).toString() + '/'
14-
15-
register('@swc-node/register/esm', url)
9+
if (disableTranspile) {
10+
// Remove --disable-transpile from arguments
11+
process.argv = process.argv.filter((arg) => arg !== '--disable-transpile')
1612

1713
const start = async () => {
1814
const { bin } = await import('./dist/bin/index.js')
1915
await bin()
2016
}
2117

2218
void start()
23-
} else if (useTsx) {
24-
// Remove --use-tsx from arguments
25-
process.argv = process.argv.filter((arg) => arg !== '--use-tsx')
19+
} else {
20+
const filename = fileURLToPath(import.meta.url)
21+
const dirname = path.dirname(filename)
22+
const url = pathToFileURL(dirname).toString() + '/'
23+
24+
if (!useSwc) {
25+
const start = async () => {
26+
// Use tsx
27+
let tsImport = (await import('tsx/esm/api')).tsImport
28+
29+
const { bin } = await tsImport('./dist/bin/index.js', url)
30+
await bin()
31+
}
32+
33+
void start()
34+
} else if (useSwc) {
35+
const { register } = await import('node:module')
36+
// Remove --use-swc from arguments
37+
process.argv = process.argv.filter((arg) => arg !== '--use-swc')
2638

27-
const start = async () => {
28-
// Use tsx
29-
let tsImport
3039
try {
31-
tsImport = (await import('tsx/esm/api')).tsImport
40+
register('@swc-node/register/esm', url)
3241
} catch (_) {
3342
console.error(
34-
'tsx is not installed. Please install tsx in your project, if you want to use tsx in payload run.',
43+
'@swc-node/register is not installed. Please install @swc-node/register in your project, if you want to use swc in payload run.',
3544
)
36-
return
3745
}
3846

39-
const { bin } = await tsImport('./dist/bin/index.js', import.meta.url)
40-
await bin()
41-
}
47+
const start = async () => {
48+
const { bin } = await import('./dist/bin/index.js')
49+
await bin()
50+
}
4251

43-
void start()
52+
void start()
53+
}
4454
}

packages/payload/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
"dependencies": {
8787
"@next/env": "^15.0.0-canary.104",
8888
"@payloadcms/translations": "workspace:*",
89-
"@swc-node/register": "1.10.9",
89+
"tsx": "4.17.0",
9090
"ajv": "8.14.0",
9191
"bson-objectid": "2.0.4",
9292
"ci-info": "^4.0.0",

packages/payload/src/bin/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import minimist from 'minimist'
2+
import { pathToFileURL } from 'node:url'
23
import path from 'path'
34

45
import type { BinScript } from '../config/types.js'
@@ -29,7 +30,7 @@ export const bin = async () => {
2930
process.argv = [process.argv[0], process.argv[1], ...args._.slice(2)]
3031

3132
try {
32-
await import(absoluteScriptPath)
33+
await import(pathToFileURL(absoluteScriptPath).toString())
3334
} catch (error) {
3435
console.error(`Error running script: ${absoluteScriptPath}`)
3536
console.error(error)
@@ -42,7 +43,7 @@ export const bin = async () => {
4243
}
4344

4445
const configPath = findConfig()
45-
const configPromise = await import(configPath)
46+
const configPromise = await import(pathToFileURL(configPath).toString())
4647
let config = await configPromise
4748
if (config.default) config = await config.default
4849

@@ -52,7 +53,7 @@ export const bin = async () => {
5253

5354
if (userBinScript) {
5455
try {
55-
const script: BinScript = await import(userBinScript.scriptPath)
56+
const script: BinScript = await import(pathToFileURL(userBinScript.scriptPath).toString())
5657
await script(config)
5758
} catch (err) {
5859
console.log(`Could not find associated bin script for the ${userBinScript.key} command`)

packages/payload/src/config/find.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ const getTSConfigPaths = (): {
2222
const rootConfigDir = path.resolve(tsConfigDir, tsConfig.compilerOptions.baseUrl || '')
2323
const srcPath = tsConfig.compilerOptions?.rootDir || path.resolve(process.cwd(), 'src')
2424
const outPath = tsConfig.compilerOptions?.outDir || path.resolve(process.cwd(), 'dist')
25-
let configPath = path.resolve(
26-
rootConfigDir,
27-
tsConfig.compilerOptions?.paths?.['@payload-config']?.[0],
28-
)
25+
let configPath = tsConfig.compilerOptions?.paths?.['@payload-config']?.[0]
2926

3027
if (configPath) {
3128
configPath = path.resolve(rootConfigDir, configPath)

pnpm-lock.yaml

Lines changed: 6 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)