diff --git a/packages/vite/LICENSE.md b/packages/vite/LICENSE.md index 3518027754ee7b..6cf735826367cc 100644 --- a/packages/vite/LICENSE.md +++ b/packages/vite/LICENSE.md @@ -458,6 +458,12 @@ Repository: https://github.com/nodelib/nodelib/tree/master/packages/fs/fs.walk --------------------------------------- +## @polka/compression +License: MIT +Repository: lukeed/polka + +--------------------------------------- + ## @polka/url License: MIT By: Luke Edwards diff --git a/packages/vite/package.json b/packages/vite/package.json index 870c77d9da1406..9d1c71406962e4 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -96,6 +96,7 @@ "@ampproject/remapping": "^2.3.0", "@babel/parser": "^7.24.0", "@jridgewell/trace-mapping": "^0.3.25", + "@polka/compression": "^1.0.0-next.25", "@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-dynamic-import-vars": "^2.1.2", diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts index 74a4728529b55a..4d2e1e645bbcdc 100644 --- a/packages/vite/src/node/preview.ts +++ b/packages/vite/src/node/preview.ts @@ -1,6 +1,7 @@ import fs from 'node:fs' import path from 'node:path' import sirv from 'sirv' +import compression from '@polka/compression' import connect from 'connect' import type { Connect } from 'dep-types/connect' import corsMiddleware from 'cors' @@ -19,7 +20,6 @@ import { setClientErrorHandler, } from './http' import { openBrowser } from './server/openBrowser' -import compression from './server/middlewares/compression' import { baseMiddleware } from './server/middlewares/base' import { htmlFallbackMiddleware } from './server/middlewares/htmlFallback' import { indexHtmlMiddleware } from './server/middlewares/indexHtml' diff --git a/packages/vite/src/node/server/middlewares/compression.ts b/packages/vite/src/node/server/middlewares/compression.ts deleted file mode 100644 index e7bc133bf3682c..00000000000000 --- a/packages/vite/src/node/server/middlewares/compression.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* eslint-disable */ -//@ts-nocheck -//TODO: replace this code with https://github.com/lukeed/polka/pull/148 once it's released - -// This is based on https://github.com/preactjs/wmr/blob/main/packages/wmr/src/lib/polkompress.js -// MIT Licensed https://github.com/preactjs/wmr/blob/main/LICENSE -import zlib from 'node:zlib' - -/* global Buffer */ - -const noop = () => {} - -const mimes = /text|javascript|\/json|xml/i -const threshold = 1024 -const level = -1 -let brotli = false -const gzip = true - -const getChunkSize = (chunk, enc) => (chunk ? Buffer.byteLength(chunk, enc) : 0) - -export default function compression() { - const brotliOpts = (typeof brotli === 'object' && brotli) || {} - const gzipOpts = (typeof gzip === 'object' && gzip) || {} - - // disable Brotli on Node<12.7 where it is unsupported: - if (!zlib.createBrotliCompress) brotli = false - - return function viteCompressionMiddleware(req, res, next = noop) { - const accept = req.headers['accept-encoding'] + '' - const encoding = ((brotli && accept.match(/\bbr\b/)) || - (gzip && accept.match(/\bgzip\b/)) || - [])[0] - - // skip if no response body or no supported encoding: - if (req.method === 'HEAD' || !encoding) return next() - - /** @type {zlib.Gzip | zlib.BrotliCompress} */ - let compress - let pendingStatus - /** @type {[string, function][]?} */ - let pendingListeners = [] - let started = false - let size = 0 - - function start() { - started = true - size = res.getHeader('Content-Length') | 0 || size - const compressible = mimes.test( - String(res.getHeader('Content-Type') || 'text/plain'), - ) - const cleartext = !res.getHeader('Content-Encoding') - const listeners = pendingListeners || [] - if (compressible && cleartext && size >= threshold) { - res.setHeader('Content-Encoding', encoding) - res.removeHeader('Content-Length') - if (encoding === 'br') { - const params = { - [zlib.constants.BROTLI_PARAM_QUALITY]: level, - [zlib.constants.BROTLI_PARAM_SIZE_HINT]: size, - } - compress = zlib.createBrotliCompress({ - params: Object.assign(params, brotliOpts), - }) - } else { - compress = zlib.createGzip(Object.assign({ level }, gzipOpts)) - } - // backpressure - compress.on( - 'data', - (chunk) => write.call(res, chunk) === false && compress.pause(), - ) - on.call(res, 'drain', () => compress.resume()) - compress.on('end', () => end.call(res)) - listeners.forEach((p) => compress.on.apply(compress, p)) - } else { - pendingListeners = null - listeners.forEach((p) => on.apply(res, p)) - } - - writeHead.call(res, pendingStatus || res.statusCode) - } - - const { end, write, on, writeHead } = res - - res.writeHead = function (status, reason, headers) { - if (typeof reason !== 'string') [headers, reason] = [reason, headers] - if (headers) for (let i in headers) res.setHeader(i, headers[i]) - pendingStatus = status - return this - } - - res.write = function (chunk, enc, cb) { - size += getChunkSize(chunk, enc) - if (!started) start() - if (!compress) return write.apply(this, arguments) - return compress.write.apply(compress, arguments) - } - - res.end = function (chunk, enc, cb) { - if (arguments.length > 0 && typeof chunk !== 'function') { - size += getChunkSize(chunk, enc) - } - if (!started) start() - if (!compress) return end.apply(this, arguments) - return compress.end.apply(compress, arguments) - } - - res.on = function (type, listener) { - if (!pendingListeners || type !== 'drain') on.call(this, type, listener) - else if (compress) compress.on(type, listener) - else pendingListeners.push([type, listener]) - return this - } - - next() - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9416659507eaac..3661880d0cdc11 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -255,6 +255,9 @@ importers: '@jridgewell/trace-mapping': specifier: ^0.3.25 version: 0.3.25 + '@polka/compression': + specifier: ^1.0.0-next.25 + version: 1.0.0-next.25 '@rollup/plugin-alias': specifier: ^5.1.0 version: 5.1.0(rollup@4.2.0) @@ -3713,6 +3716,11 @@ packages: dev: true optional: true + /@polka/compression@1.0.0-next.25: + resolution: {integrity: sha512-UlVkoSGRig87riHSn8QOxd2DzGhadRpNSj5Ukqj+Bt7WTE4Es+sE3ju3OYbe8SiV2OwA+8tDcSuHWUh5S3jCBQ==} + engines: {node: '>=6'} + dev: true + /@polka/url@1.0.0-next.24: resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==} dev: true