Skip to content
Open
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
48 changes: 48 additions & 0 deletions packages/vite/src/node/server/__tests__/send.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { IncomingMessage, ServerResponse } from 'node:http'
import { describe, expect, test } from 'vitest'
import { send } from '../send'

function createReq(url = '/foo.js'): IncomingMessage {
return { url, method: 'GET', headers: {} } as IncomingMessage
}

function createRes(): ServerResponse & { body?: string | Buffer } {
const res = {
writableEnded: false,
statusCode: 0,
headers: {} as Record<string, unknown>,
setHeader(name: string, value: unknown) {
res.headers[name] = value
return res
},
end(chunk?: string | Buffer) {
res.body = chunk
res.writableEnded = true
},
}
return res as unknown as ServerResponse & { body?: string | Buffer }
}

describe('send fallback sourcemap', () => {
test('injects a fallback sourcemap for js without a map', () => {
const req = createReq()
const res = createRes()
send(req, res, 'const a = 1', 'js', {})
expect(res.body!.toString()).toContain('//# sourceMappingURL=')
})

test('skips the fallback sourcemap for very large js', () => {
const req = createReq()
const res = createRes()
const code = `export default ${JSON.stringify('x\n'.repeat(5_000_000))}`
send(req, res, code, 'js', {})
expect(res.body!.toString()).not.toContain('//# sourceMappingURL=')
})

test('does not inject a fallback sourcemap for non-js', () => {
const req = createReq('/foo.css')
const res = createRes()
send(req, res, '.a { color: red }', 'css', {})
expect(res.body!.toString()).not.toContain('sourceMappingURL=')
})
})
5 changes: 5 additions & 0 deletions packages/vite/src/node/server/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export interface SendOptions {
map?: SourceMap | { mappings: '' } | null
}

// skip the fallback sourcemap for large code to avoid OOM (#22132)
const MAX_FALLBACK_SOURCEMAP_CODE_LENGTH = 4 * 1024 * 1024

export function send(
req: IncomingMessage,
res: ServerResponse,
Expand Down Expand Up @@ -76,6 +79,8 @@ export function send(
// if the code has existing inline sourcemap, assume it's correct and skip
if (convertSourceMap.mapFileCommentRegex.test(code)) {
debug?.(`Skipped injecting fallback sourcemap for ${req.url}`)
} else if (code.length > MAX_FALLBACK_SOURCEMAP_CODE_LENGTH) {
debug?.(`Skipped injecting fallback sourcemap for large ${req.url}`)
} else {
const urlWithoutTimestamp = removeTimestampQuery(req.url!)
const ms = new MagicString(code)
Expand Down
Loading