UNPKG

arc-vite

Version:

Declaratively bundle and execute code specific to your users ARC and Vite.

1,241 lines (1,222 loc) 39.2 kB
// src/plugins/build-ssr.ts import path4 from "path"; // src/utils/file-types.ts var assetFileReg = /\.(?:a?png|jpe?g|jfif|pipeg|pjp|gif|svg|ico|web[pm]|avif|mp4|ogg|mp3|wav|flac|aac|opus|woff2?|eot|[ot]tf|webmanifest|pdf|txt)(\?|$)/; var globalCSSFileReg = /(?<!\.module)\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/; function isAssetFile(id) { return assetFileReg.test(id); } function isGlobalCSSFile(id) { return globalCSSFileReg.test(id); } // src/utils/index-to-id.ts var ID_START_CHARS = "hjkmoquxzABCDEFGHIJKLNPQRTUVWXYZ$_"; var ID_START_CHARS_LEN = ID_START_CHARS.length; var ID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_"; var ID_CHARS_LEN = ID_CHARS.length; function indexToId(i) { let mod = i % ID_START_CHARS_LEN; let id = ID_START_CHARS[mod]; i = (i - mod) / ID_START_CHARS_LEN; while (i > 0) { mod = i % ID_CHARS_LEN; id += ID_CHARS[mod]; i = (i - mod) / ID_CHARS_LEN; } return id; } // src/utils/matches.ts import fs from "fs"; import path from "path"; import Resolver from "arc-resolver"; // src/utils/flags.ts function createFlagSets(flags) { const flagSets = [[]]; for (const group of flags) { const { length } = flagSets; for (const flag of Array.isArray(group) ? group : [group]) { for (let i = length; i--; ) { flagSets.push(flagSets[i].concat(flag)); } } } return normalizeFlagSets(flagSets); } function hasFlagSet(flagSets, flagSet) { let max = flagSets.length; let pos = 0; while (pos < max) { const mid = pos + max >>> 1; const compared = compareFlagSets(flagSets[mid], flagSet); if (compared === 0) return true; if (compared > 0) max = mid; else pos = mid + 1; } return false; } function hasFlag(flagSet, flag) { let max = flagSet.length; let pos = 0; while (pos < max) { const mid = pos + max >>> 1; const compared = compareFlags(flagSet[mid], flag); if (compared === 0) return true; if (compared > 0) max = mid; else pos = mid + 1; } return false; } function hasFlags(flagSet, flags) { for (const flag of flags) { if (!hasFlag(flagSet, flag)) { return false; } } return true; } function compareFlagSets(a, b) { const aLen = a.length; const bLen = b.length; if (aLen === bLen) { for (let i = aLen; i--; ) { const compared = compareFlags(a[i], b[i]); if (compared !== 0) return compared; } } return bLen - aLen; } function normalizeFlagSets(rawFlagSets) { if (!rawFlagSets.length) return [[]]; const sortedFlagSets = rawFlagSets.map(normalizeFlagSet).sort(compareFlagSets); let prev = sortedFlagSets[0]; const uniqueFlagSets = [prev]; for (let i = 1; i < sortedFlagSets.length; i++) { if (compareFlagSets(prev, sortedFlagSets[i]) !== 0) { uniqueFlagSets.push(prev = sortedFlagSets[i]); } } if (prev.length !== 0) { uniqueFlagSets.push([]); } return uniqueFlagSets; } function normalizeFlagSet(flags) { return [...new Set(flags)].sort(); } function compareFlaggedObject(a, b) { return compareFlagSets(a.flags, b.flags); } function compareFlags(a, b) { return a > b ? 1 : a < b ? -1 : 0; } // src/utils/matches.ts var resolver = new Resolver(fs); var hasQuery = /\?.*$/; function getMatches(id, flagSets) { if (hasQuery.test(id) || !path.isAbsolute(id)) return; const raw = tryGetRawMatches(id); if (!raw) return; let i = raw.length - 1; if (i) { const defaultMatch = raw[i].value; let alternates; for (; i--; ) { const match = normalizeMatch(raw[i]); if (hasFlagSet(flagSets, match.flags)) { if (alternates) { alternates.push(match); } else { alternates = [match]; } } } if (alternates) { return { default: defaultMatch, alternates: alternates.sort(compareFlaggedObject) }; } } } function clearCache() { resolver.clearCache(); } function tryGetRawMatches(id) { try { return resolver.getMatchesSync(id).raw; } catch { } } function normalizeMatch(match) { return { flags: normalizeFlagSet(match.flags), value: match.value }; } // src/utils/read-once-persisted-store.ts import { promises as fs2 } from "fs"; import os from "os"; import path2 from "path"; var noop = () => { }; var tmpFile = path2.join(os.tmpdir(), "vite-arc-storage.json"); var values = /* @__PURE__ */ new Map(); var loadedFromDisk; var ReadOncePersistedStore = class { constructor(uid) { this.uid = uid; } write(value) { values.set(this.uid, value); } async read() { const { uid } = this; if (values.has(uid)) { const value = values.get(uid); values.delete(uid); return value; } if (loadedFromDisk === true) { throw new Error(`Value for ${uid} could not be loaded.`); } await (loadedFromDisk ||= fs2.readFile(tmpFile, "utf-8").then(syncDataFromDisk).catch(finishLoadFromDisk)); return this.read(); } }; function syncDataFromDisk(data) { finishLoadFromDisk(); fs2.unlink(tmpFile).catch(noop); for (const [k, v] of JSON.parse(data)) { values.set(k, v); } } function finishLoadFromDisk() { loadedFromDisk = true; } process.once("beforeExit", (code) => { if (code === 0 && values.size) { fs2.writeFile(tmpFile, JSON.stringify([...values])).catch(noop); } }); // src/utils/options.ts function getInternalPluginOptions(options) { const runtimeId = `arc${options.runtimeId ? `_${options.runtimeId}` : ""}`; const { FLAGS } = process.env; return { runtimeId, store: new ReadOncePersistedStore(`vite-${runtimeId}`), forceFlagSet: FLAGS === void 0 ? void 0 : FLAGS === "" ? [] : normalizeFlagSet(FLAGS.split(".")), flagSets: "flags" in options ? createFlagSets(options.flags) : normalizeFlagSets(options.flagSets) }; } // src/utils/to-posix.ts import path3 from "path"; var POSIX_SEP = "/"; var WINDOWS_SEP = "\\"; var toPosix = path3.sep === WINDOWS_SEP ? (id) => id.replace(/\\/g, POSIX_SEP) : (id) => id; // src/plugins/build-ssr.ts var virtualArcServerModuleId = "\0arc-server-virtual"; var arcPrefix = "\0arc-"; var arcJsSuffix = ".mjs"; var arcProxyPrefix = `${arcPrefix}proxy:`; function pluginBuildSSR({ store, flagSets, forceFlagSet }) { let root; let proxyModuleId = 0; let metaForProxy = /* @__PURE__ */ new Map(); return { name: "arc-vite:build-ssr", enforce: "pre", api: { getMarkoAssetCodeForEntry(id) { return `__ARC_ASSETS__(${JSON.stringify( toPosix(path4.relative(root, id)) )})`; } }, apply(config, { command }) { return command === "build" && !!config.build?.ssr; }, configResolved(config) { root = config.root; }, async resolveId(source, importer, options) { if (importer) { switch (source) { case "arc-server": return importer === virtualArcServerModuleId ? this.resolve(source, void 0, options) : { id: virtualArcServerModuleId }; case "arc-server/proxy": return null; } if (isArcId(source)) { return source; } if (isArcId(importer)) { return source; } const resolved = await this.resolve(source, importer, { ...options, skipSelf: true }); if (resolved && !resolved.external) { const { id } = resolved; const matches = getMatches(id, flagSets); if (matches) { const proxyId = nextProxyId(); metaForProxy.set(proxyId, { resolved, matches }); return proxyId; } } return resolved; } return null; }, async load(id) { if (id === virtualArcServerModuleId) { return { code: `import * as arc from "arc-server"; export * from "arc-server"; globalThis.__ARC_FLAGS__ = arc.getFlags; ${forceFlagSet ? `const forcedFlags = {${forceFlagSet.map( (name) => `${JSON.stringify(name)}:true` )}}; export function setFlags() { return arc.setFlags(forcedFlags); } export function withFlags(_, fn) { return arc.withFlags(forcedFlags, fn); }` : ""} export function getAssets(entry, { base = import.meta.env.BASE_URL, injectAttrs = "" } = {}) { const manifest = __ARC_ASSETS__(entry); return { "head-prepend": partsToString(manifest["head-prepend"], base, injectAttrs), head: partsToString(manifest["head"], base, injectAttrs), "body-prepend": partsToString(manifest["body-prepend"], base, injectAttrs), body: partsToString(manifest["body"], base, injectAttrs) }; }; function partsToString(parts, base, injectAttrs) { if (!parts) return; let html = ""; for (const part of parts) { html += part === 0 ? injectAttrs : part === 1 ? base : part; } return html; } `, moduleSideEffects: true }; } if (isArcProxyId(id)) { const { resolved, matches } = metaForProxy.get(id); let code = ""; if (isGlobalCSSFile(resolved.id)) { for (const { value } of matches.alternates) { code += `import ${JSON.stringify(value)}; `; } code += `import ${JSON.stringify(matches.default)}; `; return { code, moduleSideEffects: "no-treeshake" }; } let matchCode = ""; let matchCodeSep = ""; let i = 0; for (const { flags, value } of matches.alternates) { const adaptedImportId = `_${indexToId(i++)}`; code += `import * as ${adaptedImportId} from ${JSON.stringify( value )}; `; matchCode += matchCodeSep + flags.map((flag) => `f.${flag}`).join("&&") + "?" + adaptedImportId; matchCodeSep = ":"; } const defaultId = `_${indexToId(i)}`; code += `import * as ${defaultId} from ${JSON.stringify( matches.default )}; `; matchCode += `:${defaultId}`; let syntheticNamedExports = false; let hasNamedExports = false; let hasDefaultExport = false; if (isAssetFile(resolved.id)) { hasDefaultExport = true; } else { let info = this.getModuleInfo(resolved.id); if (!info?.ast) { info = await this.load(resolved); } if (info.exports) { hasDefaultExport = info.hasDefaultExport === true; hasNamedExports = info.exports.length >= (hasDefaultExport ? 2 : 1); } } if (hasNamedExports || hasDefaultExport) { const proxyCode = `/*@__PURE__*/createAdaptiveProxy({default:${defaultId},match(f){return ${matchCode}}})`; code += `import createAdaptiveProxy from "arc-server/proxy"; `; if (hasNamedExports) { syntheticNamedExports = "_"; code += `export const _ = ${proxyCode}; `; if (hasDefaultExport) { code += "export default _.default;\n"; } } else { code += `export default ${proxyCode}.default; `; } } else { code += "export {};\n"; } return { code, syntheticNamedExports, moduleSideEffects: "no-treeshake" }; } return null; }, closeBundle() { clearCache(); proxyModuleId = 0; metaForProxy = /* @__PURE__ */ new Map(); }, generateBundle(outputOptions, bundle, isWrite) { if (!isWrite) { this.error("arc-vite-build-ssr requires write=true"); } const serverEntryFiles = []; const cwd2 = process.cwd(); const dir = outputOptions.dir ? path4.resolve(outputOptions.dir) : path4.resolve(outputOptions.file, ".."); for (const fileName in bundle) { const chunk = bundle[fileName]; if (chunk.type === "chunk" && chunk.isEntry && (chunk.imports.includes("arc-server") || chunk.moduleIds.includes(virtualArcServerModuleId))) { serverEntryFiles.push( path4.relative(cwd2, path4.resolve(dir, fileName)) ); } } if (!serverEntryFiles.length) { this.error("arc-vite: the server code did not import 'arc-server'"); } store.write({ serverEntryFiles }); } }; function nextProxyId() { return arcProxyPrefix + (proxyModuleId++).toString(36) + arcJsSuffix; } } function isArcId(id) { return id.startsWith(arcPrefix); } function isArcProxyId(id) { return id.startsWith(arcProxyPrefix); } // src/plugins/build-web.ts import { promises as fs3 } from "fs"; import path5 from "path"; // src/utils/filename-encoding.ts import { Buffer } from "buffer"; var cwd = process.cwd(); var encodeCwdReg = new RegExp(`~|${escapeReg(cwd)}`, "g"); var decodeCwdReg = /_?~/g; function encodeFileName(str) { return Buffer.from( str.replace(encodeCwdReg, encodeReplace), "utf-8" ).toString("base64url"); } function decodeFileName(str) { return Buffer.from(str, "base64").toString("utf-8").replace(decodeCwdReg, decodeReplace); } function encodeReplace(match) { if (match === "~") { return "_~"; } return "~"; } function decodeReplace(match) { if (match === "~") { return cwd; } return "~"; } function escapeReg(value) { return value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d"); } // src/utils/manifest.ts import { parseDocument, ElementType, DomUtils } from "htmlparser2"; var { isComment, isTag } = DomUtils; var markerComment = "ARC_VITE"; var voidElements = /* @__PURE__ */ new Set([ "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr" ]); function generatManifest(basePath, html) { const dom = parseDocument(html); const headPrepend = []; const head = []; const bodyPrepend = []; const body = []; for (const node of dom.childNodes) { if (isTag(node) && node.tagName === "html") { for (const child of node.childNodes) { if (isTag(child)) { switch (child.tagName) { case "head": splitNodesByMarker(child.childNodes, headPrepend, head); break; case "body": splitNodesByMarker(child.childNodes, bodyPrepend, body); break; } } } } } return { "head-prepend": serializeOrUndefined(basePath, headPrepend), head: serializeOrUndefined(basePath, head), "body-prepend": serializeOrUndefined(basePath, bodyPrepend), body: serializeOrUndefined(basePath, body) }; } function generateHTML(code) { return `<!DOCTYPE html><html><head><!--${markerComment}--></head><body><!--${markerComment}--><script async type="module">${code}</script></body></html>`; } function serialize(basePath, nodes, parts) { let curString = parts ? parts.pop() : ""; parts ??= []; for (const node of nodes) { switch (node.type) { case ElementType.Tag: case ElementType.Style: case ElementType.Script: { const tag = node; const { name } = tag; let urlAttr; curString += `<${name}`; switch (tag.tagName) { case "script": parts.push(curString, 0 /* AssetAttrs */); urlAttr = "src"; curString = ""; break; case "style": parts.push(curString, 0 /* AssetAttrs */); curString = ""; break; case "link": urlAttr = "href"; if (tag.attribs.rel === "stylesheet" || tag.attribs.rel === "modulepreload" || tag.attribs.as === "style" || tag.attribs.as === "script") { parts.push(curString, 0 /* AssetAttrs */); curString = ""; } break; } for (const attr of tag.attributes) { if (attr.value === "") { curString += ` ${attr.name}`; } else if (attr.name === urlAttr) { curString += ` ${attr.name}="`; parts.push( curString, 1 /* PublicPath */, stripBasePath(basePath, attr.value).replace(/^\.\//, "").replace(/"/g, "&#39;") + '"' ); curString = ""; } else { curString += ` ${attr.name}="${attr.value.replace(/"/g, "&#39;")}"`; } } curString += ">"; if (tag.children.length) { parts.push(curString); serialize(basePath, tag.children, parts); curString = parts.pop(); } if (!voidElements.has(name)) { curString += `</${name}>`; } break; } case ElementType.Text: { const text = node.data; if (!/^\s*$/.test(text)) { curString += text; } break; } case ElementType.Comment: curString += `<!--${node.data}-->`; break; } } if (curString) { parts.push(curString); } return parts; } function serializeOrUndefined(basePath, nodes) { const result = serialize(basePath, nodes); if (result.length) { return result; } } function splitNodesByMarker(nodes, before, after) { for (let i = 0; i < nodes.length; i++) { let node = nodes[i]; if (isComment(node) && node.data === markerComment) { i++; for (; i < nodes.length; i++) { node = nodes[i]; after.push(node); } break; } before.push(node); } } function stripBasePath(basePath, path7) { if (path7.startsWith(basePath)) return path7.slice(basePath.length); return path7; } // src/utils/prepare-arc-entry-html.ts import toHTML from "dom-serializer"; import { Element, Text } from "domhandler"; import { parseDocument as parseDocument2, DomUtils as DomUtils2, ElementType as ElementType2 } from "htmlparser2"; var { isTag: isTag2, filter, appendChild, prepend } = DomUtils2; var parserOptions = { decodeEntities: false, encodeEntities: false }; var emptyScriptReg = /^(?:[\s;]+|\/\/[^\n]*|\/\*[\s\S]*?\*\/)*$/; function prepareArcEntryHTML(runtimeId, html, renderAssetURL, originalChunk, adaptedChunk) { const originalChunkURL = renderAssetURL(originalChunk.fileName); if (emptyScriptReg.test(adaptedChunk.code)) { return [ { tag: "script", attrs: { type: "module", async: true, crossorigin: true, src: originalChunkURL } } ]; } const dom = parseDocument2(html, parserOptions); const originalChunkIsEmpty = emptyScriptReg.test(originalChunk.code); const adaptedChunkURL = renderAssetURL(adaptedChunk.fileName); for (const script of filter(isModule, dom)) { if (script.attribs.src === adaptedChunkURL) { if (originalChunkIsEmpty) { prepend( script, new Element( "script", {}, [new Text(`${runtimeId}={}`)], ElementType2.Script ) ); } else { delete script.attribs.src; prepend( script, new Element( "script", {}, [new Text(`${runtimeId}={}`)], ElementType2.Script ) ); appendChild( script, new Text( `import ${JSON.stringify(adaptedChunkURL)} import ${JSON.stringify( originalChunkURL )}` ) ); } } } return toHTML(dom, parserOptions); } function isModule(node) { return isTag2(node) && node.tagName === "script" && node.attribs.type === "module" && !!node.attribs.src; } // src/utils/strip-entry-script.ts import toHTML2 from "dom-serializer"; import { parseDocument as parseDocument3, DomUtils as DomUtils3 } from "htmlparser2"; var { isTag: isTag3, removeElement, filter: filter2 } = DomUtils3; function stripEntryScript(entryScriptURL, html) { const dom = parseDocument3(html); for (const script of filter2(isModule2, dom)) { if (script.attribs.src === entryScriptURL) { removeElement(script); } } return toHTML2(dom); } function isModule2(node) { return isTag3(node) && node.tagName === "script" && node.attribs.type === "module" && !!node.attribs.src; } // src/plugins/build-web.ts var arcPrefix2 = "\0arc-"; var arcJsSuffix2 = ".mjs"; var arcInitPrefix = `${arcPrefix2}init:`; var arcProxyPrefix2 = `${arcPrefix2}proxy:`; var arcChunkFileNameReg = /(.+)\.arc(?:\.(.+))?\.html$/; function pluginBuildWeb({ runtimeId, flagSets, store }) { const apply = (config, { command }) => command === "build" && !config.build?.ssr; let globalIds = /* @__PURE__ */ new Map(); let metaForProxy = /* @__PURE__ */ new Map(); let adaptiveImporters = /* @__PURE__ */ new Map(); let bindingsByAdaptiveId = /* @__PURE__ */ new Map(); let metaForAdaptiveChunk = /* @__PURE__ */ new Map(); let proxyModuleId = 0; let initModuleId = 0; let basePath = "/"; let resolveAssetURL = (fileName) => basePath + fileName; return [ { name: "arc-vite:build-web", enforce: "pre", apply, configResolved(config) { basePath = config.base; const { renderBuiltUrl: originalRenderBuiltURL } = config.experimental; if (originalRenderBuiltURL) { resolveAssetURL = (fileName, from) => { const url = originalRenderBuiltURL(fileName, { ssr: false, type: "asset", hostId: from, hostType: "html" }); if (typeof url !== "string") { throw new Error( `renderBuiltURL must return a string for html assets` ); } return url; }; } }, closeBundle() { proxyModuleId = initModuleId = 0; globalIds = /* @__PURE__ */ new Map(); adaptiveImporters = /* @__PURE__ */ new Map(); bindingsByAdaptiveId = /* @__PURE__ */ new Map(); metaForAdaptiveChunk = /* @__PURE__ */ new Map(); metaForProxy = /* @__PURE__ */ new Map(); }, async resolveId(source, importer, options) { if (importer) { if (isArcId2(source)) { return source; } if (isArcId2(importer)) { return source; } const resolved = await this.resolve(source, importer, { ...options, skipSelf: true }); if (resolved && !resolved.external) { const { id } = resolved; const matches = getMatches(id, flagSets); if (matches) { const adaptiveImportsForImporter = adaptiveImporters.get(importer); if (adaptiveImportsForImporter) { adaptiveImportsForImporter.set(source, id); } else { adaptiveImporters.set(importer, /* @__PURE__ */ new Map([[source, id]])); } const proxyId = nextProxyId(); metaForProxy.set(proxyId, { resolved, matches }); return proxyId; } } return resolved; } else if (metaForAdaptiveChunk.has(source)) { return source; } else if (options.isEntry && !isArcId2(source)) { const resolved = await this.resolve(source, importer, { ...options, skipSelf: true }); if (resolved) { const importsForEntry = /* @__PURE__ */ new Set(); const adaptiveImportsForEntry = []; const scanImports = async (childId, seenImports, adaptiveImports) => { if (seenImports.has(childId)) return; seenImports.add(childId); if (isArcProxyId2(childId)) { adaptiveImports.push(childId); } else { const info = await this.load({ id: childId, resolveDependencies: true }); if (info) { await Promise.all( info.importedIdResolutions.map( (resolvedChild) => !resolvedChild.external && scanImports( resolvedChild.id, seenImports, adaptiveImports ) ) ); } } }; await scanImports( resolved.id, importsForEntry, adaptiveImportsForEntry ); const flagSetChunkIds = await Promise.all( flagSets.map(async (flagSet) => { const importsForFlagSet = new Set(importsForEntry); const resolvedAdaptiveImports = /* @__PURE__ */ new Map(); let pendingAdaptiveImports = adaptiveImportsForEntry; while (pendingAdaptiveImports.length) { const pending = pendingAdaptiveImports; pendingAdaptiveImports = []; await Promise.all( pending.map(async (adaptiveImport) => { const { matches } = metaForProxy.get(adaptiveImport); let adaptedImport; for (const { flags, value } of matches.alternates) { if (hasFlags(flagSet, flags)) { adaptedImport = value; break; } } adaptedImport ||= matches.default; resolvedAdaptiveImports.set( adaptiveImport, adaptedImport ); await scanImports( adaptedImport, importsForFlagSet, pendingAdaptiveImports ); }) ); } const id = `${resolved.id.replace(/\.[^.]+$/, "")}.arc${flagSet.length ? `.${flagSet.join(".")}` : ""}.html`; metaForAdaptiveChunk.set(id, { entryId: resolved.id, adaptiveImports: resolvedAdaptiveImports }); return id; }) ); for (const [ importer2, resolvedAdaptiveImports ] of adaptiveImporters) { const ast = this.getModuleInfo(importer2)?.ast || (await this.load({ id: importer2 })).ast; for (const child of ast.body) { if (child.type === "ImportDeclaration") { const id = resolvedAdaptiveImports.get( child.source.value ); if (!id) continue; let bindings = bindingsByAdaptiveId.get(id); if (bindings === true) continue; for (const specifier of child.specifiers) { switch (specifier.type) { case "ImportNamespaceSpecifier": bindingsByAdaptiveId.set(id, true); continue; case "ImportDefaultSpecifier": if (bindings) { bindings.add("default"); } else { bindings = /* @__PURE__ */ new Set(["default"]); bindingsByAdaptiveId.set(id, bindings); } break; case "ImportSpecifier": if (bindings) { bindings.add(specifier.imported.name); } else { bindings = /* @__PURE__ */ new Set([specifier.imported.name]); bindingsByAdaptiveId.set(id, bindings); } break; } } } } } for (const id of flagSetChunkIds) { this.emitFile({ type: "chunk", id }); } } return resolved; } return null; }, async load(id) { const adaptiveChunkMeta = metaForAdaptiveChunk.get(id); if (adaptiveChunkMeta) { let code = ""; const adaptiveImports = [...adaptiveChunkMeta.adaptiveImports]; for (let i = adaptiveImports.length; i--; ) { const [adaptiveImport, adaptedImport] = adaptiveImports[i]; code += `import ${JSON.stringify( encodeArcInitId(adaptiveImport, adaptedImport) )}; `; } code = generateHTML(code); return { code, moduleSideEffects: "no-treeshake" }; } else if (isArcProxyId2(id)) { const { resolved } = metaForProxy.get(id); let code = ""; if (isGlobalCSSFile(resolved.id)) { return { code: "" }; } let hasNamedExports = false; let hasDefaultExport = false; let syntheticNamedExports = false; if (isAssetFile(resolved.id)) { hasDefaultExport = true; } else { let info = this.getModuleInfo(resolved.id); if (!info?.ast) { info = await this.load(resolved); } if (info.exports) { hasDefaultExport = info.hasDefaultExport === true; hasNamedExports = info.exports.length >= (hasDefaultExport ? 2 : 1); } } if (hasNamedExports || hasDefaultExport) { const arcId = getArcId(id); if (hasNamedExports) { code += `export const {${arcId}} = ${runtimeId}; `; syntheticNamedExports = arcId; if (hasDefaultExport) { code += `export default ${arcId}.default; `; } } else { code += `export default ${runtimeId}.${arcId}.default; `; } } else { code = "export {};\n"; } return { code, syntheticNamedExports, moduleSideEffects: false }; } else if (isArcInitId(id)) { const [adaptiveImport, adaptedImport] = decodeArcInitId(id); const bindings = bindingsByAdaptiveId.get(adaptiveImport); if (!bindings || isGlobalCSSFile(adaptiveImport)) { return { code: `import ${JSON.stringify(adaptedImport)}; `, moduleSideEffects: "no-treeshake" }; } const arcId = getArcId(adaptiveImport); return { code: `import * as _${arcId} from ${JSON.stringify( adaptedImport )} ${runtimeId}.${arcId}=${bindings === true ? `_${arcId}` : `{${Array.from( bindings, (binding) => `${JSON.stringify(binding)}:_${arcId}[${JSON.stringify( binding )}]` ).join(",")}}`}; `, moduleSideEffects: "no-treeshake" }; } return null; }, transformIndexHtml(html, { chunk, bundle }) { if (!bundle) return; const moduleId = chunk?.facadeModuleId; if (!moduleId) return; const adaptiveChunkMeta = metaForAdaptiveChunk.get(moduleId); if (adaptiveChunkMeta) { const { entryId } = adaptiveChunkMeta; for (const curFile in bundle) { const curChunk = bundle[curFile]; if (curChunk.type === "chunk" && curChunk.isEntry && curChunk.facadeModuleId === entryId) { return prepareArcEntryHTML( runtimeId, html, (fileName) => resolveAssetURL(fileName, entryId), curChunk, chunk ); } } return; } return stripEntryScript( resolveAssetURL(chunk.fileName, moduleId), html ); } }, { name: "arc-vite:build-web:post", enforce: "post", apply, async generateBundle(_, bundle, isWrite) { if (!isWrite) { this.error( "arc-vite: generateBundle cannot be called with isWrite=false" ); } const { serverEntryFiles } = await store.read().catch(() => { this.error( "arc-vite: failed to read manifest code. This likely means that the server bundle was not created before browser bundle." ); }); const flaggedManifestByEntry = /* @__PURE__ */ new Map(); for (const fileName in bundle) { const chunk = bundle[fileName]; if (chunk.type === "asset") { const arcHTMLChunkMatch = arcChunkFileNameReg.exec(chunk.fileName); if (!arcHTMLChunkMatch) continue; delete bundle[fileName]; const [, entryName, flagSetStr] = arcHTMLChunkMatch; const flaggedManifest = { flags: flagSetStr ? flagSetStr.split(".") : [], manifest: generatManifest(basePath, chunk.source.toString()) }; const flaggedAssetsForEntry = flaggedManifestByEntry.get(entryName); if (flaggedAssetsForEntry) { flaggedAssetsForEntry.push(flaggedManifest); flaggedManifestByEntry.set(entryName, flaggedAssetsForEntry); } else { flaggedManifestByEntry.set(entryName, [flaggedManifest]); } } } let manifestCode = `;function __ARC_ASSETS__(entry) {const f = __ARC_FLAGS__() || {};switch(entry) {`; for (const [ entryName, flaggedAssetsForEntry ] of flaggedManifestByEntry) { const defaultFlaggedAssets = flaggedAssetsForEntry.sort(compareFlaggedObject).pop(); let matchCodeSep = ""; manifestCode += `case ${JSON.stringify(entryName)}:return `; for (const { flags, manifest } of flaggedAssetsForEntry) { manifestCode += matchCodeSep + flags.map((flag) => `f.${flag}`).join("&&") + "?" + JSON.stringify(manifest); matchCodeSep = ":"; } manifestCode += `:${JSON.stringify(defaultFlaggedAssets.manifest)};`; } manifestCode += `}return {"head": ["<script>console.error('Unable to load adaptive arc files, unknown entry was provided when asking for assets.')</script>"]}}; `; await Promise.all( serverEntryFiles.map((file) => fs3.appendFile(file, manifestCode)) ); } } ]; function nextProxyId() { return arcProxyPrefix2 + (proxyModuleId++).toString(36) + arcJsSuffix2; } function encodeArcInitId(adaptiveImport, adaptedImport) { return `${arcInitPrefix + (initModuleId++).toString(36)}:${(adaptiveImport === adaptedImport ? encodeFileName(adaptiveImport) : `${encodeFileName(adaptiveImport)},${encodeFileName( adaptedImport[0] === "\0" ? adaptedImport : path5.relative(path5.dirname(adaptiveImport), adaptedImport) )}`) + arcJsSuffix2}`; } function getArcId(source) { let id = globalIds.get(source); if (id === void 0) { id = indexToId(globalIds.size); globalIds.set(source, id); } return id; } } function isArcId2(id) { return id.startsWith(arcPrefix2); } function isArcProxyId2(id) { return id.startsWith(arcProxyPrefix2); } function isArcInitId(id) { return id.startsWith(arcInitPrefix); } function decodeArcInitId(id) { const prefixEnd = id.indexOf(":", arcInitPrefix.length + 1) + 1; const sepStart = id.indexOf(",", prefixEnd); if (sepStart === -1) { const adaptedImport2 = decodeFileName( id.slice(prefixEnd, -arcJsSuffix2.length) ); return [adaptedImport2, adaptedImport2]; } const adaptiveImport = decodeFileName(id.slice(prefixEnd, sepStart)); const relativeAdaptedImport = decodeFileName( id.slice(sepStart + 1, -arcJsSuffix2.length) ); const adaptedImport = relativeAdaptedImport[0] === "\0" ? relativeAdaptedImport : path5.join(adaptiveImport, "..", relativeAdaptedImport); return [adaptiveImport, adaptedImport]; } // src/plugins/serve.ts import { createRequire } from "module"; import path6 from "path"; function pluginServe({ flagSets, forceFlagSet }) { const flagSet = forceFlagSet?.length ? forceFlagSet : void 0; return { name: "arc-vite:serve", enforce: "pre", apply(_, { command }) { return command === "serve"; }, async config(config) { Object.assign(createRequire(import.meta.url)("arc-server"), { getAssets() { return {}; } }); if (!flagSet) return; config.cacheDir = path6.resolve( `node_modules/.vite/arc/${flagSet.join(".")}` ); config.optimizeDeps ??= {}; config.optimizeDeps.esbuildOptions ??= {}; config.optimizeDeps.esbuildOptions.plugins ??= []; config.optimizeDeps.esbuildOptions.plugins.unshift({ name: "arc-vite:serve:esbuild", setup(build) { const arcProxyPrefix3 = "arc-proxy:"; build.onResolve( { filter: new RegExp(`^${arcProxyPrefix3}`) }, (args) => { return { path: args.path.slice(arcProxyPrefix3.length) }; } ); build.onLoad({ filter: /./ }, (args) => { const adaptedImport = getAdaptedMatch(args.path, flagSets, flagSet); if (adaptedImport) { const proxiedImportCode = JSON.stringify( arcProxyPrefix3 + adaptedImport ); return { loader: "js", contents: `module.exports = require(${proxiedImportCode}); ` }; } }); } }); }, async resolveId(source, importer, options) { if (importer && flagSet) { const resolved = await this.resolve(source, importer, { ...options, skipSelf: true }); if (resolved) { return getAdaptedMatch(resolved.id, flagSets, flagSet) || resolved; } } return null; } }; } function getAdaptedMatch(id, flagSets, flagSet) { if (path6.isAbsolute(id)) { const matches = getMatches(id, flagSets); if (matches) { let adaptedImport; for (const { flags, value } of matches.alternates) { if (hasFlags(flagSet, flags)) { adaptedImport = value; break; } } adaptedImport ||= matches.default; if (adaptedImport !== id) { return adaptedImport; } } } } // src/index.ts function arcVite(options) { const pluginOptions = getInternalPluginOptions(options); return [].concat( pluginServe(pluginOptions), pluginBuildWeb(pluginOptions), pluginBuildSSR(pluginOptions) ); } export { createFlagSets, arcVite as default, hasFlags };