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:
parent
55820fa784
commit
efccebb964
4 changed files with 73 additions and 0 deletions
5
.changeset/fifty-mice-bow.md
Normal file
5
.changeset/fifty-mice-bow.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Forces the correct mime type for CSS in HMR
|
|
@ -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');
|
||||
|
|
11
packages/astro/test/fixtures/hmr-css/src/pages/index.astro
vendored
Normal file
11
packages/astro/test/fixtures/hmr-css/src/pages/index.astro
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Testing</title>
|
||||
<style>
|
||||
background { background: brown; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Testing</h1>
|
||||
</body>
|
||||
</html>
|
29
packages/astro/test/hmr-css.test.js
Normal file
29
packages/astro/test/hmr-css.test.js
Normal 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');
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue