mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
7a2f4ad140
The file already had the `@ts-check` directive, so the IDE did show errors in that file. But since it was not included in the root `tsconfig.json`, those errors were not reported during CI runs. One issue found this way was that the `related` flag was defined but never used. The referenced script was removed in #67644.
177 lines
4.3 KiB
TypeScript
177 lines
4.3 KiB
TypeScript
// 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)
|
|
})
|