diff options
Diffstat (limited to 'packages/integrations/alpinejs/src/index.ts')
-rw-r--r-- | packages/integrations/alpinejs/src/index.ts | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/packages/integrations/alpinejs/src/index.ts b/packages/integrations/alpinejs/src/index.ts new file mode 100644 index 000000000..61a50d705 --- /dev/null +++ b/packages/integrations/alpinejs/src/index.ts @@ -0,0 +1,111 @@ +import { resolve } from 'node:path'; +import type { AstroIntegration } from 'astro'; +import type { Plugin } from 'vite'; + +interface Options { + /** + * You can extend Alpine by setting this option to a root-relative import specifier (for example, `entrypoint: "/src/entrypoint"`). + * + * The default export of this file should be a function that accepts an Alpine instance prior to starting, allowing the use of custom directives, plugins and other customizations for advanced use cases. + * + * ```js + * // astro.config.mjs + * import { defineConfig } from 'astro/config'; + * import alpine from '@astrojs/alpinejs'; + * + * export default defineConfig({ + * // ... + * integrations: [alpine({ entrypoint: '/src/entrypoint' })], + * }); + * ``` + * + * ```js + * // src/entrypoint.ts + * import type { Alpine } from 'alpinejs' + * + * export default (Alpine: Alpine) => { + * Alpine.directive('foo', el => { + * el.textContent = 'bar'; + * }) + * } + * ``` + */ + entrypoint?: string; +} + +function virtualEntrypoint(options?: Options): Plugin { + const virtualModuleId = 'virtual:@astrojs/alpinejs/entrypoint'; + const resolvedVirtualModuleId = '\0' + virtualModuleId; + + let isBuild: boolean; + let root: string; + let entrypoint: string | undefined; + + return { + name: '@astrojs/alpinejs/virtual-entrypoint', + config(_, { command }) { + isBuild = command === 'build'; + }, + configResolved(config) { + root = config.root; + if (options?.entrypoint) { + entrypoint = options.entrypoint.startsWith('.') + ? resolve(root, options.entrypoint) + : options.entrypoint; + } + }, + resolveId(id) { + if (id === virtualModuleId) { + return resolvedVirtualModuleId; + } + }, + load(id) { + if (id === resolvedVirtualModuleId) { + if (entrypoint) { + return `\ +import * as mod from ${JSON.stringify(entrypoint)}; + +export const setup = (Alpine) => { + if ('default' in mod) { + mod.default(Alpine); + } else { + ${ + !isBuild + ? `console.warn("[@astrojs/alpinejs] entrypoint \`" + ${JSON.stringify( + entrypoint, + )} + "\` does not export a default function. Check out https://docs.astro.build/en/guides/integrations-guide/alpinejs/#entrypoint.");` + : '' + } + } +}`; + } + return `export const setup = () => {};`; + } + }, + }; +} + +export default function createPlugin(options?: Options): AstroIntegration { + return { + name: '@astrojs/alpinejs', + hooks: { + 'astro:config:setup': ({ injectScript, updateConfig }) => { + // This gets injected into the user's page, so the import will pull + // from the project's version of Alpine.js in their package.json. + injectScript( + 'page', + `import Alpine from 'alpinejs'; +import { setup } from 'virtual:@astrojs/alpinejs/entrypoint'; +setup(Alpine); +window.Alpine = Alpine; +document.addEventListener('DOMContentLoaded', () => Alpine.start());`, + ); + updateConfig({ + vite: { + plugins: [virtualEntrypoint(options)], + }, + }); + }, + }, + }; +} |