UNPKG

@swell/cli

Version:

Swell's command line interface/utility

109 lines (108 loc) 4.65 kB
import { Flags } from '@oclif/core'; import getPort, { portNumbers } from 'get-port'; import ngrok from 'ngrok'; import ora from 'ora'; import { default as localConfig } from '../../../lib/config.js'; import style from '../../../lib/style.js'; import { PushAppCommand } from '../../../push-app-command.js'; const FALLBACK_PORT = 3000; export default class AppFrontendDev extends PushAppCommand { static examples = [ 'swell app frontend dev', 'swell app frontend dev --no-push', 'swell app frontend dev --port 3000', 'swell app frontend dev --storefront-select', 'swell app frontend dev --storefront-id <id>', ]; static flags = { 'no-push': Flags.boolean({ description: 'skip pushing app files initially', }), port: Flags.integer({ char: 'p', description: 'override the default port to run the app locally', }), 'storefront-id': Flags.string({ description: 'identify a storefront to preview with and push theme files to', }), 'storefront-select': Flags.boolean({ default: false, description: 'prompt to select a storefront to preview with', }), }; static orientation = { env: 'test', }; static summary = `Run a frontend app in dev mode from your local machine.`; logAppLocalUrl(storeId, sessionId) { const frontendAppRoute = this.app.type === 'storefront' && this.app.storefront?.external ? `/${this.app.private_id}` : ''; this.log(`View it at ${style.link(`${this.localFrontendUrl(storeId, sessionId)}${frontendAppRoute}`)}\n`); } async run() { const { flags } = await this.parse(AppFrontendDev); const { port } = flags; const noPush = flags['no-push']; if (!(await this.ensureAppExists(undefined, false))) { return; } if (!noPush) { await this.pushAppConfigs(); } if (this.app.type === 'storefront') { await this.getStorefrontToPush(flags); this.logStorefrontConnected(); } this.saveCurrentStorefront(); const projectType = this.getFrontendProjectType(); await this.startDevServer(projectType, port); } async startDevServer(projectType, port) { const currentStore = localConfig.getDefaultStore(); const spinner = ora(); // Find an open port starting at 3000 const freePort = port || (await getPort({ port: portNumbers(3000, 3100) })) || FALLBACK_PORT; this.log(`Starting ${projectType.name} dev server...\n`); // Start ngrok proxy const proxyUrl = await ngrok.connect({ addr: freePort, region: 'us', // TODO: make it configurable }); await this.updateLocalProxy(proxyUrl, spinner, this.storefront?.id); return this.exec(projectType.devCommand.replace('${PORT}', String(freePort)), (string) => { // Hide useless astro warning about image optimization if (string.includes('The current configuration does not support image optimization')) { return false; } // Hide useless astro warning about .dev.vars if (string.includes('There is no `.dev.vars` file')) { return false; } // Hide astro localhost URL/network as it can confuse the user if (string.includes('┃ Local') || string.includes('┃ Network')) { return false; } // Started, show app url (TODO for nextjs) if (string.includes('watching for file changes')) { spinner.succeed(`Started ${projectType.name} dev server on port ${freePort}.\n`); const sessionId = localConfig.getSessionId(currentStore); setTimeout(() => this.logAppLocalUrl(currentStore, sessionId), 100); this.watchForChanges(); } }); } async updateLocalProxy(proxyUrl, spinner, storefrontId) { const storefront = this.app.type === 'storefront' && (await this.getAppStorefront({ storefront_id: storefrontId })); await this.handleRequestErrors(async () => this.api.put({ adminPath: `/client/apps/${this.app.id}/local-proxy` }, { body: { proxy_url: proxyUrl, storefront_id: storefront?.id || null, storefront_slug: storefront?.slug || null, }, }), () => spinner.fail('Error starting local proxy')); } }