Building and packaging
What each command produces — build outputs (dist/, release/) on this page, catalog upload and CDN on deployment.md. See Microsoft docs: Package and deploy SPFx solutions and Host SPFx from Office 365 CDN.
For daily flow see getting-started.md; for ZIP layout see reference/FORMATS.md.
Commands
| Command | Output | Notes |
|---|---|---|
rspfx build | dist/ + release/manifests/*.manifest.json + release/assets/* | --no-minify, --sourcemap; bundler config optional |
rspfx package | sharepoint/solution/<name>.sppkg | Runs build first; --no-build to skip |
rspfx analyze | Console table + .rspfx/analyze.html | Module counts via bundler or .rspfx/stats.json |
rspfx clean | Removes dist/, release/, .rspfx, etc. | — |
rspfx doctor | Checks env, config, ports, certs | Exit 1 on fail — use in CI |
All commands read config/* and src/*/*.manifest.json.
With a bundler config (vite.config.ts, rsbuild.config.ts, or rspack.config.ts) it is loaded via jiti; without it the CLI synthesizes config from manifests and runs Vite, Rsbuild, or Rspack directly.
See migrating-from-gulp-heft.md#same-manifest-for-heftgulp-and-rspfx.
Tip: No manual
@microsoft/sp-*install for most web parts — externalized, SharePoint resolves built-in copies.
Tip:
bun run build(orpnpm/npm/yarnrun build) andrspfx buildare the same codepath — use either.
Project layout
Default is the official SPFx layout.
Customize via paths in plugin options:
| Option | Default | Controls |
|---|---|---|
paths.webpartsDir | src/webparts | Web part discovery |
paths.configDir | config | config.json + serve.json |
paths.srcDir | src | localizedResources rewriting |
Bundle name = web part folder name by default — that name becomes loaderConfig.entryModuleId.
No bundler config needed — zero-config synthesis handles standard layouts.
What rspfx build does
Reads project — bundles, externals,
localizedResourcesfromconfig.json; scanssrc/webparts/*whenbundlesis absent.Loads framework preset — JSX/TS transform, resolve, plugins.
Compiles (Vite by default, Rsbuild or Rspack if configured) — one AMD bundle per web part (
define('<id>_<version>', …)), chunks, SCSS, assets;@microsoft/sp-*never bundled; CSS inlined, no.cssin.sppkg— see styling.md.Writes manifests to
release/manifests/—versionfrompackage.json,entryModuleId= bundle name,scriptResourcesper external,internalModuleBaseUrlsfromcdnBasePath.Copies assets to
release/assets/.
rspfx build alone does not create a .sppkg — that is rspfx package.
Tip:
rspfx build --no-minify --sourcemapfor debuggable staging builds; CI should use default minified output.
What rspfx package does
Creates a DEFLATE zip at config/package-solution.json paths.zippedPackage (default sharepoint/solution/<name>.sppkg).
Content is driven by that file:
includeClientSideAssets: true— bundles embedded underClientSideAssets/, manifests rewritten toHTTPS://SPCLIENTSIDEASSETLIBRARY/— see Host SPFx from Office 365 CDN.includeClientSideAssets: falseorcdnBasePathinwrite-manifests.json— external CDN URL in manifests; uploadrelease/assets/*there.webApiPermissionRequests→RequestedWebApiPermissioninAppManifest.xml.- Extensions →
Extension_<id>.xmlwithLocation; libraries →Library_<id>.xml. - Auto-detects
teams/(icons →ClientSideAssets/teams/) andsharepoint/Resources*.resx.
Full ZIP entry list and ordering: reference/FORMATS.md.
Deployment steps (catalog, CDN, permissions, Teams): deployment.md.
rspfx deploy automates upload with a token; without it prints manual steps.
Comparison vs official
| Area | Official | RSPFx |
|---|---|---|
| Build output | dist/ + temp/ (Heft) | dist/ + release/manifests/ + release/assets/ |
| Bundle format | AMD define('<id>_<version>', …) | Same — byte-compatible (see compatibility.md) |
| CSS | Extracted or inlined per rig | Inlined — no .css files in .sppkg |
| Manifests | release/ via write-manifests | Same semantics, cdnBasePath ↔ SPCLIENTSIDEASSETLIBRARY |
| Package | gulp package-solution | rspfx package — same ZIP layout |
CI
npm ci- run: rspfx doctor
- run: rspfx package
- upload: sharepoint/solution/*.sppkgRSPFX_LOG_LEVELfor verbose logs — see commands.md#environment-variables.- Cache
node_modules+.rspack-cache(dev only; prod ignores persistent cache).
Size and speed
Defaults: minify: true, splitChunks: false, sourcemap: false.
splitChunks: false is correct for SPFx — one AMD bundle per web part.
true saves duplicate code via chunk.*.js but adds a request.
Example: PnP Modern Search (4 web parts, 178 files, Fluent UI) → ~2 s on a laptop.
Troubleshooting
| Symptom | Fix |
|---|---|
UNRESOLVED_EXTERNAL | Remove that externals key or add the package |
sp-* code in bundle | Remove resolve alias that collides with sp-* |
Can't resolve 'XxxWebPartStrings' | localizedResources missing or not lib/.../{locale}.js shaped |
@import 'pkg:...' fails | Rewritten by rspfx migrate for sass-loader <16.5 |
.html import fails | Rebuild CLI — asset/source handles it |
Bundle 404 in workbench (https://localhost:4321/dist/...) | Bundle name must match entryModuleId — default: folder name — see project-structure.md |
Package goes to solution/ | paths.zippedPackage is authoritative |