@sudharsank/spfx-selective-build
v0.1.0
Published
Reusable CLI for profile-based selective SPFx builds, packaging, backup sync, and profile scaffolding.
Maintainers
Readme
spfx-selective-build
spfx-selective-build is a reusable npm/npx CLI for profile-based selective SPFx builds.
It packages a profile-based selective build pattern into an installable tool so teams do not need to keep a one-off script in each repository.
It works against the real files in your SPFx solution. The CLI reads the live config.json, package-solution.json, and tsconfig.json, creates backup companions when they do not exist yet, and then applies profile-specific rewrites around each command.
What it automates
- lists available build profiles from
config/build-profiles.json - scopes
config/config.jsonto the selected bundle set - scopes
tsconfig.jsonto the selected web part folder(s) plussrc/shared/** - swaps
config/package-solution.jsonto the selected profile package file - runs
heft start,heft test,heft build, orheft package-solution - restores the baseline config files after the command completes or fails
- scaffolds new profile entries and starter
package-solution.<profile>.jsonfiles - updates or removes bundles from existing profiles with guard rails
- synchronizes committed backup files with a single command
Install and run
Use it directly with npx:
cd ./spfx-solution
npx spfx-selective-build list
npx spfx-selective-build build prh
npx spfx-selective-build package gov-suiteIf you run from a repo root instead of the SPFx solution folder, add --solution-dir ./spfx-solution.
Or install it as a local dev dependency and wire npm scripts:
npm install --save-dev spfx-selective-build{
"scripts": {
"wp:list": "spfx-selective-build list --solution-dir ./spfx-solution",
"wp:start": "spfx-selective-build start --solution-dir ./spfx-solution",
"wp:test": "spfx-selective-build test --solution-dir ./spfx-solution",
"wp:build": "spfx-selective-build build --solution-dir ./spfx-solution",
"wp:package": "spfx-selective-build package --solution-dir ./spfx-solution",
"wp:create-profile": "spfx-selective-build create-profile --solution-dir ./spfx-solution",
"wp:update-profile": "spfx-selective-build update-profile --solution-dir ./spfx-solution",
"wp:remove-profile": "spfx-selective-build remove-profile --solution-dir ./spfx-solution",
"wp:sync-backups": "spfx-selective-build sync-backups --solution-dir ./spfx-solution",
"wp:reset": "spfx-selective-build reset --solution-dir ./spfx-solution"
}
}Then run:
npm run wp:list
npm run wp:test -- prh
npm run wp:build -- prh
npm run wp:package -- gov-suite
npm run wp:create-profile -- --key my-webpart --name "My Web Part" --bundle my-web-part
npm run wp:update-profile -- --key gov-suite --bundle external-sharing-command-center-web-part
npm run wp:remove-profile -- --key gov-suite --bundle external-sharing-command-center-web-part
npm run wp:sync-backups
npm run wp:resetwp:start, wp:test, wp:build, and wp:package are the selective commands. Your existing default npm run build script still behaves exactly as your project defines it unless you intentionally replace it. In a stock SPFx project, npm run build continues to run the full-solution Heft flow.
When you pass arguments through npm run, always use -- before the command arguments. For example:
npm run wp:create-profile -- --key my-webpart --name "My Web Part" --bundle my-web-partTo wire those scripts automatically into the current project package, run:
npx spfx-selective-build wireIf you run that from a repo root that contains ./spfx-solution, the generated scripts automatically include --solution-dir ./spfx-solution. If you run it inside the SPFx solution folder itself, the generated scripts use the local project directly.
If you are testing from a local filesystem path instead of an installed npm package, run wire through that local path too. The generated scripts will use that same local CLI entry:
node /absolute/path/to/spfx-selective-build/bin/spfx-selective-build.js wire \
--wire-command "node /absolute/path/to/spfx-selective-build/bin/spfx-selective-build.js"Avoid using npx /absolute/path/to/spfx-selective-build wire for long-lived script wiring. npx may execute from a temporary cache path, and that cache path is not stable for future npm run wp:* commands.
First-time setup in a stock SPFx project
If your SPFx project only has the default generator output, start by creating the first profile. The CLI will:
- use the existing live SPFx files in the project
- create
config.backup.json,package-solution.backup.json, andtsconfig.backup.jsonif they are missing - create
config/build-profiles.jsonif it does not exist yet - scaffold
package-solution.<profile>.jsonfrom the currentpackage-solution.json
Example:
npx spfx-selective-build create-profile \
--key hello-world \
--name "Hello World" \
--bundle hello-world-web-part--name is the human-readable profile label. It is what shows up in wp:list, and it is also used as the basis for the generated starter package metadata. --key is the stable machine-friendly profile identifier.
Command reference
list
Lists the profiles in config/build-profiles.json.
start <profile>
Applies a profile, runs heft start --clean, and restores the baseline files afterward.
test <profile>
Applies a profile, runs heft test --clean, and restores the baseline files afterward.
Use this when you want selective test execution for the chosen profile without changing the meaning of the project's default build script.
build <profile>
Applies a profile, runs heft build --clean --production, and restores the baseline files afterward.
package <profile>
Applies a profile, runs heft build --clean --production and heft package-solution --production, and restores the baseline files afterward.
create-profile
Creates or updates a profile entry plus a starter package-solution.<profile>.json file. If build-profiles.json does not exist yet, the command bootstraps it from the current SPFx project.
Example:
npx spfx-selective-build create-profile \
--key gov-suite \
--name "Governance Insights Suite" \
--bundle global-governance-admin-web-part \
--bundle permission-risk-heatmap-web-partOptional flags:
--package-file <filename>--loc-key-override <bundle>=<resourceKey>--force
update-profile
Updates an existing profile by appending one or more bundles, or by changing the profile name, package file, or localized resource overrides.
Examples:
npx spfx-selective-build update-profile \
--key gov-suite \
--bundle external-sharing-command-center-web-partnpx spfx-selective-build update-profile \
--key gov-suite \
--name "Governance Insights Suite" \
--package-file package-solution.governance-suite.jsonUse this when a profile already exists and you need to add another web part to that profile without overwriting the existing bundle list.
If you recently added a new web part to the SPFx solution and update-profile says the bundle is unknown even though it exists in config.json, run:
npm run wp:sync-backupsThat updates config.backup.json, which is the baseline used for validation and restore.
remove-profile
Removes one or more bundles from an existing profile.
Examples:
npx spfx-selective-build remove-profile \
--key gov-suite \
--bundle external-sharing-command-center-web-partnpx spfx-selective-build remove-profile \
--key gov-suite \
--bundle external-sharing-command-center-web-part \
--bundle policy-drift-dashboard-web-partValidation rules:
- supports removing multiple bundles in one command
- warns if a requested bundle is not currently part of the profile
- prevents removing the last remaining bundle from a profile
wire
Updates the nearest project package.json with the full wp:* script set based on the current layout.
Generated scripts:
wp:listwp:startwp:testwp:buildwp:packagewp:create-profilewp:update-profilewp:remove-profilewp:sync-backupswp:reset
Example:
npx spfx-selective-build wireFor local source testing without installing the package into the project:
node /absolute/path/to/spfx-selective-build/bin/spfx-selective-build.js \
--wire-command "node /absolute/path/to/spfx-selective-build/bin/spfx-selective-build.js" \
wireAfter that, you can use:
npm run wp:list
npm run wp:create-profile -- --key hello-world --name "Hello World" --bundle hello-world-web-part
npm run wp:update-profile -- --key hello-world --bundle another-web-part
npm run wp:remove-profile -- --key hello-world --bundle another-web-part
npm run wp:test -- hello-world
npm run wp:build -- hello-worldsync-backups
Refreshes the committed baseline copies:
config/config.backup.jsonconfig/package-solution.backup.jsontsconfig.backup.json
This is useful after intentional structural changes to the full solution.
reset
Restores the baseline files from their backups.
Expected project layout
The tool expects either:
- to be run inside the SPFx solution directory, or
- to be run from a repo root that contains
./spfx-solution
Minimum expected files:
spfx-solution/
tsconfig.json
tsconfig.backup.json
config/
build-profiles.json
config.json
config.backup.json
package-solution.json
package-solution.backup.json
package-solution.<profile>.jsonBackups are created automatically from the live project files the first time they are needed. build-profiles.json is created automatically when you run create-profile in a stock SPFx project.
Why the tool scopes tsconfig.json
Filtering config.json is not enough in a multi-web-part SPFx solution. TypeScript can still compile unrelated source trees if the root tsconfig.json includes them. The CLI rewrites tsconfig.json during the run so the selected web part compiles together with src/shared/**, but unrelated web parts stay out of scope.
Practical expectation
This CLI is meant to operate on your actual SPFx solution folder, not on bundled template config files. The package uses the project’s current baseline as the source of truth and only creates backup copies to support safe restore behavior.
Troubleshooting
npm run wp:* points to a dead npx cache path
If your generated scripts point to a path under .npm/_npx/..., they were wired from a temporary npx cache location and will eventually break.
Do not wire long-lived project scripts with:
npx /absolute/path/to/spfx-selective-build wireUse one of these instead:
npx spfx-selective-build wireor, for local source testing:
node /absolute/path/to/spfx-selective-build/bin/spfx-selective-build.js \
--wire-command "node /absolute/path/to/spfx-selective-build/bin/spfx-selective-build.js" \
wireIf the project is already wired to a dead cache path, rerun wire with one of the commands above to rewrite the wp:* scripts.
Host path works locally but not inside Docker or a dev container
If your script points to a path like /Users/<name>/..., that path exists on the host machine, not inside the container.
In a containerized SPFx project, install the package inside the container filesystem or use a tarball mounted into the container, then re-run:
npx spfx-selective-build wireAfter rewiring, package.json should reference either spfx-selective-build or a path that exists inside the container.
npm install ./spfx-selective-build-0.1.0.tgz hangs or tries to hit the registry
If npm install hangs and logs show requests like:
UNABLE_TO_GET_ISSUER_CERT_LOCALLYthen the environment has a TLS trust problem, often caused by a corporate proxy or custom certificate authority.
If you can fix trust for Node, configure the container or shell with your CA bundle, for example with NODE_EXTRA_CA_CERTS, and retry the install.
If you only need to test the package and want to avoid registry access, unpack the tarball manually:
mkdir -p node_modules/spfx-selective-build node_modules/.bin
tar -xzf spfx-selective-build-0.1.0.tgz \
-C node_modules/spfx-selective-build \
--strip-components=1 package
ln -sf ../spfx-selective-build/bin/spfx-selective-build.js node_modules/.bin/spfx-selective-build
chmod +x node_modules/spfx-selective-build/bin/spfx-selective-build.jsThen wire and test normally:
npx spfx-selective-build wire
npm run wp:listwp:build fails with Sass embedded compiler errors on Linux ARM
If Heft fails with an error like this:
Embedded Dart Sass couldn't find the embedded compiler executable.
Please make sure the optional dependency sass-embedded-linux-arm64 is installed in node_modules.then the selective build command is working, but the underlying SPFx toolchain is missing an optional platform-specific Sass package.
This is a project dependency issue, not a profile-selection issue. Fix the SPFx project dependencies first, then rerun the profile command.
Typical options:
- run a normal
npm installafter TLS and registry access are working - explicitly install the platform-specific optional dependency required by the environment
- verify the container or build agent architecture matches the installed optional package
The CLI now restores config.json, package-solution.json, and tsconfig.json even when Heft fails, so a failing Sass plugin should not leave the solution in a filtered state.
npm run wp:list works but wp:build fails because build-profiles.json is missing
That is expected on a stock SPFx project before the first profile exists.
Create the first profile from the live project files:
npm run wp:create-profile -- --key hello-world --name "Hello World" --bundle hello-world-web-partThat command also creates:
config/build-profiles.jsonconfig/config.backup.jsonconfig/package-solution.backup.jsontsconfig.backup.jsonconfig/package-solution.<profile>.json
