66 */
77
88import path from 'node:path' ;
9- import url from 'node:url' ;
109import { SfCommand , Flags } from '@salesforce/sf-plugins-core' ;
11- import { Messages , SfProject } from '@salesforce/core' ;
12- import { cmpDev } from '@lwrjs/api ' ;
10+ import { Messages , SfProject , Logger } from '@salesforce/core' ;
11+ import { Platform } from '@salesforce/lwc-dev-mobile-core ' ;
1312import { ComponentUtils } from '../../../shared/componentUtils.js' ;
1413import { PromptUtils } from '../../../shared/promptUtils.js' ;
14+ import { PreviewUtils } from '../../../shared/previewUtils.js' ;
15+ import { startLWCServer } from '../../../lwc-dev-server/index.js' ;
1516
1617Messages . importMessagesDirectoryFromMetaUrl ( import . meta. url ) ;
1718const messages = Messages . loadMessages ( '@salesforce/plugin-lightning-dev' , 'lightning.dev.component' ) ;
19+ const sharedMessages = Messages . loadMessages ( '@salesforce/plugin-lightning-dev' , 'shared.utils' ) ;
1820
1921export default class LightningDevComponent extends SfCommand < void > {
2022 public static readonly summary = messages . getMessage ( 'summary' ) ;
@@ -32,15 +34,37 @@ export default class LightningDevComponent extends SfCommand<void> {
3234 char : 'c' ,
3335 default : false ,
3436 } ) ,
35- // TODO should this be required or optional?
36- // We don't technically need this if your components are simple / don't need any data from your org
37- 'target-org' : Flags . optionalOrg ( ) ,
37+ 'target-org' : Flags . requiredOrg ( ) ,
3838 } ;
3939
4040 public async run ( ) : Promise < void > {
4141 const { flags } = await this . parse ( LightningDevComponent ) ;
42+ const logger = await Logger . child ( this . ctor . name ) ;
4243 const project = await SfProject . resolve ( ) ;
4344
45+ let sfdxProjectRootPath = '' ;
46+ try {
47+ sfdxProjectRootPath = await SfProject . resolveProjectPath ( ) ;
48+ } catch ( error ) {
49+ return Promise . reject (
50+ new Error ( sharedMessages . getMessage ( 'error.no-project' , [ ( error as Error ) ?. message ?? '' ] ) )
51+ ) ;
52+ }
53+
54+ let componentName = flags [ 'name' ] ;
55+ const clientSelect = flags [ 'client-select' ] ;
56+ const targetOrg = flags [ 'target-org' ] ;
57+
58+ const { ldpServerId, ldpServerToken } = await PreviewUtils . initializePreviewConnection ( targetOrg ) ;
59+
60+ logger . debug ( 'Determining the next available port for Local Dev Server' ) ;
61+ const serverPorts = await PreviewUtils . getNextAvailablePorts ( ) ;
62+ logger . debug ( `Next available ports are http=${ serverPorts . httpPort } , https=${ serverPorts . httpsPort } ` ) ;
63+
64+ logger . debug ( 'Determining Local Dev Server url' ) ;
65+ const ldpServerUrl = PreviewUtils . generateWebSocketUrlForLocalDevServer ( Platform . desktop , serverPorts , logger ) ;
66+ logger . debug ( `Local Dev Server url is ${ ldpServerUrl } ` ) ;
67+
4468 const namespacePaths = await ComponentUtils . getNamespacePaths ( project ) ;
4569 const componentPaths = await ComponentUtils . getAllComponentPaths ( namespacePaths ) ;
4670 if ( ! componentPaths ) {
@@ -63,48 +87,49 @@ export default class LightningDevComponent extends SfCommand<void> {
6387 return undefined ;
6488 }
6589
66- const componentName = path . basename ( componentPath ) ;
67- const label = ComponentUtils . componentNameToTitleCase ( componentName ) ;
90+ const name = path . basename ( componentPath ) ;
91+ const label = ComponentUtils . componentNameToTitleCase ( name ) ;
6892
6993 return {
70- name : componentName ,
94+ name,
7195 label : xml . LightningComponentBundle . masterLabel ?? label ,
7296 description : xml . LightningComponentBundle . description ?? '' ,
7397 } ;
7498 } )
7599 )
76100 ) . filter ( ( component ) => ! ! component ) ;
77101
78- let name = flags . name ;
79- if ( ! flags [ 'client-select' ] ) {
80- if ( name ) {
102+ if ( ! clientSelect ) {
103+ if ( componentName ) {
81104 // validate that the component exists before launching the server
82- const match = components . find ( ( component ) => name === component . name || name === component . label ) ;
105+ const match = components . find (
106+ ( component ) => componentName === component . name || componentName === component . label
107+ ) ;
83108 if ( ! match ) {
84- throw new Error ( messages . getMessage ( 'error.component-not-found' , [ name ] ) ) ;
109+ throw new Error ( messages . getMessage ( 'error.component-not-found' , [ componentName ] ) ) ;
85110 }
86111
87- name = match . name ;
112+ componentName = match . name ;
88113 } else {
89114 // prompt the user for a name if one was not provided
90- name = await PromptUtils . promptUserToSelectComponent ( components ) ;
91- if ( ! name ) {
115+ componentName = await PromptUtils . promptUserToSelectComponent ( components ) ;
116+ if ( ! componentName ) {
92117 throw new Error ( messages . getMessage ( 'error.component' ) ) ;
93118 }
94119 }
95120 }
96121
97- const dirname = path . dirname ( url . fileURLToPath ( import . meta . url ) ) ;
98- const rootDir = path . resolve ( dirname , '../../../..' ) ;
99- const port = parseInt ( process . env . PORT ?? '3000' , 10 ) ;
100-
101- await cmpDev ( {
102- rootDir ,
103- mode : 'dev' ,
104- port ,
105- name : name ? `c/ ${ name } ` : undefined ,
106- namespacePaths ,
107- open : process . env . OPEN_BROWSER === 'false' ? false : true ,
108- } ) ;
122+ await startLWCServer ( logger , sfdxProjectRootPath , ldpServerToken , Platform . desktop , serverPorts ) ;
123+
124+ const targetOrgArg = PreviewUtils . getTargetOrgFromArguments ( this . argv ) ;
125+ const launchArguments = PreviewUtils . generateComponentPreviewLaunchArguments (
126+ ldpServerUrl ,
127+ ldpServerId ,
128+ componentName ,
129+ targetOrgArg
130+ ) ;
131+
132+ // Open the browser and navigate to the right page
133+ await this . config . runCommand ( 'org:open' , launchArguments ) ;
109134 }
110135}
0 commit comments