|
6 | 6 | */ |
7 | 7 | import fs from 'node:fs'; |
8 | 8 | import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; |
9 | | -import { Logger, Messages, SfProject } from '@salesforce/core'; |
| 9 | +import { Connection, Logger, Messages, SfProject } from '@salesforce/core'; |
10 | 10 | import { Platform } from '@salesforce/lwc-dev-mobile-core'; |
11 | 11 | import { expDev, SitesLocalDevOptions, setupDev } from '@lwrjs/api'; |
12 | 12 | import open from 'open'; |
@@ -74,99 +74,110 @@ export default class LightningDevSite extends SfCommand<void> { |
74 | 74 | const selectedSite = new ExperienceSite(org, siteName); |
75 | 75 |
|
76 | 76 | if (!ssr) { |
77 | | - let sfdxProjectRootPath = ''; |
78 | | - try { |
79 | | - sfdxProjectRootPath = await SfProject.resolveProjectPath(); |
80 | | - } catch (error) { |
81 | | - throw new Error(sharedMessages.getMessage('error.no-project', [(error as Error)?.message ?? ''])); |
82 | | - } |
83 | | - const previewUrl = await selectedSite.getPreviewUrl(); |
84 | | - const username = connection.getUsername(); |
85 | | - if (!username) { |
86 | | - throw new Error(sharedMessages.getMessage('error.username')); |
87 | | - } |
88 | | - |
89 | | - this.log('Configuring local web server identity'); |
90 | | - const appServerIdentity = await PreviewUtils.getOrCreateAppServerIdentity(connection); |
91 | | - const ldpServerToken = appServerIdentity.identityToken; |
92 | | - const ldpServerId = appServerIdentity.usernameToServerEntityIdMap[username]; |
93 | | - if (!ldpServerId) { |
94 | | - throw new Error(sharedMessages.getMessage('error.identitydata.entityid')); |
95 | | - } |
96 | | - |
97 | | - this.log('Determining the next available port for Local Dev Server'); |
98 | | - const serverPorts = await PreviewUtils.getNextAvailablePorts(); |
99 | | - this.log(`Next available ports are http=${serverPorts.httpPort} , https=${serverPorts.httpsPort}`); |
100 | | - |
101 | | - this.log('Determining Local Dev Server url'); |
102 | | - const ldpServerUrl = PreviewUtils.generateWebSocketUrlForLocalDevServer(Platform.desktop, serverPorts); |
103 | | - this.log(`Local Dev Server url is ${ldpServerUrl}`); |
104 | | - |
105 | | - const logger = await Logger.child(this.ctor.name); |
106 | | - await startLWCServer(logger, sfdxProjectRootPath, ldpServerToken, Platform.desktop, serverPorts); |
107 | | - const url = new URL(previewUrl); |
108 | | - url.searchParams.set('aura.lwcDevServerUrl', ldpServerUrl); |
109 | | - url.searchParams.set('aura.lwcDevServerId', ldpServerId); |
110 | | - url.searchParams.set('lwc.mode', 'dev'); |
111 | | - await open(url.toString()); |
112 | | - return; |
113 | | - } |
114 | | - |
115 | | - let siteZip: string | undefined; |
116 | | - |
117 | | - // If the site is not setup / is not based on the current release / or get-latest is requested -> |
118 | | - // generate and download a new site bundle from the org based on latest builder metadata |
119 | | - if (!selectedSite.isSiteSetup() || getLatest) { |
120 | | - const startTime = Date.now(); |
121 | | - this.log(`[local-dev] Initializing: ${siteName}`); |
122 | | - this.spinner.start('[local-dev] Downloading site (this may take a few minutes)'); |
123 | | - siteZip = await selectedSite.downloadSite(); |
124 | | - |
125 | | - // delete oldSitePath recursive |
126 | | - const oldSitePath = selectedSite.getExtractDirectory(); |
127 | | - if (fs.existsSync(oldSitePath)) { |
128 | | - fs.rmSync(oldSitePath, { recursive: true }); |
129 | | - } |
130 | | - const endTime = Date.now(); |
131 | | - const duration = (endTime - startTime) / 1000; // Convert to seconds |
132 | | - this.spinner.stop('done.'); |
133 | | - this.log(`[local-dev] Site setup completed in ${duration.toFixed(2)} seconds.`); |
134 | | - } |
135 | | - |
136 | | - this.log(`[local-dev] launching browser preview for: ${siteName}`); |
137 | | - |
138 | | - // Establish a valid access token for this site |
139 | | - const authToken = guest ? '' : await selectedSite.setupAuth(); |
140 | | - |
141 | | - // Start the dev server |
142 | | - const port = parseInt(process.env.PORT ?? '3000', 10); |
143 | | - |
144 | | - // Internal vs external mode |
145 | | - const internalProject = !fs.existsSync('sfdx-project.json') && fs.existsSync('lwr.config.json'); |
146 | | - const logLevel = process.env.LOG_LEVEL ?? 'error'; |
147 | | - |
148 | | - const startupParams: SitesLocalDevOptions = { |
149 | | - sfCLI: !internalProject, |
150 | | - authToken, |
151 | | - open: process.env.OPEN_BROWSER === 'false' ? false : true, |
152 | | - port, |
153 | | - logLevel, |
154 | | - mode: 'dev', |
155 | | - siteZip, |
156 | | - siteDir: selectedSite.getSiteDirectory(), |
157 | | - }; |
158 | | - |
159 | | - // Environment variable used to setup the site rather than setup & start server |
160 | | - if (process.env.SETUP_ONLY === 'true') { |
161 | | - await setupDev(startupParams); |
162 | | - this.log('[local-dev] setup complete!'); |
163 | | - } else { |
164 | | - await expDev(startupParams); |
165 | | - this.log('[local-dev] watching for file changes... (CTRL-C to stop)'); |
| 77 | + return await this.openPreviewUrl(selectedSite, connection); |
166 | 78 | } |
| 79 | + await this.serveSSRSite(selectedSite, getLatest, siteName, guest); |
167 | 80 | } catch (e) { |
168 | 81 | this.spinner.stop('failed.'); |
169 | 82 | this.log('Local Development setup failed', e); |
170 | 83 | } |
171 | 84 | } |
| 85 | + |
| 86 | + private async serveSSRSite( |
| 87 | + selectedSite: ExperienceSite, |
| 88 | + getLatest: boolean, |
| 89 | + siteName: string, |
| 90 | + guest: boolean |
| 91 | + ): Promise<void> { |
| 92 | + let siteZip: string | undefined; |
| 93 | + |
| 94 | + // If the site is not setup / is not based on the current release / or get-latest is requested -> |
| 95 | + // generate and download a new site bundle from the org based on latest builder metadata |
| 96 | + if (!selectedSite.isSiteSetup() || getLatest) { |
| 97 | + const startTime = Date.now(); |
| 98 | + this.log(`[local-dev] Initializing: ${siteName}`); |
| 99 | + this.spinner.start('[local-dev] Downloading site (this may take a few minutes)'); |
| 100 | + siteZip = await selectedSite.downloadSite(); |
| 101 | + |
| 102 | + // delete oldSitePath recursive |
| 103 | + const oldSitePath = selectedSite.getExtractDirectory(); |
| 104 | + if (fs.existsSync(oldSitePath)) { |
| 105 | + fs.rmSync(oldSitePath, { recursive: true }); |
| 106 | + } |
| 107 | + const endTime = Date.now(); |
| 108 | + const duration = (endTime - startTime) / 1000; // Convert to seconds |
| 109 | + this.spinner.stop('done.'); |
| 110 | + this.log(`[local-dev] Site setup completed in ${duration.toFixed(2)} seconds.`); |
| 111 | + } |
| 112 | + |
| 113 | + this.log(`[local-dev] launching browser preview for: ${siteName}`); |
| 114 | + |
| 115 | + // Establish a valid access token for this site |
| 116 | + const authToken = guest ? '' : await selectedSite.setupAuth(); |
| 117 | + |
| 118 | + // Start the dev server |
| 119 | + const port = parseInt(process.env.PORT ?? '3000', 10); |
| 120 | + |
| 121 | + // Internal vs external mode |
| 122 | + const internalProject = !fs.existsSync('sfdx-project.json') && fs.existsSync('lwr.config.json'); |
| 123 | + const logLevel = process.env.LOG_LEVEL ?? 'error'; |
| 124 | + |
| 125 | + const startupParams: SitesLocalDevOptions = { |
| 126 | + sfCLI: !internalProject, |
| 127 | + authToken, |
| 128 | + open: process.env.OPEN_BROWSER === 'false' ? false : true, |
| 129 | + port, |
| 130 | + logLevel, |
| 131 | + mode: 'dev', |
| 132 | + siteZip, |
| 133 | + siteDir: selectedSite.getSiteDirectory(), |
| 134 | + }; |
| 135 | + |
| 136 | + // Environment variable used to setup the site rather than setup & start server |
| 137 | + if (process.env.SETUP_ONLY === 'true') { |
| 138 | + await setupDev(startupParams); |
| 139 | + this.log('[local-dev] setup complete!'); |
| 140 | + } else { |
| 141 | + await expDev(startupParams); |
| 142 | + this.log('[local-dev] watching for file changes... (CTRL-C to stop)'); |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + private async openPreviewUrl(selectedSite: ExperienceSite, connection: Connection): Promise<void> { |
| 147 | + let sfdxProjectRootPath = ''; |
| 148 | + try { |
| 149 | + sfdxProjectRootPath = await SfProject.resolveProjectPath(); |
| 150 | + } catch (error) { |
| 151 | + throw new Error(sharedMessages.getMessage('error.no-project', [(error as Error)?.message ?? ''])); |
| 152 | + } |
| 153 | + const previewUrl = await selectedSite.getPreviewUrl(); |
| 154 | + const username = connection.getUsername(); |
| 155 | + if (!username) { |
| 156 | + throw new Error(sharedMessages.getMessage('error.username')); |
| 157 | + } |
| 158 | + |
| 159 | + this.log('Configuring local web server identity'); |
| 160 | + const appServerIdentity = await PreviewUtils.getOrCreateAppServerIdentity(connection); |
| 161 | + const ldpServerToken = appServerIdentity.identityToken; |
| 162 | + const ldpServerId = appServerIdentity.usernameToServerEntityIdMap[username]; |
| 163 | + if (!ldpServerId) { |
| 164 | + throw new Error(sharedMessages.getMessage('error.identitydata.entityid')); |
| 165 | + } |
| 166 | + |
| 167 | + this.log('Determining the next available port for Local Dev Server'); |
| 168 | + const serverPorts = await PreviewUtils.getNextAvailablePorts(); |
| 169 | + this.log(`Next available ports are http=${serverPorts.httpPort} , https=${serverPorts.httpsPort}`); |
| 170 | + |
| 171 | + this.log('Determining Local Dev Server url'); |
| 172 | + const ldpServerUrl = PreviewUtils.generateWebSocketUrlForLocalDevServer(Platform.desktop, serverPorts); |
| 173 | + this.log(`Local Dev Server url is ${ldpServerUrl}`); |
| 174 | + |
| 175 | + const logger = await Logger.child(this.ctor.name); |
| 176 | + await startLWCServer(logger, sfdxProjectRootPath, ldpServerToken, Platform.desktop, serverPorts); |
| 177 | + const url = new URL(previewUrl); |
| 178 | + url.searchParams.set('aura.lwcDevServerUrl', ldpServerUrl); |
| 179 | + url.searchParams.set('aura.lwcDevServerId', ldpServerId); |
| 180 | + url.searchParams.set('lwc.mode', 'dev'); |
| 181 | + await open(url.toString()); |
| 182 | + } |
172 | 183 | } |
0 commit comments