Skip to content

[Infrastructure] Make npm restore and build incremental #62466

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

javiercn
Copy link
Member

@javiercn javiercn commented Jun 25, 2025

Implement incremental restore for npm workspace build system

Summary

This PR implements incremental build support for the npm restore process in the ASP.NET Core build system. The change adds proper input/output tracking to avoid unnecessary npm restore operations when node modules are already up-to-date, providing significant performance improvements during development.

Changes Made

Modified Npm.Workspace.nodeproj

  • Added Properties:

    • NpmWorkspaceRoot: Points to the repository root for consistent path handling
    • NodeModulesMarkerFile: Uses .package-lock.json as the restore completion marker
  • Added Input Files ItemGroup: Tracks all files that should trigger a restore when modified:

    • Root package.json
    • Root package-lock.json (if exists)
    • All workspace package.json files (src/**/package.json)
    • .npmrc configuration file (if exists)
  • Added Output Files ItemGroup: Uses npm's own marker file to determine restore completion

    • .package-lock.json - Created by npm after successful restore
  • Enhanced Restore Target: Added Inputs and Outputs attributes to enable MSBuild's incremental build logic

Performance Impact

  • Before: Every restore operation took ~30-35 seconds regardless of whether it was needed
  • After:
    • Fresh restore: ~30-35 seconds (unchanged)
    • Skip restore when up-to-date: ~1.5 seconds (95% time savings)

Manual Testing Performed

Comprehensive testing was conducted to verify the incremental behavior works correctly across all input scenarios:

✅ Test Cases Verified

Test Case Action Expected Result Actual Result Time
Fresh restore Remove node_modules, run restore Full restore executes ✅ Restore ran ~32s
No changes Run restore again immediately Restore skipped ✅ Skipped with message: "all output files are up-to-date" ~1.5s
Root package.json touch package.json Restore triggered ✅ Restore ran ~32s
Root package-lock.json touch package-lock.json Restore triggered ✅ Restore ran ~32s
Workspace package.json touch src/SignalR/clients/ts/signalr/package.json Restore triggered ✅ Restore ran ~32s
NPM config touch .npmrc Restore triggered ✅ Restore ran ~30s
Multiple workspace files touch src/Components/Web.JS/package.json Restore triggered ✅ Restore ran ~32s

✅ MSBuild Messages Verified

  • When restore runs: "Restoring NPM packages..."
  • When restore skips: "Skipping target 'Restore' because all output files are up-to-date with respect to the input files"

Technical Details

  • Uses MSBuild's built-in incremental build system via Inputs and Outputs target attributes
  • Leverages npm's own .package-lock.json file as the authoritative marker for restore completion
  • Monitors all relevant npm configuration files using glob patterns and conditional includes
  • Maintains backward compatibility - no breaking changes to existing build processes

Benefits

  • Developer productivity: Eliminates 30+ second delays during development when dependencies haven't changed
  • CI/CD efficiency: Reduces build times in scenarios where npm packages are cached
  • Reliability: Uses npm's own completion markers rather than custom heuristics
  • Maintainability: Leverages MSBuild's native incremental build capabilities

@javiercn javiercn requested review from wtgodbe and a team as code owners June 25, 2025 10:57
@github-actions github-actions bot added the area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework label Jun 25, 2025
Copy link
Contributor

Hey @dotnet/aspnet-build, looks like this PR is something you want to take a look at.

@javiercn
Copy link
Member Author

I've made also build incremental. That cuts the build time for incremental builds ~600s on my box to ~350s

@javiercn javiercn changed the title [Infrastructure] Make npm restore incremental [Infrastructure] Make npm restore and build incremental Jun 25, 2025
</ItemGroup>

<!-- Output files for incremental build check -->
<ItemGroup>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How often might we have to update this list?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven’t changed anything in years I would say.

The list of outputs is not as important as the incrementalism is “all or nothing” for all the us projects.

MSBUILD requires at least one output or else it will not run the task.

The goal is that if you’re not touching the JavaScript. You don’t have to build any part of the JavaScript pipeline during your dev builds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants