⚙️ refactor: lazy-load React Query Devtools (#13639)

* perf(client): lazy-load query devtools

* fix: keep query devtools deps lazy

* fix: address query devtools review findings

* fix: exclude query devtools from pwa precache

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Ravi Kumar L 2026-06-10 13:06:20 -04:00 committed by GitHub
parent d91cec2101
commit 865e1da857
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 221 additions and 30 deletions

View file

@ -16,9 +16,11 @@ const {
isEnabled,
apiNotFound,
ErrorController,
QUERY_DEVTOOLS_HEADER,
performStartupChecks,
handleJsonParseError,
initializeFileStorage,
maybeInjectQueryDevtoolsBootstrap,
preAuthTenantMiddleware,
} = require('@librechat/api');
const { connectDb, indexSync } = require('~/db');
@ -315,6 +317,23 @@ if (cluster.isMaster) {
}
}
const sendIndexHtml = (req, res) => {
res.set({
'Cache-Control': process.env.INDEX_CACHE_CONTROL || 'no-cache, no-store, must-revalidate',
Pragma: process.env.INDEX_PRAGMA || 'no-cache',
Expires: process.env.INDEX_EXPIRES || '0',
});
res.vary(QUERY_DEVTOOLS_HEADER);
const lang = req.cookies.lang || req.headers['accept-language']?.split(',')[0] || 'en-US';
const saneLang = lang.replace(/"/g, '&quot;');
let updatedIndexHtml = indexHTML.replace(/lang="en-US"/g, `lang="${saneLang}"`);
updatedIndexHtml = maybeInjectQueryDevtoolsBootstrap(updatedIndexHtml, req);
res.type('html');
res.send(updatedIndexHtml);
};
/** Health check endpoint */
app.get('/health', (_req, res) => res.status(200).send('OK'));
@ -348,6 +367,7 @@ if (cluster.isMaster) {
logger.warn('Response compression has been disabled via DISABLE_COMPRESSION.');
}
app.get('/index.html', sendIndexHtml);
app.use(staticCache(appConfig.paths.dist));
app.use(staticCache(appConfig.paths.fonts));
app.use(staticCache(appConfig.paths.assets));
@ -406,20 +426,7 @@ if (cluster.isMaster) {
app.use('/api', apiNotFound);
/** SPA fallback - serve index.html for all unmatched routes */
app.use((req, res) => {
res.set({
'Cache-Control': process.env.INDEX_CACHE_CONTROL || 'no-cache, no-store, must-revalidate',
Pragma: process.env.INDEX_PRAGMA || 'no-cache',
Expires: process.env.INDEX_EXPIRES || '0',
});
const lang = req.cookies.lang || req.headers['accept-language']?.split(',')[0] || 'en-US';
const saneLang = lang.replace(/"/g, '&quot;');
let updatedIndexHtml = indexHTML.replace(/lang="en-US"/g, `lang="${saneLang}"`);
res.type('html');
res.send(updatedIndexHtml);
});
app.use(sendIndexHtml);
/** Error handler (must be last - Express identifies error middleware by its 4-arg signature) */
app.use(ErrorController);

View file

@ -19,9 +19,11 @@ const {
performStartupChecks,
handleJsonParseError,
GenerationJobManager,
QUERY_DEVTOOLS_HEADER,
createStreamServices,
initializeFileStorage,
initializeDeploymentSkills,
maybeInjectQueryDevtoolsBootstrap,
preAuthTenantMiddleware,
setupGracefulShutdown,
updateInterfacePermissions,
@ -140,6 +142,23 @@ const startServer = async () => {
}
}
const sendIndexHtml = (req, res) => {
res.set({
'Cache-Control': process.env.INDEX_CACHE_CONTROL || 'no-cache, no-store, must-revalidate',
Pragma: process.env.INDEX_PRAGMA || 'no-cache',
Expires: process.env.INDEX_EXPIRES || '0',
});
res.vary(QUERY_DEVTOOLS_HEADER);
const lang = req.cookies.lang || req.headers['accept-language']?.split(',')[0] || 'en-US';
const saneLang = lang.replace(/"/g, '&quot;');
let updatedIndexHtml = indexHTML.replace(/lang="en-US"/g, `lang="${saneLang}"`);
updatedIndexHtml = maybeInjectQueryDevtoolsBootstrap(updatedIndexHtml, req);
res.type('html');
res.send(updatedIndexHtml);
};
app.get('/health', (_req, res) => res.status(200).send('OK'));
app.get('/livez', (_req, res) => res.status(200).send('OK'));
app.get('/readyz', (_req, res) => {
@ -179,6 +198,7 @@ const startServer = async () => {
console.warn('Response compression has been disabled via DISABLE_COMPRESSION.');
}
app.get('/index.html', sendIndexHtml);
app.use(staticCache(appConfig.paths.dist));
app.use(staticCache(appConfig.paths.fonts));
app.use(staticCache(appConfig.paths.assets));
@ -256,20 +276,7 @@ const startServer = async () => {
app.use('/api', apiNotFound);
/** SPA fallback - serve index.html for all unmatched routes */
app.use((req, res) => {
res.set({
'Cache-Control': process.env.INDEX_CACHE_CONTROL || 'no-cache, no-store, must-revalidate',
Pragma: process.env.INDEX_PRAGMA || 'no-cache',
Expires: process.env.INDEX_EXPIRES || '0',
});
const lang = req.cookies.lang || req.headers['accept-language']?.split(',')[0] || 'en-US';
const saneLang = lang.replace(/"/g, '&quot;');
let updatedIndexHtml = indexHTML.replace(/lang="en-US"/g, `lang="${saneLang}"`);
res.type('html');
res.send(updatedIndexHtml);
});
app.use(sendIndexHtml);
/** Record trace errors before the final error controller. */
if (telemetry.enabled) {

View file

@ -212,6 +212,32 @@ describe('Server Configuration', () => {
expect(response.headers['content-type']).toMatch(/html/);
});
it('should gate React Query Devtools config in SPA HTML by debug header', async () => {
const defaultResponse = await request(app).get('/this/does/not/exist');
const debugResponse = await request(app)
.get('/this/does/not/exist')
.set('x-librechat-enable-query-devtools', '1');
const directIndexResponse = await request(app)
.get('/index.html')
.set('x-librechat-enable-query-devtools', '1');
expect(defaultResponse.status).toBe(200);
expect(defaultResponse.headers.vary).toContain('x-librechat-enable-query-devtools');
expect(defaultResponse.text).not.toContain('enableQueryDevtools');
expect(debugResponse.status).toBe(200);
expect(debugResponse.headers.vary).toContain('x-librechat-enable-query-devtools');
expect(debugResponse.text).toContain('window.__LIBRECHAT_CONFIG__');
expect(debugResponse.text).toContain('data-librechat-query-devtools="true"');
expect(debugResponse.text).toContain('"enableQueryDevtools":true');
expect(directIndexResponse.status).toBe(200);
expect(directIndexResponse.headers.vary).toContain('x-librechat-enable-query-devtools');
expect(directIndexResponse.text).toContain('window.__LIBRECHAT_CONFIG__');
expect(directIndexResponse.text).toContain('data-librechat-query-devtools="true"');
expect(directIndexResponse.text).toContain('"enableQueryDevtools":true');
});
it('should return 500 for unknown errors via ErrorController', async () => {
// Testing the error handling here on top of unit tests to ensure the middleware is correctly integrated