Conversation
|
Thanks for the contribution! Unfortunately we can't verify the commit author(s): dmungamuri <d***@s***.com>. One possible solution is to add that email to your GitHub account. Alternatively you can change your commits to another email and force push the change. After getting your commits associated with your GitHub account, refresh the status of this Pull Request. |
b66c3a3 to
2bb515f
Compare
1e37678 to
7513452
Compare
sf webapp dev command
sf webapp dev commandsf webapp dev command
Implement a local proxy server for webapp development that handles authentication, request routing, and dev server lifecycle management. FEATURES: Core Proxy Server: - HTTP proxy server with configurable port (default: 4545) - Automatic authentication injection using CLI tokens - Request routing between Salesforce APIs and local dev server - WebSocket support for Hot Module Replacement (HMR) - Code Builder environment detection and URI handling - Graceful shutdown on SIGINT/SIGTERM - Port conflict detection with user-friendly error messages Dev Server Management: - Automatic dev server lifecycle management (spawn, monitor, restart) - URL detection for Vite, Create React App, Next.js, and custom servers - ANSI color code stripping for robust URL detection - Configurable startup timeout (default: 30s) - Process cleanup on exit - Support for explicit URL mode (no spawning) Configuration Management: - webapp.json manifest loading and validation with JSON schema - File watching with automatic reload on configuration changes - Debounced change detection - Comprehensive validation error messages Error Handling & User Experience: - Beautiful HTML error page when dev server is unreachable - Auto-refresh every 5 seconds until dev server is detected - Periodic health checks (every 5s) with status updates - Standardized error messages with actionable suggestions - Sensitive data sanitization in error logs MODULES IMPLEMENTED: - AuthManager: Salesforce authentication and token management - RequestRouter: Intelligent request routing (Salesforce vs dev server) - ProxyServer: Core HTTP proxy with health checks and error handling - DevServerManager: Dev server lifecycle management with URL detection - ManifestWatcher: webapp.json loading, validation, and change detection - ErrorHandler: Standardized error messages with actionable suggestions - Logger: Simple logging utility with debug mode COMMAND: sf webapp dev --name <name> --target-org <org> [--url <url>] [--port <port>] [--open] - Orchestrates all modules - Supports multiple dev server types (Vite, CRA, Next.js) - Opens browser automatically with --open flag - Graceful shutdown and cleanup TESTING: - Comprehensive unit tests for all modules - NUT tests for command error scenarios - Manual validation scripts in docs/manual-tests/ TECHNICAL HIGHLIGHTS: - ANSI color code stripping for robust URL detection - Line-by-line output processing for chunked stdout - Organized URL patterns by server type for maintainability - Unicode support for Vite arrow character (➜) - HTML error page template with auto-refresh - JSON schema validation for configuration Work Item: W-20242483
b372cad to
2289955
Compare
- Add SF_WEBAPP_DEV_DOCUMENTATION.md: Complete guide with architecture, usage, troubleshooting, and developer guide - Add QUICK_REFERENCE.md: Quick reference with one-liners and common fixes - Add docs/README.md: Documentation index and navigation - Update main README.md: Add plugin overview, features, and quick start - Update .gitignore: Allow markdown documentation files Documentation covers: - Installation and quick start - Command usage and all flags - Configuration (webapp.json) - Architecture and how it works - Troubleshooting guide - Developer guide for extending - API reference - Best practices Work Item: W-20242483
- Remove 'Available Documentation' section - Remove 'Finding Information' section (By Topic, By Role) - Remove 'Troubleshooting' section - Remove 'Contributing' section - Remove 'Links' section - Keep only essential: Getting Started and Command Overview Work Item: W-20242483
- Remove 'Known Limitations' section from main docs - Remove 'Support' section with work item reference - Remove 'Changelog' section (first version) - Remove 'Last Updated' and work item footer - Remove intro header from docs/README.md - Remove work item reference from Getting Help in QUICK_REFERENCE.md Documentation is now cleaner and focuses on user-facing content only. Work Item: W-20242483
The compile command was reverted when yarn install ran sf-install. This restores the build script to properly copy: - src/schemas/*.json to lib/schemas/ - src/templates/*.html to lib/templates/ These files are required at runtime for: - webapp.json validation (webapp-manifest.json) - HTML error page rendering (error-page.html) Work Item: W-20242483
- Implement global error capture with stack trace extraction - Add GlobalErrorCapture for uncaught exceptions and unhandled rejections - Add StackTraceFormatter for parsing and formatting V8 stack traces - Filter intentional exits (SIGINT, oclif EEXIT) from error capture - Add beautiful runtime error UI - Create runtime-error-page.html with modern white card design - Display error type, message, and scrollable stack trace (limited to 10 lines) - Show diagnostics (Node version, platform, PID, memory usage) - Provide actionable suggestions for fixing errors - Auto-refresh every 3 seconds to detect when error is resolved - Auto-recovery: return to app when dev server becomes healthy - Fix webapp dev command exit behavior - Add SIGINT to expected exit signals in DevServerManager - Track and destroy active connections for immediate proxy shutdown - Add 2-second force-close timeout to prevent hanging - Command now exits cleanly on Ctrl+C without restart loops - Improve terminal output logging - Move verbose startup logs to debug mode - Keep only essential logs in normal mode - Standardize log messages across components - Add error handling utilities - Add runtime error codes (RUNTIME_ERROR, UNCAUGHT_EXCEPTION, UNHANDLED_REJECTION) - Add context-aware error suggestions - Integrate with existing ErrorHandler system - Comprehensive test coverage - Add 287 passing tests including error capture, stack trace formatting, and exit handling - Test intentional exit filtering (SIGINT, SIGTERM, oclif exits) - Test error page rendering and XSS prevention All changes follow strict ESLint rules with no inline disables.
- Normalize backslashes to forward slashes in path assertions - Fixes test failure on Windows CI where paths use backslashes - Test now passes on both Unix and Windows platforms
- Add ProxyServer.updateDevServerUrl() method to dynamically update dev server target - Enhance manifest change handler to detect and apply dev.url changes without restart - Add warning message when dev.command changes (requires restart) - Update manifest reference to reflect all changes - Add unit tests for dynamic configuration updates When webapp.json is modified: - dev.url changes: proxy updates immediately with health check - dev.command changes: user warned to restart command - All other fields: manifest reference updated Tests: 289 passing (all existing + 2 new tests)
- Remove old documentation files (QUICK_REFERENCE.md, README.md, SF_WEBAPP_DEV_DOCUMENTATION.md) - Add SF_WEBAPP_DEV_GUIDE.md - comprehensive guide covering: - Overview and architecture - Getting started and building - Command usage and options - File structure and components - VSCode integration details - Advanced features (hot reload, error capture, etc.) - Troubleshooting and FAQ Single source of truth for all webapp dev command documentation.
- Move SF_WEBAPP_DEV_GUIDE.md from docs/ to root for easier access - Update README documentation section with single comprehensive guide reference - Remove outdated references to deleted documentation files - Simplify documentation structure (single source of truth)
- Consolidate error templates into single unified error-page.html - Add DevServerErrorParser for parsing and categorizing dev server stderr - Improve error page design with narrower diagnostics panel (308px) - Add emergency exit commands with copy button for hung processes - Remove redundant fallback HTML methods (use plain text as last resort) - Refactor ErrorPageRenderer to separate HTML from TypeScript logic - Add comprehensive tests for DevServerErrorParser - Update error handling to display parsed dev server errors in browser All error pages now use consistent UI with: - Top header with status badge - Two-column layout (main content + diagnostics) - Emergency commands section with SVG copy buttons - Auto-refresh for recoverable errors
package.json
Outdated
| "files": [ | ||
| "src/**/*.ts", | ||
| "src/**/*.json", | ||
| "src/**/*.html", |
There was a problem hiding this comment.
This is outdated after review comments. We are now only copying error html from templates folder.
Why lib/templates/ is needed
TypeScript compiler (tsc) only converts .ts → .js files. It does NOT copy .html, .json, or other non-TS files.
The Problem
At runtime, ErrorPageRenderer.js loads the template relative to itself:
const currentDir = dirname(fileURLToPath(import.meta.url));
const templatePath = join(currentDir, 'error-page.html');Since the compiled code runs from lib/templates/, it looks for templates in lib/templates/, not src/templates/.
Additionally
The src/ folder is not published to npm (only lib/ is in the files array). When users install the plugin, they only get lib/. Templates must be there for the plugin to work.
Solution
The copy-resources wireit task copies src/templates/*.html → lib/templates/ during build.
| @@ -3,8 +3,8 @@ | |||
| "alias": [], | |||
| "command": "webapp:dev", | |||
There was a problem hiding this comment.
I'm not able to run this locally with sf plugins link . How are you testing this?
There was a problem hiding this comment.
I have used the vibe-coding-starter & my workspace orgfarm org in vscode for validation
Build & Link Plugin
Build
cd /path/to/plugin-webapp
yarn build
Link to SF CLI
sf plugins link .
Verify
sf plugins
Setup webapp.json
Create webapp.json in your project(vibe-coding-starter) root:
{
"name": "myWebApp",
"label": "My Web App",
"version": "1.0.0",
"outputDir": "dist",
"dev": {
"url": "http://localhost:5173"
}
}
Or with a command to start dev server:
{
"name": "myWebApp",
"label": "My Web App",
"version": "1.0.0",
"outputDir": "dist",
"dev": {
"command": "cd static-app && npm run dev"
}
}
Usage
cd /path/to/vibe-coding-starter
sf webapp dev --name myWebApp --open
There was a problem hiding this comment.
https://github.com/salesforcecli/plugin-webapp/blob/sf-webapp-dev-command/SF_WEBAPP_DEV_GUIDE.md - This best depicts the flow and implementation.
src/schemas/webapp-manifest.json
Outdated
| } | ||
| }, | ||
| "additionalProperties": false | ||
| } |
There was a problem hiding this comment.
Not confident this will be the final schema so I don't know that we need to be validating the webapp.json at this point.
There was a problem hiding this comment.
the schema file is no longer here. I'm using the similar approach as that of the packages/webapps.
| @@ -0,0 +1,755 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
There was a problem hiding this comment.
On proxy server startup, this error occurs:
[ErrorPageRenderer] Failed to load template from /Users/nkruk/git/cli/plugin-webapp/lib/templates/error-page.html: Error: ENOENT: no such file or directory, open '/Users/nkruk/git/cli/plugin-webapp/lib/templates/error-page.html'
at readFileSync (node:fs:441:20)
at new ErrorPageRenderer (file:///Users/nkruk/git/cli/plugin-webapp/lib/templates/ErrorPageRenderer.js:32:29)
at new ProxyServer (file:///Users/nkruk/git/cli/plugin-webapp/lib/proxy/ProxyServer.js:51:34)
at WebappDev.run (file:///Users/nkruk/git/cli/plugin-webapp/lib/commands/webapp/dev.js:207:32)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async WebappDev._run (/Users/nkruk/git/cli/plugin-webapp/node_modules/@oclif/core/lib/command.js:182:22)
at async Config.runCommand (/Users/nkruk/.local/share/sf/client/2.108.6-399bc9e/node_modules/@oclif/core/lib/config/config.js:456:25)
at async run (/Users/nkruk/.local/share/sf/client/2.108.6-399bc9e/node_modules/@oclif/core/lib/main.js:97:16)
at async file:///Users/nkruk/.local/share/sf/client/2.108.6-399bc9e/bin/run.js:15:1 {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/Users/nkruk/git/cli/plugin-webapp/lib/templates/error-page.html'
}
There was a problem hiding this comment.
This issue was fixed, pls retry. The copy-resources task is now included in the build dependencies, which copies src/templates/error-page.html to lib/templates/.
npm run build
Running only npm run compile won't copy the HTML templates - use npm run build for a complete build.
There was a problem hiding this comment.
Might still need more work when runnning from installed CLI vs linked locally. We can address in followup PR
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
|
|
||
| <head> |
There was a problem hiding this comment.
Is it possible this error page could just be part of @salesforce/webapp proxy package?
There was a problem hiding this comment.
not a high priority though, we can look at in follow up PR
| import { execCmd, TestSession } from '@salesforce/cli-plugins-testkit'; | ||
| import { expect } from 'chai'; | ||
|
|
||
| describe('webapp dev NUTs', () => { |
There was a problem hiding this comment.
TODO: need more thorough nut tests.
- Need to have an SFDX test project with multiple webapps
- Some of those are invalid configs
- 1 -> launches the devserver
- 2 -> specify the URL
- 3 -> dev server fails to launch
- 4 -> dev server specified with URL isnt running
- 5 -> webapp.json is misconfigured missing
- 6 -> Launching command from different directories (root vs webapp folder)
There was a problem hiding this comment.
Also a test to verify we properly forward the auth header and that matches the SFCLI token for the org
There was a problem hiding this comment.
Any other tests to check manifest changes -> change manifest and verify it works with proxy
- Remove maxRestarts option from DevServerOptions and DevServerConfig - Remove restartCount tracking and auto-restart behavior - Simplify handleProcessExit to just emit events and cleanup - Remove obsolete Process Restart test block - CLI will exit cleanly on crash, users restart manually
- Remove try-catch wrapper around proxyHandler (package handles errors internally) - Remove unused handleRequestError method - Package already returns proper HTTP error responses for all cases
- Remove single-function file (only used in one place) - Inline Authorization header directly in WebSocket handler - Delete empty auth/ directory
src/server/DevServerManager.ts
Outdated
| private async initLogger(): Promise<void> { | ||
| if (!this.logger) { | ||
| // Logger respects SF_LOG_LEVEL environment variable | ||
| this.logger = await Logger.child('DevServerManager'); |
There was a problem hiding this comment.
Can we use Logger.childFromRoot() (which is not an async function) and initialize the logger in constructor?
…ation - DevServerManager: initialize logger in constructor, remove initLogger() method - ProxyServer: initialize logger in constructor, remove async logger init from start() - DevServerManager.start() is now synchronous (returns void instead of Promise<void>) - Remove optional chaining on logger calls since it's always initialized - Update callers to not await DevServerManager.start()
| super(); | ||
| this.config = config; | ||
| this.errorPageRenderer = new ErrorPageRenderer(); | ||
| this.workspaceScript = ProxyServer.detectWorkspaceScript(); |
There was a problem hiding this comment.
Is this still used at all?
There was a problem hiding this comment.
Yes, It is used.
How to validate ? When the preview opens.. try to stop the dev server.
errorPageRenderer renders error pages when the dev server fails or isn't running, and workspaceScript is displayed in those error pages to help users run the correct command.
package.json
Outdated
| "/oclif.lock", | ||
| "/oclif.manifest.json", | ||
| "/schemas" | ||
| "/oclif.manifest.json" |
There was a problem hiding this comment.
We don't need the schemas and oclif.lock files. but we still need the oclif.manifest.json
`Without it, the CLI has to dynamically discover commands at runtime:
-
Scan the commands/ directory
-
Load each TypeScript/JavaScript file
-
Parse the command class to extract flags, args, descriptions
-
Build the command tree
With the manifest, all that metadata is pre-computed:
-
Read one JSON file
-
Instantly know all available commands and their structure`
There was a problem hiding this comment.
Removed /npm-shrinkwrap.json and /oclif.lock from the files array
There was a problem hiding this comment.
Took reference from here and hence those were added : https://github.com/salesforcecli/plugin-lightning-dev/blob/main/package.json#L53
There was a problem hiding this comment.
ok thats fine, I just want to be sure we are consistent with other plugins. We can leave these in
There was a problem hiding this comment.
Added back. Turns out this was just an issue with our dependencies being out of date
Remove /npm-shrinkwrap.json and /oclif.lock from the files array as they are not standard for SF CLI plugins and not required.
The generate command has been moved to a different repo. This removes all related files including tests, schemas, and documentation.
The error-page.html template wasn't being copied to lib/templates during build, causing runtime errors.
Signal handling for graceful shutdown is already done in dev.ts using prependOnceListener to work correctly with oclif. The duplicate handlers in ProxyServer were causing conflicts.
Ensures error-page.html template is copied to lib/templates during build.
sf-install from @salesforce/dev-scripts keeps removing copy-resources from build dependencies. Using postbuild script instead which runs after build and is not modified by sf-install.
postbuild script now handles copying HTML templates, so the copy-resources wireit task is no longer needed.
The Unix commands (mkdir -p, cp) don't work on Windows. Using Node.js fs module instead which works on all platforms.
- Create scripts/copy-templates.cjs for copying HTML templates - Uses Node.js built-in fs module (works on all platforms) - sf-install won't modify dedicated script files - Provides clear console output during build
| "volta": { | ||
| "node": "20.20.0", | ||
| "yarn": "1.22.22" | ||
| } |
There was a problem hiding this comment.
Added volta config to ensure we are building locally with consistent tooling
| "@salesforce/core": "^8.25.0", | ||
| "@salesforce/kit": "^3.2.4", | ||
| "@salesforce/sf-plugins-core": "^12" | ||
| "@salesforce/sf-plugins-core": "^12.2.6", |
There was a problem hiding this comment.
Our build issues we were hitting were due to out of date dependencies / hence the issues with oclif manifest not linking properly with latest CLI. These updates resolve the issue.
nrkruk
left a comment
There was a problem hiding this comment.
Should be good enough for M2. We can address any code complexity / nut tests / other bugs that arise as part of M3
sf webapp dev commandsf webapp dev command @W-20242483@
Work Item: @W-20242483@
This PR implements the
sf webapp devcommand, a local development proxy server that enables seamless webapp development with Salesforce authentication and dev server integration.🎯 What This Does
Provides developers with a local proxy server that:
✨ Key Features
For Developers:
sf webapp dev --name myapp --target-org myorg --openwebapp.jsonchangesFor Webapp Architecture:
🏗️ Architecture
Built with modular components:
webapp.jsonfor changes📝 Usage Example
🔍 What to Review
src/proxy/ProxyServer.ts,src/proxy/RequestRouter.ts)src/server/DevServerManager.ts) - especially URL detection with ANSI strippingsrc/error/ErrorHandler.ts,src/templates/error-page.html)src/config/ManifestWatcher.ts)src/commands/webapp/dev.ts)🚀 Technical Highlights