fix(pack): ship static web assets in module .nupkgs#125
Merged
antosubash merged 2 commits intomainfrom Apr 29, 2026
Merged
Conversation
Without 'npm run build' between 'npm ci' and 'dotnet pack', module
wwwroot/ directories are empty on a clean CI checkout, so packed NuGets
omit the staticwebassets/ tree. Consumers of SimpleModule.Users (and
every other module shipping a React UI) then see 404s for
/_content/{Module}/{Module}.pages.js.
Deploying simplemodule-website with
|
| Latest commit: |
db64e20
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://435d6100.simplemodule-website.pages.dev |
| Branch Preview URL: | https://claude-fix-users-packaging-b.simplemodule-website.pages.dev |
The StaticWebAssets SDK evaluates 'Content Include="wwwroot/**"' during
MSBuild item evaluation, which runs before any target executes. On a
fresh checkout wwwroot/ does not exist yet, so the SDK locks in an empty
content list before JsBuild has a chance to run Vite. The previous
'BeforeTargets="Build"' on JsBuild was insufficient for two reasons:
the SDK had already enumerated the empty directory, and several pack-
relevant targets (ResolveProjectStaticWebAssets, GenerateNuspec) ran
outside the Build dependency chain.
Two changes:
1. Broaden JsBuild's BeforeTargets so it fires before
ResolveStaticWebAssetsConfiguration, ResolveProjectStaticWebAssets,
GetCopyToOutputDirectoryItems, and GenerateNuspec, in addition to
Build.
2. Add a ReincludeWwwrootContent target that re-adds wwwroot/** to
@(Content) after JsBuild and before ResolveProjectStaticWebAssets,
mirroring the SDK's own item include. This is what actually gets the
freshly-built files in front of the static-web-asset pipeline on a
cold build.
Also adds a CI smoke job (pack-smoke) and a verification script
(scripts/verify-nupkg-static-assets.mjs) that runs 'dotnet pack' the
same way release does, then asserts each UI-shipping module's .nupkg
contains 'staticwebassets/{Id}.pages.js', at least one .mjs chunk, and
'build/{Id}.props' — exactly the shape that was missing from
SimpleModule.Users 0.0.33.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SimpleModule.Users0.0.33 (and every other UI-shipping module) was published with an emptystaticwebassets/tree, so consumers got a 404 for/_content/SimpleModule.Users/SimpleModule.Users.pages.jsand the login page rendered blank. Two independent root causes; this PR fixes both, and adds a CI smoke test so the next regression of this shape is caught at PR time.Root causes
Release workflow never built the JS.
publish-nugetrannpm cithen jumped straight todotnet pack, with nonpm run buildin between. On a clean CI checkout each module'swwwroot/was empty when pack ran, so the SDK had nothing to package.Microsoft.NET.Sdk.StaticWebAssetsevaluatesContent Include="wwwroot/**"during MSBuild item evaluation, which runs before any target executes. Even with the existingJsBuildMSBuild target (BeforeTargets="Build"), the SDK had already locked in an empty file list by the time Vite ran. Sodotnet packinvoked outside the workflow (or after agit clean) would still produce an empty package — the workflow fix alone wasn't enough.Changes
1.
npm run buildbeforedotnet pack(release workflow)Inserted between
npm cianddotnet restorein.github/workflows/release.ymlso modulewwwroot/directories are populated before pack runs. Belt-and-suspenders alongside the MSBuild fix below; also a perf win because the orchestrator builds modules in parallel.2. MSBuild: pre-populate
@(Content)from builtwwwroot/(modules/Directory.Build.targets)JsBuild'sBeforeTargetsto also fire beforeResolveStaticWebAssetsConfiguration,ResolveProjectStaticWebAssets,GetCopyToOutputDirectoryItems, andGenerateNuspec— coversdotnet packinvoked outside the Build chain.ReincludeWwwrootContenttarget (AfterTargets="JsBuild" BeforeTargets="ResolveProjectStaticWebAssets") that re-addswwwroot/**to@(Content)from inside MSBuild execution, after Vite has run. This is the actual fix for the cold-build case — without it,dotnet packfrom a clean checkout still produces an emptystaticwebassets/tree even with the workflow fix.3. CI smoke job (
pack-smoke) + verification scriptscripts/verify-nupkg-static-assets.mjsdiscovers UI-shipping modules (modules/*/src/*/with apackage.jsonnext to a.csprojand aPages/index.ts), then asserts each matching.nupkgcontains:staticwebassets/{Id}.pages.js(the SDK strips thewwwroot/prefix when packaging).mjscode-split chunk understaticwebassets/build/{Id}.props(the manifest plumbing consumers need to pick up the assets)pack-smokejob in.github/workflows/ci.ymlrunsdotnet packexactly the way release does, then runs the verifier — so the next time a module ships an empty package, CI fails before merge.Verification
Locally, with everything cleaned (
rm -rf wwwroot obj bin):SimpleModule.Users: now 89 entries includingstaticwebassets/SimpleModule.Users.pages.js, all.mjschunks, andbuild/SimpleModule.Users.props.SimpleModule.Settings: now 29 entries includingstaticwebassets/SimpleModule.Settings.pages.js, the smaller chunk set, andbuild/SimpleModule.Settings.props.Exclude="@(Content)"guard works)..nupkgis missing (regression check).Test plan
pack-smokejob runsnpm run build+dotnet pack+ verifier and reports green..nupkg(e.g.SimpleModule.Users 0.0.34) and confirm it containsstaticwebassets/SimpleModule.Users.pages.js, the.mjschunks, andbuild/SimpleModule.Users.props./_content/SimpleModule.Users/SimpleModule.Users.pages.jsreturns 200 and the login page renders end-to-end.