diff --git a/packages/cli/src/commands/app/serve.ts b/packages/cli/src/commands/app/serve.ts index 495f398059..418e1e9e86 100644 --- a/packages/cli/src/commands/app/serve.ts +++ b/packages/cli/src/commands/app/serve.ts @@ -16,8 +16,8 @@ import { spawn } from 'child_process'; import { waitForExit } from 'lib/run'; -import { watchDeps } from 'commands/watch-deps'; import { createLogFunc } from 'lib/logging'; +import { watchDeps } from 'lib/watchDeps'; export default async () => { // Start dynamic watch and build of dependencies, then serve the app diff --git a/packages/cli/src/commands/watch-deps/index.ts b/packages/cli/src/commands/watch-deps/index.ts index 58bcf5eefc..9645dec5fa 100644 --- a/packages/cli/src/commands/watch-deps/index.ts +++ b/packages/cli/src/commands/watch-deps/index.ts @@ -14,71 +14,11 @@ * limitations under the License. */ -import chalk from 'chalk'; -import fs from 'fs-extra'; -import { createLogPipeFactory } from './logger'; -import { findAllDeps } from './packages'; -import { startWatcher, startPackageWatcher } from './watcher'; -import { startCompiler } from './compiler'; -import { startChild } from './child'; -import { waitForExit, run } from 'lib/run'; -import { paths } from 'lib/paths'; +import { spawn } from 'child_process'; import { Command } from 'commander'; - -const PACKAGE_BLACKLIST = [ - // We never want to watch for changes in the cli, but all packages will depend on it. - '@backstage/cli', -]; - -const WATCH_LOCATIONS = ['package.json', 'src', 'assets']; - -export type Options = { - build?: boolean; -}; - -// Start watching for dependency changes. -// The returned promise resolves when watchers have started for all current dependencies. -export async function watchDeps(options: Options = {}) { - const localPackagePath = paths.resolveTarget('package.json'); - - // Rotate through different prefix colors to make it easier to differenciate between different deps - const createLogPipe = createLogPipeFactory([ - chalk.yellow, - chalk.blue, - chalk.magenta, - chalk.green, - chalk.cyan, - ]); - - // Find all direct and transitive local dependencies of the current package. - const packageData = await fs.readFile(localPackagePath, 'utf8'); - const packageJson = JSON.parse(packageData); - const packageName = packageJson.name; - - const deps = await findAllDeps(packageName, PACKAGE_BLACKLIST); - - if (options.build) { - await run('lerna', [ - 'run', - '--scope', - packageName, - '--include-dependencies', - 'build', - ]); - } - - // We lazily watch all our deps, as in we don't start the actual watch compiler until a change is detected - const watcher = await startWatcher(deps, WATCH_LOCATIONS, pkg => { - startCompiler(pkg, createLogPipe(pkg.name)).promise.catch(error => { - process.stderr.write(`${error}\n`); - }); - }); - - await startPackageWatcher(localPackagePath, async () => { - const newDeps = await findAllDeps(packageName, PACKAGE_BLACKLIST); - await watcher.update(newDeps); - }); -} +import { waitForExit } from 'lib/run'; +import { createLogPipe } from 'lib/logging'; +import { watchDeps, Options } from 'lib/watchDeps'; /* * The watch-deps command is meant to improve iteration speed while working in a large monorepo @@ -99,6 +39,17 @@ export default async (cmd: Command, args: string[]) => { await watchDeps(options); if (args?.length) { - await waitForExit(startChild(args)); + const child = spawn(args[0], args.slice(1), { + env: { FORCE_COLOR: 'true', ...process.env }, + stdio: ['inherit', 'pipe', 'pipe'], + shell: true, + }); + + // Use log pipe to avoid clearing the terminal + const logPipe = createLogPipe(); + child.stdout.on('data', logPipe(process.stdout)); + child.stderr.on('data', logPipe(process.stderr)); + + await waitForExit(child); } }; diff --git a/packages/cli/src/commands/watch-deps/compiler.ts b/packages/cli/src/lib/watchDeps/compiler.ts similarity index 100% rename from packages/cli/src/commands/watch-deps/compiler.ts rename to packages/cli/src/lib/watchDeps/compiler.ts diff --git a/packages/cli/src/commands/watch-deps/child.ts b/packages/cli/src/lib/watchDeps/index.ts similarity index 50% rename from packages/cli/src/commands/watch-deps/child.ts rename to packages/cli/src/lib/watchDeps/index.ts index a098e6f67c..a6fc92ca91 100644 --- a/packages/cli/src/commands/watch-deps/child.ts +++ b/packages/cli/src/lib/watchDeps/index.ts @@ -14,20 +14,4 @@ * limitations under the License. */ -import { spawn } from 'child_process'; -import { createLogPipe } from 'lib/logging'; - -export function startChild(args: string[]) { - const [command, ...commandArgs] = args; - const child = spawn(command, commandArgs, { - env: { FORCE_COLOR: 'true', ...process.env }, - stdio: ['inherit', 'pipe', 'pipe'], - shell: true, - }); - - // We need to avoid clearing the terminal, or the build feedback of dependencies will be lost - const logPipe = createLogPipe(); - child.stdout.on('data', logPipe(process.stdout)); - child.stderr.on('data', logPipe(process.stderr)); - return child; -} +export * from './watchDeps'; diff --git a/packages/cli/src/commands/watch-deps/logger.ts b/packages/cli/src/lib/watchDeps/logger.ts similarity index 100% rename from packages/cli/src/commands/watch-deps/logger.ts rename to packages/cli/src/lib/watchDeps/logger.ts diff --git a/packages/cli/src/commands/watch-deps/packages.ts b/packages/cli/src/lib/watchDeps/packages.ts similarity index 100% rename from packages/cli/src/commands/watch-deps/packages.ts rename to packages/cli/src/lib/watchDeps/packages.ts diff --git a/packages/cli/src/lib/watchDeps/watchDeps.ts b/packages/cli/src/lib/watchDeps/watchDeps.ts new file mode 100644 index 0000000000..e4b5d1e4b3 --- /dev/null +++ b/packages/cli/src/lib/watchDeps/watchDeps.ts @@ -0,0 +1,79 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import chalk from 'chalk'; +import fs from 'fs-extra'; +import { createLogPipeFactory } from './logger'; +import { findAllDeps } from './packages'; +import { startWatcher, startPackageWatcher } from './watcher'; +import { startCompiler } from './compiler'; +import { run } from 'lib/run'; +import { paths } from 'lib/paths'; + +const PACKAGE_BLACKLIST = [ + // We never want to watch for changes in the cli, but all packages will depend on it. + '@backstage/cli', +]; + +const WATCH_LOCATIONS = ['package.json', 'src', 'assets']; + +export type Options = { + build?: boolean; +}; + +// Start watching for dependency changes. +// The returned promise resolves when watchers have started for all current dependencies. +export async function watchDeps(options: Options = {}) { + const localPackagePath = paths.resolveTarget('package.json'); + + // Rotate through different prefix colors to make it easier to differenciate between different deps + const createLogPipe = createLogPipeFactory([ + chalk.yellow, + chalk.blue, + chalk.magenta, + chalk.green, + chalk.cyan, + ]); + + // Find all direct and transitive local dependencies of the current package. + const packageData = await fs.readFile(localPackagePath, 'utf8'); + const packageJson = JSON.parse(packageData); + const packageName = packageJson.name; + + const deps = await findAllDeps(packageName, PACKAGE_BLACKLIST); + + if (options.build) { + await run('lerna', [ + 'run', + '--scope', + packageName, + '--include-dependencies', + 'build', + ]); + } + + // We lazily watch all our deps, as in we don't start the actual watch compiler until a change is detected + const watcher = await startWatcher(deps, WATCH_LOCATIONS, pkg => { + startCompiler(pkg, createLogPipe(pkg.name)).promise.catch(error => { + process.stderr.write(`${error}\n`); + }); + }); + + await startPackageWatcher(localPackagePath, async () => { + const newDeps = await findAllDeps(packageName, PACKAGE_BLACKLIST); + await watcher.update(newDeps); + }); +} diff --git a/packages/cli/src/commands/watch-deps/watcher.ts b/packages/cli/src/lib/watchDeps/watcher.ts similarity index 100% rename from packages/cli/src/commands/watch-deps/watcher.ts rename to packages/cli/src/lib/watchDeps/watcher.ts