diff --git a/spec/server_test.js b/spec/server_test.js index 73fcb48c14986e33d77699094266adbd948023e6..cbf20ea34810259e4e15da4b5c6a05a646076004 100644 --- a/spec/server_test.js +++ b/spec/server_test.js @@ -1,5 +1,5 @@ import request from 'supertest' -import { generateSimpleViteManifest, mockApp, mockConfig, mockFetch, mockRedis } from './util.js' +import { brotliParser, generateSimpleViteManifest, mockApp, mockConfig, mockFetch, mockRedis } from './util.js' import { expect } from 'chai' import * as td from 'testdouble' import RedisMock from 'ioredis-mock' @@ -29,6 +29,19 @@ describe('UI Middleware', function () { it('fetches manifest data', async function () { const response = await request(app.server).get('/manifests') expect(response.statusCode).to.equal(200) + expect(response.headers['content-encoding']).to.equal('gzip') + expect(response.body).to.deep.equal([{ namespace: 'test', path: 'example' }]) + }) + + it('fetches manifest data with brotli', async function () { + const response = await request(app.server) + .get('/manifests') + .set('accept-encoding', 'deflate, gzip, br') + .buffer(true) + .parse(brotliParser) + expect(response.statusCode).to.equal(200) + expect(response.headers['content-encoding']).to.equal('br') + expect(response.headers['content-type']).to.equal('application/json; charset=utf-8') expect(response.body).to.deep.equal([{ namespace: 'test', path: 'example' }]) }) diff --git a/spec/util.js b/spec/util.js index 810ca69cbec31c1ffd1b0938b1e5d23c935fac2a..dbfe0e81806e53b0f03a6764cc0c600a5c675d95 100644 --- a/spec/util.js +++ b/spec/util.js @@ -1,6 +1,7 @@ import * as td from 'testdouble' import { register } from 'prom-client' import RedisMock from 'ioredis-mock' +import zlib from 'node:zlib' export function generateSimpleViteManifest (mapping) { const viteManifest = {} @@ -64,3 +65,17 @@ export async function mockApp () { await app.listen({ port: 0 }) return app } + +export async function brotliParser (res, cb) { + const brotli = zlib.createBrotliDecompress() + let buffer = Buffer.from('') + res.pipe(brotli) + brotli.on('data', chunk => (buffer = Buffer.concat([buffer, chunk]))) + brotli.on('end', () => { + let result = buffer.toString() + if (res.headers['content-type'].startsWith('application/json')) { + result = JSON.parse(result) + } + cb(null, result) + }) +} diff --git a/src/manifests.js b/src/manifests.js index bf014cc491f3587d32d595cde20fe2eb49eb0db0..14f71a0d81d0022512e6a3faccf8eafde7db90f2 100644 --- a/src/manifests.js +++ b/src/manifests.js @@ -2,6 +2,9 @@ import { configMap } from './configMap.js' import { getRedisKey, viteManifestToDeps, viteToOxManifest } from './util.js' import { logger } from './logger.js' import * as cache from './cache.js' +import zlib from 'node:zlib' +import { promisify } from 'node:util' +const brotliCompress = promisify(zlib.brotliCompress) export async function fetchViteManifests () { // vite manifests contains a set of objects with the vite-manifests @@ -32,9 +35,15 @@ export async function getViteManifests ({ version }) { } export function getOxManifests ({ version }) { - return cache.get(getRedisKey({ version, name: 'oxManifests' }), async () => { + return cache.getFile({ name: 'oxManifests', version }, async () => { + const headers = { 'content-type': 'application/json; charset=utf-8', 'content-encoding': 'br' } const viteManifests = await getViteManifests({ version }) - return viteToOxManifest(viteManifests) + const oxManifests = await viteToOxManifest(viteManifests) + const body = await brotliCompress(JSON.stringify(oxManifests)) + return { + body, + headers + } }) } diff --git a/src/plugins/manifests.js b/src/plugins/manifests.js index 0f074c1394f60557bcce9eabba1a508cd41fe0c1..5676ad2674edaf0fdfeb5340e5480676a0c6b2f4 100644 --- a/src/plugins/manifests.js +++ b/src/plugins/manifests.js @@ -1,8 +1,11 @@ import { getOxManifests } from '../manifests.js' export default async function manifestsPlugin (fastify, options) { - fastify.get('/manifests', async (req, res) => { - if (res.body) return - res.send(await getOxManifests({ version: res.version })) + fastify.get('/manifests', async (req, reply) => { + if (reply.body) return + + const { body, headers } = await getOxManifests({ version: reply.version }) + reply.headers(headers) + reply.send(body) }) } diff --git a/src/plugins/serve-files.js b/src/plugins/serve-files.js index 4ec1469b9c2fd6bf6f0a1dbc143d25168440db07..df9a17a1165c99a6a2bb04fe4bf25d4e44a67ba5 100644 --- a/src/plugins/serve-files.js +++ b/src/plugins/serve-files.js @@ -11,9 +11,7 @@ export default async function serveFilePlugin (fastify, options) { const path = url === '/' ? '/index.html' : url const { body, headers } = await getFile({ version, path }) - Object.entries(headers).forEach(([key, value]) => { - reply.header(key, value) - }) + reply.headers(headers) reply.send(body) } catch (err) { const errors = err.errors || [err]