diff --git a/.gitignore b/.gitignore index a8f161a6..bd16aa0c 100644 --- a/.gitignore +++ b/.gitignore @@ -52,4 +52,8 @@ node_modules # lwr __lwr_cache__ app -bld \ No newline at end of file +bld + +# sf cli +.sf +.sfdx \ No newline at end of file diff --git a/messages/shared.utils.md b/messages/shared.utils.md new file mode 100644 index 00000000..19ae6c35 --- /dev/null +++ b/messages/shared.utils.md @@ -0,0 +1,19 @@ +# lwc-dev-server-utils.port-desc + +The port number of the local dev server + +# lwc-dev-server-utils.port-message + +Must be a number between 1 and 65535 + +# lwc-dev-server-utils.workspace-desc + +The workspace name of the local lwc dev server + +# lwc-dev-server-utils.workspace-message + +Valid workspace value is "SalesforceCLI" OR "mrt" + +# identity-utils.token-desc + +The Base64-encoded identity token of the local web server diff --git a/src/commands/lightning/preview/app.ts b/src/commands/lightning/preview/app.ts index 1f88ff45..8de58306 100644 --- a/src/commands/lightning/preview/app.ts +++ b/src/commands/lightning/preview/app.ts @@ -21,6 +21,7 @@ import chalk from 'chalk'; import { OrgUtils } from '../../../shared/orgUtils.js'; import { startLWCServer } from '../../../lwc-dev-server/index.js'; import { PreviewUtils } from '../../../shared/previewUtils.js'; +import { LwcDevServerUtils } from '../../../shared/lwcDevServerUtils.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-lightning-dev', 'lightning.preview.app'); @@ -149,7 +150,10 @@ export default class LightningPreviewApp extends SfCommand { logger.debug('Determining Local Dev Server url'); // todo: figure out how to make the port dynamic instead of hard-coded value here - const ldpServerUrl = PreviewUtils.generateWebSocketUrlForLocalDevServer(platform, '8081'); + const ldpServerUrl = PreviewUtils.generateWebSocketUrlForLocalDevServer( + platform, + `${await LwcDevServerUtils.getLocalDevServerPort()}` + ); logger.debug(`Local Dev Server url is ${ldpServerUrl}`); let appId: string | undefined; diff --git a/src/configMeta.ts b/src/configMeta.ts index a0015ea3..b81d852f 100644 --- a/src/configMeta.ts +++ b/src/configMeta.ts @@ -5,7 +5,17 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import type { ConfigPropertyMeta } from '@salesforce/core'; +import type { ConfigPropertyMeta, ConfigValue } from '@salesforce/core'; +import { Workspace } from '@lwc/lwc-dev-server'; +import { Messages } from '@salesforce/core'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-lightning-dev', 'shared.utils'); +const IDENTITY_TOKEN_DESC = messages.getMessage('identity-utils.token-desc'); +const LOCAL_DEV_SERVER_PORT_DESC = messages.getMessage('lwc-dev-server-utils.port-desc'); +const LOCAL_DEV_SERVER_PORT_MESSAGE = messages.getMessage('lwc-dev-server-utils.port-message'); +const LOCAL_DEV_SERVER_WORKSPACE_DESC = messages.getMessage('lwc-dev-server-utils.workspace-desc'); +const LOCAL_DEV_SERVER_WORKSPACE_MESSAGE = messages.getMessage('lwc-dev-server-utils.workspace-message'); export const enum ConfigVars { /** @@ -13,13 +23,61 @@ export const enum ConfigVars { * validate the web server's identity to the hmr-client. */ LOCAL_WEB_SERVER_IDENTITY_TOKEN = 'local-web-server-identity-token', + + /** + * The port number of the local dev server. + */ + LOCAL_DEV_SERVER_PORT = 'local-dev-server-port', + + /** + * The Workspace name of the local dev server. + */ + LOCAL_DEV_SERVER_WORKSPACE = 'local-dev-server-workspace', } export default [ { key: ConfigVars.LOCAL_WEB_SERVER_IDENTITY_TOKEN, - description: 'The Base64-encoded identity token of the local web server', + description: IDENTITY_TOKEN_DESC, hidden: true, encrypted: true, }, + { + key: ConfigVars.LOCAL_DEV_SERVER_PORT, + description: LOCAL_DEV_SERVER_PORT_DESC, + input: { + validator: (value: ConfigValue): boolean => { + if (!value) { + return false; + } + + const parsedPort = parseInt(value as string, 10); + + if (isNaN(parsedPort) || parsedPort < 1 || parsedPort > 65535) { + return false; + } + return true; + }, + failedMessage: LOCAL_DEV_SERVER_PORT_MESSAGE, + }, + }, + { + key: ConfigVars.LOCAL_DEV_SERVER_WORKSPACE, + description: LOCAL_DEV_SERVER_WORKSPACE_DESC, + input: { + validator: (value: ConfigValue): boolean => { + if (!value) { + return false; + } + + const workspace = value as Workspace; + + if (workspace === Workspace.SfCli || workspace === Workspace.Mrt) { + return true; + } + return false; + }, + failedMessage: LOCAL_DEV_SERVER_WORKSPACE_MESSAGE, + }, + }, ] as ConfigPropertyMeta[]; diff --git a/src/lwc-dev-server/index.ts b/src/lwc-dev-server/index.ts index 9d1d69f9..9dbd344b 100644 --- a/src/lwc-dev-server/index.ts +++ b/src/lwc-dev-server/index.ts @@ -8,10 +8,9 @@ import { existsSync, lstatSync, readFileSync } from 'node:fs'; import path from 'node:path'; import process from 'node:process'; -import { LWCServer, LogLevel, ServerConfig, Workspace, startLwcDevServer } from '@lwc/lwc-dev-server'; +import { LWCServer, LogLevel, ServerConfig, startLwcDevServer } from '@lwc/lwc-dev-server'; import { Logger } from '@salesforce/core'; - -const DEV_SERVER_PORT = 8081; +import { LwcDevServerUtils } from '../shared/lwcDevServerUtils.js'; /** * Map sf cli log level to lwc dev server log level @@ -39,7 +38,7 @@ function mapLogLevel(cliLogLevel: number): number { } } -function createLWCServerConfig(rootDir: string, logger: Logger): ServerConfig { +async function createLWCServerConfig(rootDir: string, logger: Logger): Promise { const sfdxConfig = path.resolve(rootDir, 'sfdx-project.json'); if (!existsSync(sfdxConfig) || !lstatSync(sfdxConfig).isFile()) { @@ -67,18 +66,18 @@ function createLWCServerConfig(rootDir: string, logger: Logger): ServerConfig { return { rootDir, - port: DEV_SERVER_PORT, + port: await LwcDevServerUtils.getLocalDevServerPort(), protocol: 'wss', host: 'localhost', paths: namespacePaths, - workspace: Workspace.SfCli, + workspace: await LwcDevServerUtils.getLocalDevServerWorkspace(), targets: ['LEX'], // should this be something else? logLevel: mapLogLevel(logger.getLevel()), }; } export async function startLWCServer(rootDir: string, logger: Logger): Promise { - const config = createLWCServerConfig(rootDir, logger); + const config = await createLWCServerConfig(rootDir, logger); logger.trace(`Starting LWC Dev Server with config: ${JSON.stringify(config)}`); let lwcDevServer: LWCServer | null = await startLwcDevServer(config); diff --git a/src/shared/lwcDevServerUtils.ts b/src/shared/lwcDevServerUtils.ts new file mode 100644 index 00000000..2cdf4dc6 --- /dev/null +++ b/src/shared/lwcDevServerUtils.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +import { Workspace } from '@lwc/lwc-dev-server'; +import { Config } from '@salesforce/core'; +import configMeta, { ConfigVars } from '../configMeta.js'; + +export const LOCAL_DEV_SERVER_DEFAULT_PORT = 8081; +export const LOCAL_DEV_SERVER_DEFAULT_WORKSPACE = Workspace.SfCli; + +export class LwcDevServerUtils { + static #config: Config; + + public static async getConfig(): Promise { + if (this.#config) { + return this.#config; + } + this.#config = await Config.create({ isGlobal: false }); + Config.addAllowedProperties(configMeta); + return this.#config; + } + + public static async getLocalDevServerPort(): Promise { + const config = await this.getConfig(); + const configPort = config.get(ConfigVars.LOCAL_DEV_SERVER_PORT) as number; + + return configPort || LOCAL_DEV_SERVER_DEFAULT_PORT; + } + + public static async getLocalDevServerWorkspace(): Promise { + const config = await this.getConfig(); + const configWorkspace = config.get(ConfigVars.LOCAL_DEV_SERVER_WORKSPACE) as Workspace; + + return configWorkspace || LOCAL_DEV_SERVER_DEFAULT_WORKSPACE; + } +}