diff --git a/README.md b/README.md index 1c7316fd..742def5d 100644 --- a/README.md +++ b/README.md @@ -209,13 +209,14 @@ _See code: [src/commands/lightning/dev/app.ts](https://github.com/salesforcecli/ ``` USAGE - $ sf lightning dev component -o [--json] [--flags-dir ] [-n ] [-c] + $ sf lightning dev component -o [--json] [--flags-dir ] [-n ] [--api-version ] [-c] FLAGS - -c, --client-select Launch component preview without selecting a component - -n, --name= Name of a component to preview. - -o, --target-org= (required) Username or alias of the target org. Not required if the `target-org` - configuration variable is already set. + -c, --client-select Launch component preview without selecting a component + -n, --name= Name of a component to preview. + -o, --target-org= (required) Username or alias of the target org. Not required if the `target-org` + configuration variable is already set. + --api-version= Override the api version used for api requests made by this command GLOBAL FLAGS --flags-dir= Import flag values from a directory. diff --git a/command-snapshot.json b/command-snapshot.json index aa16dcf4..26cc62d9 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -12,7 +12,7 @@ "command": "lightning:dev:component", "flagAliases": [], "flagChars": ["c", "n", "o"], - "flags": ["client-select", "flags-dir", "json", "name", "target-org"], + "flags": ["api-version", "client-select", "flags-dir", "json", "name", "target-org"], "plugin": "@salesforce/plugin-lightning-dev" }, { @@ -20,7 +20,7 @@ "command": "lightning:dev:site", "flagAliases": [], "flagChars": ["l", "n", "o"], - "flags": ["flags-dir", "get-latest", "guest", "name", "target-org", "ssr"], + "flags": ["flags-dir", "get-latest", "guest", "name", "ssr", "target-org"], "plugin": "@salesforce/plugin-lightning-dev" } ] diff --git a/package.json b/package.json index f2dcb1a0..e19d134a 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "dependencies": { "@inquirer/prompts": "^5.3.8", "@inquirer/select": "^2.4.7", - "@lwc/lwc-dev-server": "~13.1.2", - "@lwc/sfdc-lwc-compiler": "~13.1.2", + "@lwc/lwc-dev-server": "~13.1.5-alpha.3+007b30e", + "@lwc/sfdc-lwc-compiler": "~13.1.5-alpha.3+007b30e", "@lwrjs/api": "0.18.3", "@oclif/core": "^4.5.0", "@salesforce/core": "^8.21.2", @@ -237,7 +237,7 @@ ], "target": { "versionNumber": "65.0", - "matchingDevServerVersion": "~13.1.2" + "matchingDevServerVersion": "~13.1.5-alpha.3+007b30e" }, "versionToTagMappings": [ { @@ -257,7 +257,7 @@ "tagName": "prerelease" }, { - "versionNumber": "66.0", + "versionNumber": "65.0", "tagName": "next" } ] diff --git a/src/commands/lightning/dev/component.ts b/src/commands/lightning/dev/component.ts index 97a1fab4..0b40dd36 100644 --- a/src/commands/lightning/dev/component.ts +++ b/src/commands/lightning/dev/component.ts @@ -18,7 +18,15 @@ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-lightning-dev', 'lightning.dev.component'); const sharedMessages = Messages.loadMessages('@salesforce/plugin-lightning-dev', 'shared.utils'); -export default class LightningDevComponent extends SfCommand { +export type ComponentPreviewResult = { + instanceUrl: string; + ldpServerUrl: string; + ldpServerId: string; + componentName: string; + previewUrl: string; +}; + +export default class LightningDevComponent extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); @@ -29,6 +37,7 @@ export default class LightningDevComponent extends SfCommand { char: 'n', requiredOrDefaulted: false, }), + 'api-version': Flags.orgApiVersion(), 'client-select': Flags.boolean({ summary: messages.getMessage('flags.client-select.summary'), char: 'c', @@ -37,7 +46,7 @@ export default class LightningDevComponent extends SfCommand { 'target-org': Flags.requiredOrg(), }; - public async run(): Promise { + public async run(): Promise { const { flags } = await this.parse(LightningDevComponent); const logger = await Logger.child(this.ctor.name); const project = await SfProject.resolve(); @@ -54,6 +63,7 @@ export default class LightningDevComponent extends SfCommand { let componentName = flags['name']; const clientSelect = flags['client-select']; const targetOrg = flags['target-org']; + const apiVersion = flags['api-version']; const { ldpServerId, ldpServerToken } = await PreviewUtils.initializePreviewConnection(targetOrg); @@ -62,44 +72,56 @@ export default class LightningDevComponent extends SfCommand { logger.debug(`Next available ports are http=${serverPorts.httpPort} , https=${serverPorts.httpsPort}`); logger.debug('Determining Local Dev Server url'); - const ldpServerUrl = PreviewUtils.generateWebSocketUrlForLocalDevServer(Platform.desktop, serverPorts, logger); + let ldpServerUrl; + + // In Code Builder, we cannot go to localhost - we need to use a proxy URI to get to the ldpServer + if (process.env.SF_CONTAINER_MODE && process.env.VSCODE_PROXY_URI) { + logger.debug('In Code Builder Mode - using proxy URI'); + ldpServerUrl = process.env.VSCODE_PROXY_URI.replace('https://', 'ws://').replace( + '{{port}}', + `${serverPorts.httpPort}` + ); + } else { + // Default behavior + ldpServerUrl = PreviewUtils.generateWebSocketUrlForLocalDevServer(Platform.desktop, serverPorts, logger); + } logger.debug(`Local Dev Server url is ${ldpServerUrl}`); - const namespacePaths = await ComponentUtils.getNamespacePaths(project); - const componentPaths = await ComponentUtils.getAllComponentPaths(namespacePaths); - if (!componentPaths) { - throw new Error(messages.getMessage('error.directory')); - } + if (!clientSelect) { + const namespacePaths = await ComponentUtils.getNamespacePaths(project); + const componentPaths = await ComponentUtils.getAllComponentPaths(namespacePaths); + if (!componentPaths) { + throw new Error(messages.getMessage('error.directory')); + } - const components = ( - await Promise.all( - componentPaths.map(async (componentPath) => { - let xml; - - try { - xml = await ComponentUtils.getComponentMetadata(componentPath); - } catch (err) { - this.warn(messages.getMessage('error.component-metadata', [componentPath])); - } - - // components must have meta xml to be previewed - if (!xml) { - return undefined; - } - - const name = path.basename(componentPath); - const label = ComponentUtils.componentNameToTitleCase(name); - - return { - name, - label: xml.LightningComponentBundle.masterLabel ?? label, - description: xml.LightningComponentBundle.description ?? '', - }; - }) - ) - ).filter((component) => !!component); + const components = ( + await Promise.all( + componentPaths.map(async (componentPath) => { + let xml; + + try { + xml = await ComponentUtils.getComponentMetadata(componentPath); + } catch (err) { + this.warn(messages.getMessage('error.component-metadata', [componentPath])); + } + + // components must have meta xml to be previewed + if (!xml) { + return undefined; + } + + const name = path.basename(componentPath); + const label = ComponentUtils.componentNameToTitleCase(name); + + return { + name, + label: xml.LightningComponentBundle.masterLabel ?? label, + description: xml.LightningComponentBundle.description ?? '', + }; + }) + ) + ).filter((component) => !!component); - if (!clientSelect) { if (componentName) { // validate that the component exists before launching the server const match = components.find( @@ -129,7 +151,31 @@ export default class LightningDevComponent extends SfCommand { targetOrgArg ); - // Open the browser and navigate to the right page - await this.config.runCommand('org:open', launchArguments); + // Construct and log the full URL that will be opened + const connection = targetOrg.getConnection(apiVersion); + + const previewUrl = PreviewUtils.generateComponentPreviewUrl( + connection.instanceUrl, + ldpServerUrl, + ldpServerId, + componentName, + false + ); + + // Prepare the result for JSON output + const result: ComponentPreviewResult = { + instanceUrl: connection.instanceUrl, + ldpServerUrl, + ldpServerId, + componentName: componentName ?? '', + previewUrl, + }; + + // Open the browser and navigate to the right page (unless OPEN_BROWSER is set to true) + if (process.env.OPEN_BROWSER !== 'false') { + await this.config.runCommand('org:open', launchArguments); + } + + return result; } } diff --git a/src/shared/previewUtils.ts b/src/shared/previewUtils.ts index 64ff30a1..ff28e262 100644 --- a/src/shared/previewUtils.ts +++ b/src/shared/previewUtils.ts @@ -246,6 +246,34 @@ export class PreviewUtils { return launchArguments; } + /** + * Generates the full URL for a component preview. + * + * @param instanceUrl The URL of the Salesforce instance + * @param ldpServerUrl The URL for the local dev server + * @param ldpServerId Record ID for the identity token + * @param componentName The name of the component to preview + * @param encodePath Whether to encode the path + * @returns The full URL for the component preview + */ + public static generateComponentPreviewUrl( + instanceUrl: string, + ldpServerUrl: string, + ldpServerId: string, + componentName?: string, + encodePath = false + ): string { + let url = `${instanceUrl}/lwr/application/e/devpreview/ai/${ + encodePath ? encodeURIComponent('localdev%2Fpreview') : 'localdev%2Fpreview' + }?ldpServerUrl=${ldpServerUrl}&ldpServerId=${ldpServerId}`; + if (componentName) { + // TODO: support other namespaces + url += `&specifier=c/${componentName}`; + } + + return url; + } + /** * Generates the proper set of arguments to be used for launching a mobile app with custom launch arguments. * diff --git a/yarn.lock b/yarn.lock index 297c7917..abdc62df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2200,10 +2200,10 @@ "@lwc/style-compiler" "8.20.5" "@lwc/template-compiler" "8.20.5" -"@lwc/dev-server-plugin-lex@13.1.3": - version "13.1.3" - resolved "https://registry.yarnpkg.com/@lwc/dev-server-plugin-lex/-/dev-server-plugin-lex-13.1.3.tgz#15e7fc1521da8d6116f915becc2aac85c81fc686" - integrity sha512-m2LNWrDN7ECerNTLq4yFfDbJo0W+LQpBKv7lNE665fy22DPyRdZiQHJHGgiN9nwNhYyCaBicA5dlGrrYIpDciQ== +"@lwc/dev-server-plugin-lex@13.1.5-alpha.3+007b30e": + version "13.1.5-alpha.3" + resolved "https://registry.yarnpkg.com/@lwc/dev-server-plugin-lex/-/dev-server-plugin-lex-13.1.5-alpha.3.tgz#b7d25a135f0f66bf4c39c5d973a7ed0d62165b87" + integrity sha512-9+SvsnahnOyflWpdHGBLht0Z14TEnV0xP0U6D/FS2WTNOMzHMEqWsIqmCBZW2TBFpd2Fa4oHTjBtIyvaxgucew== dependencies: magic-string "~0.30.17" @@ -2253,18 +2253,18 @@ dependencies: "@lwc/shared" "8.20.5" -"@lwc/lwc-dev-server-types@13.1.3": - version "13.1.3" - resolved "https://registry.yarnpkg.com/@lwc/lwc-dev-server-types/-/lwc-dev-server-types-13.1.3.tgz#5cef8b2bce0f0783cb5f69b8a7327709a07f3844" - integrity sha512-h04TfJij5t+ThbAURMt1K2PJBNpFSbSYwbrrqLrqH0s8IrucnlX2vorgDSc30f7Tqnrng9lHMhunk4RuEEsH/Q== +"@lwc/lwc-dev-server-types@13.1.5-alpha.3+007b30e": + version "13.1.5-alpha.3" + resolved "https://registry.yarnpkg.com/@lwc/lwc-dev-server-types/-/lwc-dev-server-types-13.1.5-alpha.3.tgz#7f606416e9a85e4ecc799924c4b0b167603c3709" + integrity sha512-bLh0CR77lX9yK/Ttl56ZKqxW13jszaUjVdN7ayidwFRRxJ7ZICr0FaOu3PdX89NFLnyKj81fesSgoXUA0/rsKQ== -"@lwc/lwc-dev-server@~13.1.2": - version "13.1.3" - resolved "https://registry.yarnpkg.com/@lwc/lwc-dev-server/-/lwc-dev-server-13.1.3.tgz#2bf57c668d6cb5cfb40953a100346f6b832f2c06" - integrity sha512-XfS+ts2GXDwzpE19pxi6MTk7j4ua/96jBeXCCGNF9Yf5UddDGHKsbyXYhEthvIlFTdhVAjb0rg2AvlChygLUlQ== +"@lwc/lwc-dev-server@~13.1.5-alpha.3+007b30e": + version "13.1.5-alpha.3" + resolved "https://registry.yarnpkg.com/@lwc/lwc-dev-server/-/lwc-dev-server-13.1.5-alpha.3.tgz#899bdf891c4e6a11d287158fd399a1fb568fd436" + integrity sha512-7HZenCHMItmhLcz5uYDee7hKv0NneQ4vxuEUDCsI7EMOLKSg7ejB95JfcWvB8OnnAo3WiZpDCdz5RdPvA5VmbQ== dependencies: - "@lwc/lwc-dev-server-types" "13.1.3" - "@lwc/sfdc-lwc-compiler" "13.1.3" + "@lwc/lwc-dev-server-types" "13.1.5-alpha.3+007b30e" + "@lwc/sfdc-lwc-compiler" "13.1.5-alpha.3+007b30e" chalk "~5.4.1" chokidar "~3.6.0" commander "~10.0.0" @@ -2272,15 +2272,15 @@ glob "^10.4.5" ws "^8.18.2" -"@lwc/metadata@13.1.3": - version "13.1.3" - resolved "https://registry.yarnpkg.com/@lwc/metadata/-/metadata-13.1.3.tgz#30858424ae13ecf2106f07bfc10100e718e4f936" - integrity sha512-odev/R+AIYOHmU9ll9zNgbZXnausqC7F/+QjSk1MrT/TNRog4g46g3YNk0QAx33L2cyoIoffIVWFazyyTWQ3fA== +"@lwc/metadata@13.1.5-alpha.3+007b30e": + version "13.1.5-alpha.3" + resolved "https://registry.yarnpkg.com/@lwc/metadata/-/metadata-13.1.5-alpha.3.tgz#fad15b11c1798c7a55f56e8a448a4617fd1000d7" + integrity sha512-jc/pFN15CpmBOnTHzW2wvINaL+/6l6OwY3KDkorBI6th1UlN6bQFJcoWAjeIxmcbxsqn+qAgxjpOHno+QKkOWA== dependencies: "@babel/parser" "~7.27.5" "@babel/traverse" "~7.27.4" "@babel/types" "~7.27.6" - "@lwc/sfdc-compiler-utils" "13.1.3" + "@lwc/sfdc-compiler-utils" "13.1.5-alpha.3+007b30e" postcss "~8.5.5" postcss-selector-parser "~6.1.2" postcss-value-parser "~4.2.0" @@ -2302,15 +2302,15 @@ "@lwc/shared" "8.20.5" "@rollup/pluginutils" "~5.2.0" -"@lwc/sfdc-compiler-utils@13.1.3": - version "13.1.3" - resolved "https://registry.yarnpkg.com/@lwc/sfdc-compiler-utils/-/sfdc-compiler-utils-13.1.3.tgz#5e85b10e7aebd4b34e59d98551a5fd4a74533ea9" - integrity sha512-VoS4Ggbqt5byK8VKI4KSpmh9rhoQH58vQEbfm+B7vhqL0DQR2/OvUXhr5GkATq6V3bcOfjdSmOxlPz+9gZAvZA== +"@lwc/sfdc-compiler-utils@13.1.5-alpha.3+007b30e": + version "13.1.5-alpha.3" + resolved "https://registry.yarnpkg.com/@lwc/sfdc-compiler-utils/-/sfdc-compiler-utils-13.1.5-alpha.3.tgz#8ac056199662ce14d4b7caa9f639685c555fca36" + integrity sha512-iENBGQ2X/lc0x06hT3u2KM+LdHIbVInHKiyDveQU/C+mA5EHU2tQfs1pDlNyUH9gHqzirOtUdiwu8Xtpo45GaA== -"@lwc/sfdc-lwc-compiler@13.1.3", "@lwc/sfdc-lwc-compiler@~13.1.2": - version "13.1.3" - resolved "https://registry.yarnpkg.com/@lwc/sfdc-lwc-compiler/-/sfdc-lwc-compiler-13.1.3.tgz#9f111ada602bd594179b4d8a3adad106ca5eed4f" - integrity sha512-rzVZ/rXIyAeEcMwTPAfNvzNLMoBve0YcvGFjx8wbODQ68Bwzbtyne23HPO28SST1qnnSQ+obYX4kaCvoglQ3jA== +"@lwc/sfdc-lwc-compiler@13.1.5-alpha.3+007b30e", "@lwc/sfdc-lwc-compiler@~13.1.5-alpha.3+007b30e": + version "13.1.5-alpha.3" + resolved "https://registry.yarnpkg.com/@lwc/sfdc-lwc-compiler/-/sfdc-lwc-compiler-13.1.5-alpha.3.tgz#70a5ca267d7391b62fac28ac687fe5e67ebfd4e0" + integrity sha512-S8tmFyAoiY8CE9VpSnuJmpHhFb1UGzlTro2ryIkQMpy03nSSdlP47r2IyJgsa5WYJxU7gf3bquot5mElGlZjMA== dependencies: "@babel/core" "7.27.4" "@babel/parser" "7.27.5" @@ -2319,11 +2319,11 @@ "@babel/traverse" "7.27.4" "@babel/types" "7.27.6" "@komaci/esm-generator" "258.0.0" - "@lwc/dev-server-plugin-lex" "13.1.3" + "@lwc/dev-server-plugin-lex" "13.1.5-alpha.3+007b30e" "@lwc/eslint-plugin-lwc" "3.0.0-beta.2" "@lwc/eslint-plugin-lwc-platform" "6.0.0-beta.7" - "@lwc/metadata" "13.1.3" - "@lwc/sfdc-compiler-utils" "13.1.3" + "@lwc/metadata" "13.1.5-alpha.3+007b30e" + "@lwc/sfdc-compiler-utils" "13.1.5-alpha.3+007b30e" "@rollup/plugin-babel" "^6.0.4" "@rollup/plugin-replace" "^6.0.2" "@rollup/wasm-node" "4.10.0"