Skip to content

Commit

Permalink
fix: use destination path for Content-Type header (#121)
Browse files Browse the repository at this point in the history
  • Loading branch information
tobz1000 committed Jul 2, 2024
1 parent 1898445 commit d68aec9
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 52 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-dingos-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"vite-plugin-static-copy": patch
---

The value of `Content-Type` header was inferred and set from the src file extension. It is now infered from the dest file extension.
39 changes: 11 additions & 28 deletions src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,40 +108,27 @@ function viaLocal(
return undefined
}

function getStaticHeaders(name: string, stats: Stats) {
let ctype = lookup(name) || ''
if (ctype === 'text/html') ctype += ';charset=utf-8'

const headers: OutgoingHttpHeaders = {
function getStaticHeaders(stats: Stats): OutgoingHttpHeaders {
return {
'Content-Length': stats.size,
'Content-Type': ctype,
'Last-Modified': stats.mtime.toUTCString(),
ETag: `W/"${stats.size}-${stats.mtime.getTime()}"`,
'Cache-Control': 'no-cache'
}

return headers
}

function getTransformHeaders(
name: string,
encoding: BufferEncoding | 'buffer',
content: string | Buffer
) {
let ctype = lookup(name) || ''
if (ctype === 'text/html') ctype += ';charset=utf-8'

const headers: OutgoingHttpHeaders = {
): OutgoingHttpHeaders {
return {
'Content-Length': Buffer.byteLength(
content,
encoding === 'buffer' ? undefined : encoding
),
'Content-Type': ctype,
ETag: `W/"${calculateMd5Base64(content)}"`,
'Cache-Control': 'no-cache'
}

return headers
}

function getMergeHeaders(headers: OutgoingHttpHeaders, res: ServerResponse) {
Expand All @@ -165,7 +152,7 @@ function sendStatic(
file: string,
stats: Stats
) {
const staticHeaders = getStaticHeaders(file, stats)
const staticHeaders = getStaticHeaders(stats)

if (req.headers['if-none-match'] === staticHeaders['ETag']) {
res.writeHead(304)
Expand Down Expand Up @@ -208,12 +195,10 @@ function sendStatic(
function sendTransform(
req: IncomingMessage,
res: ServerResponse,
file: string,
transform: TransformOptionObject,
transformedContent: string | Buffer
): void {
const transformHeaders = getTransformHeaders(
file,
transform.encoding,
transformedContent
)
Expand Down Expand Up @@ -243,7 +228,11 @@ function setHeaders(
// these files to be TypeScript files, and for Vite to serve them with
// this Content-Type.
if (/\.[tj]sx?$/.test(pathname)) {
res.setHeader('Content-Type', 'application/javascript')
res.setHeader('Content-Type', 'text/javascript')
} else {
let ctype = lookup(pathname) || ''
if (ctype === 'text/html') ctype += ';charset=utf-8'
res.setHeader('Content-Type', ctype)
}

if (headers) {
Expand Down Expand Up @@ -300,13 +289,7 @@ export function serveStaticCopyMiddleware(
}

setHeaders(res, pathname, server.headers)
sendTransform(
req,
res,
data.filepath,
transformOption,
transformedContent
)
sendTransform(req, res, transformOption, transformedContent)
return
}

Expand Down
24 changes: 24 additions & 0 deletions test/fixtures/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,30 @@ export default defineConfig({
transform(content) {
return content + '1'
}
},
{
src: 'foo.js',
dest: 'fixture12',
rename: filename => {
return `${filename}.txt`
}
},
{
src: 'foo.txt',
dest: 'fixture12',
transform(content) {
return JSON.stringify({ value: content.trim() })
},
rename: filename => {
return `${filename}.json`
}
},
{
src: 'foo.txt',
dest: 'fixture12',
rename: filename => {
return `${filename}.foo`
}
}
]
})
Expand Down
20 changes: 20 additions & 0 deletions test/testcases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ type Testcase = {
dest: string
transformedContent?: string
encoding?: BufferEncoding | 'buffer'
contentType?: string
}

export const testcases: Record<string, Testcase[]> = {
Expand Down Expand Up @@ -115,6 +116,25 @@ export const testcases: Record<string, Testcase[]> = {
name: 'overwrite=false with transform',
src: './public/fixture11/notOverwriteDir/bar.txt',
dest: '/fixture11/notOverwriteDir/bar.txt'
},
{
name: 'modified extension, known content-type',
src: 'foo.js',
dest: '/fixture12/foo.txt',
contentType: 'text/plain'
},
{
name: 'modified extension, transformed, known content-type',
src: null,
dest: '/fixture12/foo.json',
transformedContent: '{"value":"foo"}',
contentType: 'application/json'
},
{
name: 'modified extension, unknown content-type',
src: 'foo.txt',
dest: '/fixture12/foo.foo',
contentType: ''
}
],
'vite.absolute.config.ts': [
Expand Down
65 changes: 41 additions & 24 deletions test/tests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,23 @@ const fetchFromServer = async (
return res
}

const fetchTextContent = async (
const fetchContent = async (
server: ViteDevServer | PreviewServer,
path: string
path: string,
encoding?: BufferEncoding | 'buffer'
) => {
const res = await fetchFromServer(server, path)
const content = res.status === 200 ? await res.text() : null
return content ? normalizeLineBreak(content) : null
}
let content: string | ArrayBuffer | null = null

const fetchBufferContent = async (
server: ViteDevServer | PreviewServer,
path: string
) => {
const res = await fetchFromServer(server, path)
const content = res.status === 200 ? await res.arrayBuffer() : null
return content
if (res.status === 200) {
content =
encoding === 'buffer'
? await res.arrayBuffer()
: normalizeLineBreak(await res.text())
}

const contentType = res.headers.get('content-type')
return { content, contentType }
}

describe('serve', () => {
Expand All @@ -47,16 +48,24 @@ describe('serve', () => {
await server.close()
})

for (const { name, src, dest, transformedContent, encoding } of tests) {
for (const {
name,
src,
dest,
transformedContent,
encoding,
contentType
} of tests) {
// eslint-disable-next-line vitest/valid-title
test.concurrent(name, async () => {
const expected =
src === null ? null : await loadFileContent(src, encoding)
const actual =
encoding === 'buffer'
? await fetchBufferContent(server, dest)
: await fetchTextContent(server, dest)
expect(actual).toStrictEqual(transformedContent ?? expected)
const actual = await fetchContent(server, dest, encoding)
expect(actual.content).toStrictEqual(transformedContent ?? expected)

if (contentType !== undefined) {
expect(actual.contentType).toStrictEqual(contentType)
}
})
}
})
Expand Down Expand Up @@ -106,16 +115,24 @@ describe('build', () => {
})
})

for (const { name, src, dest, transformedContent, encoding } of tests) {
for (const {
name,
src,
dest,
transformedContent,
encoding,
contentType
} of tests) {
// eslint-disable-next-line vitest/valid-title
test.concurrent(name, async () => {
const expected =
src === null ? null : await loadFileContent(src, encoding)
const actual =
encoding === 'buffer'
? await fetchBufferContent(server, dest)
: await fetchTextContent(server, dest)
expect(actual).toStrictEqual(transformedContent ?? expected)
const actual = await fetchContent(server, dest, encoding)
expect(actual.content).toStrictEqual(transformedContent ?? expected)

if (contentType !== undefined) {
expect(actual.contentType).toStrictEqual(contentType)
}
})
}
})
Expand Down

0 comments on commit d68aec9

Please sign in to comment.