UNPKG

astro

Version:

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

73 lines (72 loc) • 2.82 kB
import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../../constants.js"; const astroEntryPrefix = "\0astro-entry:"; /** * When adding hydrated or client:only components as Rolldown inputs, sometimes we're not using all * of the export names, e.g. `import { Counter } from './ManyComponents.jsx'`. This plugin proxies * entries to re-export only the names that the user is using. */ export function pluginComponentEntry(internals) { const componentToExportNames = new Map(); mergeComponentExportNames(internals.discoveredHydratedComponents); mergeComponentExportNames(internals.discoveredClientOnlyComponents); for (const [componentId, exportNames] of componentToExportNames) { // If one of the imports has a dot, it's a namespaced import, e.g. `import * as foo from 'foo'` // and `<foo.Counter />`, in which case we re-export `foo` entirely and we don't need to handle // it in this plugin as it's default behaviour from Rolldown. if (exportNames.some((name) => name.includes(".") || name === "*")) { componentToExportNames.delete(componentId); } else { componentToExportNames.set(componentId, Array.from(new Set(exportNames))); } } function mergeComponentExportNames(components) { for (const [componentId, exportNames] of components) { if (componentToExportNames.has(componentId)) { componentToExportNames.get(componentId)?.push(...exportNames); } else { componentToExportNames.set(componentId, exportNames); } } } return { name: "@astro/plugin-component-entry", enforce: "pre", applyToEnvironment(environment) { return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client; }, config(config) { const rolldownInput = config.build?.rolldownOptions?.input; // Astro passes an array of inputs by default. Even though other Vite plugins could // change this to an object, it shouldn't happen in practice as our plugin runs first. if (Array.isArray(rolldownInput)) { // @ts-expect-error input is definitely defined here, but typescript thinks it doesn't config.build.rolldownOptions.input = rolldownInput.map((id) => { if (componentToExportNames.has(id)) { return astroEntryPrefix + id; } else { return id; } }); } }, resolveId: { filter: { id: new RegExp(`^${astroEntryPrefix}`) }, handler(id) { return id; } }, load: { filter: { id: new RegExp(`^${astroEntryPrefix}`) }, async handler(id) { const componentId = id.slice(astroEntryPrefix.length); const exportNames = componentToExportNames.get(componentId); if (exportNames) { return { code: `export { ${exportNames.join(", ")} } from ${JSON.stringify(componentId)}` }; } } } }; } export function normalizeEntryId(id) { return id.startsWith(astroEntryPrefix) ? id.slice(astroEntryPrefix.length) : id; }