Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
259 lines
7.7 KiB
TypeScript
259 lines
7.7 KiB
TypeScript
// This script must be run with tsx
|
|
|
|
import fs from 'node:fs/promises'
|
|
import yargs from 'yargs'
|
|
import { hideBin } from 'yargs/helpers'
|
|
import { default as patchPackageJson } from './pack-utils/patch-package-json.js'
|
|
import buildNative from './build-native.js'
|
|
|
|
import {
|
|
NEXT_DIR,
|
|
exec,
|
|
execAsyncWithOutput,
|
|
glob,
|
|
packageFiles,
|
|
} from './pack-util.js'
|
|
|
|
const TARBALLS = `${NEXT_DIR}/tarballs`
|
|
const NEXT_PACKAGES = `${NEXT_DIR}/packages`
|
|
const NEXT_TARBALL = `${TARBALLS}/next.tar`
|
|
const NEXT_SWC_TARBALL = `${TARBALLS}/next-swc.tar`
|
|
const NEXT_MDX_TARBALL = `${TARBALLS}/next-mdx.tar`
|
|
const NEXT_ENV_TARBALL = `${TARBALLS}/next-env.tar`
|
|
const NEXT_BA_TARBALL = `${TARBALLS}/next-bundle-analyzer.tar`
|
|
|
|
type CompressOpt = 'none' | 'strip' | 'objcopy-zlib' | 'objcopy-zstd'
|
|
|
|
const cliOptions = yargs(hideBin(process.argv))
|
|
.scriptName('pack-next')
|
|
.command('$0', 'Pack Next.js for testing in external projects')
|
|
.option('js-build', {
|
|
type: 'boolean',
|
|
default: true,
|
|
describe:
|
|
'Build JavaScript code (default). Use `--no-js-build` to skip building JavaScript',
|
|
})
|
|
.option('project', {
|
|
alias: 'p',
|
|
type: 'string',
|
|
})
|
|
.option('tar', {
|
|
type: 'boolean',
|
|
describe: 'Create tarballs instead of direct reflinks',
|
|
})
|
|
.option('compress', {
|
|
describe:
|
|
'How compress the binary, useful on platforms where tarballs can ' +
|
|
'exceed 2 GiB, which causes ERR_FS_FILE_TOO_LARGE with pnpm. Defaults ' +
|
|
'to "strip" on Linux, otherwise defaults to "none". Requires `--tar` ' +
|
|
'to be set.',
|
|
choices: [
|
|
'none',
|
|
'strip',
|
|
...(process.platform === 'linux'
|
|
? (['objcopy-zlib', 'objcopy-zstd'] as const)
|
|
: ([] as const)),
|
|
] as const,
|
|
})
|
|
.check((opts) => {
|
|
const compress = opts.compress
|
|
if (!opts.tar && (compress ?? 'none') !== 'none') {
|
|
throw new Error('--compress is only valid in combination with --tar')
|
|
}
|
|
return true
|
|
})
|
|
.middleware((opts) => {
|
|
if (opts.tar && process.platform === 'linux' && opts.compress == null) {
|
|
opts.compress = 'strip'
|
|
}
|
|
})
|
|
.strict().argv
|
|
|
|
interface PackageFiles {
|
|
nextFile: string
|
|
nextMdxFile: string
|
|
nextEnvFile: string
|
|
nextBaFile: string
|
|
nextSwcFile: string
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
if (cliOptions.jsBuild) {
|
|
exec('Install Next.js build dependencies', 'pnpm i')
|
|
exec('Build Next.js', 'pnpm run build')
|
|
}
|
|
|
|
if (cliOptions.tar && cliOptions.compress !== 'strip') {
|
|
// HACK: delete any pre-existing binaries to force napi-rs to rewrite it
|
|
// We must do this as pre-existing could've been stripped.
|
|
let binaries = await nextSwcBinaries()
|
|
await Promise.all(binaries.map((bin) => fs.rm(bin)))
|
|
}
|
|
|
|
await buildNative(cliOptions._ as string[])
|
|
|
|
if (cliOptions.tar) {
|
|
await fs.mkdir(TARBALLS, { recursive: true })
|
|
|
|
// build all tarfiles in parallel
|
|
await Promise.all([
|
|
packNextSwcWithTar(cliOptions.compress ?? 'none'),
|
|
...[
|
|
[`${NEXT_PACKAGES}/next`, NEXT_TARBALL],
|
|
[`${NEXT_PACKAGES}/next-mdx`, NEXT_MDX_TARBALL],
|
|
[`${NEXT_PACKAGES}/next-env`, NEXT_ENV_TARBALL],
|
|
[`${NEXT_PACKAGES}/next-bundle-analyzer`, NEXT_BA_TARBALL],
|
|
].map(([packagePath, tarballPath]) =>
|
|
packWithTar(packagePath, tarballPath)
|
|
),
|
|
])
|
|
}
|
|
|
|
const packageFiles = getPackageFiles(cliOptions.tar)
|
|
|
|
if (cliOptions.project != null) {
|
|
const patchedPath = await patchPackageJson(cliOptions.project, {
|
|
nextTarball: packageFiles.nextFile,
|
|
nextMdxTarball: packageFiles.nextMdxFile,
|
|
nextEnvTarball: packageFiles.nextEnvFile,
|
|
nextBundleAnalyzerTarball: packageFiles.nextBaFile,
|
|
nextSwcTarball: packageFiles.nextSwcFile,
|
|
})
|
|
console.log(`Patched ${patchedPath}`)
|
|
} else {
|
|
console.log('Add the following overrides to your workspace package.json:')
|
|
console.log(` "pnpm": {`)
|
|
console.log(` "overrides": {`)
|
|
console.log(
|
|
` "next": ${JSON.stringify(`file:${packageFiles.nextFile}`)},`
|
|
)
|
|
console.log(
|
|
` "@next/mdx": ${JSON.stringify(`file:${packageFiles.nextMdxFile}`)},`
|
|
)
|
|
console.log(
|
|
` "@next/env": ${JSON.stringify(`file:${packageFiles.nextEnvFile}`)},`
|
|
)
|
|
console.log(
|
|
` "@next/bundle-analyzer": ${JSON.stringify(`file:${packageFiles.nextBaFile}`)}`
|
|
)
|
|
console.log(` }`)
|
|
console.log(` }`)
|
|
console.log()
|
|
console.log(
|
|
'Add the following dependencies to your workspace package.json:'
|
|
)
|
|
console.log(` "dependencies": {`)
|
|
console.log(
|
|
` "@next/swc": ${JSON.stringify(`file:${packageFiles.nextSwcFile}`)},`
|
|
)
|
|
console.log(` ...`)
|
|
console.log(` }`)
|
|
console.log()
|
|
}
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error(e)
|
|
process.exit(1)
|
|
})
|
|
|
|
async function nextSwcBinaries(): Promise<string[]> {
|
|
return await glob('next-swc/native/*.node', {
|
|
cwd: NEXT_PACKAGES,
|
|
absolute: true,
|
|
})
|
|
}
|
|
|
|
// We use neither:
|
|
// * npm pack, as it doesn't include native modules in the tarball
|
|
// * pnpm pack, as it tries to include target directories and compress them,
|
|
// which takes forever.
|
|
// Instead, we generate non-compressed tarballs.
|
|
async function packWithTar(
|
|
packagePath: string,
|
|
tarballPath: string,
|
|
extraArgs: string[] = []
|
|
): Promise<void> {
|
|
const paths = await packageFiles(packagePath)
|
|
|
|
const command = [
|
|
'tar',
|
|
'-c',
|
|
// https://apple.stackexchange.com/a/444073
|
|
...(process.platform === 'darwin' ? ['--no-mac-metadata'] : []),
|
|
'-f',
|
|
tarballPath,
|
|
...extraArgs,
|
|
'--',
|
|
...paths.map((p) => `./${p}`),
|
|
]
|
|
|
|
await execAsyncWithOutput(`Pack ${packagePath}`, command, {
|
|
cwd: packagePath,
|
|
})
|
|
}
|
|
|
|
// Special-case logic for packing next-swc.
|
|
//
|
|
// pnpm emits `ERR_FS_FILE_TOO_LARGE` if the tarfile is >2GiB due to limits
|
|
// in libuv (https://github.com/libuv/libuv/pull/1501). This is common with
|
|
// next-swc due to the large amount of debugging symbols. We can fix this one
|
|
// of two ways: strip or compression.
|
|
//
|
|
// We default to stripping (usually faster), but on Linux, we can compress
|
|
// instead with objcopy, keeping debug symbols intact. This is controlled by
|
|
// `PACK_NEXT_COMPRESS`.
|
|
async function packNextSwcWithTar(compress: CompressOpt): Promise<void> {
|
|
const packagePath = `${NEXT_PACKAGES}/next-swc`
|
|
switch (compress) {
|
|
case 'strip':
|
|
await execAsyncWithOutput('Stripping next-swc native binary', [
|
|
'strip',
|
|
...(process.platform === 'darwin' ? ['-x', '-'] : ['--']),
|
|
...(await nextSwcBinaries()),
|
|
])
|
|
await packWithTar(packagePath, NEXT_SWC_TARBALL)
|
|
break
|
|
case 'objcopy-zstd':
|
|
case 'objcopy-zlib':
|
|
// Linux-specific, feature is gated by yargs choices array
|
|
const format = compress === 'objcopy-zstd' ? 'zstd' : 'zlib'
|
|
await Promise.all(
|
|
(await nextSwcBinaries()).map((bin) =>
|
|
execAsyncWithOutput(
|
|
'Compressing debug symbols in next-swc native binary',
|
|
['objcopy', `--compress-debug-sections=${format}`, '--', bin]
|
|
)
|
|
)
|
|
)
|
|
await packWithTar(packagePath, NEXT_SWC_TARBALL)
|
|
break
|
|
case 'none':
|
|
await packWithTar(packagePath, NEXT_SWC_TARBALL)
|
|
break
|
|
default:
|
|
// should never happen, yargs enforces the `choices` array
|
|
throw new Error('compress value is invalid')
|
|
}
|
|
}
|
|
|
|
function getPackageFiles(shouldCreateTarballs?: boolean): PackageFiles {
|
|
if (shouldCreateTarballs) {
|
|
return {
|
|
nextFile: NEXT_TARBALL,
|
|
nextMdxFile: NEXT_MDX_TARBALL,
|
|
nextEnvFile: NEXT_ENV_TARBALL,
|
|
nextBaFile: NEXT_BA_TARBALL,
|
|
nextSwcFile: NEXT_SWC_TARBALL,
|
|
}
|
|
}
|
|
|
|
return {
|
|
nextFile: `${NEXT_PACKAGES}/next`,
|
|
nextMdxFile: `${NEXT_PACKAGES}/next-mdx`,
|
|
nextEnvFile: `${NEXT_PACKAGES}/next-env`,
|
|
nextBaFile: `${NEXT_PACKAGES}/next-bundle-analyzer`,
|
|
nextSwcFile: `${NEXT_PACKAGES}/next-swc`,
|
|
}
|
|
}
|