UNPKG

iles

Version:

Vite & Vue powered static site generator with partial hydration

758 lines (757 loc) 26.2 kB
import { a as DIST_CLIENT_PATH, m as resolveAliases, o as HYDRATION_DIST_PATH, s as ISLAND_COMPONENT_PATH } from "./alias-Cyp8pcW6.mjs"; import { existsSync, promises } from "fs"; import { basename, extname, join, resolve } from "pathe"; import { loadConfigFromFile, mergeConfig } from "vite"; import MagicString from "magic-string"; import pc from "picocolors"; import creatDebugger from "debug"; import vue from "@vitejs/plugin-vue"; import components from "unplugin-vue-components/vite"; import pages from "@islands/pages"; import mdx from "@islands/mdx"; import { constants, promises as promises$1 } from "node:fs"; import process$1 from "node:process"; import { resolve as resolve$1 } from "node:path"; import childProcess from "node:child_process"; import util from "node:util"; import newSpinner from "mico-spinner"; import { detectPackageManager } from "@antfu/install-pkg"; import serialize from "@nuxt/devalue"; import { parse } from "vue/compiler-sfc"; import { init, parse as parse$1 } from "es-module-lexer"; //#region src/node/modules.ts function unwrapDefault(mod) { return mod?.default ? unwrapDefault(mod.default) : mod; } function slash(path) { return path.replace(/\\/g, "/"); } function importModule(path) { if (process.platform === "win32") { if (path.match(/^\w:\\/)) return import(`file:///${slash(path)}`).then(unwrapDefault); if (path.match(/^\w:\//)) return import(`file:///${path}`).then(unwrapDefault); } return import(path).then(unwrapDefault); } //#endregion //#region src/node/plugin/utils.ts const exec = util.promisify(childProcess.exec); const debug$1 = { config: creatDebugger("iles:config"), documents: creatDebugger("iles:documents"), mdx: creatDebugger("iles:mdx"), layout: creatDebugger("iles:layout"), detect: creatDebugger("iles:detect"), resolve: creatDebugger("iles:resolve"), build: creatDebugger("iles:build") }; async function installPackage(names, options = {}) { const detectedAgent = options.packageManager || await detectPackageManager(options.cwd) || "npm"; const [agent] = detectedAgent.split("@"); if (!Array.isArray(names)) names = [names]; const args = options.additionalArgs || []; if (options.preferOffline) if (detectedAgent === "yarn@berry") args.unshift("--cached"); else args.unshift("--prefer-offline"); if (agent === "pnpm" && await exists(resolve$1(options.cwd ?? process$1.cwd(), "pnpm-workspace.yaml"))) args.unshift("-w"); const command = `${agent} ${agent === "yarn" ? "add" : "install"} ${options.dev ? "-D" : ""} ${names.join(" ")} ${args.join(" ")}`; try { await exec(command, { cwd: options.cwd || process$1.cwd() }); } catch (error) { const { stderr, stdout } = error; if (stdout) console.log(stdout); if (stderr) console.error(stderr); throw new Error(`Auto-install of ${names.join(" ")} failed, install manually and try again!`); } } async function tryImportOrInstallModule(name) { try { return await importModule(name); } catch (error) { if (error.code !== "MODULE_NOT_FOUND") throw error; console.info(`\n${name} not found. Proceeding to auto-install.\n`); await withSpinner(`Installing ${name}`, async () => await installPackage(name, { dev: true, preferOffline: true, silent: true })); return await importModule(name); } } async function importLibrary(pkgName) { return await tryImportOrInstallModule(pkgName); } async function withSpinner(message, fn) { const spinner = newSpinner(message).start(); try { const result = await fn(); spinner.succeed(); return result; } catch (e) { spinner.fail(); throw e; } } function isString(val) { return typeof val === "string"; } function isStringPlugin(val) { return Array.isArray(val) && isString(val[0]); } function uniq(arr) { return [...new Set(arr.filter((x) => x))]; } function pascalCase(str) { return capitalize(camelCase(str)); } function camelCase(str) { return str.replace(/[^\w_]+(\w)/g, (_, c) => c ? c.toUpperCase() : ""); } function uncapitalize(str) { return str.charAt(0).toLowerCase() + str.slice(1); } function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } async function exists(filePath) { return await promises$1.access(filePath, constants.F_OK).then(() => true, () => false); } function compact(val) { return val.filter((x) => x); } //#endregion //#region src/node/plugin/parse.ts function parseId(id) { const index = id.indexOf("?"); if (index < 0) return { path: id, query: {} }; const query = Object.fromEntries(new URLSearchParams(id.slice(index))); return { path: id.slice(0, index), query }; } async function parseExports(code) { try { await init; return parse$1(code)[1].map((spec) => spec.n); } catch (error) { console.error(error); return []; } } async function parseImports(code) { try { await init; const imports = parse$1(code)[0]; const importMap = Object.create(null); imports.forEach(({ d: isDynamic, n: from, ss: statementStart, s: importPathStart }) => { if (isDynamic > -1 || !from) return; parseImportVariables(code.substring(statementStart, importPathStart)).forEach(([name, as = name]) => { importMap[as] = { name, as, from }; }); }); return importMap; } catch (error) { console.error(error); return {}; } } const importStatementRegex = /import\s*(.*?)\s*from['"\s]+$/s; const importVarRegex = /(?:\{\s*((?:[^,}]+[,\s]*)+)\}|([^,]+))(?:[,\s]*|\s*$)+/gs; const trim = (s) => s.trim(); function parseImportVariables(partialStatement) { const variablesStr = partialStatement.match(importStatementRegex)?.[1].trim(); if (!variablesStr) return []; return Array.from(variablesStr.matchAll(importVarRegex)).flatMap(([, inBrackets, outer]) => { if (inBrackets) return inBrackets.split(",").map(trim).filter((x) => x); outer = outer.trim(); return outer.includes(" as ") ? outer : `default as ${outer}`; }).map((variable) => variable.split(" as ").map(trim)); } //#endregion //#region src/node/plugin/wrap.ts async function wrapLayout(code, filename) { const { descriptor: { template }, errors } = parse(code, { filename }); if (errors.length > 0 || !template || !isString(template.attrs.layout)) return; const s = new MagicString(code); const nodes = template.ast?.children; if (!nodes?.length) return; const Layout = `${pascalCase(template.attrs.layout)}Layout`; debug$1.layout(`${template.attrs.layout} ${filename}`); s.appendLeft(nodes[0].loc.start.offset, `<${Layout}>`); s.appendRight(nodes[nodes.length - 1].loc.end.offset, `</${Layout}>`); return { code: s.toString(), map: s.generateMap({ hires: true }) }; } const scriptClientRE = /<script\b([^>]*\bclient:[^>]*)>([^]*?)<\/script>/; async function wrapIslandsInSFC(config, code, filename) { code = code.replace(scriptClientRE, (_, attrs, content) => `<script-client${attrs}>${content}<\/script-client>`); const { descriptor: { template, script, scriptSetup, customBlocks }, errors } = parse(code, { filename }); const scriptClientIndex = customBlocks.findIndex((b) => b.type === "script-client"); const scriptClient = scriptClientIndex > -1 && customBlocks[scriptClientIndex]; if (errors.length > 0) return; if (scriptClient && "setup" in scriptClient.attrs || scriptSetup && Object.keys(scriptSetup.attrs).some((attr) => attr.startsWith("client:"))) throw new Error("Incorrect usage of hydration strategy in script setup.\nSee https://iles-docs.netlify.app/guide/client-scripts#client-script-block"); if (!template?.ast?.children.length) { if (scriptClient) throw new Error(`Vue components with <script client:...> must define a template containing at least one tag. No valid template found in ${filename}`); return; } const sfcRootNode = template.ast; const s = new MagicString(code); const components = config.namedPlugins.components.api; if (scriptClient) await injectClientScript(sfcRootNode, s, filename, scriptClientIndex, scriptClient); const jsCode = scriptSetup?.loc?.source || script?.loc?.source; const imports = jsCode ? await parseImports(jsCode) : {}; let componentCounter = 0; let injectionOffset = scriptSetup?.loc?.start?.offset; const elements = sfcRootNode.children.filter((n) => n.tag); for (const child of elements) await visitSFCNode(child, s, resolveComponentImport); if (!scriptSetup && injectionOffset === 0) s.appendRight(0, "\n<\/script>\n"); return { code: s.toString(), map: s.generateMap({ hires: true }) }; async function resolveComponentImport(strategy, tagName) { debug$1.detect(`<${tagName} ${strategy}>`); if (imports[tagName]) return await resolveImportPath(config, imports[tagName], filename); const info = await resolveComponent(components, tagName, filename, componentCounter++); if (strategy !== "client:only") injectComponentImport(info); return info; } function injectComponentImport(info) { if (injectionOffset === void 0) { const opening = `<script setup lang="${script?.attrs?.lang || "ts"}">`; s.prepend(opening); injectionOffset = 0; } s.appendRight(injectionOffset, `\n${components.stringifyImport(info)};`); } } async function visitSFCNode(node, s, resolveComponentImport) { const strategy = "props" in node && node.props.find((prop) => prop.name.startsWith("client:"))?.name; if (strategy) { const { tag, loc: { start, end } } = node; const importMeta = await resolveComponentImport(strategy, tag); const componentProps = ` :component="${strategy === "client:only" ? null : importMeta.as}" componentName="${tag}" importName="${importMeta.name}" importFrom="${importMeta.from}" `; s.overwrite(start.offset + 1, start.offset + 1 + tag.length, `Island ${componentProps.replace(/\n\s*/g, " ")}`, { contentOnly: true }); if (!node.isSelfClosing) s.overwrite(end.offset - 1 - tag.length, end.offset - 1, "Island", { contentOnly: true }); } if ("children" in node) for (const child of node.children) await visitSFCNode(child, s, resolveComponentImport); } async function resolveComponent(components, tag, filename, counter) { const info = await components.findComponent(pascalCase(tag), filename); if (!info) throw new Error(`Could not resolve ${tag} in ${filename}. Make sure to import it explicitly, or add a component resolver.`); return { name: "default", ...info, as: `__ile_components_${counter}` }; } async function resolveImportPath(config, info, importer) { info.from = await config.resolvePath(info.from, importer) || info.from; return info; } async function injectClientScript(node, s, filename, index, block) { const { attrs, content, loc: { end } } = block; const { lang = "ts", ...props } = attrs; const importFrom = `${filename}?vue&index=${index}&clientScript=true&lang.${lang}`; if (!(await parseExports(content)).includes("onLoad")) if (attrs["client:load"] || attrs["client:only"]) s.appendLeft(end.offset, "\nexport const onLoad = undefined\n"); else { const prettyFilename = filename.slice(Math.max(0, filename.indexOf("src/"))); throw new Error(`Client script in ${prettyFilename} does not export 'onLoad'. Should be a function to execute when the strategy condition is met.`); } const elements = node.children.filter((n) => n.tag); if (elements.length === 1) { const el = elements[0]; if (!el.props.some((prop) => prop.name === "bind" && prop.loc.source.includes("$attrs"))) s.appendRight(el.loc.start.offset + 1 + el.tag.length, " v-bind=\"$attrs\""); } const lastTemplateChildNode = elements[elements.length - 1]; s.appendRight(lastTemplateChildNode.loc.end.offset, ` <Island v-bind='${JSON.stringify({ ...props, component: {}, componentName: "clientScript", importName: "onLoad", using: "vanilla", importFrom })}'/>`); } //#endregion //#region src/node/plugin/remarkWrapIslands.ts var remarkWrapIslands_default = ({ config }) => async (ast, file) => { let components = config.namedPlugins.components.api; let imports; let componentPromises = []; let componentCounter = 0; const unistUtilVisit = await importModule("unist-util-visit"); const visit = unistUtilVisit.visit || unistUtilVisit; const SKIP = unistUtilVisit.SKIP; visit(ast, (node) => { const strategy = isJsxElement(node) && node.attributes.find(isClientDirective)?.name; if (strategy) { wrapWithIsland(strategy, node, resolveComponentImport); return SKIP; } }); const componentsToImport = await Promise.all(componentPromises); if (componentsToImport.length > 0) ast.children.unshift(defineImports(componentsToImport)); async function resolveComponentImport(strategy, tagName) { debug$1.detect(`<${tagName} ${strategy}>`); if (!imports) imports = extractImports(ast.children.filter((node) => node.type === "mdxjsEsm")); if (imports[tagName]) return await resolveImportPath(config, imports[tagName], file.path); const info = resolveComponent(components, tagName, file.path, componentCounter++); if (strategy !== "client:only") componentPromises.push(info); return await info; } }; function isJsxElement(node) { return node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement"; } function isClientDirective(attr) { return "name" in attr && attr.name.startsWith("client:"); } function isImport(statement) { return statement.type === "ImportDeclaration"; } async function wrapWithIsland(strategy, node, resolveComponentImport) { const tagName = node.name; if (!tagName) return; node.name = "Island"; const importMeta = await resolveComponentImport(strategy, tagName); node.attributes.unshift(...jsxAttributes({ component: jsxExpression(strategy === "client:only" ? { type: "Literal", value: null, raw: "null" } : { type: "Identifier", name: importMeta.as }), componentName: tagName, importName: importMeta.name, importFrom: importMeta.from })); } function extractImports(nodes) { const imports = Object.create(null); nodes.flatMap((node) => node.data?.estree?.body?.filter(isImport)).forEach(({ specifiers, source: { value: from } }) => { if (isString(from)) specifiers.forEach((specifier) => { const as = specifier.local.name; imports[as] = { as, name: importedName(specifier), from }; }); }); return imports; } function importedName(specifier) { switch (specifier.type) { case "ImportDefaultSpecifier": return "default"; case "ImportNamespaceSpecifier": return "*"; default: if ("name" in specifier.imported) return specifier.imported.name; throw new Error(`Unpexected literal in import declaration: ${specifier.imported}`); } } function jsxExpression(expression) { return { type: "mdxJsxAttributeValueExpression", value: expression.name || expression.raw, data: { estree: { type: "Program", sourceType: "module", body: [{ type: "ExpressionStatement", expression }] } } }; } function jsxAttributes(val) { return Object.entries(val).map(([name, value]) => ({ type: "mdxJsxAttribute", name, value })); } function defineImports(components) { return { type: "mdxjsEsm", data: { estree: { type: "Program", sourceType: "module", body: components.map((component) => ({ type: "ImportDeclaration", specifiers: [{ type: "ImportSpecifier", imported: { type: "Identifier", name: component.name }, local: { type: "Identifier", name: component.as } }], source: { type: "Literal", value: component.from, raw: `'${component.from}'` } })) } } }; } //#endregion //#region src/node/utils.ts function pathToHtmlFilename(path, filename) { if (extname(path)) return path; if (!path.endsWith("/") && filename && basename(filename).split(".")[0] === "index") path += "/"; return path + (path.endsWith("/") ? "index.html" : ".html"); } function explicitHtmlPath(path, filename) { const htmlFilename = pathToHtmlFilename(path, filename); return htmlFilename.endsWith("/index.html") ? htmlFilename.replace(/\/index\.html$/, "/") : htmlFilename; } //#endregion //#region src/node/config.ts const debug = creatDebugger("iles:config"); const IlesComponentResolver = (name) => { if (name === "Island") return { from: ISLAND_COMPONENT_PATH }; if (name === "Head") return { name: "Head", from: "@unhead/vue/components" }; }; function IlesLayoutResolver(config) { return (name) => { const [layoutName, isLayout] = name.split("Layout", 2); if (layoutName && isLayout === "") { const layoutFile = join(config.layoutsDir, `${uncapitalize(camelCase(layoutName))}.vue`); if (existsSync(layoutFile)) return { name: "default", from: layoutFile }; } }; } async function resolveConfig(root, env) { if (!root) root = process.cwd(); if (!env) env = { mode: "development", command: "serve", isSsrBuild: false }; const appConfig = await resolveUserConfig(root, env); const srcDir = resolve(root, appConfig.srcDir); Object.assign(appConfig, { srcDir, pagesDir: resolve(srcDir, appConfig.pagesDir), outDir: resolve(root, appConfig.outDir), tempDir: resolve(root, appConfig.tempDir), layoutsDir: resolve(srcDir, appConfig.layoutsDir) }); for (const mod of appConfig.modules) await mod.configResolved?.(appConfig, env); appConfig.vite.define["import.meta.env.DISPOSE_ISLANDS"] = env.mode === "development" || appConfig.turbo; checkDeprecations(appConfig); return appConfig; } async function resolveUserConfig(root, configEnv) { const config = { root }; const { modules = [], ...userConfig } = await loadUserConfigFile(root, configEnv); if (userConfig.plugins) throw new Error(`îles 'plugins' have been renamed to 'modules'. If you want to provide Vite plugins instead, place them in 'vite:'. Received 'plugins' in ${userConfig.configPath}:\n${JSON.stringify(userConfig.plugins)}`); config.modules = compact(await resolveIlesModules([ { name: "iles:base-config", ...appConfigDefaults(config, userConfig, configEnv) }, mdx(), { name: "user-config", ...userConfig }, ...modules, pages() ]).then((modules) => modules.flat())); Object.assign(config, await applyModules(config, configEnv)); await setNamedPlugins(config, configEnv, config.namedPlugins); const siteUrl = config.siteUrl || ""; const protocolIndex = siteUrl.indexOf("//"); const baseIndex = siteUrl.indexOf("/", protocolIndex > -1 ? protocolIndex + 2 : 0); config.siteUrl = baseIndex > -1 ? siteUrl.slice(0, baseIndex) : siteUrl; config.base = baseIndex > -1 ? siteUrl.slice(baseIndex) : "/"; if (!config.base.endsWith("/")) config.base = `${config.base}/`; config.vite.base = config.base; config.vite.build.assetsDir = config.assetsDir; return config; } async function loadUserConfigFile(root, configEnv) { try { const { path, config = {} } = await loadConfigFromFile(configEnv, "iles.config.ts", root) || {}; if (path && config) { config.configPath = path; debug(`loaded config at ${pc.yellow(path)}`); } else debug("no iles.config.ts file found."); return config; } catch (error) { if (error.message.includes("Could not resolve")) { debug("no iles.config.ts file found."); return {}; } throw error; } } async function setNamedPlugins(config, env, plugins) { const ceChecks = config.modules.map((mod) => mod.vue?.template?.compilerOptions?.isCustomElement).filter((x) => x); config.vue.template.compilerOptions.isCustomElement = (tagName) => tagName.startsWith("ile-") || ceChecks.some((fn) => fn(tagName)); plugins.components = components(config.components); plugins.vue = vue(config.vue); const optionalPlugins = { async solid(options) { return (await importLibrary("vite-plugin-solid"))({ ssr: true, ...options }); }, async preact(options) { return (await importLibrary("@preact/preset-vite"))(options); }, async svelte(options) { const { svelte } = await importLibrary("@sveltejs/vite-plugin-svelte"); const dev = env.mode === "development"; return svelte({ emitCss: true, ...options, compilerOptions: { dev, ...options.compilerOptions } }); } }; for (const [optionName, createPlugin] of Object.entries(optionalPlugins)) { const addPlugin = config[optionName] || config.jsx === optionName; if (addPlugin) { const options = isObject(addPlugin) ? addPlugin : {}; config.vitePlugins.push(await createPlugin(options)); if (optionName === "preact") await tryImportOrInstallModule("preact-render-to-string"); } } } async function applyModules(config, configEnv) { for (const mod of config.modules) { if (mod.modules && mod.modules.length > 0) throw new Error(`Modules in îles can't specify the 'modules' option, return an array of modules instead. Found in ${mod.name}: ${JSON.stringify(mod.modules)}`); const { name, config: configFn, configResolved: _, ...moduleConfig } = mod; config = mergeConfig$1(config, moduleConfig); if (configFn) { const partialConfig = await configFn(config, configEnv); if (partialConfig) config = mergeConfig$1(config, partialConfig); } } chainModuleCallbacks(config, [ "extendFrontmatter", "extendRoute", "extendRoutes" ]); chainModuleCallbacks(config, [ "beforePageRender", "onSiteBundled", "onSiteRendered" ], "ssg"); return config; } async function resolveIlesModules(modules) { return await Promise.all(modules.map(resolveModule)); } async function resolveModule(mod) { if (isString(mod)) return await createIlesModule(mod); if (isStringPlugin(mod)) return await createIlesModule(...mod); return await mod; } async function createIlesModule(pkgName, ...options) { return (await tryImportOrInstallModule(pkgName))(...options); } function inferJSX(config) { const plugins = (config.vite?.plugins ?? []).flat(); for (const plugin of plugins) { if (!plugin) continue; const { name = "" } = plugin; if (name.includes("preact")) return "preact"; if (name.includes("solid")) return "solid"; } } function appConfigDefaults(appConfig, userConfig, env) { const { root } = appConfig; const isDevelopment = env.mode === "development"; const { drafts = isDevelopment, jsx = inferJSX(userConfig), srcDir = "src" } = userConfig; return { debug: true, drafts, turbo: false, jsx, root, base: "/", siteUrl: "", prettyUrls: true, ssg: { sitemap: true }, configPath: resolve(root, "iles.config.ts"), assetsDir: "assets", pagesDir: "pages", srcDir, outDir: "dist", layoutsDir: "layouts", tempDir: ".iles-ssg-temp", modules: [], namedPlugins: {}, resolvePath: void 0, vitePlugins: [], vite: viteConfigDefaults(root, userConfig), vue: { template: { compilerOptions: {} } }, async extendFrontmatter(frontmatter, filename) { frontmatter.meta.lastUpdated = (await promises.stat(filename)).mtime; }, extendRoute(route) { if (appConfig.prettyUrls === false) route.path = explicitHtmlPath(route.path, route.componentFilename); }, extendRoutes(routes) { if (isDevelopment) return [...routes, { path: "/:zzz(.*)*", name: "NotFoundInDev", componentFilename: "@islands/components/NotFound" }]; else if (!drafts) return routes.filter((route) => !route.frontmatter?.draft); }, markdown: { jsxRuntime: "automatic", jsxImportSource: "iles", providerImportSource: "iles", rehypePlugins: [], remarkPlugins: [[remarkWrapIslands_default, { get config() { return appConfig; } }]] }, components: { dts: true, extensions: [ "vue", "jsx", "tsx", "js", "ts", "mdx", "svelte" ], include: [ /\.vue$/, /\.vue\?vue/, /\.mdx?/ ], dirs: `${srcDir}/components`, resolvers: [IlesComponentResolver, IlesLayoutResolver(appConfig)], transformer: "vue3" } }; } function viteConfigDefaults(root, userConfig) { return { root, resolve: { alias: resolveAliases(root, userConfig), conditions: [ "module", "browser", "development" ], dedupe: [ "vue", "vue-router", "@unhead/vue", "@vue/devtools-api" ] }, server: { fs: { allow: [ root, DIST_CLIENT_PATH, HYDRATION_DIST_PATH ] } }, build: { cssCodeSplit: false }, define: {}, optimizeDeps: { include: [ "vue", "vue-router", "@unhead/vue", "@vue/devtools-api" ], exclude: [ "iles", "@nuxt/devalue", "@islands/hydration", "@islands/prerender", "vue/server-renderer" ] } }; } function mergeConfig$1(a, b, isRoot = true) { const merged = { ...a }; for (const key in b) { const value = b[key]; if (value == null) continue; const existing = merged[key]; if (Array.isArray(existing) && Array.isArray(value)) { merged[key] = [...existing, ...value]; continue; } if (isObject(existing) && isObject(value)) { if (isRoot && key === "vite") merged[key] = mergeConfig(existing, value); else merged[key] = mergeConfig$1(existing, value, false); continue; } merged[key] = value; } return merged; } function chainModuleCallbacks(config, callbackNames, option) { callbackNames.forEach((callbackName) => { const moduleCallbacks = config.modules.map((plugin) => (option ? plugin[option] : plugin)?.[callbackName]).filter((x) => x); if (moduleCallbacks.length > 0) { const original = option ? config[option] : config; original[callbackName] = chainCallbacks(moduleCallbacks); } }); } function chainCallbacks(fns) { return async (...args) => { for (let i = 0; i < fns.length; i++) { const result = await fns[i](...args); if (result) args[0] = result; } return args[0]; }; } function isObject(value) { return Object.prototype.toString.call(value) === "[object Object]"; } function checkDeprecations(config) { if (config.markdown?.extendFrontmatter) throw new Error("CHANGES REQUIRED: `markdown.extendFrontmatter` is now `extendFrontmatter`"); if (config.pages?.extendRoute) throw new Error("CHANGES REQUIRED: `pages.extendRoute` is now `extendRoute`"); if (config.pages?.onRoutesGenerated) throw new Error("CHANGES REQUIRED: `pages.onRoutesGenerated` is now `extendRoutes`"); if (config.pages) throw new Error("CHANGES REQUIRED: `pages` is no longer an option, see @islands/pages"); } //#endregion export { parseId as a, exists as c, uniq as d, wrapLayout as i, pascalCase as l, pathToHtmlFilename as n, parseImports as o, wrapIslandsInSFC as r, debug$1 as s, resolveConfig as t, serialize as u };