mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 04:07:05 +00:00
⚙️ 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:
parent
d91cec2101
commit
865e1da857
12 changed files with 221 additions and 30 deletions
|
|
@ -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, '"');
|
||||
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, '"');
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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, '"');
|
||||
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, '"');
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue