vite-plugin-zephyr
Version:
Vite plugin for Zephyr
796 lines (795 loc) • 45 kB
JavaScript
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