summaryrefslogtreecommitdiff
path: root/packages/integrations/vue
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/vue')
-rw-r--r--packages/integrations/vue/client.js14
-rw-r--r--packages/integrations/vue/package.json41
-rw-r--r--packages/integrations/vue/server.js22
-rw-r--r--packages/integrations/vue/src/index.ts35
-rw-r--r--packages/integrations/vue/static-html.js27
-rw-r--r--packages/integrations/vue/tsconfig.json10
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"
+ }
+}