0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-04-07 23:41:43 -05:00

Vue: Remove hasDefaultExport check from appEntrypoint logic (#9333)

This commit is contained in:
Nate Moore 2023-12-05 18:38:29 -06:00 committed by GitHub
parent cfb20550d3
commit b832cd1901
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 149 additions and 6 deletions

View file

@ -0,0 +1,5 @@
---
'@astrojs/vue': patch
---
Fixes issue with `appEntrypoint` when running `astro dev`

View file

@ -1,7 +1,7 @@
import type { Options as VueOptions } from '@vitejs/plugin-vue';
import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx';
import type { AstroIntegration, AstroIntegrationLogger, AstroRenderer } from 'astro';
import type { UserConfig, Rollup } from 'vite';
import type { UserConfig, Plugin } from 'vite';
import { fileURLToPath } from 'node:url';
import vue from '@vitejs/plugin-vue';
@ -42,15 +42,32 @@ function getJsxRenderer(): AstroRenderer {
function virtualAppEntrypoint(options: ViteOptions) {
const virtualModuleId = 'virtual:@astrojs/vue/app';
const resolvedVirtualModuleId = '\0' + virtualModuleId;
let getExports: (id: string) => Promise<string[]>;
return {
name: '@astrojs/vue/virtual-app',
buildStart() {
if (!getExports) {
getExports = async (id: string) => {
const info = await this.load.call(this, { id });
return info.exports ?? [];
}
}
},
configureServer(server) {
if (!getExports) {
getExports = async (id: string) => {
const mod = await server.ssrLoadModule(id);
return Object.keys(mod) ?? [];
}
}
},
resolveId(id: string) {
if (id == virtualModuleId) {
return resolvedVirtualModuleId;
}
},
async load(id: string) {
const noop = `export const setup = () => {}`;
const noop = `export const setup = (app) => app;`;
if (id === resolvedVirtualModuleId) {
if (options.appEntrypoint) {
try {
@ -66,8 +83,8 @@ function virtualAppEntrypoint(options: ViteOptions) {
// This error is handled below, the message isn't shown to the user
throw new Error('Unable to resolve appEntrypoint');
}
const loaded = await this.load(resolved);
if (!loaded.hasDefaultExport) {
const exports = await getExports(resolved.id);
if (!exports.includes('default')) {
options.logger.warn(
`appEntrypoint \`${options.appEntrypoint}\` does not export a default function. Check out https://docs.astro.build/en/guides/integrations-guide/vue/#appentrypoint.`
);
@ -83,7 +100,7 @@ function virtualAppEntrypoint(options: ViteOptions) {
return noop;
}
},
} satisfies Rollup.Plugin;
} satisfies Plugin;
}
async function getViteConfiguration(options: ViteOptions): Promise<UserConfig> {

View file

@ -52,6 +52,39 @@ describe('App Entrypoint', () => {
});
});
describe('App Entrypoint no export default (dev)', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
let devServer;
before(async () => {
fixture = await loadFixture({
root: './fixtures/app-entrypoint-no-export-default/',
});
devServer = await fixture.startDevServer();
});
after(async () => {
await devServer.stop();
});
it('loads during SSR', async () => {
const html = await fixture.fetch('/').then(res => res.text());
const { document } = parseHTML(html);
const bar = document.querySelector('#foo > #bar');
expect(bar).not.to.be.undefined;
expect(bar.textContent).to.eq('works');
});
it('loads svg components without transforming them to assets', async () => {
const html = await fixture.fetch('/').then(res => res.text());
const { document } = parseHTML(html);
const client = document.querySelector('astro-island svg');
expect(client).not.to.be.undefined;
});
});
describe('App Entrypoint no export default', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
@ -121,3 +154,34 @@ describe('App Entrypoint relative', () => {
expect(js).not.to.match(/\w+\.component\(\"Bar\"/gm);
});
});
describe('App Entrypoint /src/absolute', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
before(async () => {
fixture = await loadFixture({
root: './fixtures/app-entrypoint-src-absolute/',
});
await fixture.build();
});
it('loads during SSR', async () => {
const data = await fixture.readFile('/index.html');
const { document } = parseHTML(data);
const bar = document.querySelector('#foo > #bar');
expect(bar).not.to.be.undefined;
expect(bar.textContent).to.eq('works');
});
it('component not included in renderer bundle', async () => {
const data = await fixture.readFile('/index.html');
const { document } = parseHTML(data);
const island = document.querySelector('astro-island');
const client = island.getAttribute('renderer-url');
expect(client).not.to.be.undefined;
const js = await fixture.readFile(client);
expect(js).not.to.match(/\w+\.component\(\"Bar\"/gm);
});
});

View file

@ -1,3 +1,3 @@
console.log(123);
export const setup = () => {}
// no default export

View file

@ -0,0 +1,8 @@
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';
export default defineConfig({
integrations: [vue({
appEntrypoint: '/src/vue.ts'
})]
})

View file

@ -0,0 +1,12 @@
{
"name": "@test/vue-app-entrypoint-src-absolute",
"version": "0.0.0",
"private": true,
"scripts": {
"astro": "astro"
},
"dependencies": {
"@astrojs/vue": "workspace:*",
"astro": "workspace:*"
}
}

View file

@ -0,0 +1,3 @@
<template>
<div id="bar">works</div>
</template>

View file

@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" fill="#ff0" r="40" stroke="#008000" stroke-width="4"/></svg>

After

Width:  |  Height:  |  Size: 158 B

View file

@ -0,0 +1,11 @@
<script setup>
import Bar from './Bar.vue'
import Circle from './Circle.svg?component'
</script>
<template>
<div id="foo">
<Bar />
<Circle/>
</div>
</template>

View file

@ -0,0 +1,12 @@
---
import Foo from '../components/Foo.vue';
---
<html>
<head>
<title>Vue App Entrypoint</title>
</head>
<body>
<Foo client:load />
</body>
</html>

View file

@ -0,0 +1 @@
export default () => {}

9
pnpm-lock.yaml generated
View file

@ -4860,6 +4860,15 @@ importers:
specifier: workspace:*
version: link:../../../../../astro
packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute:
dependencies:
'@astrojs/vue':
specifier: workspace:*
version: link:../../..
astro:
specifier: workspace:*
version: link:../../../../../astro
packages/integrations/vue/test/fixtures/basics:
dependencies:
'@astrojs/vue':