UNPKG

iles

Version:

Vite & Vue powered static site generator with partial hydration

128 lines (125 loc) 4.17 kB
import { resolveComponent, resolveImportPath } from "./chunk-CZOBZ67L.js"; import { debug, isString } from "./chunk-ROUSHGC2.js"; import { importModule } from "./chunk-HKPEBJDI.js"; // 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.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 = /* @__PURE__ */ Object.create(null); const declarations = nodes.flatMap((node) => node.data?.estree?.body?.filter(isImport)); declarations.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}'` } })) } } }; } export { remarkWrapIslands_default };