mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-10 04:22:12 +00:00
[now-cli] Add the core Runtimes as npm dependencies for now dev (#4117)
Rather than creating a `builders.tar.gz` file with the core Runtimes and bundling that tarball with Now CLI, simply have them be regular npm dependencies so that they are installed into Now CLI's `node_modules` directory. When one of the core runtimes is specified for a build, the runtime will be required as a regular module dependency of Now CLI, and the builders cache will never touched. Bundled runtimes are also no longer updated, making the runtime versions pinned to the version of Now CLI. Logic for the builders cache directory still remains, but will now only be used when using a Community Runtime (or development tarball URL).
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,8 +9,6 @@ coverage
|
|||||||
*.swp
|
*.swp
|
||||||
*.bak
|
*.bak
|
||||||
*.tgz
|
*.tgz
|
||||||
packages/now-cli/.builders
|
|
||||||
packages/now-cli/assets
|
|
||||||
packages/now-cli/src/util/dev/templates/*.ts
|
packages/now-cli/src/util/dev/templates/*.ts
|
||||||
packages/now-cli/src/util/constants.ts
|
packages/now-cli/src/util/constants.ts
|
||||||
packages/now-cli/test/**/yarn.lock
|
packages/now-cli/test/**/yarn.lock
|
||||||
|
|||||||
@@ -61,6 +61,15 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@now/build-utils": "2.2.2-canary.2",
|
||||||
|
"@now/go": "1.0.8-canary.0",
|
||||||
|
"@now/next": "2.5.5-canary.1",
|
||||||
|
"@now/node": "1.5.2-canary.3",
|
||||||
|
"@now/python": "1.1.7-canary.0",
|
||||||
|
"@now/ruby": "1.1.1-canary.0",
|
||||||
|
"@now/static-build": "0.16.1-canary.2"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sentry/node": "5.5.0",
|
"@sentry/node": "5.5.0",
|
||||||
"@sindresorhus/slugify": "0.11.0",
|
"@sindresorhus/slugify": "0.11.0",
|
||||||
|
|||||||
@@ -1,61 +1,10 @@
|
|||||||
import cpy from 'cpy';
|
import cpy from 'cpy';
|
||||||
import tar from 'tar-fs';
|
|
||||||
import execa from 'execa';
|
import execa from 'execa';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import pipe from 'promisepipe';
|
import { remove, writeFile } from 'fs-extra';
|
||||||
import { createGzip } from 'zlib';
|
|
||||||
import {
|
|
||||||
createWriteStream,
|
|
||||||
mkdirp,
|
|
||||||
remove,
|
|
||||||
writeJSON,
|
|
||||||
writeFile,
|
|
||||||
} from 'fs-extra';
|
|
||||||
|
|
||||||
import { getDistTag } from '../src/util/get-dist-tag';
|
|
||||||
import pkg from '../package.json';
|
|
||||||
import { getBundledBuilders } from '../src/util/dev/get-bundled-builders';
|
|
||||||
|
|
||||||
const dirRoot = join(__dirname, '..');
|
const dirRoot = join(__dirname, '..');
|
||||||
|
|
||||||
async function createBuildersTarball() {
|
|
||||||
const distTag = getDistTag(pkg.version);
|
|
||||||
const builders = Array.from(getBundledBuilders()).map(b => `${b}@${distTag}`);
|
|
||||||
console.log(`Creating builders tarball with: ${builders.join(', ')}`);
|
|
||||||
|
|
||||||
const buildersDir = join(dirRoot, '.builders');
|
|
||||||
const assetsDir = join(dirRoot, 'assets');
|
|
||||||
await mkdirp(buildersDir);
|
|
||||||
await mkdirp(assetsDir);
|
|
||||||
|
|
||||||
const buildersTarballPath = join(assetsDir, 'builders.tar.gz');
|
|
||||||
|
|
||||||
try {
|
|
||||||
const buildersPkg = join(buildersDir, 'package.json');
|
|
||||||
await writeJSON(buildersPkg, { private: true }, { flag: 'wx' });
|
|
||||||
} catch (err) {
|
|
||||||
if (err.code !== 'EEXIST') {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await execa(
|
|
||||||
'npm',
|
|
||||||
['install', '--save-exact', '--no-package-lock', ...builders],
|
|
||||||
{
|
|
||||||
cwd: buildersDir,
|
|
||||||
stdio: 'inherit',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const packer = tar.pack(buildersDir);
|
|
||||||
await pipe(
|
|
||||||
packer,
|
|
||||||
createGzip(),
|
|
||||||
createWriteStream(buildersTarballPath)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createConstants() {
|
async function createConstants() {
|
||||||
console.log('Creating constants.ts');
|
console.log('Creating constants.ts');
|
||||||
const filename = join(dirRoot, 'src/util/constants.ts');
|
const filename = join(dirRoot, 'src/util/constants.ts');
|
||||||
@@ -84,10 +33,6 @@ async function main() {
|
|||||||
// During local development, these secrets will be empty.
|
// During local development, these secrets will be empty.
|
||||||
await createConstants();
|
await createConstants();
|
||||||
|
|
||||||
// Create a tarball from all the `@now` scoped builders which will be bundled
|
|
||||||
// with Now CLI
|
|
||||||
await createBuildersTarball();
|
|
||||||
|
|
||||||
// `now dev` uses chokidar to watch the filesystem, but opts-out of the
|
// `now dev` uses chokidar to watch the filesystem, but opts-out of the
|
||||||
// `fsevents` feature using `useFsEvents: false`, so delete the module here so
|
// `fsevents` feature using `useFsEvents: false`, so delete the module here so
|
||||||
// that it is not compiled by ncc, which makes the npm package size larger
|
// that it is not compiled by ncc, which makes the npm package size larger
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
import execa from 'execa';
|
import execa from 'execa';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import pipe from 'promisepipe';
|
|
||||||
import retry from 'async-retry';
|
import retry from 'async-retry';
|
||||||
import npa from 'npm-package-arg';
|
import npa from 'npm-package-arg';
|
||||||
import pluralize from 'pluralize';
|
import pluralize from 'pluralize';
|
||||||
import { extract } from 'tar-fs';
|
|
||||||
import { createHash } from 'crypto';
|
|
||||||
import { createGunzip } from 'zlib';
|
|
||||||
import { basename, join, resolve } from 'path';
|
import { basename, join, resolve } from 'path';
|
||||||
import { PackageJson } from '@now/build-utils';
|
import { PackageJson } from '@now/build-utils';
|
||||||
import XDGAppPaths from 'xdg-app-paths';
|
import XDGAppPaths from 'xdg-app-paths';
|
||||||
import {
|
import { mkdirp, readJSON, writeJSON } from 'fs-extra';
|
||||||
createReadStream,
|
import nowCliPkg from '../pkg';
|
||||||
mkdirp,
|
|
||||||
readFile,
|
|
||||||
readJSON,
|
|
||||||
writeFile,
|
|
||||||
} from 'fs-extra';
|
|
||||||
import pkg from '../../../package.json';
|
|
||||||
|
|
||||||
import { NoBuilderCacheError } from '../errors-ts';
|
import { NoBuilderCacheError } from '../errors-ts';
|
||||||
import { Output } from '../output';
|
import { Output } from '../output';
|
||||||
@@ -34,41 +24,16 @@ const registryTypes = new Set(['version', 'tag', 'range']);
|
|||||||
const localBuilders: { [key: string]: BuilderWithPackage } = {
|
const localBuilders: { [key: string]: BuilderWithPackage } = {
|
||||||
'@now/static': {
|
'@now/static': {
|
||||||
runInProcess: true,
|
runInProcess: true,
|
||||||
|
requirePath: '@now/static',
|
||||||
builder: Object.freeze(staticBuilder),
|
builder: Object.freeze(staticBuilder),
|
||||||
package: Object.freeze({ name: '@now/static', version: '' }),
|
package: Object.freeze({ name: '@now/static', version: '' }),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const distTag = getDistTag(pkg.version);
|
const distTag = nowCliPkg.version ? getDistTag(nowCliPkg.version) : 'canary';
|
||||||
|
|
||||||
export const cacheDirPromise = prepareCacheDir();
|
export const cacheDirPromise = prepareCacheDir();
|
||||||
export const builderDirPromise = prepareBuilderDir();
|
export const builderDirPromise = prepareBuilderDir();
|
||||||
export const builderModulePathPromise = prepareBuilderModulePath();
|
|
||||||
|
|
||||||
function readFileOrNull(
|
|
||||||
filePath: string,
|
|
||||||
encoding?: null
|
|
||||||
): Promise<Buffer | null>;
|
|
||||||
function readFileOrNull(
|
|
||||||
filePath: string,
|
|
||||||
encoding: string
|
|
||||||
): Promise<string | null>;
|
|
||||||
async function readFileOrNull(
|
|
||||||
filePath: string,
|
|
||||||
encoding?: string | null
|
|
||||||
): Promise<Buffer | string | null> {
|
|
||||||
try {
|
|
||||||
if (encoding) {
|
|
||||||
return await readFile(filePath, encoding);
|
|
||||||
}
|
|
||||||
return await readFile(filePath);
|
|
||||||
} catch (err) {
|
|
||||||
if (err.code === 'ENOENT') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare cache directory for installing now-builders
|
* Prepare cache directory for installing now-builders
|
||||||
@@ -92,51 +57,19 @@ export async function prepareBuilderDir() {
|
|||||||
const builderDir = join(await cacheDirPromise, 'builders');
|
const builderDir = join(await cacheDirPromise, 'builders');
|
||||||
await mkdirp(builderDir);
|
await mkdirp(builderDir);
|
||||||
|
|
||||||
// Extract the bundled `builders.tar.gz` file, if necessary
|
// Create an empty `package.json` file, only if one does not already exist
|
||||||
const bundledTarballPath = join(__dirname, '../../../assets/builders.tar.gz');
|
try {
|
||||||
|
const buildersPkg = join(builderDir, 'package.json');
|
||||||
const existingPackageJson =
|
await writeJSON(buildersPkg, { private: true }, { flag: 'wx' });
|
||||||
(await readFileOrNull(join(builderDir, 'package.json'), 'utf8')) || '{}';
|
} catch (err) {
|
||||||
const { dependencies = {} } = JSON.parse(existingPackageJson);
|
if (err.code !== 'EEXIST') {
|
||||||
|
throw err;
|
||||||
if (!hasBundledBuilders(dependencies)) {
|
}
|
||||||
const extractor = extract(builderDir);
|
|
||||||
await pipe(
|
|
||||||
createReadStream(bundledTarballPath),
|
|
||||||
createGunzip(),
|
|
||||||
extractor
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return builderDir;
|
return builderDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function prepareBuilderModulePath() {
|
|
||||||
const [builderDir, builderContents] = await Promise.all([
|
|
||||||
builderDirPromise,
|
|
||||||
readFile(join(__dirname, 'builder-worker.js')),
|
|
||||||
]);
|
|
||||||
let needsWrite = false;
|
|
||||||
const builderSha = getSha(builderContents);
|
|
||||||
const cachedBuilderPath = join(builderDir, 'builder.js');
|
|
||||||
|
|
||||||
const cachedBuilderContents = await readFileOrNull(cachedBuilderPath);
|
|
||||||
if (cachedBuilderContents) {
|
|
||||||
const cachedBuilderSha = getSha(cachedBuilderContents);
|
|
||||||
if (builderSha !== cachedBuilderSha) {
|
|
||||||
needsWrite = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
needsWrite = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsWrite) {
|
|
||||||
await writeFile(cachedBuilderPath, builderContents);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cachedBuilderPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNpmVersion(use = ''): string {
|
function getNpmVersion(use = ''): string {
|
||||||
const parsed = npa(use);
|
const parsed = npa(use);
|
||||||
if (registryTypes.has(parsed.type)) {
|
if (registryTypes.has(parsed.type)) {
|
||||||
@@ -166,12 +99,20 @@ function parseVersionSafe(rawSpec: string) {
|
|||||||
export function filterPackage(
|
export function filterPackage(
|
||||||
builderSpec: string,
|
builderSpec: string,
|
||||||
distTag: string,
|
distTag: string,
|
||||||
buildersPkg: PackageJson
|
buildersPkg: PackageJson,
|
||||||
|
nowCliPkg: PackageJson = {}
|
||||||
) {
|
) {
|
||||||
if (builderSpec in localBuilders) return false;
|
if (builderSpec in localBuilders) return false;
|
||||||
const parsed = npa(builderSpec);
|
const parsed = npa(builderSpec);
|
||||||
const parsedVersion = parseVersionSafe(parsed.rawSpec);
|
const parsedVersion = parseVersionSafe(parsed.rawSpec);
|
||||||
// skip install of already installed Runtime
|
|
||||||
|
// If it's a builder that is part of Now CLI's `dependencies` then
|
||||||
|
// the builder is already installed into `node_modules`
|
||||||
|
if (isBundledBuilder(parsed, nowCliPkg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip install of already installed Runtime
|
||||||
if (
|
if (
|
||||||
parsed.name &&
|
parsed.name &&
|
||||||
parsed.type === 'version' &&
|
parsed.type === 'version' &&
|
||||||
@@ -300,6 +241,7 @@ export async function updateBuilders(
|
|||||||
builderDir = await builderDirPromise;
|
builderDir = await builderDirPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updatedPackages: string[] = [];
|
||||||
const packages = Array.from(packagesSet);
|
const packages = Array.from(packagesSet);
|
||||||
const buildersPkgPath = join(builderDir, 'package.json');
|
const buildersPkgPath = join(builderDir, 'package.json');
|
||||||
const buildersPkgBefore = await readJSON(buildersPkgPath);
|
const buildersPkgBefore = await readJSON(buildersPkgPath);
|
||||||
@@ -308,39 +250,47 @@ export async function updateBuilders(
|
|||||||
...buildersPkgBefore.dependencies,
|
...buildersPkgBefore.dependencies,
|
||||||
};
|
};
|
||||||
|
|
||||||
packages.push(getBuildUtils(packages));
|
const packagesToUpdate = packages.filter(p => {
|
||||||
|
if (p in localBuilders) return false;
|
||||||
|
|
||||||
await retry(
|
// If it's a builder that is part of Now CLI's `dependencies` then
|
||||||
() =>
|
// don't update it
|
||||||
execa(
|
if (isBundledBuilder(npa(p), nowCliPkg)) {
|
||||||
'npm',
|
return false;
|
||||||
[
|
|
||||||
'install',
|
|
||||||
'--save-exact',
|
|
||||||
'--no-package-lock',
|
|
||||||
...packages.filter(p => p !== '@now/static'),
|
|
||||||
],
|
|
||||||
{
|
|
||||||
cwd: builderDir,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
{ retries: 2 }
|
|
||||||
);
|
|
||||||
|
|
||||||
const updatedPackages: string[] = [];
|
|
||||||
const buildersPkgAfter = await readJSON(buildersPkgPath);
|
|
||||||
const depsAfter = {
|
|
||||||
...buildersPkgAfter.devDependencies,
|
|
||||||
...buildersPkgAfter.dependencies,
|
|
||||||
};
|
|
||||||
for (const [name, version] of Object.entries(depsAfter)) {
|
|
||||||
if (version !== depsBefore[name]) {
|
|
||||||
output.debug(`Runtime "${name}" updated to version \`${version}\``);
|
|
||||||
updatedPackages.push(name);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
purgeRequireCache(updatedPackages, builderDir, output);
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (packagesToUpdate.length > 0) {
|
||||||
|
packages.push(getBuildUtils(packages));
|
||||||
|
|
||||||
|
await retry(
|
||||||
|
() =>
|
||||||
|
execa(
|
||||||
|
'npm',
|
||||||
|
['install', '--save-exact', '--no-package-lock', ...packagesToUpdate],
|
||||||
|
{
|
||||||
|
cwd: builderDir,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
{ retries: 2 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const buildersPkgAfter = await readJSON(buildersPkgPath);
|
||||||
|
const depsAfter = {
|
||||||
|
...buildersPkgAfter.devDependencies,
|
||||||
|
...buildersPkgAfter.dependencies,
|
||||||
|
};
|
||||||
|
for (const [name, version] of Object.entries(depsAfter)) {
|
||||||
|
if (version !== depsBefore[name]) {
|
||||||
|
output.debug(`Runtime "${name}" updated to version \`${version}\``);
|
||||||
|
updatedPackages.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
purgeRequireCache(updatedPackages, builderDir, output);
|
||||||
|
}
|
||||||
|
|
||||||
return updatedPackages;
|
return updatedPackages;
|
||||||
}
|
}
|
||||||
@@ -359,21 +309,32 @@ export async function getBuilder(
|
|||||||
if (!builderDir) {
|
if (!builderDir) {
|
||||||
builderDir = await builderDirPromise;
|
builderDir = await builderDirPromise;
|
||||||
}
|
}
|
||||||
|
let requirePath: string;
|
||||||
const parsed = npa(builderPkg);
|
const parsed = npa(builderPkg);
|
||||||
const buildersPkg = await readJSON(join(builderDir, 'package.json'));
|
|
||||||
const pkgName = getPackageName(parsed, buildersPkg) || builderPkg;
|
// First check if it's a bundled Runtime in Now CLI's `node_modules`
|
||||||
const dest = join(builderDir, 'node_modules', pkgName);
|
const bundledBuilder = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
if (bundledBuilder && parsed.name) {
|
||||||
|
requirePath = parsed.name;
|
||||||
|
} else {
|
||||||
|
const buildersPkg = await readJSON(join(builderDir, 'package.json'));
|
||||||
|
const pkgName = getPackageName(parsed, buildersPkg) || builderPkg;
|
||||||
|
requirePath = join(builderDir, 'node_modules', pkgName);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mod = require(dest);
|
output.debug(`Requiring runtime: "${requirePath}"`);
|
||||||
const pkg = require(join(dest, 'package.json'));
|
const mod = require(requirePath);
|
||||||
|
const pkg = require(join(requirePath, 'package.json'));
|
||||||
builderWithPkg = {
|
builderWithPkg = {
|
||||||
|
requirePath,
|
||||||
builder: Object.freeze(mod),
|
builder: Object.freeze(mod),
|
||||||
package: Object.freeze(pkg),
|
package: Object.freeze(pkg),
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code === 'MODULE_NOT_FOUND' && !isRetry) {
|
if (err.code === 'MODULE_NOT_FOUND' && !isRetry) {
|
||||||
output.debug(
|
output.debug(
|
||||||
`Attempted to require ${builderPkg}, but it is not installed`
|
`Attempted to require ${requirePath}, but it is not installed`
|
||||||
);
|
);
|
||||||
const pkgSet = new Set([builderPkg]);
|
const pkgSet = new Set([builderPkg]);
|
||||||
await installBuilders(pkgSet, output, builderDir);
|
await installBuilders(pkgSet, output, builderDir);
|
||||||
@@ -383,10 +344,39 @@ export async function getBuilder(
|
|||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it's a bundled builder, then cache the require call
|
||||||
|
if (bundledBuilder) {
|
||||||
|
localBuilders[builderPkg] = builderWithPkg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return builderWithPkg;
|
return builderWithPkg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isBundledBuilder(
|
||||||
|
parsed: npa.Result,
|
||||||
|
pkg: PackageJson
|
||||||
|
): boolean {
|
||||||
|
if (!parsed.name || !pkg.dependencies) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bundledVersion = pkg.dependencies[parsed.name];
|
||||||
|
if (bundledVersion) {
|
||||||
|
if (parsed.type === 'tag') {
|
||||||
|
if (parsed.fetchSpec === 'canary') {
|
||||||
|
return bundledVersion.includes('canary');
|
||||||
|
} else if (parsed.fetchSpec === 'latest') {
|
||||||
|
return !bundledVersion.includes('canary');
|
||||||
|
}
|
||||||
|
} else if (parsed.type === 'version') {
|
||||||
|
return parsed.fetchSpec === bundledVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function getPackageName(
|
function getPackageName(
|
||||||
parsed: npa.Result,
|
parsed: npa.Result,
|
||||||
buildersPkg: PackageJson
|
buildersPkg: PackageJson
|
||||||
@@ -406,21 +396,6 @@ function getPackageName(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSha(buffer: Buffer): string {
|
|
||||||
const hash = createHash('sha256');
|
|
||||||
hash.update(buffer);
|
|
||||||
return hash.digest('hex');
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasBundledBuilders(dependencies: { [name: string]: string }): boolean {
|
|
||||||
for (const name of getBundledBuilders()) {
|
|
||||||
if (!(name in dependencies)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function purgeRequireCache(
|
function purgeRequireCache(
|
||||||
packages: string[],
|
packages: string[],
|
||||||
builderDir: string,
|
builderDir: string,
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ function onMessage(message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function processMessage(message) {
|
async function processMessage(message) {
|
||||||
const { builderName, buildOptions } = message;
|
const { requirePath, buildOptions } = message;
|
||||||
const builder = require(builderName);
|
const builder = require(requirePath);
|
||||||
|
|
||||||
// Convert the `files` to back into `FileFsRef` instances
|
// Convert the `files` to back into `FileFsRef` instances
|
||||||
for (const name of Object.keys(buildOptions.files)) {
|
for (const name of Object.keys(buildOptions.files)) {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { relative } from '../path-helpers';
|
|||||||
import { LambdaSizeExceededError } from '../errors-ts';
|
import { LambdaSizeExceededError } from '../errors-ts';
|
||||||
|
|
||||||
import DevServer from './server';
|
import DevServer from './server';
|
||||||
import { builderModulePathPromise, getBuilder } from './builder-cache';
|
import { getBuilder } from './builder-cache';
|
||||||
import {
|
import {
|
||||||
NowConfig,
|
NowConfig,
|
||||||
BuildMatch,
|
BuildMatch,
|
||||||
@@ -54,11 +54,10 @@ async function createBuildProcess(
|
|||||||
workPath: string,
|
workPath: string,
|
||||||
output: Output
|
output: Output
|
||||||
): Promise<ChildProcess> {
|
): Promise<ChildProcess> {
|
||||||
const { execPath } = process;
|
const builderWorkerPath = join(__dirname, 'builder-worker.js');
|
||||||
const modulePath = await builderModulePathPromise;
|
|
||||||
|
|
||||||
// Ensure that `node` is in the builder's `PATH`
|
// Ensure that `node` is in the builder's `PATH`
|
||||||
let PATH = `${dirname(execPath)}${delimiter}${process.env.PATH}`;
|
let PATH = `${dirname(process.execPath)}${delimiter}${process.env.PATH}`;
|
||||||
|
|
||||||
const env: Env = {
|
const env: Env = {
|
||||||
...process.env,
|
...process.env,
|
||||||
@@ -67,11 +66,9 @@ async function createBuildProcess(
|
|||||||
NOW_REGION: 'dev1',
|
NOW_REGION: 'dev1',
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildProcess = fork(modulePath, [], {
|
const buildProcess = fork(builderWorkerPath, [], {
|
||||||
cwd: workPath,
|
cwd: workPath,
|
||||||
env,
|
env,
|
||||||
execPath,
|
|
||||||
execArgv: [],
|
|
||||||
});
|
});
|
||||||
match.buildProcess = buildProcess;
|
match.buildProcess = buildProcess;
|
||||||
|
|
||||||
@@ -105,7 +102,7 @@ export async function executeBuild(
|
|||||||
filesRemoved?: string[]
|
filesRemoved?: string[]
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {
|
const {
|
||||||
builderWithPkg: { runInProcess, builder, package: pkg },
|
builderWithPkg: { runInProcess, requirePath, builder, package: pkg },
|
||||||
} = match;
|
} = match;
|
||||||
const { entrypoint } = match;
|
const { entrypoint } = match;
|
||||||
const { debug, envConfigs, cwd: workPath } = devServer;
|
const { debug, envConfigs, cwd: workPath } = devServer;
|
||||||
@@ -157,7 +154,7 @@ export async function executeBuild(
|
|||||||
if (buildProcess) {
|
if (buildProcess) {
|
||||||
buildProcess.send({
|
buildProcess.send({
|
||||||
type: 'build',
|
type: 'build',
|
||||||
builderName: pkg.name,
|
requirePath,
|
||||||
buildOptions,
|
buildOptions,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import {
|
|||||||
|
|
||||||
import link from '../output/link';
|
import link from '../output/link';
|
||||||
import { Output } from '../output';
|
import { Output } from '../output';
|
||||||
import { treeKill } from '../tree-kill';
|
|
||||||
import { relative } from '../path-helpers';
|
import { relative } from '../path-helpers';
|
||||||
import { getDistTag } from '../get-dist-tag';
|
import { getDistTag } from '../get-dist-tag';
|
||||||
import getNowConfigPath from '../config/local-path';
|
import getNowConfigPath from '../config/local-path';
|
||||||
@@ -937,7 +936,7 @@ export default class DevServer {
|
|||||||
debug(`Killing builder dev server with PID ${pid}`);
|
debug(`Killing builder dev server with PID ${pid}`);
|
||||||
this.devServerPids.delete(pid);
|
this.devServerPids.delete(pid);
|
||||||
try {
|
try {
|
||||||
await treeKill(pid);
|
process.kill(pid, 'SIGTERM');
|
||||||
debug(`Killed builder dev server with PID ${pid}`);
|
debug(`Killed builder dev server with PID ${pid}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(`Failed to kill builder dev server with PID ${pid}: ${err}`);
|
debug(`Failed to kill builder dev server with PID ${pid}: ${err}`);
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ export interface BuildResultV4 {
|
|||||||
|
|
||||||
export interface BuilderWithPackage {
|
export interface BuilderWithPackage {
|
||||||
runInProcess?: boolean;
|
runInProcess?: boolean;
|
||||||
|
requirePath: string;
|
||||||
builder: Readonly<Builder>;
|
builder: Readonly<Builder>;
|
||||||
package: Readonly<PackageJson>;
|
package: Readonly<PackageJson>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
import path from 'path';
|
import _pkg from '../../package.json';
|
||||||
import pkg from '../../package.json';
|
import { PackageJson } from '@now/build-utils';
|
||||||
|
|
||||||
try {
|
const pkg: PackageJson = _pkg;
|
||||||
const distDir = path.dirname(process.execPath);
|
|
||||||
// @ts-ignore
|
|
||||||
pkg._npmPkg = require(`${path.join(distDir, '../../package.json')}`);
|
|
||||||
} catch (err) {
|
|
||||||
// @ts-ignore
|
|
||||||
pkg._npmPkg = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default pkg;
|
export default pkg;
|
||||||
|
|||||||
113
packages/now-cli/test/dev-builder.unit.js
vendored
113
packages/now-cli/test/dev-builder.unit.js
vendored
@@ -1,7 +1,8 @@
|
|||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import { filterPackage } from '../src/util/dev/builder-cache';
|
import npa from 'npm-package-arg';
|
||||||
|
import { filterPackage, isBundledBuilder } from '../src/util/dev/builder-cache';
|
||||||
|
|
||||||
test('[dev-builder] filter install "latest", cached canary', async t => {
|
test('[dev-builder] filter install "latest", cached canary', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@now/build-utils': '0.0.1-canary.0',
|
'@now/build-utils': '0.0.1-canary.0',
|
||||||
@@ -11,7 +12,7 @@ test('[dev-builder] filter install "latest", cached canary', async t => {
|
|||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install "canary", cached stable', async t => {
|
test('[dev-builder] filter install "canary", cached stable', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@now/build-utils': '0.0.1',
|
'@now/build-utils': '0.0.1',
|
||||||
@@ -25,7 +26,7 @@ test('[dev-builder] filter install "canary", cached stable', async t => {
|
|||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install "latest", cached stable', async t => {
|
test('[dev-builder] filter install "latest", cached stable', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@now/build-utils': '0.0.1',
|
'@now/build-utils': '0.0.1',
|
||||||
@@ -35,7 +36,7 @@ test('[dev-builder] filter install "latest", cached stable', async t => {
|
|||||||
t.is(result, false);
|
t.is(result, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install "canary", cached canary', async t => {
|
test('[dev-builder] filter install "canary", cached canary', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@now/build-utils': '0.0.1-canary.0',
|
'@now/build-utils': '0.0.1-canary.0',
|
||||||
@@ -49,7 +50,7 @@ test('[dev-builder] filter install "canary", cached canary', async t => {
|
|||||||
t.is(result, false);
|
t.is(result, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install URL, cached stable', async t => {
|
test('[dev-builder] filter install URL, cached stable', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@now/build-utils': '0.0.1',
|
'@now/build-utils': '0.0.1',
|
||||||
@@ -59,7 +60,7 @@ test('[dev-builder] filter install URL, cached stable', async t => {
|
|||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install URL, cached canary', async t => {
|
test('[dev-builder] filter install URL, cached canary', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@now/build-utils': '0.0.1-canary.0',
|
'@now/build-utils': '0.0.1-canary.0',
|
||||||
@@ -69,7 +70,7 @@ test('[dev-builder] filter install URL, cached canary', async t => {
|
|||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install "latest", cached URL - stable', async t => {
|
test('[dev-builder] filter install "latest", cached URL - stable', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@now/build-utils': 'https://tarball.now.sh',
|
'@now/build-utils': 'https://tarball.now.sh',
|
||||||
@@ -79,7 +80,7 @@ test('[dev-builder] filter install "latest", cached URL - stable', async t => {
|
|||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install "latest", cached URL - canary', async t => {
|
test('[dev-builder] filter install "latest", cached URL - canary', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@now/build-utils': 'https://tarball.now.sh',
|
'@now/build-utils': 'https://tarball.now.sh',
|
||||||
@@ -89,7 +90,7 @@ test('[dev-builder] filter install "latest", cached URL - canary', async t => {
|
|||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install not bundled version, cached same version', async t => {
|
test('[dev-builder] filter install not bundled version, cached same version', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'not-bundled-package': '0.0.1',
|
'not-bundled-package': '0.0.1',
|
||||||
@@ -99,7 +100,7 @@ test('[dev-builder] filter install not bundled version, cached same version', as
|
|||||||
t.is(result, false);
|
t.is(result, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install not bundled version, cached different version', async t => {
|
test('[dev-builder] filter install not bundled version, cached different version', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'not-bundled-package': '0.0.9',
|
'not-bundled-package': '0.0.9',
|
||||||
@@ -109,7 +110,7 @@ test('[dev-builder] filter install not bundled version, cached different version
|
|||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install not bundled stable, cached version', async t => {
|
test('[dev-builder] filter install not bundled stable, cached version', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'not-bundled-package': '0.0.1',
|
'not-bundled-package': '0.0.1',
|
||||||
@@ -119,7 +120,7 @@ test('[dev-builder] filter install not bundled stable, cached version', async t
|
|||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[dev-builder] filter install not bundled tagged, cached tagged', async t => {
|
test('[dev-builder] filter install not bundled tagged, cached tagged', t => {
|
||||||
const buildersPkg = {
|
const buildersPkg = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'not-bundled-package': '16.9.0-alpha.0',
|
'not-bundled-package': '16.9.0-alpha.0',
|
||||||
@@ -128,3 +129,89 @@ test('[dev-builder] filter install not bundled tagged, cached tagged', async t =
|
|||||||
const result = filterPackage('not-bundled-package@alpha', '_', buildersPkg);
|
const result = filterPackage('not-bundled-package@alpha', '_', buildersPkg);
|
||||||
t.is(result, true);
|
t.is(result, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('[dev-builder] isBundledBuilder() - stable', t => {
|
||||||
|
const nowCliPkg = {
|
||||||
|
dependencies: {
|
||||||
|
'@now/node': '1.5.2',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// "canary" tag
|
||||||
|
{
|
||||||
|
const parsed = npa('@now/node@canary');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// "latest" tag
|
||||||
|
{
|
||||||
|
const parsed = npa('@now/node');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// specific matching version
|
||||||
|
{
|
||||||
|
const parsed = npa('@now/node@1.5.2');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// specific non-matching version
|
||||||
|
{
|
||||||
|
const parsed = npa('@now/node@1.5.1');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL
|
||||||
|
{
|
||||||
|
const parsed = npa('https://example.com');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[dev-builder] isBundledBuilder() - canary', t => {
|
||||||
|
const nowCliPkg = {
|
||||||
|
dependencies: {
|
||||||
|
'@now/node': '1.5.2-canary.3',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// "canary" tag
|
||||||
|
{
|
||||||
|
const parsed = npa('@now/node@canary');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// "latest" tag
|
||||||
|
{
|
||||||
|
const parsed = npa('@now/node');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// specific matching version
|
||||||
|
{
|
||||||
|
const parsed = npa('@now/node@1.5.2-canary.3');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// specific non-matching version
|
||||||
|
{
|
||||||
|
const parsed = npa('@now/node@1.5.2-canary.2');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL
|
||||||
|
{
|
||||||
|
const parsed = npa('https://example.com');
|
||||||
|
const result = isBundledBuilder(parsed, nowCliPkg);
|
||||||
|
t.is(result, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user