diff --git a/change/change-4a40cff7-6ec5-4fb0-b450-149b45575d41.json b/change/change-4a40cff7-6ec5-4fb0-b450-149b45575d41.json new file mode 100644 index 000000000..bf7f44230 --- /dev/null +++ b/change/change-4a40cff7-6ec5-4fb0-b450-149b45575d41.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "type": "patch", + "comment": "Tweak error message for missing worker script", + "packageName": "@lage-run/runners", + "email": "dobes@formative.com", + "dependentChangeType": "patch" + } + ] +} \ No newline at end of file diff --git a/docs/docs/reference/config.md b/docs/docs/reference/config.md index c3f4465e9..266b67b0f 100644 --- a/docs/docs/reference/config.md +++ b/docs/docs/reference/config.md @@ -29,23 +29,219 @@ Roll over the various properties to tour the different configs // ---cut--- module.exports = { pipeline: { + babel: { + /** + * Specify which input files are used to generate the output files. These + * are included in the cache hash to determine whether the result can be + * fetched from the cache instead of running the build, so it is important + * that the list is complete and as precise as possible. + * + * This uses 'micromatch' package to check the patterns against the files + * found on disk. Refer that package's documentation for the full syntax supported: + * + * https://github.com/micromatch/micromatch#readme + * + * Path patterns are applied to the list of files found inside the package + * the task would run in. + * + * If a path pattern is prefixed with '^' then files in packages the given + * package depends on which match the pattern will also be considered an input. + * + * Relative paths (with './' or '../' prefix) and absolute paths are not supported + * for inputs and will be ignored if provided as they will not match anything. + */ + inputs: ['src/**/*.{js,jsx,ts,tsx}'], + + /** + * Specify which files are expected to be produced. These are the files that + * will be stored in the cache and reproduced in case of a cache hit. It is + * important that this list be as complete and precise as possible so that + * if results are returned from the cache there is nothing missing, that there + * are not irrelevant extra files in the cache, and outputs from two different + * tasks do not conflict. + * + * The provided values are passed to the "globby" package, using the package directory + * as the working directory, to identify the files to hash and cache. Refer to its + * documentation for details: + * + * https://github.com/sindresorhus/globby#readme + * + */ + outputs: ['dist/*.js', 'dist/*.js.map'], + + /** + * For npm script, you can optionally set type: "npmScript" to explicitly indicate + * this would run a script from package.json in "scripts". + * + * By default type is set to "npmScript" if the task name matches an npm script + * in ANY package, otherwise it is set to "noop". + * + * Note that if you run lage with additional options after the task name(s) those + * arguments are passed through to the scripts that are run. For example + * "lage run build -- -e node" would pass "-e node" to the command for every script. + */ + type: "npmScript", + + /** + * For npm scripts there are some options available + */ + options: { + /** + * Actual npm script that will be run. Defaults to the same as the task name + * (excluding the package name if the task was defined for a specific package) + */ + script: "babel", + + /** + * Additional arguments passed to the script when it is run. Empty by default. + * + * These are added AFTER any arguments propagated from the lage command line. + */ + taskArgs: ["--env-name", "node"], + + /** + * Set the NODE_OPTIONS for running the task. Empty by default. + */ + nodeOptions: ["--max-old-space-size", "6000"] + } + }, build: ["^build"], test: { outputs: [], dependsOn: ["build"] }, + // Example worker task lint: { + /** + * When you set type: "worker" it creates a worker pool where + * the tasks are run by a worker script you provide instead of + * running the npm script. + * + * Because the worker retains state and loaded modules between + * tasks, it can cache modules, config, and other things in + * memory between tasks, reducing the per-task startup time. + * + * The underlying implementation is workerpool: + * + * https://www.npmjs.com/package/workerpool + * + * The main worker function (exported as either "run" or as the + * default export) is passed an object with these fields to run + * a task: + * + * - target: Information about the target, including: + * - target.id: Unique ID of the target (e.g. "pkg-a#build") + * - target.label: A display label of the target + * - target.cwd: Working directory of the target - full path + * - target.task: Name of the task for the target (e.g. "build", "test", "lint") + * - target.packageName: Package name of the target. Undefined if this target is associated with repo root. + * - target.options: Same options provided here, can be used to provide some additional + * options to your worker if you use the same worker in multiple tasks + * - weight: Specified/calculated weight of the target from the task config, + * this can be used to calculate parallelism or resource usage in the worker + * - taskArgs: Command line arguments provided to lage and taskArgs + * - abortSignal: Object used to signal that the task should exit ASAP + * - abortSignal.aborted: If true, the worker should stop working + * - abortSignal.addEventListener('abort', cb): Provide a callback that will be + * invoked if the build is aborted + * + * The worker can also export "shouldRun", an async function that returns a boolean + * indicating whether the task is applicable for a given workspace. It is provided + * with the target as its argument. + */ type: "worker", options: { + /** Limit the number of concurrent workers running tasks */ maxWorkers: 4, + /** Path to the script that implements the worker */ worker: "path/to/scripts/worker/lint.js" + }, + }, + + // Abstract task to requires a package and its dependencies are built + "build-recursive": { + /** + * If set type: "noop" then the task will not run; it will only cause + * tasks that it depends on to run. + * + * outputs are ignored for "noop" type tasks. + * + * Note that the task type will default to "noop" if no type is provided, + * and there is no package.json in the monorepo with a matching entry + * in "scripts". + */ + type: "noop", + + /** + * Specify tasks that should run before this one is considered done. + */ + dependsOn: [ + /** + * An unprefixed task references a task with that name in the same package. + */ + "build", + + /** + * If a task has a prefix '^' then it refers to tasks by that name + * in the direct dependencies of this package. + */ + "^build", + + /** + * If a task has a prefix '^^' then it refers to tasks by that name + * in the direct and indirect dependencies of this package. + */ + "^^build", + + /** + * A task can have a prefix of a package name plus '#' to create a + * dependency on a task just in a specific package. This is useful + * if the script runs a tool that is built in another package, for + * example. + */ + "some-package#build", + ], + + /** + * A shouldRun() function can be defined for any task to filter which + * workspaces it applies to. + * + * For example this could be used to only run a task if there's an + * appropriate config file present. + * + * For a worker task, this is in addition to any "shouldRun" exported from the + * worker script. + * + * For an npm script, this in addition to checking that the script is defined + * in package.json for that package. + * + * This could also be just a boolean instead of a function if the calculation + * can be statically determined (e.g. based on an environment variable). + */ + shouldRun(target) { + // Only run this if package.json defines a "bin" field, indicating there + // is something to run in there + return !!require(path.join(target.cwd, 'package.json')).bin } }, - start: [], // Calls "start" in all the packages + + // Calls "start" in all the packages + start: { + /** + * Set cache: false on any task whose results should not be cached + */ + cache: false, + /** + * An empty dependsOn array means the task can always run immediately. + */ + dependsOn: [] + }, "specific-package-a#test": ["specific-package-b#build"] }, - // optional, by default "npm run" is used; "yarn" can exhibit slightly different behavior, + /** + * Specify whether to use "yarn" or "npm" to run scripts from package.json. Defaults to "npm" + */ npmClient: "yarn", cacheOptions: { @@ -66,7 +262,8 @@ module.exports = { environmentGlob: [".github/**", ".azure-devops/**"], /** - * Useful for when caches need to be versioned + * Useful for when caches need to be versioned. Can potentially include the + * values of any environment variables in here that should trigger a rebuild. */ cacheKey: "v1", diff --git a/packages/runners/src/WorkerRunner.ts b/packages/runners/src/WorkerRunner.ts index 7865ebaf9..9ec6650ed 100644 --- a/packages/runners/src/WorkerRunner.ts +++ b/packages/runners/src/WorkerRunner.ts @@ -79,7 +79,7 @@ export class WorkerRunner implements TargetRunner { const scriptFile = target.options?.worker ?? target.options?.script; if (!scriptFile) { - throw new Error('WorkerRunner: "script" configuration is required - e.g. { type: "worker", script: "./worker.js" }'); + throw new Error('WorkerRunner: "worker" configuration is required - e.g. { type: "worker", options: { worker: "path/to/worker.js" } }'); } let importScript = scriptFile;