mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
160 lines
4.2 KiB
TypeScript
160 lines
4.2 KiB
TypeScript
// It was ported from `bob runify --single` command.
|
|
// The idea here is to compile a node service to a single file (not in case of next) and make it executable.
|
|
import { join, normalize, resolve, sep } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import fs from 'fs-extra';
|
|
import { build as tsup } from 'tsup';
|
|
|
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
|
|
const requireShim = fs.readFileSync(normalize(join(__dirname, './banner.js')), 'utf-8');
|
|
|
|
interface BuildOptions {
|
|
external?: string[];
|
|
next?: {
|
|
header?: string;
|
|
};
|
|
}
|
|
|
|
runify(normalize(join(process.cwd(), 'package.json')));
|
|
|
|
async function runify(packagePath: string) {
|
|
const cwd = packagePath.replace(`${sep}package.json`, '');
|
|
const pkg = await readPackageJson(cwd);
|
|
const buildOptions: BuildOptions = pkg.buildOptions || {};
|
|
console.log(`Building...`);
|
|
|
|
if (isNext(pkg)) {
|
|
const additionalRequire = pkg?.buildOptions?.next?.header ?? null;
|
|
await buildWithNext(cwd, additionalRequire);
|
|
await rewritePackageJson(pkg, cwd, newPkg => ({
|
|
...newPkg,
|
|
dependencies: pkg.dependencies,
|
|
type: 'commonjs',
|
|
}));
|
|
} else {
|
|
await compile(
|
|
cwd,
|
|
'src/index.ts',
|
|
buildOptions,
|
|
Object.keys(pkg.dependencies ?? {}),
|
|
pkg.type === 'module',
|
|
);
|
|
await rewritePackageJson(pkg, cwd);
|
|
}
|
|
|
|
console.log(`Built!`);
|
|
}
|
|
|
|
export async function readPackageJson(baseDir: string) {
|
|
return JSON.parse(
|
|
await fs.readFile(resolve(baseDir, 'package.json'), {
|
|
encoding: 'utf-8',
|
|
}),
|
|
);
|
|
}
|
|
|
|
async function rewritePackageJson(
|
|
pkg: Record<string, any>,
|
|
cwd: string,
|
|
modify?: (pkg: any) => any,
|
|
) {
|
|
let filename = 'index.js';
|
|
|
|
let newPkg: Record<string, any> = {
|
|
bin: filename,
|
|
};
|
|
const fields = ['name', 'version', 'description', 'registry', 'repository', 'type'];
|
|
|
|
fields.forEach(field => {
|
|
if (typeof pkg[field] !== 'undefined') {
|
|
newPkg[field] = pkg[field];
|
|
}
|
|
});
|
|
|
|
if (modify) {
|
|
newPkg = modify(newPkg);
|
|
}
|
|
|
|
await fs.writeFile(join(cwd, 'dist', 'package.json'), JSON.stringify(newPkg, null, 2), {
|
|
encoding: 'utf-8',
|
|
});
|
|
}
|
|
|
|
function isNext(pkg: any): boolean {
|
|
return pkg?.dependencies?.next || pkg?.devDependencies?.next;
|
|
}
|
|
|
|
async function buildWithNext(cwd: string, additionalRequire: string | null) {
|
|
console.log('📦 Building local Docker images...');
|
|
await fs.mkdirp(normalize(join(cwd, 'dist')));
|
|
if (additionalRequire) {
|
|
await tsup({
|
|
entryPoints: [normalize(join(cwd, additionalRequire))],
|
|
outDir: normalize(join(cwd, 'dist')),
|
|
target: 'node18',
|
|
format: ['cjs'],
|
|
splitting: false,
|
|
skipNodeModulesBundle: true,
|
|
});
|
|
}
|
|
|
|
await Promise.all([
|
|
fs.copy(join(cwd, '.next'), join(cwd, 'dist/.next'), {
|
|
filter(src) {
|
|
// copy without webpack cache (it's 900mb...)
|
|
return src.includes('cache/webpack') === false;
|
|
},
|
|
}),
|
|
fs.copy(join(cwd, 'public'), join(cwd, 'dist/public')),
|
|
fs.writeFile(
|
|
join(cwd, 'dist/index.js'),
|
|
[
|
|
`#!/usr/bin/env node`,
|
|
`process.on('SIGTERM', () => process.exit(0))`,
|
|
`process.on('SIGINT', () => process.exit(0))`,
|
|
additionalRequire ? `require('${additionalRequire.replace('.ts', '')}')` : ``,
|
|
`
|
|
require('next/dist/server/lib/start-server').startServer({
|
|
dir: __dirname,
|
|
hostname: '0.0.0.0',
|
|
port: parseInt(process.env.PORT),
|
|
conf: {},
|
|
isDev: false,
|
|
useWorkers: false,
|
|
}).catch((err)=>{
|
|
console.error(err);
|
|
process.exit(1);
|
|
})
|
|
`,
|
|
].join('\n'),
|
|
),
|
|
]);
|
|
}
|
|
|
|
async function compile(
|
|
cwd: string,
|
|
entryPoint: string,
|
|
buildOptions: BuildOptions,
|
|
dependencies: string[],
|
|
useEsm = false,
|
|
) {
|
|
const out = normalize(join(cwd, 'dist'));
|
|
|
|
await tsup({
|
|
entryPoints: [normalize(join(cwd, entryPoint))],
|
|
outDir: out,
|
|
target: 'node18',
|
|
format: [useEsm ? 'esm' : 'cjs'],
|
|
splitting: false,
|
|
sourcemap: true,
|
|
clean: true,
|
|
shims: true,
|
|
skipNodeModulesBundle: false,
|
|
noExternal: dependencies,
|
|
external: buildOptions.external,
|
|
banner: {
|
|
js: requireShim,
|
|
},
|
|
});
|
|
}
|