Skip to content

Commit

Permalink
Support Vue JSX (#4897)
Browse files Browse the repository at this point in the history
Co-authored-by: Dan Jutan <danjutan@gmail.com>
  • Loading branch information
bluwy and Dan Jutan authored Sep 29, 2022
1 parent 24bad5a commit fd9d323
Show file tree
Hide file tree
Showing 12 changed files with 329 additions and 5 deletions.
6 changes: 6 additions & 0 deletions .changeset/honest-melons-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@astrojs/vue': minor
'astro': patch
---

Support Vue JSX
2 changes: 1 addition & 1 deletion packages/astro/src/runtime/server/render/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function guessRenderers(componentUrl?: string): string[] {
return ['@astrojs/vue'];
case 'jsx':
case 'tsx':
return ['@astrojs/react', '@astrojs/preact'];
return ['@astrojs/react', '@astrojs/preact', '@astrojs/vue (jsx)'];
default:
return ['@astrojs/react', '@astrojs/preact', '@astrojs/vue', '@astrojs/svelte'];
}
Expand Down
7 changes: 7 additions & 0 deletions packages/astro/test/fixtures/vue-jsx/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';

// https://astro.build/config
export default defineConfig({
integrations: [vue({ jsx: true })],
});
10 changes: 10 additions & 0 deletions packages/astro/test/fixtures/vue-jsx/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@test/vue-jsx",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/vue": "workspace:*",
"astro": "workspace:*",
"vue": "^3.2.39"
}
}
28 changes: 28 additions & 0 deletions packages/astro/test/fixtures/vue-jsx/src/components/Counter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { defineComponent, ref } from 'vue';

export default defineComponent({
props: {
start: {
type: String,
required: true
},
stepSize: {
type: String,
default: "1"
}
},
setup(props) {
const count = ref(parseInt(props.start))
const stepSize = ref(parseInt(props.stepSize))
const add = () => (count.value = count.value + stepSize.value);
const subtract = () => (count.value = count.value - stepSize.value);
return () => (
<div class="counter">
<h1><slot /></h1>
<button onClick={subtract}>-</button>
<pre>{count.value}</pre>
<button onClick={add}>+</button>
</div>
)
},
})
15 changes: 15 additions & 0 deletions packages/astro/test/fixtures/vue-jsx/src/components/Result.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<pre>{{ value }}</pre>
</template>

<script>
export default {
props: {
value: {
type: Number,
required: true
}
}
}
</script>
35 changes: 35 additions & 0 deletions packages/astro/test/fixtures/vue-jsx/src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
import Counter from '../components/Counter.jsx'
import Result from '../components/Result.vue'
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width"
/>
<title>Vue component</title>
<style>
:global(:root) {
font-family: system-ui;
padding: 1em;
}
</style>
</head>
<body>
<main>
<Result value={2345}></Result>
<Counter start="0">SSR Rendered, No Client</Counter>
<Counter start="1" client:load>SSR Rendered, client:load</Counter>
<!-- Test island deduplication, i.e. same UID as the component above. -->
<Counter start="1" client:load>SSR Rendered, client:load</Counter>
<!-- Test island deduplication account for non-render affecting props. -->
<Counter start="1" step-size="2" client:load>SSR Rendered, client:load</Counter>
<Counter start="10" client:idle>SSR Rendered, client:idle</Counter>
<!-- Test that two client:visibles have unique uids -->
<Counter start="100" client:visible>SSR Rendered, client:visible</Counter>
<Counter start="1000" client:visible>SSR Rendered, client:visible</Counter>
</main>
</body>
</html>
30 changes: 30 additions & 0 deletions packages/astro/test/vue-jsx.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { expect } from 'chai';
import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';

describe('Vue JSX', () => {
let fixture;

before(async () => {
fixture = await loadFixture({
root: './fixtures/vue-jsx/',
});
});

describe('build', () => {
before(async () => {
await fixture.build();
});

it('Can load Vue JSX', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);

const allPreValues = $('pre')
.toArray()
.map((el) => $(el).text());

expect(allPreValues).to.deep.equal(['2345', '0', '1', '1', '1', '10', '100', '1000']);
});
});
});
37 changes: 37 additions & 0 deletions packages/integrations/vue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,40 @@ export default {
})],
}
```

### jsx

You can use Vue JSX by setting `jsx: true`.

__`astro.config.mjs`__

```js
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';

export default defineConfig({
integrations: [
vue({ jsx: true })
],
});
```

This will enable rendering for both Vue and Vue JSX components. To customize the Vue JSX compiler, pass an options object instead of a boolean. See the `@vitejs/plugin-vue-jsx` [docs](https://github.com/vitejs/vite/tree/main/packages/plugin-vue-jsx) for more details.

__`astro.config.mjs`__

```js
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';

export default defineConfig({
integrations: [
vue({
jsx: {
// treat any tag that starts with ion- as custom elements
isCustomElement: tag => tag.startsWith('ion-')
}
})
],
});
```
2 changes: 2 additions & 0 deletions packages/integrations/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
},
"dependencies": {
"@vitejs/plugin-vue": "^3.0.0",
"@vitejs/plugin-vue-jsx": "^2.0.1",
"@vue/babel-plugin-jsx": "^1.1.1",
"@vue/compiler-sfc": "^3.2.39"
},
"devDependencies": {
Expand Down
39 changes: 35 additions & 4 deletions packages/integrations/vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { Options } from '@vitejs/plugin-vue';
import type { Options as VueOptions } from '@vitejs/plugin-vue';
import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx';
import vue from '@vitejs/plugin-vue';
import type { AstroIntegration, AstroRenderer } from 'astro';
import type { UserConfig } from 'vite';

interface Options extends VueOptions {
jsx?: boolean | VueJsxOptions;
}

function getRenderer(): AstroRenderer {
return {
name: '@astrojs/vue',
Expand All @@ -11,8 +16,23 @@ function getRenderer(): AstroRenderer {
};
}

function getViteConfiguration(options?: Options): UserConfig {
function getJsxRenderer(): AstroRenderer {
return {
name: '@astrojs/vue (jsx)',
clientEntrypoint: '@astrojs/vue/client.js',
serverEntrypoint: '@astrojs/vue/server.js',
jsxImportSource: 'vue',
jsxTransformOptions: async () => {
const jsxPlugin = (await import('@vue/babel-plugin-jsx')).default;
return {
plugins: [jsxPlugin],
};
},
};
}

async function getViteConfiguration(options?: Options): Promise<UserConfig> {
const config: UserConfig = {
optimizeDeps: {
include: ['@astrojs/vue/client.js', 'vue'],
exclude: ['@astrojs/vue/server.js'],
Expand All @@ -23,15 +43,26 @@ function getViteConfiguration(options?: Options): UserConfig {
noExternal: ['vueperslides'],
},
};

if (options?.jsx) {
const vueJsx = (await import('@vitejs/plugin-vue-jsx')).default;
const jsxOptions = typeof options.jsx === 'object' ? options.jsx : undefined;
config.plugins?.push(vueJsx(jsxOptions));
}

return config;
}

export default function (options?: Options): AstroIntegration {
return {
name: '@astrojs/vue',
hooks: {
'astro:config:setup': ({ addRenderer, updateConfig }) => {
'astro:config:setup': async ({ addRenderer, updateConfig }) => {
addRenderer(getRenderer());
updateConfig({ vite: getViteConfiguration(options) });
if (options?.jsx) {
addRenderer(getJsxRenderer());
}
updateConfig({ vite: await getViteConfiguration(options) });
},
},
};
Expand Down
Loading

0 comments on commit fd9d323

Please sign in to comment.