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/fix-cloudflare-style-propagation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes styles from Markdoc/MDX custom components not being extracted to `<head>` in the dev server when using the Cloudflare adapter with `prerenderEnvironment: 'node'` and rendering content through a wrapper component.
3 changes: 1 addition & 2 deletions packages/astro/src/core/module-loader/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import type { RunnableDevEnvironment } from 'vite';
import { collectErrorMetadata } from '../errors/dev/utils.js';
import { getViteErrorPayload } from '../errors/dev/vite.js';
import type { ModuleLoader, ModuleLoaderEventEmitter } from './runner.js';
import { ASTRO_VITE_ENVIRONMENT_NAMES } from '../constants.js';

export function createViteLoader(
viteServer: vite.ViteDevServer,
Expand Down Expand Up @@ -110,7 +109,7 @@ export function createViteLoader(
return viteServer.environments.client.hot.send(msg);
},
getSSREnvironment() {
return viteServer.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr] as RunnableDevEnvironment;
return ssrEnvironment;
},
isHttps() {
return !!ssrEnvironment.config.server.https;
Expand Down
74 changes: 74 additions & 0 deletions packages/astro/test/units/dev/module-loader.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as assert from 'node:assert/strict';
import { EventEmitter } from 'node:events';
import { describe, it } from 'node:test';
import { createViteLoader } from '../../../dist/core/module-loader/vite.js';

/**
* Creates a minimal mock ViteDevServer with stub watcher and client hot.
*/
function createMockViteServer(environments: Record<string, unknown>) {
return /** @type {any} */ ({
watcher: new EventEmitter(),
environments: {
client: { hot: { send: () => {} } },
...environments,
},
ssrFixStacktrace() {},
config: { root: '/tmp' },
}) as any;
}

/**
* Creates a minimal mock RunnableDevEnvironment.
*/
function createMockEnvironment(name: string) {
return /** @type {any} */ ({
name,
runner: { import: async () => ({}) },
pluginContainer: {
resolveId: async () => null,
getModuleInfo: () => null,
},
moduleGraph: {
getModuleById: () => undefined,
getModulesByFile: () => undefined,
idToModuleMap: new Map(),
invalidateModule: () => {},
},
config: { server: { https: false } },
}) as any;
}

describe('createViteLoader', () => {
it('getSSREnvironment returns the passed ssrEnvironment, not always the ssr env', () => {
const ssrEnv = createMockEnvironment('ssr');
const prerenderEnv = createMockEnvironment('prerender');

const viteServer = createMockViteServer({
ssr: ssrEnv,
prerender: prerenderEnv,
});

// Create a loader with the prerender environment (as Cloudflare adapter does
// when prerenderEnvironment: 'node' is set)
const loader = createViteLoader(viteServer, prerenderEnv);

// getSSREnvironment() should return the passed environment (prerender),
// not the hardcoded viteServer.environments['ssr']
assert.equal(loader.getSSREnvironment(), prerenderEnv);
assert.notEqual(loader.getSSREnvironment(), ssrEnv);
});

it('getSSREnvironment returns ssr env when ssr env is passed', () => {
const ssrEnv = createMockEnvironment('ssr');

const viteServer = createMockViteServer({
ssr: ssrEnv,
});

const loader = createViteLoader(viteServer, ssrEnv);

// When the ssr env is passed directly, getSSREnvironment returns it
assert.equal(loader.getSSREnvironment(), ssrEnv);
});
});
Loading