mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
🔧 refactor: Build Process and Static Asset Handling (#7605)
* 🔧 chore: Update build script to include post-build image removal
* refactor: staticCache middleware with options and special handling for manifest/sw/index files
* refactor(pwa): optimize service worker caching strategy
* refactor: streamline post-build process and update public directory handling
* chore: remove external images from rollupOptions in Vite config
* chore: enhance logging message in post-build script for clarity
This commit is contained in:
parent
2f462c9b3c
commit
f556aaeaea
4 changed files with 64 additions and 13 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
const path = require('path');
|
||||||
const expressStaticGzip = require('express-static-gzip');
|
const expressStaticGzip = require('express-static-gzip');
|
||||||
|
|
||||||
const oneDayInSeconds = 24 * 60 * 60;
|
const oneDayInSeconds = 24 * 60 * 60;
|
||||||
|
|
@ -5,16 +6,45 @@ const oneDayInSeconds = 24 * 60 * 60;
|
||||||
const sMaxAge = process.env.STATIC_CACHE_S_MAX_AGE || oneDayInSeconds;
|
const sMaxAge = process.env.STATIC_CACHE_S_MAX_AGE || oneDayInSeconds;
|
||||||
const maxAge = process.env.STATIC_CACHE_MAX_AGE || oneDayInSeconds * 2;
|
const maxAge = process.env.STATIC_CACHE_MAX_AGE || oneDayInSeconds * 2;
|
||||||
|
|
||||||
const staticCache = (staticPath) =>
|
/**
|
||||||
expressStaticGzip(staticPath, {
|
* Creates an Express static middleware with gzip compression and configurable caching
|
||||||
enableBrotli: false, // disable Brotli, only using gzip
|
*
|
||||||
|
* @param {string} staticPath - The file system path to serve static files from
|
||||||
|
* @param {Object} [options={}] - Configuration options
|
||||||
|
* @param {boolean} [options.noCache=false] - If true, disables caching entirely for all files
|
||||||
|
* @returns {ReturnType<expressStaticGzip>} Express middleware function for serving static files
|
||||||
|
*/
|
||||||
|
function staticCache(staticPath, options = {}) {
|
||||||
|
const { noCache = false } = options;
|
||||||
|
return expressStaticGzip(staticPath, {
|
||||||
|
enableBrotli: false,
|
||||||
orderPreference: ['gz'],
|
orderPreference: ['gz'],
|
||||||
setHeaders: (res, _path) => {
|
setHeaders: (res, filePath) => {
|
||||||
if (process.env.NODE_ENV?.toLowerCase() === 'production') {
|
if (process.env.NODE_ENV?.toLowerCase() !== 'production') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (noCache) {
|
||||||
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (filePath.includes('/dist/images/')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fileName = path.basename(filePath);
|
||||||
|
|
||||||
|
if (
|
||||||
|
fileName === 'index.html' ||
|
||||||
|
fileName.endsWith('.webmanifest') ||
|
||||||
|
fileName === 'manifest.json' ||
|
||||||
|
fileName === 'sw.js'
|
||||||
|
) {
|
||||||
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
|
||||||
|
} else {
|
||||||
res.setHeader('Cache-Control', `public, max-age=${maxAge}, s-maxage=${sMaxAge}`);
|
res.setHeader('Cache-Control', `public, max-age=${maxAge}, s-maxage=${sMaxAge}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
index: false,
|
index: false,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = staticCache;
|
module.exports = staticCache;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"data-provider": "cd .. && npm run build:data-provider",
|
"data-provider": "cd .. && npm run build:data-provider",
|
||||||
"build:file": "cross-env NODE_ENV=production vite build --debug > vite-output.log 2>&1",
|
"build:file": "cross-env NODE_ENV=production vite build --debug > vite-output.log 2>&1",
|
||||||
"build": "cross-env NODE_ENV=production vite build",
|
"build": "cross-env NODE_ENV=production vite build && node ./scripts/post-build.cjs",
|
||||||
"build:ci": "cross-env NODE_ENV=development vite build --mode ci",
|
"build:ci": "cross-env NODE_ENV=development vite build --mode ci",
|
||||||
"dev": "cross-env NODE_ENV=development vite",
|
"dev": "cross-env NODE_ENV=development vite",
|
||||||
"preview-prod": "cross-env NODE_ENV=development vite preview",
|
"preview-prod": "cross-env NODE_ENV=development vite preview",
|
||||||
|
|
|
||||||
14
client/scripts/post-build.cjs
Normal file
14
client/scripts/post-build.cjs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
|
async function postBuild() {
|
||||||
|
try {
|
||||||
|
await fs.copy('public/assets', 'dist/assets');
|
||||||
|
await fs.copy('public/robots.txt', 'dist/robots.txt');
|
||||||
|
console.log('✅ PWA icons and robots.txt copied successfully. Glob pattern warnings resolved.');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('❌ Error copying files:', err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postBuild();
|
||||||
|
|
@ -8,7 +8,7 @@ import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig(({ command }) => ({
|
||||||
server: {
|
server: {
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 3090,
|
port: 3090,
|
||||||
|
|
@ -37,13 +37,21 @@ export default defineConfig({
|
||||||
enabled: false, // disable service worker registration in development mode
|
enabled: false, // disable service worker registration in development mode
|
||||||
},
|
},
|
||||||
useCredentials: true,
|
useCredentials: true,
|
||||||
|
includeManifestIcons: false,
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: ['**/*'],
|
globPatterns: [
|
||||||
|
'**/*.{js,css,html}',
|
||||||
|
'assets/favicon*.png',
|
||||||
|
'assets/icon-*.png',
|
||||||
|
'assets/apple-touch-icon*.png',
|
||||||
|
'assets/maskable-icon.png',
|
||||||
|
'manifest.webmanifest',
|
||||||
|
],
|
||||||
globIgnores: ['images/**/*', '**/*.map'],
|
globIgnores: ['images/**/*', '**/*.map'],
|
||||||
maximumFileSizeToCacheInBytes: 4 * 1024 * 1024,
|
maximumFileSizeToCacheInBytes: 4 * 1024 * 1024,
|
||||||
navigateFallbackDenylist: [/^\/oauth/],
|
navigateFallbackDenylist: [/^\/oauth/],
|
||||||
},
|
},
|
||||||
includeAssets: ['**/*'],
|
includeAssets: [],
|
||||||
manifest: {
|
manifest: {
|
||||||
name: 'LibreChat',
|
name: 'LibreChat',
|
||||||
short_name: 'LibreChat',
|
short_name: 'LibreChat',
|
||||||
|
|
@ -94,14 +102,13 @@ export default defineConfig({
|
||||||
template: 'treemap', // 'treemap' | 'sunburst' | 'network'
|
template: 'treemap', // 'treemap' | 'sunburst' | 'network'
|
||||||
}),
|
}),
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
publicDir: './public',
|
publicDir: command === 'serve' ? './public' : false,
|
||||||
build: {
|
build: {
|
||||||
sourcemap: process.env.NODE_ENV === 'development',
|
sourcemap: process.env.NODE_ENV === 'development',
|
||||||
outDir: './dist',
|
outDir: './dist',
|
||||||
minify: 'terser',
|
minify: 'terser',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
preserveEntrySignatures: 'strict',
|
preserveEntrySignatures: 'strict',
|
||||||
// external: ['uuid'],
|
|
||||||
output: {
|
output: {
|
||||||
manualChunks(id: string) {
|
manualChunks(id: string) {
|
||||||
if (id.includes('node_modules')) {
|
if (id.includes('node_modules')) {
|
||||||
|
|
@ -230,10 +237,10 @@ export default defineConfig({
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'~': path.join(__dirname, 'src/'),
|
'~': path.join(__dirname, 'src/'),
|
||||||
$fonts: '/fonts',
|
$fonts: path.resolve(__dirname, 'public/fonts'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
|
|
||||||
interface SourcemapExclude {
|
interface SourcemapExclude {
|
||||||
excludeNodeModules?: boolean;
|
excludeNodeModules?: boolean;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue