|
| 1 | +# Node.js Package Installer Refactoring |
| 2 | + |
| 3 | +This refactoring transforms the Node.js package installers from lifecycle hooks to ExecutableResource-based resources, addressing issue #732. |
| 4 | + |
| 5 | +## What Changed |
| 6 | + |
| 7 | +### Before (Lifecycle Hook Approach) |
| 8 | +- Package installation was handled by lifecycle hooks during `BeforeStartAsync` |
| 9 | +- No visibility into installation progress in the dashboard |
| 10 | +- Limited logging capabilities |
| 11 | +- Process management handled manually via `Process.Start` |
| 12 | + |
| 13 | +### After (Resource-Based Approach) |
| 14 | +- Package installers are now proper `ExecutableResource` instances |
| 15 | +- They appear as separate resources in the Aspire dashboard |
| 16 | +- Full console output visibility and logging |
| 17 | +- DCP (Distributed Application Control Plane) handles process management |
| 18 | +- Parent-child relationships ensure proper startup ordering |
| 19 | + |
| 20 | +## New Resource Classes |
| 21 | + |
| 22 | +### NpmInstallerResource |
| 23 | +```csharp |
| 24 | +var installer = new NpmInstallerResource("npm-installer", "/path/to/project", useCI: true); |
| 25 | +// Supports both 'npm install' and 'npm ci' commands |
| 26 | +``` |
| 27 | + |
| 28 | +### YarnInstallerResource |
| 29 | +```csharp |
| 30 | +var installer = new YarnInstallerResource("yarn-installer", "/path/to/project"); |
| 31 | +// Executes 'yarn install' command |
| 32 | +``` |
| 33 | + |
| 34 | +### PnpmInstallerResource |
| 35 | +```csharp |
| 36 | +var installer = new PnpmInstallerResource("pnpm-installer", "/path/to/project"); |
| 37 | +// Executes 'pnpm install' command |
| 38 | +``` |
| 39 | + |
| 40 | +## Usage Examples |
| 41 | + |
| 42 | +### Basic Usage (No API Changes) |
| 43 | +```csharp |
| 44 | +var builder = DistributedApplication.CreateBuilder(); |
| 45 | + |
| 46 | +// API remains the same - behavior is now resource-based |
| 47 | +var viteApp = builder.AddViteApp("frontend", "./frontend") |
| 48 | + .WithNpmPackageInstallation(useCI: true); |
| 49 | + |
| 50 | +var backendApp = builder.AddYarnApp("backend", "./backend") |
| 51 | + .WithYarnPackageInstallation(); |
| 52 | +``` |
| 53 | + |
| 54 | +### What Happens Under the Hood |
| 55 | +```csharp |
| 56 | +// This now creates: |
| 57 | +// 1. NodeAppResource named "frontend" |
| 58 | +// 2. NpmInstallerResource named "frontend-npm-install" (child of frontend) |
| 59 | +// 3. WaitAnnotation on frontend to wait for installer completion |
| 60 | +// 4. ResourceRelationshipAnnotation linking installer to parent |
| 61 | +``` |
| 62 | + |
| 63 | +## Benefits |
| 64 | + |
| 65 | +### Dashboard Visibility |
| 66 | +- Installer resources appear as separate items in the Aspire dashboard |
| 67 | +- Real-time console output from package installation |
| 68 | +- Clear status indication (starting, running, completed, failed) |
| 69 | +- Ability to re-run installations if needed |
| 70 | + |
| 71 | +### Better Resource Management |
| 72 | +- DCP handles process lifecycle instead of manual `Process.Start` |
| 73 | +- Proper resource cleanup and error handling |
| 74 | +- Integration with Aspire's logging and monitoring systems |
| 75 | + |
| 76 | +### Improved Startup Ordering |
| 77 | +- Parent resources automatically wait for installer completion |
| 78 | +- Failed installations prevent app startup (fail-fast behavior) |
| 79 | +- Clear dependency visualization in the dashboard |
| 80 | + |
| 81 | +### Development vs Production |
| 82 | +- Installers only run during development (excluded from publish mode) |
| 83 | +- No overhead in production deployments |
| 84 | +- Maintains backward compatibility |
| 85 | + |
| 86 | +## Migration Guide |
| 87 | + |
| 88 | +### For Users |
| 89 | +No changes required! The existing APIs (`WithNpmPackageInstallation`, `WithYarnPackageInstallation`, `WithPnpmPackageInstallation`) work exactly the same. |
| 90 | + |
| 91 | +### For Contributors |
| 92 | +The lifecycle hook classes are marked as `[Obsolete]` but remain functional for backward compatibility: |
| 93 | +- `NpmPackageInstallerLifecycleHook` |
| 94 | +- `YarnPackageInstallerLifecycleHook` |
| 95 | +- `PnpmPackageInstallerLifecycleHook` |
| 96 | +- `NodePackageInstaller` |
| 97 | + |
| 98 | +These will be removed in a future version once all usage has migrated to the resource-based approach. |
| 99 | + |
| 100 | +## Testing |
| 101 | + |
| 102 | +Comprehensive test coverage includes: |
| 103 | +- Unit tests for installer resource properties and command generation |
| 104 | +- Integration tests for parent-child relationships |
| 105 | +- Cross-platform compatibility (Windows vs Unix commands) |
| 106 | +- Publish mode exclusion verification |
| 107 | +- Wait annotation and resource relationship validation |
0 commit comments