Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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/open-melons-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes a bug where vite virtual module ids were incorrectly added in the dev server
10 changes: 10 additions & 0 deletions packages/astro/e2e/fixtures/vite-virtual-modules/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from 'astro/config';

import virtual from "./src/plugins/virtual";

// https://astro.build/config
export default defineConfig({
vite: {
plugins: [virtual],
},
});
9 changes: 9 additions & 0 deletions packages/astro/e2e/fixtures/vite-virtual-modules/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@e2e/vite-virtual-modules",
"type": "module",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
import "virtual:dynamic.css";
---

<html lang="en">
<head>
<!-- Head Stuff -->
</head>
<body>
<h1>Astro</h1>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Plugin } from "vite";

const VIRTUAL_MODULE_ID = "virtual:dynamic.css";
const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;

export default {
name: VIRTUAL_MODULE_ID,
resolveId(source) {
if (!source.startsWith(VIRTUAL_MODULE_ID)) return;

return RESOLVED_VIRTUAL_MODULE_ID;
},
load(id) {
if (!id.startsWith(RESOLVED_VIRTUAL_MODULE_ID)) return;

return "body { background: red; }";
},
} satisfies Plugin;
52 changes: 52 additions & 0 deletions packages/astro/e2e/vite-virtual-modules.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { expect } from '@playwright/test';
import { testFactory } from './test-utils.js';

const test = testFactory(import.meta.url, { root: './fixtures/vite-virtual-modules/' });
const VIRTUAL_MODULE_ID = '/@id/__x00__virtual:dynamic.css';

let devServer;

test.beforeAll(async ({ astro }) => {
devServer = await astro.startDevServer();
});

test.afterAll(async () => {
await devServer.stop();
});

/**
*
* @param {import("@playwright/test").Page} page
* @param {string} element
* @param {string} attribute
* @returns {Promise<import("@playwright/test").Locator>}
*/
async function getElemForVirtual(page, element, attribute) {
const elements = await page.locator(element).all();

for (const elem of elements) {
const attr = await elem.getAttribute(attribute);

if (attr !== VIRTUAL_MODULE_ID) continue;

return elem;
}
}

test.describe('Vite Virtual Modules', () => {
test('contains style tag with virtual module id', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));

const style = await getElemForVirtual(page, 'style', 'data-vite-dev-id');

expect(style).not.toBeUndefined();
});

test('contains script tag with virtual module id', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));

const script = await getElemForVirtual(page, 'script', 'src');

expect(script).not.toBeUndefined();
});
});
6 changes: 6 additions & 0 deletions packages/astro/src/core/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export function viteID(filePath: URL): string {

export const VALID_ID_PREFIX = `/@id/`;
const NULL_BYTE_PLACEHOLDER = `__x00__`;
const NULL_BYTE_REGEX = /^\0/;

// Strip valid id prefix and replace null byte placeholder. Both are prepended to resolved ids
// as they are not valid browser import specifiers (by the Vite's importAnalysis plugin)
Expand All @@ -110,6 +111,11 @@ export function unwrapId(id: string): string {
: id;
}

// Reverses `unwrapId` function
export function wrapId(id: string): string {
return id.replace(NULL_BYTE_REGEX, `${VALID_ID_PREFIX}${NULL_BYTE_PLACEHOLDER}`);
}

export function resolvePages(config: AstroConfig) {
return new URL('./pages', config.srcDir);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/astro/src/vite-plugin-astro-server/css.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ModuleLoader } from '../core/module-loader/index.js';
import { viteID } from '../core/util.js';
import { viteID, wrapId } from '../core/util.js';
import { isBuildableCSSRequest } from './util.js';
import { crawlGraph } from './vite.js';

Expand Down Expand Up @@ -55,8 +55,8 @@ export async function getStylesForURL(
}

importedStylesMap.set(importedModule.url, {
id: importedModule.id ?? importedModule.url,
url: importedModule.url,
id: wrapId(importedModule.id ?? importedModule.url),
url: wrapId(importedModule.url),
content: css,
});
}
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

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

Loading