{"id":16292465,"url":"https://github.com/exogen/postinstall-build","last_synced_at":"2025-04-09T07:10:33.048Z","repository":{"id":57328868,"uuid":"46254089","full_name":"exogen/postinstall-build","owner":"exogen","description":"Helper for conditionally building your npm package on postinstall","archived":false,"fork":false,"pushed_at":"2019-06-14T15:57:21.000Z","size":78,"stargazers_count":91,"open_issues_count":14,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-02T05:09:38.960Z","etag":null,"topics":["build","build-tool","hooks","lifecycle","npm","npm-scripts","postinstall"],"latest_commit_sha":null,"homepage":"","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/exogen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-16T05:31:58.000Z","updated_at":"2024-11-30T05:46:13.000Z","dependencies_parsed_at":"2022-09-15T00:12:30.562Z","dependency_job_id":null,"html_url":"https://github.com/exogen/postinstall-build","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exogen%2Fpostinstall-build","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exogen%2Fpostinstall-build/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exogen%2Fpostinstall-build/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/exogen%2Fpostinstall-build/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/exogen","download_url":"https://codeload.github.com/exogen/postinstall-build/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247500457,"owners_count":20948879,"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":["build","build-tool","hooks","lifecycle","npm","npm-scripts","postinstall"],"created_at":"2024-10-10T20:06:48.388Z","updated_at":"2025-04-09T07:10:33.011Z","avatar_url":"https://github.com/exogen.png","language":"JavaScript","readme":"[![Travis Status](https://travis-ci.org/exogen/postinstall-build.svg)](https://travis-ci.org/exogen/postinstall-build)\n[![AppVeyor Status](https://ci.appveyor.com/api/projects/status/github/exogen/postinstall-build?svg=true)](https://ci.appveyor.com/project/exogen/postinstall-build)\n[![npm Version](https://img.shields.io/npm/v/postinstall-build.svg)](https://www.npmjs.com/package/postinstall-build)\n[![npm Downloads](https://img.shields.io/npm/dm/postinstall-build.svg)](https://www.npmjs.com/package/postinstall-build)\n\n# postinstall-build\n\n| ⚠️ **NOTE!** |\n|---|\n| **As of npm 5.0.0 (2017-05-25), this functionality is built into npm!** The new `prepare` lifecycle script will build your package when installed from git. If possible, I recommend migrating off of `postinstall-build` and onto the officially supported `prepare`. It works much better! |\n\nConditionally build in the `postinstall` hook without moving your\n`devDependencies` to `dependencies`.\n\n```console\nnpm install postinstall-build --save\n```\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## Contents\n\n- [What does it do?](#what-does-it-do)\n- [Why?](#why)\n- [Usage](#usage)\n  - [Options](#options)\n    - [Specifying build dependencies in package.json](#specifying-build-dependencies-in-packagejson)\n- [Examples](#examples)\n- [Motivation](#motivation)\n- [Caveats](#caveats)\n  - [Bugs in Yarn](#bugs-in-yarn)\n  - [Bugs in npm](#bugs-in-npm)\n  - [Excluding source files via `.npmignore` or `files`](#excluding-source-files-via-npmignore-or-files)\n  - [Building a file referenced by package.json `bin`](#building-a-file-referenced-by-packagejson-bin)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## What does it do?\n\n1. Check if your build artifacts exist.\n2. If not, temporarily install `devDependencies` and build.\n3. Clean up anything left behind… and that’s it!\n\n## Why?\n\nSo that your package with a build step can support Git (and other non-npm)\ninstall locations without checking build artifacts into source control or making\neveryone install your build dependencies. See [Motivation](#motivation) for more\ndetails.\n\n## Usage\n\n```console\npostinstall-build [options] \u003cartifact\u003e [command]\n```\n\n### Options\n\n* `--script`: Run the given npm script from `package.json` instead of supplying\n  a full build command. Specified like: `--script name` or `--script=name`. This\n  is the **recommended** way to supply the build command if it is an npm script,\n  because it is guaranteed to use the same `$npm_execpath` that triggered\n  `postinstall` (as opposed to potentially using an incompatible version of npm\n  installed in `node_modules` by a dependency), if the user agent is npm.\n* `--only-as-dependency`: Run only if the package is being installed as a\n  dependency, not if `npm install` (no args) is being run in the package’s own\n  directory (usually while you are developing the package itself).\n* `--silent`: Silence the build command’s stdout and stderr, as well as any\n  warnings from `postinstall-build` itself. Fatal errors will still be printed.\n  Note that this may make debugging much more difficult if something goes wrong.\n  Overrides `--verbose` (the last one specified wins).\n* `--verbose`: Print information about what `postinstall-build` is doing and\n  why (as well as the usual warnings and errors). Overrides `--silent` (the last\n  one specified wins).\n\nIf neither `command` nor `--script` is supplied, the build command defaults to\n`npm run build`.\n\nAn `artifact` path is required. It should point to a file or directory that\nwill be generated by the build command. If the file already exists, the build\ncommand won’t be run. The build artifact should almost certainly be included\nin the published npm package, so that normal installs from the npm registry don’t\ntrigger a build (you can build in the `prepublish` hook, for example). If you want\nto always build, you may pass a bogus file path, but this is **not recommended**\n(if you’re always going to build, just make your `devDependencies` real\n`dependencies` instead of using `postinstall-build`).\n\nNote that if your `command` contains arguments (and thus has spaces), you should\nwrap it in escaped double quotes (`\\\"`) instead of single quotes for maximum\nportability – Windows does not treat single-quoted strings as a single\nparameter. (This is the case in any npm script regardless of `postinstall-build`\nusage.)\n\n#### Specifying build dependencies in package.json\n\nIf you specify a `buildDependencies` array in `package.json`, you can control\nwhich dependencies are installed before your build command is run. `buildDependencies`\nmust be an array of package names that also appear in `devDependencies`. If a\npackage named in `buildDependencies` does not exist in `devDependencies`, then\nit is assumed to already be available (as a global, peer, or production\ndependency), will not be installed, and a warning will be printed.\n\n## Examples\n\nRun the `build` script (the default) if `lib` doesn’t exist during `postinstall`:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel --presets es2015 --out-dir lib src\",\n    \"postinstall\": \"postinstall-build lib\"\n  },\n  \"dependencies\": {\n    \"postinstall-build\": \"^3.0.0\"\n  },\n  \"devDependencies\": {\n    \"babel-cli\": \"^6.0.0\",\n    \"babel-preset-es2015\": \"^6.0.0\"\n  }\n}\n```\n\n\nRun a different script:\n\n```json\n{\n  \"scripts\": {\n    \"build:lib\": \"babel --presets=es2015 --out-dir=lib src\",\n    \"postinstall\": \"postinstall-build lib --script build:lib\"\n  }\n}\n```\n\nRun a non-npm script:\n\n```json\n{\n  \"scripts\": {\n    \"postinstall\": \"postinstall-build dist \\\"make dist\\\"\"\n  }\n}\n```\n\nInstall only the necessary build dependencies:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel --presets es2015 --out-dir lib src\",\n    \"postinstall\": \"postinstall-build lib\"\n  },\n  \"dependencies\": {\n    \"postinstall-build\": \"^3.0.0\"\n  },\n  \"devDependencies\": {\n    \"ava\": \"latest\",\n    \"babel-cli\": \"^6.0.0\",\n    \"babel-preset-es2015\": \"^6.0.0\",\n    \"nyc\": \"latest\",\n    \"prettier\": \"latest\"\n  },\n  \"buildDependencies\": [\n    \"babel-cli\",\n    \"babel-preset-es2015\"\n  ]\n}\n```\n\n---\n\n⚠️ **INCORRECT USAGE** ⚠️\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"babel --presets es2015 --out-dir lib src\",\n    \"postinstall\": \"postinstall-build \\\"npm run build\\\"\"\n  }\n}\n```\n\nThis example is missing a build artifact – or rather, `npm run build` is\nmistakenly being passed as the build artifact. Since that file will never exist,\nthe build task is always run. Since `npm run build` is provided as the build\nartifact and not the build command, the default build command is used – which\nhappens to also be `npm run build`. Things will appear to work, but in fact it\nis building on every `postinstall` unconditionally. `postinstall-build` will\nissue a warning if it suspects the arguments are incorrect.\n\n---\n\n## Motivation\n\nSometimes you want to install or depend on a package from someplace other than\nnpm – for example, from a `git` URL. If the package needs to be transpiled by\na tool like Babel, then this can be tricky: most people put their build step in\nthe `version` or `prepublish` hooks, and if you’re not installing from npm then\nthis step probably wasn’t run (unless the build artifacts are checked into\nsource control).\n\nOne solution is to add a check to the package’s `postinstall` hook: if the\nbuild artifacts don’t exist, then build! The annoying part is that this\nnecessitates having your build dependencies (like Babel or webpack) available –\nin other words, they’d need to be production `dependencies` instead of\n`devDependencies`, even though the module itself doesn’t `require` them (unlike\nreal dependencies, they’re only used in the build step). That means even\neveryone installing from npm wastes time installing them, even though they\nalready have the build artifacts!\n\nThis helper fixes that. Just tell it where a build artifact is and what your\nbuild step is, and it’ll do the rest. Used as intended, `postinstall-build`\nshould be in `dependencies`.\n\n## Caveats\n\n### Bugs in Yarn\n\n* **'your-package' is not in the npm registry.**\n\n  Yarn will read your custom registry setting from `.npmrc`, but fails to\n  communicate this via the `$npm_config_registry` environment variable. So any\n  `npm` commands that were triggered by a Yarn install (like those run by\n  `postinstall-build`) pick up Yarn‘s default `$npm_config_registry` setting\n  instead of the one specified in `.npmrc`.\n\n  For the time being you can solve this by adding a `.yarnrc` file alongside your\n  `.npmrc`, which will cause `$npm_config_registry` to behave as expected.\n\n### Bugs in npm\n\n**I recommend using npm 3 or better, except for npm 4.1.x–4.5.x.**\n\nThere are several distinct bugs in npm itself that you may encounter when using\n`postinstall-build` with npm 2. I have not been able to work around these nor\neven reproduce them locally; they are especially prevalent on the combination\nof Node 0.12, npm 2, and the Docker environment used by Travis. To the best of\nmy knowledge they are no fault of this package and are widely reported npm bugs.\n\n* **extraneous packages**\n\n  The `prune` command is broken in npm 4.1.x–4.5.x, and is unable to correctly\n  prune `devDependencies`. Thus, when `postinstall-build` is finishing up, it\n  leaves behind extraneous packages. (See issues [#15727](https://github.com/npm/npm/issues/15727),\n  [#15669](https://github.com/npm/npm/issues/15669), [#15646](https://github.com/npm/npm/issues/15646).)\n\n* **postinstall-build: not found**\n\n  Sometimes npm triggers `postinstall` when a package’s dependencies aren’t\n  actually available yet.\n\n* **Callback called more than once.**\n\n  npm has some faulty async code. This message comes from within the npm\n  codebase and does not refer to any callbacks within `postinstall-build`.\n\n* **ENOENT during npm prune**\n\n  npm is probably trying to prune a file that was already removed or never\n  existed. Seems to happen when there is a larger `devDependency` tree to prune.\n\n* **ECONNRESET**\n\n  npm has trouble making lots of connections to its own registry. You can use\n  `npm config set fetch-retries 5` (for example) to work around this; using the\n  non-HTTPS registry might also help.\n\n### Excluding source files via `.npmignore` or `files`\n\nWhen npm installs from a Git repository or any other non-package location, it\nwill first prepare the directory as if it were publishing a package. This\nincludes respecting the `.npmignore` file and `files` field in `package.json`,\nwhich means that `postinstall` scripts may be executed with a subset of the\nfiles you need to run your build step. Thus, in order for `postinstall-build`\nto work, you should **not** ignore the source files or any necessary\nconfiguration (for example, `.babelrc`).\n\nThis is not ideal, but it’s how npm works. If you are determined to exclude\nunnecessary source and configuration files from the published npm package,\nyou may want to consider a publishing step that alters the `.npmignore` or\n`files` settings.\n\n### Building a file referenced by package.json `bin`\n\nIf your `package.json` file uses the `bin` field, and any of the referenced\nfiles do not exist before building, you may see an error like this:\n\n```console\nENOENT: no such file or directory, chmod '[…]/lib/index.js'\n```\n\nThis happens because npm needs to symlink any files referenced in the `bin`\nfield and make them executable, but this step is performed before `postinstall`.\n`postinstall-build` can’t do anything to address this shortcoming, but there is\nan easy workaround. Create a simple non-built file (that is, not created during\nthe build step) that imports the built file you actually want to target. For\nexample, you could create a top-level file called `cli.js` like so:\n\n```js\nrequire('./lib/index');\n```\n\nOr, export the program’s behavior in a function and call it:\n\n```js\nrequire('./lib/index').run();\n```\n\nMake sure to update your `bin` field to the new file (in this case, `cli.js`)\nand include it in your npm package and repository.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexogen%2Fpostinstall-build","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexogen%2Fpostinstall-build","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexogen%2Fpostinstall-build/lists"}