Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue: Remove hasDefaultExport check from appEntrypoint logic #9333

Merged
merged 6 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/selfish-lamps-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/vue': patch
---

Fixes issue with `appEntrypoint` when running `astro dev`
27 changes: 22 additions & 5 deletions packages/integrations/vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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 {
Expand All @@ -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.`
);
Expand All @@ -83,7 +100,7 @@ function virtualAppEntrypoint(options: ViteOptions) {
return noop;
}
},
} satisfies Rollup.Plugin;
} satisfies Plugin;
}

async function getViteConfiguration(options: ViteOptions): Promise<UserConfig> {
Expand Down
75 changes: 75 additions & 0 deletions packages/integrations/vue/test/app-entrypoint.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,50 @@ 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('component not included on page', async () => {
const html = await fixture.fetch('/').then(res => res.text());
const { document } = parseHTML(html);
const island = document.querySelector('astro-island');
const client = island.getAttribute('renderer-url');
expect(client).not.to.be.undefined;

const js = await fixture.fetch(client);
expect(js).not.to.match(/\w+\.component\(\"Bar\"/gm);
});

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;
Expand Down Expand Up @@ -121,3 +165,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);
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
console.log(123);
export const setup = () => {}

// no default export
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';

export default defineConfig({
integrations: [vue({
appEntrypoint: '/src/vue.ts'
})]
})
Original file line number Diff line number Diff line change
@@ -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:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<div id="bar">works</div>
</template>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
import Foo from '../components/Foo.vue';
---

<html>
<head>
<title>Vue App Entrypoint</title>
</head>
<body>
<Foo client:load />
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => {}
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading