UNPKG

vite-plugin-zephyr

Version:

Vite plugin for Zephyr

796 lines (795 loc) • 45 kB
import { readFile } from "node:fs/promises"; import { createHash, randomUUID } from "node:crypto"; import { createRequire } from "node:module"; import magic_string from "magic-string"; import { ApplicationContext, ZeErrors, ZephyrEngine, ZephyrError, assertZephyrBuildTarget, captureSource, claimPartialAssetMapBatch, commitPartialAssetMapClaimBatch, createManifestContent, handleGlobalError, logFn, normalizeBasePath, rewriteEnvReadsToVirtualModule, rollbackPartialAssetMapClaimBatch, savePartialAssetMap, zeBuildAssets, zeBuildDashData, ze_log } from "zephyr-agent"; import { extractEntrypoint } from "./internal/extract/extract-entrypoint.mjs"; import { extract_mf_plugins } from "./internal/extract/extract_mf_plugin.mjs"; import { extract_vite_assets_map } from "./internal/extract/extract_vite_assets_map.mjs"; import { RESOLVED_ZEPHYR_MF_RUNTIME_PLUGIN_ID, ZEPHYR_MF_RUNTIME_PLUGIN_ID, ensureRuntimePlugin, getRuntimePluginPath } from "./internal/mf-vite-etl/ensure_runtime_plugin.mjs"; import { extract_remotes_dependencies } from "./internal/mf-vite-etl/extract-mf-vite-remotes.mjs"; import { createViteModuleFederationPublicationMetadata, getConfigIdentities } from "./internal/mf-vite-etl/federation-metadata.mjs"; import { resolveVitePartialBuildScope } from "./internal/partial-build-scope.mjs"; import { fileURLToPath as __rspack_fileURLToPath } from "node:url"; var __rspack_import_meta_filename__ = __rspack_fileURLToPath(import.meta.url); import * as __rspack_external_node_path_806ed179 from "node:path"; const DEFAULT_LIBRARY_TYPE = 'module'; const VITE_ENVIRONMENT_OUTPUT_PREFIX = 'vite-environment:'; const runtimeRequire = createRequire(__rspack_import_meta_filename__); function mergeClaimedPartialMaps(claims) { const merged = {}; for (const claim of claims)for (const [partialKey, assetsMap] of Object.entries(claim.partialAssetMaps)){ if (Object.prototype.hasOwnProperty.call(merged, partialKey)) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Vite partial output "${partialKey}" was produced by multiple build scopes.` }); merged[partialKey] = assetsMap; } return merged; } function mergeAssetMaps(maps) { const merged = {}; const paths = new Map(); for (const assetsMap of maps)for (const [hash, asset] of Object.entries(assetsMap)){ const existingHash = paths.get(asset.path); if (existingHash && existingHash !== hash) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Vite emitted conflicting partial assets for "${asset.path}".` }); paths.set(asset.path, hash); merged[hash] = asset; } return merged; } function viteEnvironmentOutputPrefix(environmentName) { return `${VITE_ENVIRONMENT_OUTPUT_PREFIX}${encodeURIComponent(environmentName)}:`; } function viteEnvironmentOutputKey(environmentName, outputDirectory, outputFile, outputFormat, assetsMap) { const destination = outputFile ? __rspack_external_node_path_806ed179.join(outputDirectory, __rspack_external_node_path_806ed179.basename(outputFile)) : outputDirectory; const assets = Object.values(assetsMap).map((asset)=>[ asset.path.replace(/\\/g, '/'), asset.hash, asset.size ]).sort(([leftPath, leftHash], [rightPath, rightHash])=>leftPath === rightPath ? leftHash.localeCompare(rightHash) : leftPath.localeCompare(rightPath)); const identity = createHash('sha256').update(JSON.stringify({ destination: destination.replace(/\\/g, '/'), format: outputFormat ?? null, assets })).digest('hex'); return `${viteEnvironmentOutputPrefix(environmentName)}${identity}`; } function parseViteEnvironmentOutputName(key) { if (!key.startsWith(VITE_ENVIRONMENT_OUTPUT_PREFIX)) return null; const outputIdentity = key.slice(VITE_ENVIRONMENT_OUTPUT_PREFIX.length); const separator = outputIdentity.indexOf(':'); if (separator <= 0 || separator === outputIdentity.length - 1) return null; try { const environmentName = decodeURIComponent(outputIdentity.slice(0, separator)); return environmentName || null; } catch { return null; } } function prefixAssetsMap(assetsMap, prefix) { const normalized = prefix?.replace(/\\/g, '/').replace(/^\/+|\/+$/g, ''); if (!normalized) return assetsMap; return Object.fromEntries(Object.values(assetsMap).map((asset)=>{ const assetPath = asset.path.replace(/\\/g, '/').replace(/^\/+/, ''); const prefixedPath = assetPath.startsWith(`${normalized}/`) ? assetPath : `${normalized}/${assetPath}`; const prefixedAsset = zeBuildAssets({ filepath: prefixedPath, content: asset.buffer }); return [ prefixedAsset.hash, prefixedAsset ]; })); } function inferServerEntrypoint(partials, override, serverEnvironmentNames) { if (override) return normalizeEntrypoint(override); const allPaths = Object.values(partials).flatMap((assetsMap)=>Object.values(assetsMap).map((asset)=>asset.path)); const serverEnvironments = new Set(serverEnvironmentNames); const serverPaths = Object.entries(partials).flatMap(([key, assetsMap])=>{ const environmentName = parseViteEnvironmentOutputName(key); return environmentName && serverEnvironments.has(environmentName) ? Object.values(assetsMap).map((asset)=>asset.path) : []; }); const paths = serverEnvironmentNames.length > 0 ? serverPaths : allPaths; const preferred = [ 'server/index.js', 'server/index.mjs', 'server/index.cjs', 'ssr/index.js', 'ssr/index.mjs', 'ssr/index.cjs', 'rsc/index.js', 'rsc/index.mjs', 'rsc/index.cjs' ]; return preferred.find((candidate)=>paths.includes(candidate)) ?? paths.find((candidate)=>/(^|\/)(server|index)\.(mjs|cjs|js)$/.test(candidate)); } function hasLateOutputHook(value) { if (Array.isArray(value)) return value.some(hasLateOutputHook); if (!value || 'object' != typeof value) return false; if ('then' in value) return true; return [ 'outputOptions', 'writeBundle' ].some((name)=>{ const hook = value[name]; return Boolean(hook && 'object' == typeof hook && 'order' in hook && 'post' === hook.order); }); } function commonDirectory(paths) { if (0 === paths.length) return; const resolvedPaths = paths.map((item)=>__rspack_external_node_path_806ed179.resolve(item)); let candidate = resolvedPaths[0]; while(candidate && !resolvedPaths.every((item)=>{ const relative = __rspack_external_node_path_806ed179.relative(candidate, item); return !relative || !relative.startsWith(`..${__rspack_external_node_path_806ed179.sep}`) && '..' !== relative; })){ const parent = __rspack_external_node_path_806ed179.dirname(candidate); if (parent === candidate) return; candidate = parent; } if (candidate === __rspack_external_node_path_806ed179.parse(candidate).root && resolvedPaths.length > 1) return; return candidate; } function normalizeEntrypoint(entrypoint) { const normalized = entrypoint.replace(/\\/g, '/').replace(/^\.?\/+/, ''); const segments = normalized.split('/').filter((segment)=>segment && '.' !== segment); if (!normalized || 0 === segments.length || segments.includes('..')) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Vite entrypoint must be a relative path inside the snapshot: "${entrypoint}".` }); return segments.join('/'); } function uniqueParticipant(base, reserved) { let participant = base; let suffix = 1; const used = new Set(reserved); while(used.has(participant))participant = `${base}-${suffix++}`; return participant; } function toModuleFederationConfigArray(mfConfig) { if (!mfConfig) return []; return Array.isArray(mfConfig) ? mfConfig : [ mfConfig ]; } function attachViteFederationBuildStats(buildStats, federationMetadata) { const federation = federationMetadata.federation; if (!federation || 0 === federation.length) return buildStats; const legacyFederation = 1 === federation.length ? federation[0] : void 0; return { ...buildStats, federation, ...legacyFederation ? { remote: legacyFederation.remote, mf_manifest: legacyFederation.mf_manifest, library_type: legacyFederation.library_type, exposes: legacyFederation.exposes, shared: legacyFederation.shared } : { remote: void 0, mf_manifest: void 0, library_type: void 0, exposes: void 0, shared: void 0 } }; } function loadModuleFederationPlugin() { let moduleFederation; try { moduleFederation = runtimeRequire('@module-federation/vite'); } catch (error) { throw new ZephyrError(ZeErrors.ERR_UNKNOWN, { message: `vite-plugin-zephyr: @module-federation/vite is required when mfConfig is provided. Install a compatible version of @module-federation/vite to use Module Federation with withZephyr().${error instanceof Error ? ` Original error: ${error.message}` : ''}` }); } if ('function' != typeof moduleFederation.federation) throw new ZephyrError(ZeErrors.ERR_UNKNOWN, { message: 'vite-plugin-zephyr: failed to load @module-federation/vite federation plugin' }); return moduleFederation.federation; } function withZephyrCore(options = {}) { const { zephyr_engine_defer, zephyr_defer_create } = ZephyrEngine.defer_create(); const hooks = options.hooks; const preservesLockedArtifactPaths = 'tap-app' === options.target; const buildInvocationId = `vite-${randomUUID()}`; const usesExternalPartialBuild = void 0 !== options.partialBuild || Boolean(process.env['ZE_BUILD_INVOCATION_ID']?.trim()); const externalPartialScope = usesExternalPartialBuild ? resolveVitePartialBuildScope(options.partialBuild) : void 0; let resolve_vite_internal_options; const vite_internal_options_defer = new Promise((resolve)=>{ resolve_vite_internal_options = resolve; }); let cachedSpecifier; let entrypoint; const configureModuleFederationRuntime = (config)=>preservesLockedArtifactPaths ? config : ensureRuntimePlugin(config); const mfConfigSources = toModuleFederationConfigArray(options.mfConfig).map(configureModuleFederationRuntime); const ownedConfigIdentities = new Set(mfConfigSources.flatMap((config)=>getConfigIdentities(config))); let environmentNames = []; let environmentMetadata = new Map(); let sharedOutputRoot; let isWatchMode = false; let buildGeneration = 0; let applicationContext; let uploadMetadata; let baseHref = ''; let isApplicationBuild = false; let unsupportedVite6Builder = false; let directOutputs = []; let directBuildFailed = false; let directSsr = false; let expectedDirectOutputs = 1; let buildManifest; let hasLaterWriteHook = false; let hasLaterCloseHook = false; let hasLaterOutputOptionsHook = false; const instantiatedEnvironments = new Set(); let environmentBuildStarted = false; const buildAppStart = { name: 'with-zephyr:build-app-start', enforce: 'pre', sharedDuringBuild: true, buildApp: { order: 'pre', async handler () { isApplicationBuild = true; } } }; const registerModuleFederationConfigs = (configs)=>{ for (const config of configs){ const identities = getConfigIdentities(config); if (identities.some((identity)=>ownedConfigIdentities.has(identity))) continue; const runtimeConfigured = configureModuleFederationRuntime(config); if (!mfConfigSources.includes(runtimeConfigured)) { mfConfigSources.push(runtimeConfigured); for (const identity of getConfigIdentities(runtimeConfigured))ownedConfigIdentities.add(identity); } } }; const getModuleFederationPublicationMetadata = ()=>createViteModuleFederationPublicationMetadata(mfConfigSources); const publishDirectOutputs = async (outputs)=>{ const partialClaims = []; const zephyrEngine = await zephyr_engine_defer; try { const outputRoot = commonDirectory(outputs.map((output)=>output.directory)); if (!outputRoot) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Could not determine a shared output root for the Vite build.' }); const serverEntries = new Set(); const maps = outputs.map((output)=>{ const prefix = preservesLockedArtifactPaths ? void 0 : __rspack_external_node_path_806ed179.relative(outputRoot, output.directory).split(__rspack_external_node_path_806ed179.sep).join('/'); for (const entry of output.entrypoints)serverEntries.add(prefix ? `${prefix}/${entry}` : entry); return prefixAssetsMap(output.assetsMap, prefix); }); let assetsMap = 1 === maps.length ? maps[0] : mergeAssetMaps(maps); if (!isWatchMode && externalPartialScope) { const batch = await claimPartialAssetMapBatch(zephyrEngine.application_uid, [ externalPartialScope ]); if (!batch) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Vite partialBuild was configured, but its external partial output was unavailable or already claimed.' }); partialClaims.push(...batch.claims); assetsMap = mergeAssetMaps([ ...Object.values(mergeClaimedPartialMaps(partialClaims)), assetsMap ]); } const snapshotType = options.snapshotType ?? (!preservesLockedArtifactPaths && outputs.some((output)=>output.ssr) ? 'ssr' : 'csr'); const finalEntrypoint = 'ssr' === snapshotType ? options.entrypoint ? normalizeEntrypoint(options.entrypoint) : 1 === serverEntries.size ? [ ...serverEntries ][0] : void 0 : preservesLockedArtifactPaths ? void 0 : entrypoint; if ('ssr' === snapshotType && (!finalEntrypoint || !Object.values(assetsMap).some((asset)=>asset.path === finalEntrypoint))) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Could not identify an emitted Vite server entrypoint. Set withZephyr({ entrypoint }) to an emitted server chunk.' }); if (!zephyrEngine.hasActiveBuild) await zephyrEngine.start_new_build(); const federationMetadata = getModuleFederationPublicationMetadata(); await zephyrEngine.upload_assets({ assetsMap, buildStats: attachViteFederationBuildStats(await zeBuildDashData(zephyrEngine), federationMetadata), mfConfig: federationMetadata.mfConfig, mfConfigs: federationMetadata.mfConfigs, hooks, entrypoint: finalEntrypoint, snapshotType }); await zephyrEngine.build_finished(); await commitPartialAssetMapClaimBatch(zephyrEngine.application_uid, partialClaims.map(({ claimId })=>claimId)); } catch (error) { zephyrEngine.build_failed(); if (partialClaims.length > 0) try { await rollbackPartialAssetMapClaimBatch(zephyrEngine.application_uid, partialClaims.map(({ claimId })=>claimId)); } catch (rollbackError) { logFn('error', ZephyrError.format(rollbackError)); } throw error; } }; const plugin = { name: 'with-zephyr', sharedDuringBuild: true, enforce: 'pre', config: (config)=>{ registerModuleFederationConfigs(extract_mf_plugins(config.plugins ?? []).map((plugin)=>plugin._options)); return null; }, configResolved: async (config)=>{ const vite = await import("vite"); const viteMajor = Number.parseInt(vite.version.split('.')[0] ?? '0', 10); if (environmentBuildStarted) { instantiatedEnvironments.clear(); environmentBuildStarted = false; } const createEnvironment = config.build?.createEnvironment; if (createEnvironment) config.build.createEnvironment = function(name, environmentConfig) { const environment = createEnvironment.call(this, name, environmentConfig); instantiatedEnvironments.add(name); return environment; }; isApplicationBuild = false; directOutputs = []; directBuildFailed = false; buildManifest = void 0; directSsr = Boolean(config.build?.ssr); const configuredOutput = config.build?.rolldownOptions?.output ?? config.build?.rollupOptions?.output; expectedDirectOutputs = Array.isArray(configuredOutput) ? configuredOutput.length : config.build?.lib ? config.build.lib.formats?.length ?? 2 : 1; const firstBuildAppPlugin = config.getSortedPlugins?.('buildApp')[0]; if (viteMajor >= 7 && firstBuildAppPlugin && firstBuildAppPlugin !== buildAppStart) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Place withZephyr() before other pre-ordered buildApp plugins so Zephyr can collect application output atomically.' }); const writePlugins = config.getSortedPlugins?.('writeBundle'); hasLaterWriteHook = Boolean(writePlugins?.length && writePlugins.at(-1) !== plugin); const closePlugins = config.getSortedPlugins?.('closeBundle'); hasLaterCloseHook = Boolean(closePlugins?.length && closePlugins.at(-1) !== plugin); const outputOptionPlugins = config.getSortedPlugins?.('outputOptions'); hasLaterOutputOptionsHook = Boolean(outputOptionPlugins?.length && outputOptionPlugins.at(-1) !== plugin); const root = config.root; baseHref = normalizeBasePath(config.base); entrypoint = normalizeEntrypoint(options.entrypoint ?? extractEntrypoint(config)); isWatchMode = Boolean(config.build?.watch); const configuredEnvironments = config.environments ?? {}; environmentNames = Object.keys(configuredEnvironments); unsupportedVite6Builder = 6 === viteMajor && (Boolean(config.builder) || environmentNames.length > 1); environmentMetadata = new Map(Object.entries(configuredEnvironments).map(([name, environment])=>[ name, { consumer: environment.consumer, outputDir: environment.build?.outDir ? __rspack_external_node_path_806ed179.resolve(root, environment.build.outDir) : void 0 } ])); const outputDirectories = [ ...environmentMetadata.values() ].map(({ outputDir })=>outputDir).filter((value)=>!!value); sharedOutputRoot = preservesLockedArtifactPaths || outputDirectories.length !== environmentNames.length ? void 0 : commonDirectory(outputDirectories); zephyr_defer_create({ builder: 'vite', context: root, target: options.target }); resolve_vite_internal_options({ root, outDir: config.build?.outDir, publicDir: config.publicDir, target: options.target }); registerModuleFederationConfigs(extract_mf_plugins(config.plugins ?? []).map((plugin)=>plugin._options)); const federationMetadata = getModuleFederationPublicationMetadata(); const mfConfigs = federationMetadata.mfConfigs ?? []; if (mfConfigs.length > 0 && !preservesLockedArtifactPaths) try { const dependencyPairs = [ ...new Map(mfConfigs.flatMap((mfConfig)=>extract_remotes_dependencies(root, mfConfig) ?? []).map((dependency)=>[ `${dependency.name}:${dependency.version}`, dependency ])).values() ]; if (dependencyPairs.length > 0) { const zephyr_engine = await zephyr_engine_defer; await zephyr_engine.resolve_remote_dependencies(dependencyPairs, DEFAULT_LIBRARY_TYPE); ze_log.remotes(`Resolved ${dependencyPairs.length} remote dependencies in configResolved`); } } catch (error) { handleGlobalError(error); } try { const loaded = vite.loadEnv(config.mode || 'production', root, ''); for (const [k, v] of Object.entries(loaded))if (k.startsWith('ZE_PUBLIC_') && 'string' == typeof v && !(k in process.env)) process.env[k] = v; } catch {} }, resolveId: async (source)=>{ if (source === ZEPHYR_MF_RUNTIME_PLUGIN_ID) return RESOLVED_ZEPHYR_MF_RUNTIME_PLUGIN_ID; try { const zephyr_engine = await zephyr_engine_defer; if (!cachedSpecifier) cachedSpecifier = `env:vars:${zephyr_engine.application_uid}`; if (source === cachedSpecifier) { if ('development' === process.env['NODE_ENV']) return '/zephyr-manifest.json'; return { id: source, external: true }; } } catch {} return null; }, load: async (id)=>{ if (id === RESOLVED_ZEPHYR_MF_RUNTIME_PLUGIN_ID) return readFile(getRuntimePluginPath(), 'utf8'); return null; }, transform: { order: 'post', filter: { id: /\.(mjs|cjs|js|ts|jsx|tsx)/ }, handler: async (code, id)=>{ if (preservesLockedArtifactPaths) return null; try { if (!id.includes('node_modules')) { const zephyr_engine = await zephyr_engine_defer; if (!cachedSpecifier) cachedSpecifier = `env:vars:${zephyr_engine.application_uid}`; const res = rewriteEnvReadsToVirtualModule(String(code), cachedSpecifier); if (res && 'string' == typeof res.code && res.code !== code) { code = res.code; return { code, map: new magic_string(code).generateMap({ hires: true }) }; } } return null; } catch (error) { handleGlobalError(error); return null; } } }, renderChunk: { order: 'post', handler (code) { if (preservesLockedArtifactPaths || !cachedSpecifier) return null; const importWithoutAttribute = new RegExp(`import\\s+([^\\s]+)\\s+from\\s*['"]${cachedSpecifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}['"]`, 'g'); const nextCode = code.replace(importWithoutAttribute, `import $1 from '${cachedSpecifier}' with { type: 'json' }`); return nextCode === code ? null : { code: nextCode, map: null }; } }, generateBundle: async function() { if (preservesLockedArtifactPaths) return; try { const zephyr_engine = await zephyr_engine_defer; const dependencies = zephyr_engine.federated_dependencies || []; const manifestContent = isApplicationBuild || isWatchMode ? createManifestContent(dependencies, true) : buildManifest ??= createManifestContent(dependencies, true); this.emitFile({ type: 'asset', fileName: 'zephyr-manifest.json', source: manifestContent }); } catch (error) { handleGlobalError(error); this.emitFile({ type: 'asset', fileName: 'zephyr-manifest.json', source: JSON.stringify({ version: '1.0.0', timestamp: new Date().toISOString(), dependencies: {}, zeVars: {} }, null, 2) }); } }, configureServer: async (server)=>{ try { const zephyr_engine = await zephyr_engine_defer; if (!cachedSpecifier) cachedSpecifier = `env:vars:${zephyr_engine.application_uid}`; server.middlewares.use((req, res, next)=>{ (async ()=>{ if (!req.url) return void next(); const requestUrl = req.url.split('?')[0]; if ('/zephyr-manifest.json' === requestUrl) try { const dependencies = zephyr_engine.federated_dependencies || []; const manifestContent = createManifestContent(dependencies, true); res.setHeader('Content-Type', 'application/json; charset=utf-8'); res.setHeader('Access-Control-Allow-Origin', '*'); res.end(manifestContent); return; } catch (error) { handleGlobalError(error); } next(); })(); }); } catch {} }, outputOptions: { order: 'post', handler (output) { if (!isApplicationBuild && !isWatchMode && (hasLaterOutputOptionsHook || hasLateOutputHook(output.plugins))) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Zephyr cannot verify post-ordered or asynchronous output-plugin writers. Use normal outputOptions and writeBundle ordering in synchronous output plugins.' }); return null; } }, async buildStart () { environmentBuildStarted = true; try { const engine = await zephyr_engine_defer; if (engine.sourceContext && engine.sourceCapture?.phase !== 'build-start' && !engine.pendingSourceCapture) { const capture = captureSource(engine.sourceContext, 'build-start'); if (engine.hasActiveBuild) engine.sourceCapture = capture; else engine.pendingSourceCapture = capture; } } catch (error) { handleGlobalError(error); } }, buildEnd (error) { if (error) directBuildFailed = true; }, renderError () { directBuildFailed = true; }, closeBundle: { order: 'post', sequential: true, async handler () { if (isApplicationBuild || isWatchMode || 0 === directOutputs.length) return; const outputs = directOutputs; directOutputs = []; if (directBuildFailed || outputs.length !== expectedDirectOutputs) return; try { await publishDirectOutputs(outputs); } catch (error) { handleGlobalError(error); } } }, writeBundle: { order: 'post', sequential: true, async handler (outputOptions, bundle) { try { const [vite_internal_options, zephyr_engine] = await Promise.all([ vite_internal_options_defer, zephyr_engine_defer ]); zephyr_engine.buildProperties.baseHref = baseHref; const environmentName = this.environment?.name; const isMultiEnvironment = environmentNames.length > 1; if (!isWatchMode && unsupportedVite6Builder) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Vite 6 application-builder publication requires Vite 7 or newer. Vite 6 supports only single-environment builds without a builder configuration.' }); if (isWatchMode && isMultiEnvironment) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: "Vite multi-environment watch publication is not supported because environment rebuilds do not expose an atomic application generation." }); const outputDirectory = __rspack_external_node_path_806ed179.resolve(vite_internal_options.root, outputOptions.dir ?? (outputOptions.file ? __rspack_external_node_path_806ed179.dirname(outputOptions.file) : vite_internal_options.outDir)); const resolvedEnvironmentName = environmentName ?? [ ...environmentMetadata.entries() ].find(([, metadata])=>metadata.outputDir === outputDirectory)?.[0] ?? (1 === environmentNames.length ? environmentNames[0] : void 0); const coordinateWithBuildApp = isApplicationBuild && !isWatchMode; if (!coordinateWithBuildApp && instantiatedEnvironments.size > 1) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Use builder.buildApp() to publish multiple Vite environments atomically; individual builder.build(environment) calls cannot finalize the application.' }); if (!coordinateWithBuildApp && !isWatchMode && (hasLaterWriteHook || hasLaterCloseHook)) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Zephyr must be the last writeBundle and closeBundle hook. Use normal hook ordering for other plugins so publication cannot precede a failed build.' }); if (coordinateWithBuildApp && !resolvedEnvironmentName) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Could not associate Vite output directory "${outputDirectory}" with an environment.` }); let assetPrefix; if (coordinateWithBuildApp && isMultiEnvironment && !preservesLockedArtifactPaths) { if (!sharedOutputRoot) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Could not determine a shared output root for Vite environments.' }); const relativeOutput = __rspack_external_node_path_806ed179.relative(sharedOutputRoot, outputDirectory); if ('..' === relativeOutput || relativeOutput.startsWith(`..${__rspack_external_node_path_806ed179.sep}`) || __rspack_external_node_path_806ed179.isAbsolute(relativeOutput)) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Vite environment output "${outputDirectory}" is outside shared output root "${sharedOutputRoot}".` }); assetPrefix = relativeOutput ? relativeOutput.split(__rspack_external_node_path_806ed179.sep).join('/') : void 0; } const extractionOptions = { ...vite_internal_options, dir: outputOptions.dir, outDir: outputDirectory, assets: bundle, publicDir: isMultiEnvironment && resolvedEnvironmentName && environmentMetadata.get(resolvedEnvironmentName)?.consumer === 'server' ? void 0 : vite_internal_options.publicDir }; const assetsMap = await extract_vite_assets_map(zephyr_engine, extractionOptions); if (coordinateWithBuildApp) { if (!resolvedEnvironmentName) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Could not associate Vite output directory "${outputDirectory}" with an environment.` }); const persistedAssetsMap = preservesLockedArtifactPaths ? assetsMap : prefixAssetsMap(assetsMap, assetPrefix); await savePartialAssetMap(zephyr_engine.application_uid, viteEnvironmentOutputKey(resolvedEnvironmentName, outputDirectory, outputOptions.file, outputOptions.format, persistedAssetsMap), persistedAssetsMap, { invocationId: buildInvocationId, generation: buildGeneration }); return; } const output = { assetsMap, directory: outputDirectory, entrypoints: Object.values(bundle).flatMap((asset)=>'chunk' === asset.type && asset.isEntry ? [ asset.fileName ] : []), ssr: directSsr || void 0 !== resolvedEnvironmentName && environmentMetadata.get(resolvedEnvironmentName)?.consumer === 'server' }; if (isWatchMode) await publishDirectOutputs([ output ]); else directOutputs.push(output); } catch (error) { directBuildFailed = true; try { const zephyr_engine = await zephyr_engine_defer; zephyr_engine.build_failed(); } catch {} handleGlobalError(error); } } }, buildApp: { order: 'post', async handler (builder) { isApplicationBuild = true; const environments = Object.entries(builder.environments); if (isWatchMode) { if (environments.length > 1) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: "Vite multi-environment watch publication is not supported because environment rebuilds do not expose an atomic application generation." }); return; } if (0 === environments.length) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Vite exposed no build environments for Zephyr publication.' }); let incomplete = environments.filter(([, environment])=>!environment.isBuilt).map(([name])=>name); if (incomplete.length === environments.length) { for (const [, environment] of environments)await builder.build(environment); incomplete = environments.filter(([, environment])=>!environment.isBuilt).map(([name])=>name); } if (incomplete.length > 0) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Vite completed without these environments: ${incomplete.join(', ')}. Zephyr will not publish partial compiler output.` }); const partialClaims = []; const generation = buildGeneration++; try { const zephyrEngine = await zephyr_engine_defer; zephyrEngine.buildProperties.baseHref = baseHref; const claimScopes = [ { invocationId: buildInvocationId, generation }, ...externalPartialScope ? [ externalPartialScope ] : [] ]; const batch = await claimPartialAssetMapBatch(zephyrEngine.application_uid, claimScopes); if (!batch) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: externalPartialScope ? 'Vite could not atomically claim both environment and configured external partial output.' : 'Vite environment output was unavailable or already claimed.' }); partialClaims.push(...batch.claims); const claimedPartials = mergeClaimedPartialMaps(partialClaims); if (0 === Object.keys(claimedPartials).length) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Vite produced no environment assets for Zephyr publication.' }); const expectedEnvironmentNames = new Set(environments.map(([name])=>name)); const environmentOutputCounts = new Map(environments.map(([name])=>[ name, 0 ])); const unexpectedEnvironmentOutputs = []; for (const key of Object.keys(claimedPartials)){ if (!key.startsWith(VITE_ENVIRONMENT_OUTPUT_PREFIX)) continue; const environmentName = parseViteEnvironmentOutputName(key); if (!environmentName || !expectedEnvironmentNames.has(environmentName)) { unexpectedEnvironmentOutputs.push(key); continue; } environmentOutputCounts.set(environmentName, (environmentOutputCounts.get(environmentName) ?? 0) + 1); } const missingEnvironmentOutputs = environments.map(([name])=>name).filter((name)=>0 === environmentOutputCounts.get(name)).map(viteEnvironmentOutputPrefix); if (missingEnvironmentOutputs.length > 0) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Vite did not produce Zephyr output for: ${missingEnvironmentOutputs.join(', ')}` }); if (unexpectedEnvironmentOutputs.length > 0) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Vite found stale or unexpected environment output for: ' + unexpectedEnvironmentOutputs.join(', ') }); const serverEnvironmentNames = environments.filter(([name, environment])=>environment.config?.consumer === 'server' || environmentMetadata.get(name)?.consumer === 'server').map(([name])=>name); const inferredSsr = serverEnvironmentNames.length > 0; const snapshotType = options.snapshotType ?? (!preservesLockedArtifactPaths && inferredSsr ? 'ssr' : 'csr'); const finalEntrypoint = 'ssr' === snapshotType ? inferServerEntrypoint(claimedPartials, options.entrypoint, serverEnvironmentNames) : preservesLockedArtifactPaths ? void 0 : options.entrypoint ?? entrypoint; if ('ssr' === snapshotType && !finalEntrypoint) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Could not infer a Vite server entrypoint. Set withZephyr({ entrypoint }).' }); if ('ssr' === snapshotType && finalEntrypoint && !Object.values(claimedPartials).some((assetsMap)=>Object.values(assetsMap).some((asset)=>asset.path === finalEntrypoint))) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `Vite server entrypoint "${finalEntrypoint}" was not emitted in the coordinated snapshot.` }); uploadMetadata = { snapshotType, entrypoint: finalEntrypoint }; applicationContext ??= new ApplicationContext({ applicationUid: zephyrEngine.application_uid, prepare: ()=>zephyrEngine.hasActiveBuild ? void 0 : zephyrEngine.start_new_build(), publish: async ({ assetsMap })=>{ if (!uploadMetadata) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: 'Vite upload metadata was not prepared.' }); const federationMetadata = getModuleFederationPublicationMetadata(); await zephyrEngine.upload_assets({ assetsMap, buildStats: attachViteFederationBuildStats(await zeBuildDashData(zephyrEngine), federationMetadata), mfConfig: federationMetadata.mfConfig, mfConfigs: federationMetadata.mfConfigs, hooks, snapshotType: uploadMetadata.snapshotType, entrypoint: uploadMetadata.entrypoint }); }, finish: ()=>zephyrEngine.build_finished(), onFailure: ()=>zephyrEngine.build_failed() }); const outputParticipant = uniqueParticipant('vite-output', environments.map(([name])=>name)); const session = applicationContext.beginBuild({ invocationId: `${buildInvocationId}:${generation}`, generation, participants: [ ...environments.map(([name, environment])=>({ name, role: environment.config?.consumer ?? environmentMetadata.get(name)?.consumer ?? name })), { name: outputParticipant, role: snapshotType } ] }); for (const [name] of environments)session.completeParticipant(name); for (const [key, assetsMap] of Object.entries(claimedPartials))session.contribute({ participant: outputParticipant, key, assetsMap }); session.completeParticipant(outputParticipant); await session.publish(); await commitPartialAssetMapClaimBatch(zephyrEngine.application_uid, partialClaims.map(({ claimId })=>claimId)); } catch (error) { try { const zephyrEngine = await zephyr_engine_defer; zephyrEngine.build_failed(); } catch {} if (partialClaims.length > 0) try { const zephyrEngine = await zephyr_engine_defer; await rollbackPartialAssetMapClaimBatch(zephyrEngine.application_uid, partialClaims.map(({ claimId })=>claimId)); } catch (restoreError) { logFn('error', ZephyrError.format(restoreError)); } handleGlobalError(error); } } } }; return [ plugin, buildAppStart ]; } function withZephyr(options = {}) { if (void 0 !== options.target) assertZephyrBuildTarget(options.target, 'withZephyr({ target })'); const plugins = []; const mfConfigs = toModuleFederationConfigArray(options.mfConfig); if (mfConfigs.length > 0) { const federation = loadModuleFederationPlugin(); const preservesLockedArtifactPaths = 'tap-app' === options.target; for (const mfConfig of mfConfigs)plugins.push(...federation(preservesLockedArtifactPaths ? mfConfig : ensureRuntimePlugin(mfConfig))); } plugins.push(...withZephyrCore(options)); return plugins; } export { withZephyr }; //# sourceMappingURL=vite-plugin-zephyr.mjs.map