-
Notifications
You must be signed in to change notification settings - Fork 31.9k
Expand file tree
/
Copy pathpatch-next.ts
More file actions
176 lines (153 loc) · 4.3 KB
/
Copy pathpatch-next.ts
File metadata and controls
176 lines (153 loc) · 4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// the script must be run with tsx
import fs from 'fs'
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import path from 'path'
import { NEXT_DIR, exec, execFn, packageFiles } from './pack-util.js'
import buildNative from './build-native.js'
interface Options {
project: string
build: boolean
'build-native': boolean
verbose: number
_: string[]
}
// --- Parse command line arguments ---
const argv = yargs(hideBin(process.argv))
.scriptName('patch-next')
.command(
'$0 <project> [options]',
'Patch local Next.js packages to the target project directory',
(yargs) => {
return yargs
.positional('project', {
type: 'string',
describe: 'Target directory of the Next.js project to patch',
demandOption: true,
})
.example(
'$0 ../my-app --no-build --no-build-native',
'Patch Next.js packages in the "my-app" directory'
)
.example(
'$0 ../my-app -- --release',
'Patch using a release-mode native build. `--release` is passed through to the napi CLI'
)
}
)
.option('build', {
type: 'boolean',
default: true,
description: 'Run the Next.js build step (`pnpm i` and `pnpm build`).',
})
.option('build-native', {
alias: 'native-build',
type: 'boolean',
default: true,
description: 'Run the native modules build step.',
})
.option('verbose', {
type: 'number',
choices: [0, 1, 2, 3],
count: true,
alias: 'v',
description: 'Set the verbosity level (-v: WARN, -vv: INFO, -vvv: DEBUG)',
})
.wrap(null)
.help()
.alias('help', 'h')
.demandCommand(1, 'A project directory is required.')
.strictCommands()
.parse()
const {
project: projectDir,
build,
'build-native': buildNativeEnabled,
verbose: verboseLevel,
_: buildNativeArgs,
} = argv as Options
function WARN(...args: any[]) {
verboseLevel >= 1 && console.warn(...args)
}
function INFO(...args: any[]) {
verboseLevel >= 2 && console.info(...args)
}
function DEBUG(...args: any[]) {
verboseLevel >= 3 && console.log(...args)
}
const PROJECT_DIR = path.resolve(projectDir)
const NEXT_PACKAGES = path.join(NEXT_DIR, 'packages')
function realPathIfAny(path: string): string | null {
try {
return fs.realpathSync(path)
} catch {
return null
}
}
async function copy(src: string, dst: string): Promise<void> {
const realDst = realPathIfAny(dst)
if (!realDst) {
WARN(`[x] Destination path ${dst} does not exist. Skipping copy.`)
return
}
if (realDst && realDst === src) {
WARN(
`[x] Source and destination paths are the same: ${src}. Skipping copy.`
)
return
}
if (!fs.existsSync(src)) {
WARN(`[x] Source path ${src} does not exist. Skipping copy.`)
return
}
const files = await packageFiles(src)
DEBUG(`[x] Found ${files.length} files to copy from ${src}`)
for (const file of files) {
const srcFile = path.join(src, file)
const dstFile = path.join(realDst, file)
DEBUG(`Copying ${srcFile} to ${dstFile}`)
fs.cpSync(srcFile, dstFile, {
recursive: true,
})
}
}
// --- Main execution ---
async function main(): Promise<void> {
if (!fs.existsSync(PROJECT_DIR)) {
console.error(`Error: Project directory "${PROJECT_DIR}" does not exist.`)
process.exit(1)
}
INFO(`[x] Project Directory: ${PROJECT_DIR}`)
INFO(`[x] Next.js Source: ${NEXT_PACKAGES}`)
if (build) {
exec('Install Next.js build dependencies', 'pnpm i')
exec('Build Next.js', 'pnpm run build')
}
if (buildNativeEnabled) {
INFO('Building native modules...')
await buildNative(buildNativeArgs)
}
const packagesToPatch = [
{ name: 'next', path: 'next' },
{ name: '@next/swc', path: 'next-swc' },
{ name: '@next/mdx', path: 'next-mdx' },
{ name: '@next/bundle-analyzer', path: 'next-bundle-analyzer' },
]
INFO(
`[x] Patching packages: ${packagesToPatch.map((pkg) => pkg.name).join(', ')}`
)
for (const pkg of packagesToPatch) {
await execFn(`Patching ${pkg.name}`, () =>
copy(
path.join(NEXT_PACKAGES, pkg.path),
path.join(PROJECT_DIR, 'node_modules', pkg.name)
)
)
}
console.log(`\n\x1b[1;4mPatching complete!\x1b[0m\n`)
}
main().catch((e) => {
console.error('An unexpected error occurred:')
console.error(e)
process.exit(1)
})