{"id":13532418,"url":"https://github.com/FormidableLabs/builder","last_synced_at":"2025-04-01T20:32:06.411Z","repository":{"id":1984791,"uuid":"44566613","full_name":"FormidableLabs/builder","owner":"FormidableLabs","description":"An npm-based task runner","archived":true,"fork":false,"pushed_at":"2022-03-03T22:32:10.000Z","size":845,"stargazers_count":319,"open_issues_count":48,"forks_count":26,"subscribers_count":56,"default_branch":"master","last_synced_at":"2025-03-11T22:24:04.305Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://github.com/FormidableLabs/builder","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FormidableLabs.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-19T22:00:13.000Z","updated_at":"2024-02-08T19:53:48.000Z","dependencies_parsed_at":"2022-08-06T11:16:32.657Z","dependency_job_id":null,"html_url":"https://github.com/FormidableLabs/builder","commit_stats":null,"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Fbuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Fbuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Fbuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Fbuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FormidableLabs","download_url":"https://codeload.github.com/FormidableLabs/builder/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246709923,"owners_count":20821297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T07:01:10.826Z","updated_at":"2025-04-01T20:32:01.391Z","avatar_url":"https://github.com/FormidableLabs.png","language":"JavaScript","readme":"[![Travis Status][trav_img]][trav_site]\n[![Appveyor Status][av_img]][av_site]\n[![Coverage Status][cov_img]][cov_site]\n[![Maintenance Status][maintenance-image]](#maintenance-status)\n\n\nBuilder\n=======\n\nBuilder takes your `npm` tasks and makes them composable, controllable from\na single point, and flexible.\n\n`npm` is fantastic for controlling tasks (via `scripts`) and general project\nworkflows. But a project-specific `package.json` simply doesn't scale when\nyou're managing many (say 5-50) very similar repositories.\n\n_Enter Builder._ Builder is \"almost\" `npm`, but provides for off-the-shelf\n\"archetypes\" to provide central sets of `package.json` `scripts` tasks, and\n`dependencies` and `devDependencies` for those tasks. The rest of this page will\ndive into the details and machinations of the tool, but first here are a few of\nthe rough goals and motivations behind the project.\n\n* **Single Point of Control**: A way to define a specific set of tasks /\n  configs / etc. for one \"type\" of project. For example, we have an\n  ever-expanding set of related repos for our\n  [Victory](https://github.com/FormidableLabs/?utf8=%E2%9C%93\u0026query=victory)\n  project which all share a nearly-identical dev / prod / build workflow.\n* **Flexibility**: There are a number of meta tools for controlling JavaScript\n  workflows / development lifecycles. However, most are of the \"buy the farm\"\n  nature. This works great when everything is within the workflow but falls\n  apart once you want to be \"just slightly\" different. Builder solves this by\n  allowing fine grain task overriding by name, where the larger composed tasks\n  still stay the same and allow a specific repo's deviation from \"completely off\n  the shelf\" to be painless.\n* **You Can Give Up**: One of the main goals of builder is to remain very\n  close to a basic `npm` workflow. So much so, that we include a section in this\n  guide on how to abandon the use of Builder in a project and revert everything\n  from archetypes back to vanilla `npm` `package.json` `scripts`, `dependencies`\n  and `devDependencies`.\n* **A Few \"Nice to Haves\" Over `npm run \u003ctask\u003e`**: Setting aside archetypes and\n  multi-project management, `builder` provides cross-OS compatible helpers for\n  common task running scenarios like concurrent execution (`concurrent`) and\n  spawning the _same_ tasks in parallel with different environment variables\n  (`env`). It also provides useful controls for task retries, buffered output,\n  setup tasks, etc.\n\n**Contents**:\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n\n- [Overview](#overview)\n  - [Usage](#usage)\n    - [Global Install](#global-install)\n    - [Local Install](#local-install)\n      - [PATH Augmentation](#path-augmentation)\n      - [Full Path Invocation](#full-path-invocation)\n    - [Configuration](#configuration)\n    - [Builder Actions](#builder-actions)\n      - [builder run](#builder-run)\n      - [builder concurrent](#builder-concurrent)\n      - [builder envs](#builder-envs)\n    - [Setup Task](#setup-task)\n    - [Task Lifecycle](#task-lifecycle)\n      - [The Basics](#the-basics)\n      - [Other Builder Actions](#other-builder-actions)\n      - [Builder Flags During Pre and Post](#builder-flags-during-pre-and-post)\n      - [Task Prefix Complexities](#task-prefix-complexities)\n    - [Custom Flags](#custom-flags)\n    - [Expanding the Archetype Path](#expanding-the-archetype-path)\n- [Tasks](#tasks)\n- [npm Config](#npm-config)\n  - [`npm` Config Overview](#npm-config-overview)\n  - [Builder Configs](#builder-configs)\n  - [Config Notes](#config-notes)\n    - [Tip - Use String Values](#tip---use-string-values)\n    - [npmrc Configuration](#npmrc-configuration)\n    - [Command Line Environment Variables](#command-line-environment-variables)\n- [Archetypes](#archetypes)\n  - [Task Resolution](#task-resolution)\n  - [Special Archetype Tasks](#special-archetype-tasks)\n  - [Creating an Archetype](#creating-an-archetype)\n    - [Initializing a Project](#initializing-a-project)\n    - [Managing the `dev` Archetype](#managing-the-dev-archetype)\n    - [Node Require Resolution and Module Pattern](#node-require-resolution-and-module-pattern)\n      - [The Module Pattern](#the-module-pattern)\n        - [ES.next Imports and The Module Pattern](#esnext-imports-and-the-module-pattern)\n        - [Webpack and Module Pattern](#webpack-and-module-pattern)\n    - [Application vs. Archetype Dependencies](#application-vs-archetype-dependencies)\n    - [Moving `dependencies` and `scripts` to a New Archetype](#moving-dependencies-and-scripts-to-a-new-archetype)\n      - [Moving `dependencies` and `devDependencies` from an Existing `package.json`](#moving-dependencies-and-devdependencies-from-an-existing-packagejson)\n      - [Moving `scripts` and Config Files](#moving-scripts-and-config-files)\n      - [Updating Path and Module References in Config Files](#updating-path-and-module-references-in-config-files)\n    - [Example `builder` Archetype Project Structure](#example-builder-archetype-project-structure)\n- [Tips, Tricks, \u0026 Notes](#tips-tricks--notes)\n  - [PATH, NODE_PATH Resolution](#path-node_path-resolution)\n  - [Environment Variables](#environment-variables)\n  - [Alternative to `npm link`](#alternative-to-npm-link)\n  - [Project Root](#project-root)\n  - [Avoid npm Lifecycle Commands](#avoid-npm-lifecycle-commands)\n  - [Other Process Execution](#other-process-execution)\n  - [I Give Up. How Do I Abandon Builder?](#i-give-up-how-do-i-abandon-builder)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Overview\n\nAt a high level `builder` is a tool for consuming `package.json` `scripts`\ncommands, providing sensible / flexible defaults, and supporting various scenarios\n(\"archetypes\") for your common use cases across multiple projects.\n\nBuilder is not opinionated, although archetypes _are_ and typically dictate\nfile structure, standard configurations, and dev workflows. Builder supports\nthis in an agnostic way, providing essentially the following:\n\n* `NODE_PATH`, `PATH` enhancements and module patterns to run, build, import\n  from archetypes so task dependencies and configurations don't have to be\n  installed directly in a root project.\n* A task runner capable of single tasks (`run`) or multiple concurrent tasks\n  (`concurrent`).\n* An intelligent merging of `package.json` `scripts` tasks.\n\n... and that's about it!\n\n### Usage\n\nTo start using builder, install and save `builder` and any archetypes you\nintend to use. We'll use the [builder-react-component][] archetype as an\nexample.\n\n**Note**: Most archetypes have an `ARCHETYPE` package and parallel\n`ARCHETYPE-dev` npm package. The `ARCHETYPE` package contains _almost_\neverything needed for the archetype (prod dependencies, scripts, etc.) except\nfor the `devDependencies` which the latter `ARCHETYPE-dev` package is solely\nresponsible for bringing in.\n\n#### Global Install\n\nFor ease of use, one option is to globally install `builder` and locally install\narchetypes:\n\n```sh\n$ npm install -g builder\n$ npm install --save builder-react-component\n$ npm install --save-dev builder-react-component-dev\n```\n\nLike a global install of _any_ Node.js meta / task runner tool (e.g., `eslint`,\n`mocha`, `gulp`, `grunt`) doing a global install is painful because:\n\n* You are tied to _just one_ version of the tool for all projects.\n* You must also globally install the tool in CI, on servers, etc.\n\n... so instead, we **strongly recommend** a local install described in the\nnext section!\n\nTo help you keep up with project-specific builder requirements, a globally-installed\n`builder` will detect if a locally-installed version of `builder` is\navailable and switch to that instead:\n\n```sh\n$ /GLOBAL/PATH/TO/builder\n[builder:local-detect] Switched to local builder at: ./node_modules/builder/bin/builder-core.js\n\n... now using local builder! ...\n```\n\n#### Local Install\n\nTo avoid tying yourself to a single, global version of `builder`, the option\nthat we endorse is locally installing both `builder` and archetypes:\n\n```sh\n$ npm install --save builder\n$ npm install --save builder-react-component\n$ npm install --save-dev builder-react-component-dev\n```\n\nHowever, to call `builder` from the command line you will either need to either\naugment `PATH` or call the long form of the command:\n\n##### PATH Augmentation\n\nOur recommended approach is to augment your `PATH` variable with a shell\nconfiguration as follows:\n\n**Mac / Linux**\n\n```sh\n# Safer version, but if you _have_ global installs, those come first.\nexport PATH=\"${PATH}:./node_modules/.bin\"\n\n# (OR) Less safe, but guarantees local node modules come first.\nexport PATH=\"./node_modules/.bin:${PATH}\"\n\n# Check results with:\necho $PATH\n```\n\nTo make these changes **permanent**, add the `export` command to your `.bashrc`\nor analogous shell configuration file.\n\n**Windows**\n\n```sh\n# Safer version, but if you _have_ global installs, those come first.\nset PATH=%PATH%;node_modules\\.bin\n\n# (OR) Less safe, but guarantees local node modules come first.\nset PATH=node_modules\\.bin;%PATH%\n\n# Check results with:\necho %PATH%\n```\n\nTo make these changes **permanent**, please see this multi-OS article on\nchanging the `PATH` variable: https://www.java.com/en/download/help/path.xml\n(the article is targeted for a Java executable, but it's analogous to our\nsituation). You'll want to paste in `;node_modules\\.bin` at the end _or_\n`node_modules\\.bin;` at the beginning of the PATH field in the gui. If there\nis no existing `PATH` then add a user entry with `node_modules\\.bin` as a value.\n(It is unlikely to be empty because an `npm` installation on Windows sets the\nuser `PATH` analogously.)\n\n##### Full Path Invocation\n\nOr you can run the complete path to the builder script with:\n\n**Mac / Linux**\n\n```sh\nnode_modules/.bin/builder \u003caction\u003e \u003ctask\u003e\n```\n\n**Windows**\n\n```sh\nnode_modules\\.bin\\builder \u003caction\u003e \u003ctask\u003e\n```\n\n#### Configuration\n\nAfter `builder` is available, you can edit `.builderrc` like:\n\n```yaml\n---\narchetypes:\n  - builder-react-component\n```\n\nto bind archetypes.\n\n... and from here you are set for `builder`-controlled meta goodness!\n\n#### Builder Actions\n\nDisplay general or command-specific help (which shows available specific flags).\n\n```sh\n$ builder [-h|--help|help]\n$ builder help \u003caction\u003e\n$ builder help \u003carchetype\u003e\n```\n\nRun `builder help \u003caction\u003e` for all available options. Version information is\navailable with:\n\n```sh\n$ builder [-v|--version]\n```\n\nLet's dive a little deeper into the main builder actions:\n\n##### builder run\n\nRun a single task from `script`. Analogous to `npm run \u003ctask\u003e`\n\n```sh\n$ builder run \u003ctask\u003e\n```\n\nFlags:\n\n* `--tries`: Number of times to attempt a task (default: `1`)\n* `--setup`: Single task to run for the entirety of `\u003caction\u003e`\n* `--quiet`: Silence logging\n* `--log-level`: Level to log at (`debug`, `info`, `warn`, `error`, `none`) (default: `error`)\n* `--env`: JSON object of keys to add to environment.\n* `--env-path`: JSON file path of keys to add to environment.\n* `--expand-archetype`: Expand `node_modules/\u003carchetype\u003e` with full path (default: `false`)\n* `--builderrc`: Path to builder config file (default: `.builderrc`)\n\n##### builder concurrent\n\nRun multiple tasks from `script` concurrently. Roughly analogous to\n`npm run \u003ctask1\u003e \u0026 npm run \u003ctask2\u003e \u0026 npm run \u003ctask3\u003e`, but kills all processes on\nfirst non-zero exit (which makes it suitable for test tasks), unless `--no-bail`\nis provided.\n\n```sh\n$ builder concurrent \u003ctask1\u003e \u003ctask2\u003e \u003ctask3\u003e\n```\n\nFlags:\n\n* `--tries`: Number of times to attempt a task (default: `1`)\n* `--setup`: Single task to run for the entirety of `\u003caction\u003e`.\n    * **Note**: The `--setup` task is run at the start of the first main task\n      to actually run. This may _not_ be the first specified task however,\n      as `pre` tasks could end up with main tasks starting out of order.\n* `--queue`: Number of concurrent processes to run (default: unlimited - `0|null`)\n* `--[no-]buffer`: Buffer output until process end (default: `false`)\n* `--[no-]bail`: End all processes after the first failure (default: `true`)\n* `--quiet`: Silence logging\n* `--log-level`: Level to log at (`debug`, `info`, `warn`, `error`, `none`) (default: `error`)\n* `--env`: JSON object of keys to add to environment.\n* `--env-path`: JSON file path of keys to add to environment.\n* `--expand-archetype`: Expand `node_modules/\u003carchetype\u003e` with full path (default: `false`)\n* `--builderrc`: Path to builder config file (default: `.builderrc`)\n\nNote that `tries` will retry _individual_ tasks that are part of the concurrent\ngroup, not the group itself. So, if `builder concurrent --tries=3 foo bar baz`\nis run and bar fails twice, then only `bar` would be retried. `foo` and `baz`\nwould only execute _once_ if successful.\n\n##### builder envs\n\nRun a single task from `script` concurrently for each item in an array of different\nenvironment variables. Roughly analogous to:\n\n```sh\n$ FOO=VAL1 npm run \u003ctask\u003e \u0026 FOO=VAL2 npm run \u003ctask\u003e \u0026 FOO=VAL3 npm run \u003ctask\u003e\n```\n\n... but kills all processes on first non-zero exit (which makes it suitable for\ntest tasks), unless `--no-bail` is provided. Usage:\n\n```sh\n$ builder envs \u003ctask\u003e \u003cjson-array\u003e\n$ builder envs \u003ctask\u003e --envs-path=\u003cpath-to-json-file\u003e\n```\n\nExamples:\n\n**Mac / Linux**\n\n```sh\n$ builder envs \u003ctask\u003e '[{ \"FOO\": \"VAL1\" }, { \"FOO\": \"VAL2\" }, { \"FOO\": \"VAL3\" }]'\n$ builder envs \u003ctask\u003e '[{ \"FOO\": \"VAL1\", \"BAR\": \"VAL2\" }, { \"FOO\": \"VAL3\" }]'\n```\n\n**Mac / Linux / Windows**\n\n```sh\n$ builder envs \u003ctask\u003e \"[{ \\\"FOO\\\": \\\"VAL1\\\" }, { \\\"FOO\\\": \\\"VAL2\\\" }, { \\\"FOO\\\": \\\"VAL3\\\" }]\"\n$ builder envs \u003ctask\u003e \"[{ \\\"FOO\\\": \\\"VAL1\\\", \\\"BAR\\\": \\\"VAL2\\\" }, { \\\"FOO\\\": \\\"VAL3\\\" }]\"\n```\n\nFlags:\n\n* `--tries`: Number of times to attempt a task (default: `1`)\n* `--setup`: Single task to run for the entirety of `\u003caction\u003e`\n    * **Note**: The `--setup` task is run at the start of the first main task\n      to actually run. This may _not_ be the first specified task however,\n      as `pre` tasks could end up with main tasks per environment object\n      starting out of order.\n* `--queue`: Number of concurrent processes to run (default: unlimited - `0|null`)\n* `--[no-]buffer`: Buffer output until process end (default: `false`)\n* `--[no-]bail`: End all processes after the first failure (default: `true`)\n* `--envs-path`: Path to JSON env variable array file (default: `null`)\n* `--quiet`: Silence logging\n* `--log-level`: Level to log at (`debug`, `info`, `warn`, `error`, `none`) (default: `error`)\n* `--env`: JSON object of keys to add to environment.\n* `--env-path`: JSON file path of keys to add to environment.\n* `--expand-archetype`: Expand `node_modules/\u003carchetype\u003e` with full path (default: `false`)\n* `--builderrc`: Path to builder config file (default: `.builderrc`)\n\n_Note_: The environments JSON array will overwrite **existing** values in the\nenvironment. This includes environment variables provided to / from `builder`\nfrom things such as `npm` `config` and the `--env`/`--env-path` flags.\n\nSo, for example, if you invoke `builder` with:\n\n```js\n$ builder envs \u003ctask\u003e '[{\"FOO\": \"ENVS\"}]' --env='{\"FOO\": \"FLAG\"}'\n```\n\nThe environment variable `FOO` will have a value of `\"ENVS\"` with the single\nenvironment object array item given to `builder envs` overriding the `--env`\nflag value.\n\n#### Setup Task\n\nA task specified in `--setup \u003ctask\u003e` will have the following flags apply to\nthe setup task as apply to the main task:\n\n* `--env`\n* `--env-path`\n* `--quiet`\n* `--log-level`\n\nThe following flags do _not_ apply to a setup task:\n\n* `--` custom flags\n* `--tries`\n* `--expand-archetype`\n* `--queue`\n* `--buffer`\n\nThat said, if you need things like `--tries`, etc., these can be always coded\ninto a wrapped task like:\n\n```js\n\"scripts\": {\n  \"setup-alone\": \"while sleep 1; do echo SETUP; done\",\n  \"setup\": \"builder run --tries=5 setup-alone\",\n  \"test\": \"mocha\",\n  \"test-full\": \"builder run --setup=setup test\"\n}\n```\n\n#### Task Lifecycle\n\nBuilder executes `pre\u003ctask\u003e` and `post\u003ctask\u003e` tasks the same as `npm` does,\nwith some perhaps not completely obvious corner cases.\n\n##### The Basics\n\nIf you have:\n\n```js\n\"scripts\": {\n  \"prefoo\": \"echo PRE\",\n  \"foo\": \"echo TEMP\",\n  \"postfoo\": \"echo POST\"\n}\n```\n\nAnd run `builder run foo`, then just like `npm`, builder will run in order:\n\n1. `prefoo`\n2. `foo`\n3. `postfoo`\n\nassuming each task succeeds, otherwise execution is terminated.\n\n`pre` and `post` tasks can be provided in an archetype and overridden in a root\n`package.json` in the exact same manner as normal Builder tasks.\n\n##### Other Builder Actions\n\n`builder run` works essentially the same as `npm run`. Things get a little\nmessy with Builder's other execution options:\n\n`builder envs` runs `pre|post` tasks exactly **once** regardless of how many\nconcurrent executions of the underlying task (with different environment\nvariables) occur.\n\n`builder concurrent` runs appropriate `pre|post` tasks for each independent\ntask. So, for something like:\n\n```js\n\"scripts\": {\n  \"prefoo\": \"echo PRE FOO\",\n  \"foo\": \"echo TEMP FOO\",\n  \"postfoo\": \"echo POST FOO\",\n  \"prebar\": \"echo PRE BAR\",\n  \"bar\": \"echo TEMP BAR\",\n  \"postbar\": \"echo POST BAR\"\n}\n```\n\nrunning `builder concurrent foo bar` would run **all** of the above tasks at\nthe appropriate lifecycle moment.\n\nNote that things like a `--queue=NUM` limit on a concurrent task will have\n*all* of the `pre`, main, and `post` task need to finish serial execution before\nthe next spot is freed up.\n\nThe `--bail` flag applies to all of a single tasks `pre`, main, and `post`\ngroup. So if any of those fail, it's as if the main task failed.\n\n##### Builder Flags During Pre and Post\n\n*Applicable Flags*\n\nWhen executing a `\u003ctask\u003e` that has `pre\u003ctask\u003e` and/or `post\u003ctask\u003e` entries, the\nfollowing execution flags **do** apply to the `pre|post` tasks.\n\n* `--env`\n* `--env-path`\n* `--quiet`\n* `--log-level`\n* `--expand-archetype`\n\nThese flags have mixed application:\n\n* `--queue`: Applies for `concurrent`, but not `envs`. The flag is invalid for\n  `run`.\n* `--buffer`: Applies for `concurrent`, but not `envs`. The flag is invalid for\n  `run`.\n* `--bail`: Applies for `concurrent`, but not `envs`. The flag is invalid for\n  `run`. A `pre\u003ctask\u003e`, `\u003ctask\u003e`, and a `post\u003ctask\u003e` are treated as a group, so\n  a failure of any short-circuits the rests and ends with failures. But with\n  `--bail=false` a failure doesn't stop execution of the _other_ groups.\n\nThe following flags do _not_ apply to pre/post tasks:\n\n* `--` custom flags\n* `--tries`\n* `--setup`: A task specified in `--setup \u003ctask\u003e` will not have `pre|post`\n  tasks apply.\n\nWe will explain a few of these situations in a bit more depth:\n\n*Custom Flags*\n\nThe special `--` flag with any subsequent custom flags to the underlying task\nare only passed to the the main `\u003ctask\u003e` and not `pre\u003ctask\u003e` or `post\u003ctask\u003e`.\nThe rationale here is that custom command line flags most likely just apply to\na single shell command (the main one).\n\nSo, for example\n\n```js\n\"scripts\": {\n  \"prefoo\": \"echo PRE\",\n  \"foo\": \"echo TEMP\",\n  \"postfoo\": \"echo POST\"\n}\n```\n\nrunning `builder run foo -- --hi` would produce:\n\n```\nPRE\nTEMP --hi\nPOST\n```\n\n*Other Flags*\n\nBy contrast, the various other Builder-specific flags that can be applied to a\ntask like `--env`, etc., **will** apply to `pre|post` tasks, under the\nassumption that control flags + environment variables will most likely want to\nbe used for the execution of all commands in the workflow.\n\nSo, for example:\n\n```js\n\"scripts\": {\n  \"prefoo\": \"echo PRE $VAR\",\n  \"foo\": \"echo TEMP $VAR\",\n  \"postfoo\": \"echo POST $VAR\"\n}\n```\n\nrunning `builder run foo --env '{\"VAR\":\"HI\"}'` would produce:\n\n```\nPRE HI\nTEMP HI\nPOST HI\n```\n\n##### Task Prefix Complexities\n\nFor the above example, if you have a task named `preprefoo`, then running\n`foo` **or** even `prefoo` directly will **not** run `preprefoo`. Builder\nfollows `npm`'s current implementation which is roughly \"add `pre|post` tasks\nto current execution as long as the task itself is not prefixed with\n`pre|post`\". (_Note_ that `yarn` does not follow this logic in task execution).\n\n#### Custom Flags\n\nJust like [`npm run \u003ctask\u003e [-- \u003cargs\u003e...]`](https://docs.npmjs.com/cli/run-script),\nflags after a ` -- ` token in a builder task or from the command line are passed\non to the underlying tasks. This is slightly more complicated for builder in\nthat composed tasks pass on the flags _all the way down_. So, for tasks like:\n\n```js\n\"scripts\": {\n  \"down\": \"echo down\",\n  \"way\": \"builder run down -- --way\",\n  \"the\": \"builder run way -- --the\",\n  \"all\": \"builder run the -- --all\"\n}\n```\n\nWe can run some basics (alone and with a user-added flag):\n\n```sh\n$ builder run down\ndown\n\n$ builder run down -- --my-custom-flag\ndown --my-custom-flag\n```\n\nIf we run the composed commands, the `--` flags are accumulated:\n\n```sh\n$ builder run all\ndown --way --the --all\n\n$ builder run all -- --my-custom-flag\ndown --way --the --all --my-custom-flag\n```\n\nThe rough heuristic here is if we have custom arguments:\n\n1. If a `builder \u003caction\u003e` command, pass through using builder-specific\n   environment variables. (Builder uses `_BUILDER_ARGS_CUSTOM_FLAGS`).\n2. If a non-`builder` command, then append without ` -- ` token.\n\n#### Expanding the Archetype Path\n\nBuilder tasks often refer to configuration files in the archetype itself like:\n\n```js\n\"postinstall\": \"webpack --bail --config node_modules/\u003carchetype\u003e/config/webpack/webpack.config.js\",\n```\n\nIn npm v2 this wasn't a problem because dependencies were usually nested. In\nnpm v3, this all changes with aggressive\n[flattening](https://docs.npmjs.com/cli/dedupe) of dependencies. With flattened\ndependencies, the chance that the archetype and its dependencies no longer have\na predictable contained structure increases.\n\nThus, commands like the above succeed if the installation ends up like:\n\n```\nnode_modules/\n  \u003ca module\u003e/\n    node_modules/\n      \u003carchetype\u003e/\n        node_modules/\n          webpack/\n```\n\nIf npm flattens the tree like:\n\n```\nnode_modules/\n  \u003ca module\u003e/\n  \u003carchetype\u003e/\n  webpack/\n```\n\nThen `builder` can still find `webpack` due to its `PATH` and `NODE_PATH`\nmutations. But an issue arises with something like a `postinstall` step after\nthis flattening in that the current working directory of the process will be\n`PATH/TO/node_modules/\u003ca module\u003e/`, which in this flattened scenario would\n**not** find the file:\n\n```\nnode_modules/\u003carchetype\u003e/config/webpack/webpack.config.js\n```\n\nbecause relative to `node_modules/\u003ca module\u003e/` it is now at:\n\n```\n../\u003carchetype\u003e/config/webpack/webpack.config.js\n```\n\nTo address this problem `builder` has an `--expand-archetype` flag that will\nreplace an occurrence of the specific `node_modules/\u003carchetype\u003e` in one of the\narchetype commands with the _full path_ to the archetype, to guarantee\nreferenced files are correctly available.\n\nThe basic heuristic of things to replace is:\n\n* `^node_modules/\u003carchetype\u003e`: Token is very first string.\n* `[\\s\\t]node_modules/\u003carchetype\u003e`: Whitespace before token.\n* `['\"]node_modules/\u003carchetype\u003e`: Quotes before token.\n    * _Note_ that the path coming back from the underlying\n     `require.resolve(module)` will likely be escaped, so things like\n     whitespace in a path + quotes around it may not expand correctly.\n\nSome notes:\n\n* The only real scenario you'll need this is for a module that needs to run\n  a `postinstall` or something as part of an install in a larger project.\n  Root git clone projects controlled by an archetype should work just fine\n  because the archetype will be predictably located at:\n  `node_modules/\u003carchetype\u003e`\n* The `--expand-archetype` flag gets propagated down to all composed `builder`\n  commands internally.\n* The `--expand-archetype` only expands the specific archetype string for its\n  **own** commands and not those in the root projects or other archetypes.\n* The replacement assumes you are using `/` forward slash characters which\n  are the recommended cross-platform way to construct file paths (even on\n  windows).\n* The replacement only replaces at the _start_ of a command string or after\n  whitespace. This means it _won't_ replace `../node_modules/\u003carchetype\u003e` or\n  even `./node_modules/\u003carchetype\u003e`. (In the last case, just omit the `./`\n  in front of a path -- it's a great habit to pick up as `./` breaks on Windows\n  and omitting `./` works on all platforms!)\n\n## Tasks\n\nThe underlying concept here is that `builder` `script` commands simply _are_\nnpm-friendly `package.json` `script` commands. Pretty much anything that you\ncan execute with `npm run \u003ctask\u003e` can be executed with `builder run \u003ctask\u003e`.\n\nBuilder can run 1+ tasks based out of `package.json` `scripts`. For a basic\nscenario like:\n\n```js\n{\n  \"scripts\": {\n    \"foo\": \"echo FOO\",\n    \"bar\": \"echo BAR\"\n  }\n}\n```\n\nBuilder can run these tasks individually:\n\n```sh\n$ builder run foo\n$ builder run bar\n```\n\nSequentially via `||` or `\u0026\u0026` shell helpers:\n\n```sh\n$ builder run foo \u0026\u0026 builder run bar\n```\n\nConcurrently via the Builder built-in `concurrent` command:\n\n```sh\n$ builder concurrent foo bar\n```\n\nWith `concurrent`, all tasks continue running until they all complete _or_\nany task exits with a non-zero exit code, in which case all still alive tasks\nare killed and the Builder process exits with the error code.\n\n\n## npm Config\n\n`builder` supports `package.json` `config` properties the same way that `npm`\ndoes, with slight enhancements in consideration of multiple `package.json`'s\nin play.\n\n### `npm` Config Overview\n\nAs a refresher, `npm` utilizes the `config` field of `package.json` to make\n\"per-package\" environment variables to `scripts` tasks. For example, if you\nhave:\n\n```js\n{\n  \"config\": {\n    \"my_name\": \"Bob\"\n  },\n  \"scripts\": {\n    \"get-name\": \"echo Hello, ${npm_package_config_my_name}.\"\n  }\n}\n```\n\nand ran:\n\n```sh\n$ npm run get-name\nHello, Bob.\n```\n\nMore documentation about how `npm` does per-package configuration is at:\n\n* https://docs.npmjs.com/files/package.json#config\n* https://docs.npmjs.com/misc/config#per-package-config-settings\n\n\n### Builder Configs\n\nIn `builder`, for a single `package.json` this works essentially the same in\nthe above example.\n\n```sh\n$ builder run get-name\nHello, Bob.\n```\n\nHowever, `builder` has the added complexity of adding in `config` variables\nfrom archetypes and the environment. So the basic resolution order for a\nconfig environment variable is:\n\n1. Look to `npm_package_config_\u003cVAR_NAME\u003e=\u003cVAR_VAL\u003e` on command line.\n2. If not set, then use `\u003croot\u003e/package.json:config:\u003cVAR_NAME\u003e` value.\n3. If not set, then use `\u003carchetype\u003e/package.json:config:\u003cVAR_NAME\u003e` value.\n\nSo, let's dive in to a slightly more complex example:\n\n```js\n// \u003carchetype\u003e/package.json\n{\n  \"config\": {\n    \"my_name\": \"ARCH BOB\"\n  },\n  \"scripts\": {\n    \"get-name\": \"echo Hello, ${npm_package_config_my_name}.\"\n  }\n}\n\n// \u003croot\u003e/package.json\n{\n  \"config\": {\n    \"my_name\": \"ROOT JANE\"\n  }\n}\n```\n\nWhen we run the `builder` command, the `\u003croot\u003e` value overrides:\n\n```sh\n$ builder run get-name\nHello, ROOT JANE.\n```\n\nWe can inject a command line flag to override even this value:\n\n```sh\n$ npm_package_config_my_name=\"CLI JOE\" builder run get-name\nHello, CLI JOE.\n```\n\n_Note_ that the ability to override via the process environment is unique\nto `builder` and not available in real `npm`.\n\n### Config Notes\n\n#### Tip - Use String Values\n\nAlthough `config` properties can be something like:\n\n```js\n\"config\": {\n  \"enabled\": true\n}\n```\n\nWe strongly recommend that you always set _strings_ like:\n\n```js\n\"config\": {\n  \"enabled\": \"true\"\n}\n```\n\nAnd deal just with _string values_ in your tasks, and files. The reasoning here\nis that when overriding values from the command line, the values will always\nbe strings, which has a potential for messy, hard-to-diagnose bugs if the\noverridden value is not also a string.\n\n#### npmrc Configuration\n\n`npm` has additional functionality for `config` values that are **not**\npresently supported, such as issuing commands like\n`npm config set \u003cpkg-name\u003e:my_name Bill` that store values in `~/.npmrc` and\nthen override the `package.json` values at execution time. We _may_ extend\nsupport for this as well, but not at the present.\n\n#### Command Line Environment Variables\n\n`npm` does **not** support overriding `config` environment variables from the\nactual environment. So doing something in our original example like:\n\n```sh\n$ npm_package_config_my_name=George npm run get-name\nHello, Bob.\n```\n\nIn fact, npm will refuse to even add environment variables starting with\n`npm_package_config` to the `npm run` environment. E.g.\n\n```js\n{\n  \"config\": {},\n  \"scripts\": {\n    \"get-npm-val\": \"echo NPM VAR: ${npm_package_config_var}\",\n    \"get-env-val\": \"echo ENV VAR: ${env_var}\"\n  }\n}\n```\n\nThe `npm` config variable doesn't make it through:\n\n```sh\n$ npm_package_config_var=SET npm run get-npm-val\nNPM VAR:\n```\n\nWhile a normal environment variable will:\n\n```sh\n$ env_var=SET npm run get-env-val\nENV VAR: SET\n```\n\nBy contrast, `builder` _does_ pass through environment variables already\nexisting on the command line, and moreover those overrides takes precedence over\nthe root and archetype package.json values. Those same examples with `builder`\nshow that the environment variables _do_ make it through:\n\n```sh\n$ npm_package_config_var=SET builder run get-npm-val\nNPM VAR: SET\n\n$ env_var=SET builder run get-env-val\nENV VAR: SET\n```\n\nThings are a little more complex when using with `builder envs`, but the\nrough rule is that the environment JSON array wins when specified, otherwise\nthe existing environment is used:\n\n```sh\n$ npm_package_config_var=CLI builder envs get-npm-val --queue=1 \\\n  '[{}, {\"npm_package_config_var\":\"This Overrides\"}]'\nNPM VAR: CLI\nNPM VAR: This Overrides\n```\n\n## Archetypes\n\nArchetypes deal with common scenarios for your projects. Like:\n\n* [builder-react-component][]: A React component\n* A React application server\n* A Chai / jQuery / VanillaJS widget\n\nArchetypes typically provide:\n\n* A `package.json` with `builder`-friendly `script` tasks.\n* Dependencies and dev dependencies for all of the archetype `script` tasks.\n* Configuration files for all `script` tasks.\n\nIn most cases, you won't need to override anything. But, if you do, pick the\nmost granular `scripts` command in the archetype you need to override and\ndefine _just that_ in your project's `package.json` `script` section. Copy\nany configuration files that you need to tweak and re-define the command.\n\n### Task Resolution\n\nThe easiest bet is to just have _one_ archetype per project. But, multiple are\nsupported. In terms of `scripts` tasks, we end up with the following example:\n\n```\nROOT/package.json\nROOT/node_modules/ARCHETYPE_ONE/package.json\nROOT/node_modules/ARCHETYPE_TWO/package.json\n```\n\nSay we have a `.builderrc` like:\n\n```yaml\n---\narchetypes:\n  - ARCHETYPE_ONE\n  - ARCHETYPE_TWO\n```\n\nThe resolution order for a `script` task (say, `foo`) present in all three\n`package.json`'s would be the following:\n\n* Look through `ROOT/package.json` then the configured archetypes in _reverse_\n  order: `ARCHETYPE_TWO/package.json`, then `ARCHETYPE_ONE/package.json` for\n  a matching task `foo`\n* If found `foo`, check if it is a \"pass-through\" task, which means it delegates\n  to a later instance -- basically `\"foo\": \"builder run foo\"`. If so, then look\n  to next instance of task found in order above.\n\n### Special Archetype Tasks\n\nArchetypes use conventional `scripts` task names, except for the following\nspecial cases:\n\n* `\"npm:postinstall\"`\n* `\"npm:preversion\"`\n* `\"npm:version\"`\n* `\"npm:test\"`\n\nThese tasks are specifically actionable during the `npm` lifecycle, and\nconsequently, the archetype mostly ignores those for installation by default,\noffering them up for actual use in _your_ project.\n\nWe strongly recommend entirely\n[avoiding npm lifecycle task names](#avoid-npm-lifecycle-commands)\nin your archetype `package.json` files. So, instead of having:\n\n```js\n// \u003carchetype\u003e/package.json\n// Bad\n\"test\": \"builder concurrent --buffer test-frontend test-backend\"\n```\n\nWe recommend something like:\n\n```js\n// \u003carchetype\u003e/package.json\n// Good / OK\n\"npm:test\": \"builder run test-all\",\n\"test-all\": \"builder concurrent --buffer test-frontend test-backend\"\n\n// Also OK\n\"npm:test\": \"builder concurrent --buffer test-frontend test-backend\"\n```\n\nand then in your `\u003croot\u003e/package.json` using the _real_ lifecycle task name.\n\n```js\n\"test\": \"builder run npm:test\"\n```\n\n### Creating an Archetype\n\nMoving common tasks into an archetype is fairly straightforward and requires\njust a few tweaks to the paths defined in configuration and scripts in order\nto work correctly.\n\n#### Initializing a Project\n\nAn archetype is simply a standard npm module with a valid `package.json`. To set\nup a new archetype from scratch, make a directory for your new archetype,\ninitialize `npm` and link it for ease of development.\n\n```sh\n$ cd path/to/new/archetype\n$ npm init\n$ npm link\n```\n\nFrom your consuming project, you can now link to the archetype directly for ease\nof development after including it in your `dependencies` and creating a\n`.builderrc` as outlined above in [configuration](#configuration).\n\n```sh\n$ cd path/to/consuming/project\n$ npm link new-archetype-name\n```\n\n#### Managing the `dev` Archetype\n\nBecause `builder` archetypes are included as simple npm modules, two separate\nnpm modules are required for archetypes: one for normal dependencies and one for\ndev dependencies. Whereas in a non-builder-archetype project you'd specify dev\ndependencies in `devDependencies`, with `builder` all dev dependencies must be\nregular `dependencies` on a separate dev npm module.\n\n`builder` is designed so that when defining which archetypes to use in a\nconsuming project's `.builderrc`, `builder` will look for two modules, one named\nappropriately in `dependencies` (ex: `my-archetype`) and one in\n`devDependencies` but with `-dev` appended to the name (ex: `my-archetype-dev`).\n\nTo help with managing these while building a builder archetype, install\n[`builder-support`](https://github.com/FormidableLabs/builder-support)\nto create and manage a `dev/` directory within your archetype project with it's\nown `package.json` which can be published as a separate npm module.\n`builder-support` will not only create a `dev/package.json` with an appropriate\npackage name, but will also keep all the other information from your archetype's\nprimary `package.json` up to date as well as keep `README.md` and `.gitignore`\nin parity for hosting the project as a separate npm module.\n\nGet started by installing and running `builder-support gen-dev`:\n\n```sh\n$ npm install builder-support --save-dev\n$ ./node_modules/.bin/builder-support gen-dev\n```\n\n_TIP: Create a task called `\"builder:gen-dev\": \"builder-support gen-dev\"` in\nyour archetype to avoid having to type out the full path each time you update\nyour project's details._\n\nFor ease of development, `npm link` the dev dependency separately:\n\n```sh\n$ cd dev\n$ npm link\n```\n\nThen from your consuming project, you can link to the dev package.\n\n```sh\n$ cd path/to/consuming/project\n$ npm link new-archetype-name-dev\n```\n\nRead the [`builder-support` docs](https://github.com/FormidableLabs/builder-support)\nto learn more about how dev archetypes are easily managed with\n`builder-support gen-dev`.\n\n#### Node Require Resolution and Module Pattern\n\nAs a background primer, whenever a file has a `require(\"lib-name\")` in it, Node\nperforms the following check for `/path/to/ultimate/file.js`:\n\n```\n/path/to/ultimate/node_modules/lib-name\n/path/to/node_modules/lib-name\n/path/node_modules/lib-name\n/node_modules/lib-name\n```\n\nAfter this, Node then checks for `NODE_PATH` for additional paths to search.\nThis presents a potentially awkward pattern when combined with npm\ndeduplication / flattening for say a file like:\n`\u003croot\u003e/node_modules/\u003carchetype\u003e/config/my-config.js` that requires\n`lib-name@right-version` as follows:\n\nNode modules layout:\n\n```\n\u003croot\u003e/\n  node_modules/\n    lib-name@wrong-version\n    \u003carchetype\u003e/\n      config/my-config.js         // require(\"lib-name\");\n    \u003carchetype-dev\u003e/\n      node_modules/\n        lib-name@right-version\n```\n\nThis unfortunately means that the search path for `require(\"lib-name\")` is:\n\n```\n# From file path priority resolution\n\u003croot\u003e/node_modules/\u003carchetype\u003e/config/node_modules\n\u003croot\u003e/node_modules/\u003carchetype\u003e/node_modules\n\u003croot\u003e/node_modules/node_modules\n\u003croot\u003e/node_modules                                   // Matches `lib-name@wrong-version`!!!\n\n# Now, from `NODE_PATH`\n\u003croot\u003e/node_modules/\u003carchetype\u003e/node_modules\n\u003croot\u003e/node_modules/\u003carchetype-dev\u003e/node_modules      // Too late for `right-version`.\n```\n\n##### The Module Pattern\n\nTo remedy this situation, we encourage a very simple pattern to have Node.js\n`require`'s start from the dev archetype when appropriate by adding a one-line\nfile to the dev archetype: `\u003carchetype-dev\u003e/require.js`\n\n```js\n// Contents of \u003carchetype-dev\u003e/require.js\nmodule.exports = require;\n```\n\nBy exporting the `require` from the dev archetype, the resolution starts in the\ndev archetype and thus ensures the dev archetype \"wins\" for the archetype tasks.\nThus in any archetype files that do a `require`, simply switch to:\n\n```js\nvar mod = require(\"\u003carchetype-dev\u003e/require\")(\"lib-name\");             // Module\nvar modPath = require(\"\u003carchetype-dev\u003e/require\").resolve(\"lib-name\"); // Module path\n```\n\nAnd the dependency from the dev archetype is guaranteed to \"win\" no matter what\nhappens with actual module layout from npm installation.\n\n_Note_ that because a file from within the normal `\u003carchetype\u003e` will naturally\nsearch `\u003carchetype\u003e/node_modules` before hitting `\u003croot\u003e/node_modules` you do\nnot need to use this `require` pattern for normal archetype dependencies in\narchetype Node.js files.\n\nNode.js files in the normal production archetype do not need a\n`\u003carchetype\u003e/require.js` file akin to the dev archetype because\n`\u003carchetype\u003e/node_modules` is already at the top of the require search path.\nHowever, some projects may wish to have an archetype control _and provide_\napplication dependencies and dev dependencies, which we discuss in the\n[next section](#application-vs-archetype-dependencies)\n\n###### ES.next Imports and The Module Pattern\n\nThe module pattern works great for any `require()`-based CommonJS code.\nUnfortunately, when using babel and ES.next imports like:\n\n```js\nimport _ from \"lodash\";\n```\n\nThe module pattern is _not_ available because the actual `require(\"lodash\")`\nstatement spit out during transpilation is not directly accessible to the\ndeveloper.\n\nFortunately (and unsurprisingly) we have a babel plugin to enable the module\npattern in ES.next code: [`babel-plugin-replace-require`][babel-plugin-replace-require].\nThe plugin can easily be configured with tokens to insert dev archetypes in\n`require`s produced by babel transpilation. For example, say we wanted to get\n`lodash` from above from our dev archetype, we would configure a `.babelrc`\nlike:\n\n```js\n{\n  \"plugins\": [\n    [\"replace-require\", {\n      \"DEV_ARCHETYPE\": \"require('\u003carchetype-dev\u003e/require')\"\n    }]\n  ]\n}\n```\n\nThen prepend our custom token to the source ES.next code:\n\n```js\nimport _ from \"DEV_ARCHETYPE/lodash\";\n```\n\nWhen transpiled, the output would become:\n\n```js\n\"use strict\";\n\nvar _lodash = require('\u003carchetype-dev\u003e/require')(\"lodash\");\n\nvar _lodash2 = _interopRequireDefault(_lodash);\n\nfunction _interopRequireDefault(obj) { return obj \u0026\u0026 obj.__esModule ? obj : { default: obj }; }\n```\n\ngiving us the correct module pattern.\n\n###### Webpack and Module Pattern\n\nAn analogous situation occurs for frontend JS code in the production archetype,\nbut with a different solution. The underlying issue is that Webpack cannot\ningest:\n\n```js\n// src/foo.js\nvar mod = require(\"\u003carchetype-dev\u003e/require\")(\"lib-name\");\n```\n\nlike Node.js can, so we need a little help in the form of a loader.\n\n**Note**: Previous incarnations of this documentation suggested mutating\nWebpack code (`resolve.root`) and loader (`resolveLoader.root`) configurations.\nWe no longer suggest this as the loader pattern in this section is much more\nprecise and doesn't lead to potential prod-vs-dev ambiguities in module use.\n\nTurning to the above example, we can use the\n[`webpack-alternate-require-loader`][webpack-alternate-require-loader] to\nrewrite CommonJS forms of the module pattern into fully-resolved paths on disk\nthat work for webpack.\n\nLet's start with our webpack configuration:\n\n```js\n// webpack.config.js\nmodule.exports = {\n  module: {\n    loaders: [\n      {\n        test: /\\.js$/,\n        loader: \"webpack-alternate-require-loader\",\n        query: JSON.stringify({\n          \"\u003carchetype-dev\u003e/require\": require.resolve(\"\u003carchetype-dev\u003e/require\")\n        })\n      }\n    ]\n  }\n};\n```\n\nWith this configuration, Webpack will parse our above code sample and actually\n_perform_ the resolution of `lib-name` using the `require` provided in\n`\u003carchetype-dev\u003e/require` producing ultimate code like:\n\n```js\n// lib/foo.js\nvar mod = require(\"/RESOLVED/PATH/TO/lib-name\");\n```\n\nThis essentially converts a runtime lookup of the `require` starting from\nthe dev archetype to a build time lookup performed by webpack.\n\nConveniently, this plugin _also_ works with code produced by\n`babel-plugin-replace-require` when configured as specified in the previous\nsection.\n\n**Shared Node / Frontend Code**: The best part of this plugin is that if you\nhave shared code between Node.js and the frontend, you can have the exact same\ncode work in both places -- unparsed for Node.js and processed via Webpack for\nthe frontend.\n\n#### Application vs. Archetype Dependencies\n\nOut of the box `builder` does not manage application dependencies, instead\nmanaging dependencies only for builder _workflows_ and _tasks_, e.g. things\nstarting with the `builder` command.\n\nMost notably, this means that if your _application_ code includes a dependency\nlike `lodash`:\n\n```js\n// \u003croot\u003e/src/index.js\nvar _ = require(\"lodash\");\n\nmodule.exports = _.camelCase(\"Hi There\");\n```\n\nand the root project is consumed by _anything besides a `builder` command_,\nthen it **must** have a dependency like:\n\n```js\n// \u003croot\u003e/package.json\n\"dependencies\": {\n  \"lodash\": \"^4.2.1\"\n}\n```\n\nHowever, if you want to use builder to _also_ manage application dependencies,\nthen you can follow [the module pattern](#the-module-pattern) and provide an\n`\u003carchetype\u003e/require.js` file consisting of:\n\n```js\n// Contents of \u003carchetype\u003e/require.js\nmodule.exports = require;\n```\n\nThe root project could then require code like:\n\n\n```js\nvar modFromProd = require(\"\u003carchetype\u003e/require\")(\"lib-name\");               // Module\nvar pathFromProd = require(\"\u003carchetype\u003e/require\").resolve(\"lib-name\");      // Module path\nvar modFromDev = require(\"\u003carchetype-dev\u003e/require\")(\"lib-name\");            // Module\nvar pathFromDev = require(\"\u003carchetype-dev\u003e/require\").resolve(\"lib-name\");   // Module path\n```\n\nUsing the above pattern, `\u003carchetype\u003e` or `\u003carchetype-dev\u003e` dependencies would\noverride `\u003croot\u003e/node_modules` dependencies reliably and irrespective of npm\nflattening.\n\nSo, turning back to our original example, we could utilize archetype\ndependencies by refactoring to something like:\n\n\n```js\n// \u003croot\u003e/src/index.js\nvar _ = require(\"\u003carchetype\u003e/require\")(\"lodash\");\n\nmodule.exports = _.camelCase(\"Hi There\");\n```\n\nand dev code like:\n\n\n```js\n// \u003croot\u003e/test/index.js\nvar _ = require(\"\u003carchetype-dev\u003e/require\")(\"lodash\");\n\nmodule.exports = _.camelCase(\"Hi There\");\n```\n\nafter which you would _not_ need a `lodash` dependency in `root/package.json`.\n\n#### Moving `dependencies` and `scripts` to a New Archetype\n\nOnce everything is configured and `npm link`'d, it should be easy to move\nscripts to your archetype and quickly test them out from a consuming project.\n\n##### Moving `dependencies` and `devDependencies` from an Existing `package.json`\n\n* copy `dependencies` to `package.json` `dependencies`.\n* copy `devDependencies` to `dev/package.json` `dependencies`.\n\n_Note_ that you should only copy `dependencies` from `\u003croot\u003e/package.json` to\n`\u003carchetype\u003e/package.json` that are needed within the archetype itself for:\n\n* Execution of a script. (E.g., the `istanbul` script).\n* Required by a configuration file in the archetype. (E.g., `webpack` if a\n  webpack configuration calls `require(\"webpack\")`).\n\nYou can then remove any dependencies _only_ used by the `scripts` tasks that\nyou have moved to the archetype. However, take care to\n[not remove real application dependencies](#application-vs-archetype-dependencies)\nunless you are using a module pattern to provide\n[application dependencies](#application-dependencies).\n\n\n##### Moving `scripts` and Config Files\n\nAll scripts defined in archetypes will be run from the root of the project\nconsuming the archetype. This means you have to change all paths in your scripts\nto reference their new location within the archetype.\n\nAn example script and config you may be moving to an archetype would look like:\n\n```js\n\"test-server-unit\": \"mocha --opts test/server/mocha.opts test/server/spec\"\n```\n\nWhen moving this script to an archetype, we'd also move the config from\n`test/server/mocha.opts` within the original project to within the\narchetype such as `config/mocha/server/mocha.opts`.\n\nFor this example script, we'd need to update the path to `mocha.opts` as so:\n\n```js\n\"test-server-unit\": \"mocha --opts node_modules/new-archetype-name/config/mocha/server/mocha.opts test/server/spec\"\n```\n\nAny paths that reference files expected in the consuming app (in this example\n`test/server/spec`) do not need to change.\n\n##### Updating Path and Module References in Config Files\n\nAny JavaScript files run from within an archetype (such as config files) require\na few changes related to paths now that the files are being run from within\nan npm module. This includes all `require()` calls referencing npm modules and\nall paths to files that aren't relative.\n\nFor example, `karma.conf.js`:\n\n```js\nmodule.exports = function (config) {\n  require(\"./karma.conf.dev\")(config);\n\n  config.set({\n    preprocessors: {\n      \"test/client/main.js\": [\"webpack\"]\n    },\n    files: [\n      \"sinon/pkg/sinon\",\n      \"test/client/main.js\"\n    ],\n  });\n};\n```\n\nAll non-relative paths to files and npm modules need to be full paths, even ones\nnot in the archetype directory. For files expected to be in the consuming\nproject, this can be achieved by prepending `process.cwd()` to all paths. For\nnpm modules, full paths can be achieved by using\n[`require.resolve()`](https://nodejs.org/api/globals.html#globals_require_resolve).\n\nAn updated config might look like:\n\n```js\nvar path = require(\"path\");\nvar ROOT = process.cwd();\nvar MAIN_PATH = path.join(ROOT, \"test/client/main.js\");\n\nmodule.exports = function (config) {\n  require(\"./karma.conf.dev\")(config);\n\n  config.set({\n    preprocessors: {\n      [MAIN_PATH]: [\"webpack\"]\n    },\n    files: [\n      require.resolve(\"sinon/pkg/sinon\"),                             // Normal archetype\n      require(\"\u003carchetype-dev\u003e/require\").resolve(\"sinon/pkg/sinon\"),  // Dev archetype\n      MAIN_PATH\n    ],\n  });\n};\n```\n\n#### Example `builder` Archetype Project Structure\n\n```\n.\n├── CONTRIBUTING.md\n├── HISTORY.md\n├── LICENSE.txt\n├── README.md\n├── config\n│   ├── eslint\n│   ├── karma\n│   ├── mocha\n│   │   ├── func\n│   │   │   ├── mocha.dev.opts\n│   │   │   └── mocha.opts\n│   │   └── server\n│   │       └── mocha.opts\n│   └── webpack\n│       ├── webpack.config.coverage.js\n│       ├── webpack.config.dev.js\n│       ├── webpack.config.hot.js\n│       ├── webpack.config.js\n│       └── webpack.config.test.js\n├── dev\n│   └── package.json\n│   └── require.js\n└── package.json\n```\n\n## Tips, Tricks, \u0026 Notes\n\n### PATH, NODE_PATH Resolution\n\nBuilder uses some magic to enhance `PATH` and `NODE_PATH` to look in the\ninstalled modules of builder archetypes and in the root of your project (per\nnormal). We mutate both of these environment variables to resolve in the\nfollowing order:\n\n`PATH`:\n\n1. `\u003ccwd\u003e/node_modules/\u003carchetype\u003e/.bin`\n2. `\u003ccwd\u003e/node_modules/\u003carchetype-dev\u003e/.bin`\n3. `\u003ccwd\u003e/node_modules/.bin`\n4. Existing `PATH`\n\n`require` + `NODE_PATH`: For `file.js` with a `require`\n\n1. `/PATH/TO/file.js` (all sub directories + `node_modules` going down the tree)\n2. `\u003ccwd\u003e/node_modules/\u003carchetype\u003e/node_modules`\n3. `\u003ccwd\u003e/node_modules/\u003carchetype-dev\u003e/node_modules`\n4. `\u003ccwd\u003e/node_modules`\n5. Existing `NODE_PATH`\n\nThe order of resolution doesn't often come up, but can sometimes be a factor\nin diagnosing archetype issues and script / file paths, especially when using\n`npm` v3.\n\n### Environment Variables\n\nBuilder clones the entire environment object before mutating it for further\nexecution of tasks. On Mac/Linux, this has no real change of behavior of how\nthe execution environment works. However, on Windows, there are some subtle\nissues with the fact that Windows has a case-insensitive environment variable\nmodel wherein you can set `PATH` in a node process, but internally this is\ntransformed to set `Path`. Builder specifically handles `PATH` correctly across\nplatforms for it's own specific mutation.\n\nHowever, if your tasks rely on the Windows coercion of case-insensitivity of\nenvironment variables, you may run into some idiosyncratic problems with tasks.\n\n### Alternative to `npm link`\n\nIn some cases, `npm link` can interfere with the order of resolution. If you\nrun into resolution problems, you can develop locally with the\nfollowing in your consuming project's `package.json` as an alternative to `npm link`:\n\n```json\n{\n  \"dependencies\": {\n    \"YOUR_ARCHETYPE_NAME\": \"file:../YOUR_ARCHETYPE_REPO\"\n  },\n  \"devDependencies\": {\n    \"YOUR_ARCHETYPE_NAME_dev\": \"file:../YOUR_ARCHETYPE_REPO/dev\"\n  }\n}\n```\n\n### Project Root\n\nThe enhancements to `NODE_PATH` that `builder` performs can throw tools /\nlibraries for a loop. Generally speaking, we recommend using\n`require.resolve(\"LIBRARY_OR_REQUIRE_PATH\")` to get the appropriate installed\nfile path to a dependency.\n\nThis comes up in situations including:\n\n* Webpack loaders\n* Karma included files\n\nThe other thing that comes up in our Archetype configuration file is the\ngeneral _requirement_ that builder is running from the project root, not\nrelative to an archetype. However, some libraries / tools will interpret\n`\"./\"` as relative to the _configuration file_ which may be in an archetype.\n\nSo, for these instances and instances where you typically use `__dirname`,\nan archetype may need to use `process.cwd()` and be constrained to **only**\never running from the project root. Some scenarios where the `process.cwd()`\npath base is necessary include:\n\n* Webpack entry points, aliases\n* Karma included files (that cannot be `require.resolve`-ed)\n\n### Avoid npm Lifecycle Commands\n\nWe recommend _not_ using any of the special `npm` `scripts` commands listed in\nhttps://docs.npmjs.com/misc/scripts such as:\n\n* prepublish, postinstall\n* test\n* stop, start\n\nin your archetype `scripts`. This is due to the fact that the archetype\n`package.json` files are themselves consumed by `npm` for publishing (which\ncan lead to tasks executing for the _archetype_ instead of the project _using_\nthe archetype) and potentially lead to awkward recursive composed task\nscenarios.\n\nInstead, we recommend adding an `npm:\u003ctask\u003e` prefix to your tasks to identify\nthem as usable in root projects for real `npm` lifecycle tasks.\n\nWe plan on issuing warnings for archetypes that do implement lifecycle tasks\nin: https://github.com/FormidableLabs/builder/issues/81\n\n### Other Process Execution\n\nThe execution of tasks generally must _originate_ from Builder, because of all\nof the environment enhancements it adds. So, for things that themselves exec\nor spawn processes, like `concurrently`, this can be a problem. Typically, you\nwill need to have the actual command line processes invoked _by_ Builder.\n\n### I Give Up. How Do I Abandon Builder?\n\nBuilder is designed to be as close to vanilla npm as possible. So, if for\nexample you were using the `builder-react-component` archetype with a project\n`package.json` like:\n\n```js\n\"scripts\": {\n  \"postinstall\": \"builder run npm:postinstall\",\n  \"preversion\": \"builder run npm:preversion\",\n  \"version\": \"builder run npm:version\",\n  \"test\": \"builder run npm:test\",\n  /* other deps */\n},\n\"dependencies\": {\n  \"builder\": \"v2.0.0\",\n  \"builder-react-component\": \"v0.0.5\",\n  /* other deps */\n},\n\"devDependencies\": {\n  \"builder-react-component-dev\": \"v0.0.5\",\n  /* other deps */\n}\n```\n\nand decided to _no longer_ use Builder, here is a rough set of steps to unpack\nthe archetype into your project and remove all Builder dependencies:\n\n* Copy all `ARCHETYPE/package.json:dependencies` to your\n  `PROJECT/package.json:dependencies` (e.g., from `builder-react-component`).\n  You _do not_ need to copy over `ARCHETYPE/package.json:devDependencies`.\n* Copy all `ARCHETYPE/package.json:scripts` to your\n  `PROJECT/package.json:scripts` that do not begin with the `builder:` prefix.\n  Remove the `npm:` prefix from any `scripts` tasks and note that you may have\n  to manually resolve tasks of the same name within the archetype and also with\n  your project.\n* Copy all `ARCHETYPE/package.json:config` variables to your\n  `PROJECT/package.json:config`.\n* Copy all `ARCHETYPE-dev/package.json:dependencies` to your\n  `PROJECT/package.json:devDependencies`\n  (e.g., from `builder-react-component-dev`)\n* Copy all configuration files used in your `ARCHETYPE` into the root project.\n  For example, for `builder-react-component` you would need to copy the\n  `builder-react-component/config` directory to `PROJECT/config` (or a renamed\n  directory).\n* Replace all instances of `require(\"\u003carchetype-dev\u003e/require\")` and\n  `require(\"\u003carchetype\u003e/require\")` with `require` in configuration / other\n  Node.js files from the archetype.\n* Review all of the combined `scripts` tasks and:\n    * resolve duplicate task names\n    * revise configuration file paths for the moved files\n    * replace instances of `builder run \u003ctask\u003e` with `npm run \u003ctask\u003e`\n    * for `builder concurrent \u003ctask1\u003e \u003ctask2\u003e` tasks, first install the\n      `concurrently` package and then rewrite to:\n      `concurrent 'npm run \u003ctask1\u003e' 'npm run \u003ctask2\u003e'`\n\n... and (with assuredly a few minor hiccups) that's about it! You are\nBuilder-free and back to a normal `npm`-controlled project.\n\n### Maintenance Status:\n\n**Archived:** This project is no longer maintained by Formidable. We are no longer responding to issues or pull requests unless they relate to security concerns. We encourage interested developers to fork this project and make it their own!\n","funding_links":[],"categories":["仓库管理工具","JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFormidableLabs%2Fbuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFormidableLabs%2Fbuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFormidableLabs%2Fbuilder/lists"}