{"id":14473,"library":"build-if-changed","title":"Build if Changed","description":"build-if-changed (bic) is a utility designed to optimize monorepo build processes by executing `npm run build` scripts only for packages that have undergone changes since their last build. It achieves this by crawling specified directories within a package, generating SHA-1 hashes of watched files, and storing them in a `.bic_cache` file alongside each `package.json`. If the hashes indicate a change, the build script is triggered. The current stable version is 1.5.5. It focuses on reducing build times and CI/CD costs by avoiding redundant builds, differentiating itself through its simple `package.json`-based configuration and custom glob syntax for file watching.","status":"active","version":"1.5.5","language":"javascript","source_language":"en","source_url":"https://github.com/aleclarson/build-if-changed","tags":["javascript"],"install":[{"cmd":"npm install build-if-changed","lang":"bash","label":"npm"},{"cmd":"yarn add build-if-changed","lang":"bash","label":"yarn"},{"cmd":"pnpm add build-if-changed","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[],"quickstart":{"code":"const { execSync } = require('child_process');\nconst fs = require('fs');\nconst path = require('path');\n\n// Ensure a package.json exists for a mock build\nconst pkgPath = path.join(process.cwd(), 'package.json');\nif (!fs.existsSync(pkgPath)) {\n  console.log('Creating a dummy package.json...');\n  fs.writeFileSync(pkgPath, JSON.stringify({\n    \"name\": \"my-test-app\",\n    \"version\": \"1.0.0\",\n    \"scripts\": {\n      \"build\": \"echo 'Building my-test-app...' && touch build-output.txt\"\n    },\n    \"devDependencies\": {}\n  }, null, 2));\n}\n\nconsole.log('Installing build-if-changed as a dev dependency...');\nexecSync('npm install build-if-changed -D', { stdio: 'inherit' });\n\nconsole.log('Running build-if-changed for the first time...');\nexecSync('npx build-if-changed', { stdio: 'inherit' });\n\n// Simulate a file change to trigger a build next time\nconsole.log('\\nSimulating a file change...');\nfs.writeFileSync(path.join(process.cwd(), 'src/index.js'), '// Some new content', { flag: 'a' });\n\nconsole.log('Running build-if-changed again after a change...');\nexecSync('npx build-if-changed', { stdio: 'inherit' });\n\nconsole.log('\\nCleanup (optional)...');\n// fs.unlinkSync(pkgPath);\n// fs.unlinkSync(path.join(process.cwd(), '.bic_cache'));\n// fs.rmSync(path.join(process.cwd(), 'node_modules'), { recursive: true, force: true });\n// fs.rmSync(path.join(process.cwd(), 'src'), { recursive: true, force: true });\n\nconsole.log('Quickstart complete. Check build-output.txt.');","lang":"javascript","description":"This quickstart installs `build-if-changed`, creates a dummy `package.json` with a build script, runs `bic` initially, then simulates a file change to demonstrate how `bic` triggers a build only when necessary."},"warnings":[{"fix":"Consult the `recrawl` package documentation (e.g., `https://www.npmjs.com/package/recrawl#pattern-syntax`) to correctly define file watch patterns in your `package.json` `bic` field.","message":"The `bic` configuration in `package.json` uses a custom glob syntax, not standard glob patterns. Refer to the `recrawl` package documentation for specific pattern syntax rules.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Structure your `bic` configuration with `skip` patterns as overriding exclusions. Ensure files you intend to watch are not inadvertently included in `skip`.","message":"When configuring watched files via the `bic` field in `package.json`, the `skip` array takes precedence over the `only` array. Files explicitly listed in `skip` will always be ignored, even if also present in `only`.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Plan your file watching configurations knowing that version control and dependency directories are inherently ignored by `build-if-changed`.","message":"By default, the `.git` and `node_modules` directories are always skipped during file crawling. This behavior cannot be overridden by `only` configurations.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure your `build` script does not contain 'bic' or 'build-if-changed' as substrings if you intend for `build-if-changed` to run it. For example, use `my:build` instead of `bic:build`.","message":"Any package whose 'build' script in `package.json` contains either 'bic' or 'build-if-changed' will be skipped to prevent infinite loops.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Install `build-if-changed` as a dev dependency (`npm install build-if-changed -D` or `yarn add build-if-changed -D`) and then run it using `npx build-if-changed` (for npm) or `yarn build-if-changed` (for yarn).","cause":"The `build-if-changed` command (or `bic` alias) is not found in the system's PATH, usually because the package was not installed or installed incorrectly.","error":"Error: Command failed with exit code 127: build-if-changed"},{"fix":"Add a `\"build\": \"your-build-command-here\"` entry to the `scripts` section of the `package.json` for each package that `build-if-changed` should process.","cause":"The specified packages' `package.json` files do not contain a `scripts.build` entry, which `build-if-changed` expects to execute.","error":"No build scripts found in the following packages: [list of packages]"},{"fix":"Carefully review the `bic` field in your `package.json`. Verify the custom glob patterns against the `recrawl` documentation and ensure the `skip` array does not inadvertently exclude desired files.","cause":"Incorrect `bic` configuration in `package.json`, often due to misunderstanding the custom glob syntax or `skip`/`only` precedence.","error":"Files are not being watched/skipped as expected."}],"ecosystem":"npm"}