Set the correct content-type for CSS HMR (#3459)

* Set the correct content-type for CSS HMR

* Adds a changeset
This commit is contained in:
Matthew Phillips 2022-05-31 11:40:34 -04:00 committed by GitHub
parent 55820fa784
commit efccebb964
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 0 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Forces the correct mime type for CSS in HMR

View file

@ -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');

View file

@ -0,0 +1,11 @@
<html>
<head>
<title>Testing</title>
<style>
background { background: brown; }
</style>
</head>
<body>
<h1>Testing</h1>
</body>
</html>

View file

@ -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');
});
});