From efccebb9643f927d88e6b6f592e53c7c95e7c2b6 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Tue, 31 May 2022 11:40:34 -0400 Subject: [PATCH] Set the correct content-type for CSS HMR (#3459) * Set the correct content-type for CSS HMR * Adds a changeset --- .changeset/fifty-mice-bow.md | 5 ++++ .../src/vite-plugin-astro-server/index.ts | 28 ++++++++++++++++++ .../fixtures/hmr-css/src/pages/index.astro | 11 +++++++ packages/astro/test/hmr-css.test.js | 29 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 .changeset/fifty-mice-bow.md create mode 100644 packages/astro/test/fixtures/hmr-css/src/pages/index.astro create mode 100644 packages/astro/test/hmr-css.test.js diff --git a/.changeset/fifty-mice-bow.md b/.changeset/fifty-mice-bow.md new file mode 100644 index 000000000..b36bc3b64 --- /dev/null +++ b/.changeset/fifty-mice-bow.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Forces the correct mime type for CSS in HMR diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts index f71e28ba0..ba5b54813 100644 --- a/packages/astro/src/vite-plugin-astro-server/index.ts +++ b/packages/astro/src/vite-plugin-astro-server/index.ts @@ -335,6 +335,31 @@ async function handleRequest( } } +/** + * Vite HMR sends requests for new CSS and those get returned as JS, but we want it to be CSS + * since they are inside of a link tag for Astro. + */ +const forceTextCSSForStylesMiddleware: vite.Connect.NextHandleFunction = function(req, res, next) { + if(req.url) { + // We are just using this to parse the URL to get the search params object + // so the second arg here doesn't matter + const url = new URL(req.url, 'https://astro.build'); + // lang.css is a search param that exists on Astro, Svelte, and Vue components. + // We only want to override for astro files. + if(url.searchParams.has('astro') && url.searchParams.has('lang.css')) { + // Override setHeader so we can set the correct content-type for this request. + const setHeader = res.setHeader; + res.setHeader = function(key, value) { + if(key.toLowerCase() === 'content-type') { + return setHeader.call(this, key, 'text/css'); + } + return setHeader.apply(this, [key, value]); + }; + } + } + next(); +}; + export default function createPlugin({ config, logging }: AstroPluginOptions): vite.Plugin { return { name: 'astro:server', @@ -354,6 +379,9 @@ export default function createPlugin({ config, logging }: AstroPluginOptions): v viteServer.watcher.on('change', rebuildManifest.bind(null, false)); return () => { removeViteHttpMiddleware(viteServer.middlewares); + + // Push this middleware to the front of the stack so that it can intercept responses. + viteServer.middlewares.stack.unshift({ route: '', handle: forceTextCSSForStylesMiddleware }); viteServer.middlewares.use(async (req, res) => { if (!req.url || !req.method) { throw new Error('Incomplete request'); diff --git a/packages/astro/test/fixtures/hmr-css/src/pages/index.astro b/packages/astro/test/fixtures/hmr-css/src/pages/index.astro new file mode 100644 index 000000000..840e60e01 --- /dev/null +++ b/packages/astro/test/fixtures/hmr-css/src/pages/index.astro @@ -0,0 +1,11 @@ + + + Testing + + + +

Testing

+ + diff --git a/packages/astro/test/hmr-css.test.js b/packages/astro/test/hmr-css.test.js new file mode 100644 index 000000000..2705d8fd1 --- /dev/null +++ b/packages/astro/test/hmr-css.test.js @@ -0,0 +1,29 @@ +import { isWindows, loadFixture } from './test-utils.js'; +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; + +describe('HMR - CSS', () => { + if (isWindows) return; + + /** @type {import('./test-utils').Fixture} */ + let fixture; + /** @type {import('./test-utils').DevServer} */ + let devServer; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/hmr-css/', + }); + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('Timestamp URL used by Vite gets the right mime type', async () => { + let res = await fixture.fetch('/src/pages/index.astro?astro=&type=style&index=0&lang.css=&t=1653657441095'); + let headers = res.headers; + expect(headers.get('content-type')).to.equal('text/css'); + }); +});