Merge pull request #490 from spotify/rugvip/with-cache
packages/cli: make plugin:build have built-in caching
This commit is contained in:
@@ -14,27 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import { Command } from 'commander';
|
||||
import { run } from 'helpers/run';
|
||||
import { Cache } from './cache';
|
||||
import { parseOptions } from './options';
|
||||
import { parseOptions, Options } from './options';
|
||||
|
||||
function print(msg: string) {
|
||||
process.stdout.write(`[build-cache] ${msg}\n`);
|
||||
}
|
||||
|
||||
/*
|
||||
* The build-cache command is used to make builds a no-op if there are no changes to the package.
|
||||
* It supports both local development where the output directory remains intact, as well as CI
|
||||
* where the output directory is stored in a separate cache dir.
|
||||
*/
|
||||
export default async (cmd: Command, args: string[]) => {
|
||||
const options = await parseOptions(cmd);
|
||||
|
||||
// Wrap a build function with a cache, which won't call the build function on cache hit
|
||||
export async function withCache(
|
||||
options: Options,
|
||||
buildFunc: () => Promise<void>,
|
||||
): Promise<void> {
|
||||
const key = await Cache.readInputKey(options.inputs);
|
||||
if (!key) {
|
||||
print('input directory is dirty, skipping cache');
|
||||
await run(args[0], args.slice(1));
|
||||
await fs.remove(options.output);
|
||||
await buildFunc();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,9 +51,23 @@ export default async (cmd: Command, args: string[]) => {
|
||||
}
|
||||
|
||||
print('cache miss, need to build');
|
||||
await fs.remove(options.output);
|
||||
await buildFunc();
|
||||
|
||||
await run(args[0], args.slice(1));
|
||||
|
||||
print('caching build output');
|
||||
await cacheResult.archive(options.output, options.maxCacheEntries);
|
||||
}
|
||||
|
||||
/*
|
||||
* The build-cache command is used to make builds a no-op if there are no changes to the package.
|
||||
* It supports both local development where the output directory remains intact, as well as CI
|
||||
* where the output directory is stored in a separate cache dir.
|
||||
*/
|
||||
export default async (cmd: Command, args: string[]) => {
|
||||
const options = await parseOptions(cmd);
|
||||
|
||||
await withCache(options, async () => {
|
||||
await run(args[0], args.slice(1));
|
||||
});
|
||||
};
|
||||
|
||||
export * from './options';
|
||||
|
||||
@@ -18,6 +18,7 @@ import { resolve as resolvePath } from 'path';
|
||||
import { Command } from 'commander';
|
||||
import { paths } from 'helpers/paths';
|
||||
|
||||
const DEFAULT_CACHE_DIR = '<repoRoot>/node_modules/.cache/backstage-builds';
|
||||
const DEFAULT_MAX_ENTRIES = 10;
|
||||
|
||||
export type Options = {
|
||||
@@ -27,19 +28,34 @@ export type Options = {
|
||||
maxCacheEntries: number;
|
||||
};
|
||||
|
||||
export async function parseOptions(cmd: Command): Promise<Options> {
|
||||
const argTransformer = (arg: string) =>
|
||||
resolvePath(arg.replace(/<repoRoot>/g, paths.targetRoot).replace(/'/g, ''));
|
||||
function transformPath(path: string): string {
|
||||
return resolvePath(
|
||||
path.replace(/<repoRoot>/g, paths.targetRoot).replace(/'/g, ''),
|
||||
);
|
||||
}
|
||||
|
||||
const inputs = cmd.input.map(argTransformer) as string[];
|
||||
export async function parseOptions(cmd: Command): Promise<Options> {
|
||||
const inputs = cmd.input.map(transformPath) as string[];
|
||||
if (inputs.length === 0) {
|
||||
inputs.push(argTransformer('.'));
|
||||
inputs.push(transformPath('.'));
|
||||
}
|
||||
const output = argTransformer(cmd.output);
|
||||
const cacheDir = argTransformer(
|
||||
const output = transformPath(cmd.output);
|
||||
const cacheDir = transformPath(
|
||||
process.env.BACKSTAGE_CACHE_DIR || cmd.cacheDir,
|
||||
);
|
||||
const maxCacheEntries =
|
||||
Number(process.env.BACKSTAGE_CACHE_MAX_ENTRIES) || DEFAULT_MAX_ENTRIES;
|
||||
return { inputs, output, cacheDir, maxCacheEntries };
|
||||
}
|
||||
|
||||
export function getDefaultCacheOptions(): Options {
|
||||
return {
|
||||
inputs: [transformPath('.')],
|
||||
output: transformPath('dist'),
|
||||
cacheDir: transformPath(
|
||||
process.env.BACKSTAGE_CACHE_DIR || DEFAULT_CACHE_DIR,
|
||||
),
|
||||
maxCacheEntries:
|
||||
Number(process.env.BACKSTAGE_CACHE_MAX_ENTRIES) || DEFAULT_MAX_ENTRIES,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import { rollup, watch, OutputOptions } from 'rollup';
|
||||
import conf from './rollup.config';
|
||||
import { Command } from 'commander';
|
||||
import { withCache, getDefaultCacheOptions } from 'commands/build-cache';
|
||||
|
||||
export default async (cmd: Command) => {
|
||||
if (cmd.watch) {
|
||||
@@ -40,10 +41,12 @@ export default async (cmd: Command) => {
|
||||
});
|
||||
}
|
||||
|
||||
const bundle = await rollup({
|
||||
input: conf.input,
|
||||
plugins: conf.plugins,
|
||||
await withCache(getDefaultCacheOptions(), async () => {
|
||||
const bundle = await rollup({
|
||||
input: conf.input,
|
||||
plugins: conf.plugins,
|
||||
});
|
||||
await bundle.generate(conf.output as OutputOptions);
|
||||
await bundle.write(conf.output as OutputOptions);
|
||||
});
|
||||
await bundle.generate(conf.output as OutputOptions);
|
||||
await bundle.write(conf.output as OutputOptions);
|
||||
};
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build:watch": "backstage-cli plugin:build --watch",
|
||||
"build": "backstage-cli build-cache -- backstage-cli plugin:build",
|
||||
"build": "backstage-cli plugin:build",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test"
|
||||
},
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build:watch": "backstage-cli plugin:build --watch",
|
||||
"build": "backstage-cli build-cache -- backstage-cli plugin:build",
|
||||
"build": "backstage-cli plugin:build",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test"
|
||||
},
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build:watch": "backstage-cli plugin:build --watch",
|
||||
"build": "backstage-cli build-cache -- backstage-cli plugin:build",
|
||||
"build": "backstage-cli plugin:build",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test"
|
||||
},
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"build:watch": "backstage-cli plugin:build --watch",
|
||||
"build": "backstage-cli build-cache -- backstage-cli plugin:build",
|
||||
"build": "backstage-cli plugin:build",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user