Files
vercel/utils/run.js
Kiko Beats 6dded87426 [node] Add streaming support for vc dev (#9745)
Until now, the user code response it's buffered and serialized. This is
mismatching how Vercel works these days.

This PR enables streaming response in `vc dev` for Edge/Serverless.

As part of the implementation, the `node-bridge` which spawns a process
to consume the user code is not necessary anymore.

Some necessary files (like HTTP server helpers) have been moved to live
in node builder package instead.

---------

Co-authored-by: Ethan Arrowood <ethan.arrowood@vercel.com>
Co-authored-by: Sean Massa <EndangeredMassa@gmail.com>
2023-04-19 23:56:41 +02:00

127 lines
3.0 KiB
JavaScript
Vendored

const { execSync, spawn } = require('child_process');
const { join, relative, sep } = require('path');
// The order matters because we must build dependencies first
const allPackages = [
'routing-utils',
'frameworks',
'fs-detectors',
'build-utils',
'static-config',
'client',
'next',
'node',
'go',
'python',
'ruby',
'redwood',
'remix',
'static-build',
'cli',
];
process.chdir(join(__dirname, '..'));
async function main() {
const script = process.argv[2];
const all = process.argv[3];
let modifiedPackages = new Set(allPackages);
if (!script) {
console.error('Please provide at least one argument');
process.exit(2);
}
if (all === 'all') {
console.log(`Running script "${script}" for all packages`);
} else {
const branch =
process.env.GITHUB_HEAD_REF ||
execSync('git branch --show-current').toString().trim();
const gitPath = branch === 'main' ? 'HEAD~1' : 'origin/main...HEAD';
const diff = execSync(`git diff ${gitPath} --name-only`).toString();
const changed = diff
.split('\n')
.filter(item => Boolean(item) && item.startsWith('packages'))
.map(item => relative('packages', item).split(sep)[0])
.concat('cli'); // Always run tests for Vercel CLI
modifiedPackages = new Set(changed);
console.log(
`Running "${script}" on branch "${branch}" with the following packages:\n`
);
}
for (const pkgName of allPackages) {
if (modifiedPackages.has(pkgName)) {
console.log(` - ${pkgName}`);
}
}
for (const pkgName of allPackages) {
if (modifiedPackages.has(pkgName)) {
await runScript(pkgName, script);
}
}
}
function runScript(pkgName, script) {
return new Promise((resolve, reject) => {
const cwd = join(__dirname, '..', 'packages', pkgName);
let pkgJson = null;
try {
pkgJson = require(join(cwd, 'package.json'));
} catch (e) {
pkgJson = null;
}
if (pkgJson && pkgJson.scripts && pkgJson.scripts[script]) {
console.log(`\n[${pkgName}] Running pnpm ${script}`);
const child = spawn('pnpm', [script], {
cwd,
stdio: 'inherit',
shell: true,
env: {
// Only add this for unit tests, as it's not relevant to others.
...(script === 'test-unit'
? {
NODE_OPTIONS: '--max-old-space-size=4096',
}
: null),
...process.env,
},
});
child.on('error', reject);
child.on('close', (code, signal) => {
if (code === 0) {
return resolve();
}
reject(
new Error(
`[${pkgName}] Exited script "${script}" with code ${
code || signal
}.`
)
);
});
} else {
console.log(
`[${pkgName}] Skipping since script "${script}" is missing from package.json`
);
resolve();
}
});
}
main()
.then(() => {
console.log('Success!');
process.exit(0);
})
.catch(e => {
console.error(e);
process.exit(1);
});