diff options
Diffstat (limited to 'packages/integrations/vue')
-rw-r--r-- | packages/integrations/vue/client.js | 14 | ||||
-rw-r--r-- | packages/integrations/vue/package.json | 41 | ||||
-rw-r--r-- | packages/integrations/vue/server.js | 22 | ||||
-rw-r--r-- | packages/integrations/vue/src/index.ts | 35 | ||||
-rw-r--r-- | packages/integrations/vue/static-html.js | 27 | ||||
-rw-r--r-- | packages/integrations/vue/tsconfig.json | 10 |
6 files changed, 149 insertions, 0 deletions
diff --git a/packages/integrations/vue/client.js b/packages/integrations/vue/client.js new file mode 100644 index 000000000..0ba4e8106 --- /dev/null +++ b/packages/integrations/vue/client.js @@ -0,0 +1,14 @@ +import { h, createSSRApp } from 'vue'; +import StaticHtml from './static-html.js'; + +export default (element) => (Component, props, children) => { + delete props['class']; + // Expose name on host component for Vue devtools + const name = Component.name ? `${Component.name} Host` : undefined; + const slots = {}; + if (children != null) { + slots.default = () => h(StaticHtml, { value: children }); + } + const app = createSSRApp({ name, render: () => h(Component, props, slots) }); + app.mount(element, true); +}; diff --git a/packages/integrations/vue/package.json b/packages/integrations/vue/package.json new file mode 100644 index 000000000..8fce8e77a --- /dev/null +++ b/packages/integrations/vue/package.json @@ -0,0 +1,41 @@ +{ + "name": "@astrojs/vue", + "version": "0.0.1", + "description": "Use Vue components within Astro", + "type": "module", + "types": "./dist/index.d.ts", + "author": "withastro", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/withastro/astro.git", + "directory": "packages/integrations/vue" + }, + "bugs": "https://github.com/withastro/astro/issues", + "homepage": "https://astro.build", + "exports": { + ".": "./dist/index.js", + "./*": "./*", + "./client.js": "./client.js", + "./server.js": "./server.js", + "./package.json": "./package.json" + }, + "scripts": { + "build": "astro-scripts build \"src/**/*.ts\" && tsc", + "dev": "astro-scripts dev \"src/**/*.ts\"" + }, + "dependencies": { + "@vitejs/plugin-vue": "^2.2.0" + }, + "devDependencies": { + "astro": "workspace:*", + "astro-scripts": "workspace:*", + "vue": "^3.2.30" + }, + "peerDependencies": { + "vue": "^3.2.30" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" + } +} diff --git a/packages/integrations/vue/server.js b/packages/integrations/vue/server.js new file mode 100644 index 000000000..1ae2b757b --- /dev/null +++ b/packages/integrations/vue/server.js @@ -0,0 +1,22 @@ +import { h, createSSRApp } from 'vue'; +import { renderToString } from 'vue/server-renderer'; +import StaticHtml from './static-html.js'; + +function check(Component) { + return !!Component['ssrRender']; +} + +async function renderToStaticMarkup(Component, props, children) { + const slots = {}; + if (children != null) { + slots.default = () => h(StaticHtml, { value: children }); + } + const app = createSSRApp({ render: () => h(Component, props, slots) }); + const html = await renderToString(app); + return { html }; +} + +export default { + check, + renderToStaticMarkup, +}; diff --git a/packages/integrations/vue/src/index.ts b/packages/integrations/vue/src/index.ts new file mode 100644 index 000000000..20adf0f66 --- /dev/null +++ b/packages/integrations/vue/src/index.ts @@ -0,0 +1,35 @@ +import type { AstroIntegration, AstroRenderer } from 'astro'; +import vue from '@vitejs/plugin-vue'; + +function getRenderer(): AstroRenderer { + return { + name: '@astrojs/vue', + clientEntrypoint: '@astrojs/vue/client.js', + serverEntrypoint: '@astrojs/vue/server.js', + }; +} + +function getViteConfiguration() { + return { + optimizeDeps: { + include: ['@astrojs/vue/client.js', 'vue'], + exclude: ['@astrojs/vue/server.js'], + }, + plugins: [vue()], + ssr: { + external: ['@vue/server-renderer'], + }, + }; +} + +export default function (): AstroIntegration { + return { + name: '@astrojs/vue', + hooks: { + 'astro:config:setup': ({ addRenderer, updateConfig }) => { + addRenderer(getRenderer()); + updateConfig({ vite: getViteConfiguration() }); + }, + }, + }; +} diff --git a/packages/integrations/vue/static-html.js b/packages/integrations/vue/static-html.js new file mode 100644 index 000000000..ff1459b6f --- /dev/null +++ b/packages/integrations/vue/static-html.js @@ -0,0 +1,27 @@ +import { h, defineComponent } from 'vue'; + +/** + * Astro passes `children` as a string of HTML, so we need + * a wrapper `div` to render that content as VNodes. + * + * This is the Vue + JSX equivalent of using `<div v-html="value" />` + */ +const StaticHtml = defineComponent({ + props: { + value: String, + }, + setup({ value }) { + if (!value) return () => null; + return () => h('astro-fragment', { innerHTML: value }); + }, +}); + +/** + * Other frameworks have `shouldComponentUpdate` in order to signal + * that this subtree is entirely static and will not be updated + * + * Fortunately, Vue is smart enough to figure that out without any + * help from us, so this just works out of the box! + */ + +export default StaticHtml; diff --git a/packages/integrations/vue/tsconfig.json b/packages/integrations/vue/tsconfig.json new file mode 100644 index 000000000..44baf375c --- /dev/null +++ b/packages/integrations/vue/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "allowJs": true, + "module": "ES2020", + "outDir": "./dist", + "target": "ES2020" + } +} |