UNPKG

netlify-cli

Version:

Netlify command line tool

177 lines • 7.37 kB
import process from 'process'; import { applyMutations } from '@netlify/config'; import { BLOBS_CONTEXT_VARIABLE, encodeBlobsContext, getBlobsContextWithEdgeAccess } from '../../lib/blobs/blobs.js'; import { promptEditorHelper } from '../../lib/edge-functions/editor-helper.js'; import { startFunctionsServer } from '../../lib/functions/server.js'; import { printBanner } from '../../utils/banner.js'; import { NETLIFYDEV, NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, chalk, log, normalizeConfig, } from '../../utils/command-helpers.js'; import detectServerSettings, { getConfigWithPlugins } from '../../utils/detect-server-settings.js'; import { UNLINKED_SITE_MOCK_ID, getDotEnvVariables, getSiteInformation, injectEnvVariables } from '../../utils/dev.js'; import { getEnvelopeEnv } from '../../utils/env/index.js'; import { ensureNetlifyIgnore } from '../../utils/gitignore.js'; import { getLiveTunnelSlug, startLiveTunnel } from '../../utils/live-tunnel.js'; import openBrowser from '../../utils/open-browser.js'; import { generateInspectSettings, startProxyServer } from '../../utils/proxy-server.js'; import { getProxyUrl } from '../../utils/proxy.js'; import { runDevTimeline } from '../../utils/run-build.js'; const handleLiveTunnel = async ({ api, options, settings, site, state, }) => { const { live } = options; if (live) { const customSlug = typeof live === 'string' && live.length !== 0 ? live : undefined; const slug = getLiveTunnelSlug(state, customSlug); let message = `${NETLIFYDEVWARN} Creating live URL with ID ${chalk.yellow(slug)}`; if (!customSlug) { message += ` (to generate a custom URL, use ${chalk.magenta('--live=<subdomain>')})`; } log(message); const sessionUrl = await startLiveTunnel({ siteId: site.id, netlifyApiToken: api.accessToken, localPort: settings.port, slug, }); process.env.BASE_URL = sessionUrl; return sessionUrl; } }; export const dev = async (options, command) => { log(NETLIFYDEV); const { api, cachedConfig, config, repositoryRoot, site, siteInfo, state } = command.netlify; config.dev = config.dev != null ? { ...config.dev } : undefined; config.build = { ...config.build }; const devConfig = { framework: '#auto', autoLaunch: Boolean(options.open), ...(cachedConfig.siteInfo.dev_server_settings && { command: cachedConfig.siteInfo.dev_server_settings.cmd, targetPort: cachedConfig.siteInfo.dev_server_settings.target_port, }), ...(config.functionsDirectory && { functions: config.functionsDirectory }), ...('publish' in config.build && config.build.publish && { publish: config.build.publish }), ...(config.build.base && { base: config.build.base }), ...config.dev, ...options, }; let { env } = cachedConfig; env.NETLIFY_DEV = { sources: ['internal'], value: 'true' }; const blobsContext = await getBlobsContextWithEdgeAccess({ debug: options.debug, projectRoot: command.workingDir, siteID: site.id ?? UNLINKED_SITE_MOCK_ID, }); env[BLOBS_CONTEXT_VARIABLE] = { sources: ['internal'], value: encodeBlobsContext(blobsContext) }; if (!options.offline && !options.offlineEnv) { env = await getEnvelopeEnv({ api, context: options.context, env, siteInfo }); log(`${NETLIFYDEVLOG} Injecting environment variable values for ${chalk.yellow('all scopes')}`); } env = await getDotEnvVariables({ devConfig, env, site }); injectEnvVariables(env); await promptEditorHelper({ chalk, config, log, NETLIFYDEVLOG, repositoryRoot, state }); const { accountId, addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({ // inherited from base command --offline offline: options.offline, api, site, siteInfo, }); let settings; try { settings = await detectServerSettings(devConfig, options, command); const { NETLIFY_INCLUDE_DEV_SERVER_PLUGIN } = process.env; if (NETLIFY_INCLUDE_DEV_SERVER_PLUGIN) { const plugins = NETLIFY_INCLUDE_DEV_SERVER_PLUGIN.split(','); if (options.debug) { log(`${NETLIFYDEVLOG} Including dev server plugins: ${NETLIFY_INCLUDE_DEV_SERVER_PLUGIN}`); } settings.plugins = [...(settings.plugins ?? []), ...plugins]; } // TODO(serhalp): Doing this as a side effect inside `BaseCommand` like this is WILD. // Refactor this to be more explicit and less brittle. cachedConfig.config = getConfigWithPlugins(cachedConfig.config, settings); } catch (error) { if (error instanceof Error) { log(NETLIFYDEVERR, error.message); } process.exit(1); } command.setAnalyticsPayload({ live: options.live }); const liveTunnelUrl = await handleLiveTunnel({ options, site, api, settings, state }); const url = liveTunnelUrl || getProxyUrl(settings); process.env.URL = url; process.env.DEPLOY_URL = url; log(`${NETLIFYDEVWARN} Setting up local development server`); const { configMutations, configPath: configPathOverride } = await runDevTimeline({ command, options, settings, env: { URL: url, DEPLOY_URL: url, }, }); // FIXME(serhalp): `applyMutations` is `(any, any) => any)`. Add types in `@netlify/config`. const mutatedConfig = applyMutations(config, configMutations); const functionsRegistry = await startFunctionsServer({ blobsContext, command, config: mutatedConfig, debug: options.debug, settings, site, siteInfo, siteUrl, capabilities, timeouts, geolocationMode: options.geo, geoCountry: options.country, offline: options.offline, state, accountId, }); // Try to add `.netlify` to `.gitignore`. try { await ensureNetlifyIgnore(repositoryRoot); } catch { // no-op } // TODO: We should consolidate this with the existing config watcher. const getUpdatedConfig = async () => { const { config: newConfig } = await command.getConfig({ cwd: command.workingDir, offline: true, }); return normalizeConfig(newConfig); }; const inspectSettings = generateInspectSettings(options.edgeInspect, options.edgeInspectBrk); await startProxyServer({ addonsUrls, api, blobsContext, command, config: mutatedConfig, configPath: configPathOverride, debug: options.debug, disableEdgeFunctions: options.internalDisableEdgeFunctions, projectDir: command.workingDir, env, getUpdatedConfig, inspectSettings, offline: options.offline, settings, site, siteInfo, state, geolocationMode: options.geo, geoCountry: options.country, accountId, functionsRegistry, repositoryRoot, }); if (devConfig.autoLaunch !== false) { await openBrowser({ url, silentBrowserNoneError: true }); } printBanner({ url }); }; //# sourceMappingURL=dev.js.map