mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
# What The turborepo cache appears to corrupt or truncate the docker file in the cache - we can instead just hit the API directly and skip a few steps.
212 lines
5.5 KiB
JavaScript
Executable File
212 lines
5.5 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
// Local wrapper for running native docker builds.
|
|
//
|
|
// Usage: node scripts/docker-native-build.js [flags] [filter]
|
|
// --quick Use release-with-assertions profile (no LTO, faster)
|
|
// --host-target Share host target/ dir with container for caching
|
|
// --rebuild Force Docker image rebuild
|
|
// --test Smoke-test built binaries (native arch only)
|
|
// filter Substring match on target name (e.g. "musl", "x86_64")
|
|
|
|
const { execFileSync } = require('child_process')
|
|
const path = require('path')
|
|
const fs = require('fs')
|
|
const os = require('os')
|
|
|
|
const REPO_ROOT = path.resolve(__dirname, '..')
|
|
const DOCKER_IMAGE = 'next-swc-builder:latest'
|
|
|
|
const TARGETS = [
|
|
{
|
|
target: 'x86_64-unknown-linux-gnu',
|
|
arch: 'x86_64',
|
|
abi: 'gnu',
|
|
napiPlatform: 'linux-x64-gnu',
|
|
},
|
|
{
|
|
target: 'aarch64-unknown-linux-gnu',
|
|
arch: 'aarch64',
|
|
abi: 'gnu',
|
|
napiPlatform: 'linux-arm64-gnu',
|
|
},
|
|
{
|
|
target: 'x86_64-unknown-linux-musl',
|
|
arch: 'x86_64',
|
|
abi: 'musl',
|
|
napiPlatform: 'linux-x64-musl',
|
|
},
|
|
{
|
|
target: 'aarch64-unknown-linux-musl',
|
|
arch: 'aarch64',
|
|
abi: 'musl',
|
|
napiPlatform: 'linux-arm64-musl',
|
|
},
|
|
]
|
|
|
|
// Map uname -m to our arch names
|
|
const HOST_ARCH =
|
|
os.arch() === 'arm64' || os.arch() === 'aarch64' ? 'aarch64' : 'x86_64'
|
|
|
|
// --- Parse args ---
|
|
const { parseArgs } = require('node:util')
|
|
const { values: flags, positionals } = parseArgs({
|
|
args: process.argv.slice(2),
|
|
options: {
|
|
quick: { type: 'boolean', default: false },
|
|
'host-target': { type: 'boolean', default: false },
|
|
rebuild: { type: 'boolean', default: false },
|
|
test: { type: 'boolean', default: false },
|
|
help: { type: 'boolean', short: 'h', default: false },
|
|
},
|
|
allowPositionals: true,
|
|
})
|
|
|
|
if (flags.help) {
|
|
console.log(
|
|
'Usage: node scripts/docker-native-build.js [--quick] [--host-target] [--rebuild] [--test] [filter]'
|
|
)
|
|
process.exit(0)
|
|
}
|
|
|
|
const quick = flags.quick
|
|
const hostTarget = flags['host-target']
|
|
const rebuild = flags.rebuild
|
|
const test = flags.test
|
|
const filter = positionals[0] || ''
|
|
|
|
// --- Filter targets ---
|
|
let targets = TARGETS
|
|
if (filter) {
|
|
targets = TARGETS.filter((t) => t.target.includes(filter))
|
|
}
|
|
if (targets.length === 0) {
|
|
console.error(`No targets match filter: "${filter}"`)
|
|
console.error('Available:', TARGETS.map((t) => t.target).join(', '))
|
|
process.exit(1)
|
|
}
|
|
|
|
// --- Build/restore Docker image ---
|
|
function ensureDockerImage() {
|
|
const args = rebuild ? ['--force'] : []
|
|
execFileSync(
|
|
'node',
|
|
[path.join(__dirname, 'docker-image-cache.js'), ...args],
|
|
{ stdio: 'inherit' }
|
|
)
|
|
}
|
|
|
|
ensureDockerImage()
|
|
|
|
// --- Build targets ---
|
|
const buildTask = quick
|
|
? 'build-native-release-with-assertions'
|
|
: 'build-native-release'
|
|
|
|
if (quick) {
|
|
console.log(
|
|
'Quick mode: using release-with-assertions profile (no LTO, 64 codegen units)'
|
|
)
|
|
}
|
|
console.log(
|
|
`Building ${targets.length} target(s): ${targets.map((t) => t.target).join(', ')}\n`
|
|
)
|
|
|
|
const HOME = os.homedir()
|
|
const VOLUMES = [
|
|
`${HOME}/.cargo/git:/root/.cargo/git`,
|
|
`${HOME}/.cargo/registry:/root/.cargo/registry`,
|
|
`${REPO_ROOT}:/build`,
|
|
]
|
|
|
|
for (const { target, arch, abi, napiPlatform } of targets) {
|
|
console.log('='.repeat(50))
|
|
console.log(`Building: ${target}`)
|
|
console.log(`Docker: ${DOCKER_IMAGE}`)
|
|
console.log(`Task: ${buildTask}`)
|
|
console.log('='.repeat(50))
|
|
|
|
// Clean only this target's previous build (preserve other targets' .node files)
|
|
const nativeDir = path.join(REPO_ROOT, 'packages/next-swc/native')
|
|
const nodeFile = path.join(nativeDir, `next-swc.${napiPlatform}.node`)
|
|
if (fs.existsSync(nodeFile)) fs.unlinkSync(nodeFile)
|
|
|
|
const ENV = {
|
|
CI: '1',
|
|
RUST_BACKTRACE: '1',
|
|
CARGO_TERM_COLOR: 'always',
|
|
CARGO_INCREMENTAL: '0',
|
|
TARGET: target,
|
|
ABI: abi,
|
|
ARCH: arch,
|
|
BUILD_TASK: buildTask,
|
|
}
|
|
|
|
const dockerArgs = [
|
|
'run',
|
|
'--rm',
|
|
...Object.entries(ENV).flatMap(([k, v]) => ['-e', `${k}=${v}`]),
|
|
...VOLUMES.flatMap((v) => ['-v', v]),
|
|
...(hostTarget ? [] : ['-v', '/build/target']),
|
|
'-w',
|
|
'/build',
|
|
'--entrypoint',
|
|
'bash',
|
|
DOCKER_IMAGE,
|
|
'-xeo',
|
|
'pipefail',
|
|
'scripts/docker-native-build.sh',
|
|
]
|
|
|
|
execFileSync('docker', dockerArgs, { stdio: 'inherit' })
|
|
|
|
console.log(`\nSuccessfully built: ${target}\n`)
|
|
}
|
|
|
|
// --- Smoke test ---
|
|
if (test) {
|
|
console.log('='.repeat(50))
|
|
console.log('Running smoke tests...')
|
|
console.log('='.repeat(50))
|
|
|
|
for (const { target, arch, abi, napiPlatform } of targets) {
|
|
// Skip cross-built binaries (would need qemu)
|
|
if (arch !== HOST_ARCH) {
|
|
console.log(`Skipping smoke test for ${target} (cross-built, needs qemu)`)
|
|
continue
|
|
}
|
|
|
|
const testImage = abi === 'musl' ? 'node:20-alpine' : 'node:20-slim'
|
|
const nodeFile = `./packages/next-swc/native/next-swc.${napiPlatform}.node`
|
|
|
|
console.log(`Testing ${target} in ${testImage}...`)
|
|
|
|
const testScript = [
|
|
`const b = require('${nodeFile}')`,
|
|
`const t = b.getTargetTriple()`,
|
|
`console.log('OK: getTargetTriple() =', t)`,
|
|
`if (!t.includes('linux')) { console.error('FAIL: expected linux in triple'); process.exit(1) }`,
|
|
].join('; ')
|
|
|
|
execFileSync(
|
|
'docker',
|
|
[
|
|
'run',
|
|
'--rm',
|
|
'-v',
|
|
`${REPO_ROOT}:/work`,
|
|
'-w',
|
|
'/work',
|
|
testImage,
|
|
'node',
|
|
'-e',
|
|
testScript,
|
|
],
|
|
{ stdio: 'inherit' }
|
|
)
|
|
|
|
console.log(`Smoke test passed: ${target}\n`)
|
|
}
|
|
}
|
|
|
|
console.log('All targets built successfully!')
|