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/adapter-node-manifest-mime-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-node': patch
---

fix: serve static files with the Content-Type recorded in the manifest
5 changes: 5 additions & 0 deletions .changeset/kit-prerendered-mime-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: record the mime types of prerendered paths in the server manifest
26 changes: 15 additions & 11 deletions packages/adapter-node/src/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,21 @@ function serve(path, client = false) {
etag: true,
gzip: PRECOMPRESS,
brotli: PRECOMPRESS,
setHeaders: client
? (res, pathname) => {
// only apply to build directory, not e.g. version.json
if (
pathname.startsWith(`/${manifest.appPath}/immutable/`) &&
res.statusCode === 200
) {
res.setHeader('cache-control', 'public,max-age=31536000,immutable');
}
}
: undefined
setHeaders: (res, pathname) => {
// `sirv` uses its own bundled `mrmime`, which the manifest's added types never reach
let type = manifest.mimeTypes[pathname.slice(pathname.lastIndexOf('.'))];
if (type === 'text/html') type += ';charset=utf-8';
if (type) res.setHeader('content-type', type);

// only apply to build directory, not e.g. version.json
if (
client &&
pathname.startsWith(`/${manifest.appPath}/immutable/`) &&
res.statusCode === 200
) {
res.setHeader('cache-control', 'public,max-age=31536000,immutable');
}
}
})
: undefined;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const prerender = true;

export function GET() {
return new Response(new Uint8Array([0, 0, 1, 0]), {
headers: { 'content-type': 'image/x-icon' }
});
}
2 changes: 2 additions & 0 deletions packages/adapter-node/test/apps/basic/static/page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!doctype html>
<p>hi</p>
Binary file not shown.
21 changes: 21 additions & 0 deletions packages/adapter-node/test/apps/basic/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,24 @@ test('does not set X-Accel-Buffering header on other responses', async ({ reques
const response = await request.get('/');
expect(response.headers()['x-accel-buffering']).toBeUndefined();
});

test('serves static files with the Content-Type from the manifest', async ({ request }) => {
// https://github.com/sveltejs/kit/issues/13753
const response = await request.get('/test.ico');
expect(response.status()).toBe(200);
expect(response.headers()['content-type']).toBe('image/x-icon');
});

test('serves prerendered endpoints with the Content-Type from the manifest', async ({
request
}) => {
const response = await request.get('/prerendered.ico');
expect(response.status()).toBe(200);
expect(response.headers()['content-type']).toBe('image/x-icon');
});

test('serves static HTML with a charset', async ({ request }) => {
const response = await request.get('/page.html');
expect(response.status()).toBe(200);
expect(response.headers()['content-type']).toBe('text/html;charset=utf-8');
});
6 changes: 6 additions & 0 deletions packages/kit/src/core/generate_manifest/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ export function generate_manifest({
mime_types[ext] ??= mime_lookup(ext) || '';
}

// record extensions that only exist in prerendered output, e.g. a prerendered favicon.ico
for (const pathname of prerendered) {
const ext = path.extname(pathname);
if (ext) mime_types[ext] ??= mime_lookup(ext) || '';
}

// prettier-ignore
// String representation of
/** @template {import('@sveltejs/kit').SSRManifest} T */
Expand Down
Loading