Intellectual Webpack cache management (#5295)
* Intellectual Webpack cache management * Check if webpackRoot exists. * Wrap webpack directory reading in try-catch * Enhance cache pruning console output
This commit is contained in:
@@ -26,16 +26,18 @@ export default function getWebpackServeMiddleware() {
|
|||||||
/**
|
/**
|
||||||
* Wait until Webpack is done compiling.
|
* Wait until Webpack is done compiling.
|
||||||
* @param {object} param Parameters.
|
* @param {object} param Parameters.
|
||||||
* @param {boolean} [param.forceDist] Whether to force the use the /dist folder.
|
* @param {boolean} [param.forceDist=false] Whether to force the use the /dist folder.
|
||||||
|
* @param {boolean} [param.pruneCache=false] Whether to prune old cache directories before compiling.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
devMiddleware.runWebpackCompiler = ({ forceDist = false } = {}) => {
|
devMiddleware.runWebpackCompiler = ({ forceDist = false, pruneCache = false } = {}) => {
|
||||||
const publicLibConfig = getPublicLibConfig(forceDist);
|
console.log();
|
||||||
|
console.log('Compiling frontend libraries...');
|
||||||
|
|
||||||
|
const publicLibConfig = getPublicLibConfig({ forceDist, pruneCache });
|
||||||
const compiler = webpack(publicLibConfig);
|
const compiler = webpack(publicLibConfig);
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
console.log();
|
|
||||||
console.log('Compiling frontend libraries...');
|
|
||||||
compiler.run((_error, stats) => {
|
compiler.run((_error, stats) => {
|
||||||
const output = stats?.toString(publicLibConfig.stats);
|
const output = stats?.toString(publicLibConfig.stats);
|
||||||
if (output) {
|
if (output) {
|
||||||
|
|||||||
+1
-1
@@ -328,7 +328,7 @@ async function preSetupTasks() {
|
|||||||
initRequestProxy({ enabled: cliArgs.requestProxyEnabled, url: cliArgs.requestProxyUrl, bypass: cliArgs.requestProxyBypass });
|
initRequestProxy({ enabled: cliArgs.requestProxyEnabled, url: cliArgs.requestProxyUrl, bypass: cliArgs.requestProxyBypass });
|
||||||
|
|
||||||
// Wait for frontend libs to compile
|
// Wait for frontend libs to compile
|
||||||
await webpackMiddleware.runWebpackCompiler();
|
await webpackMiddleware.runWebpackCompiler({ pruneCache: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+64
-14
@@ -1,45 +1,95 @@
|
|||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import crypto from 'node:crypto';
|
||||||
import isDocker from 'is-docker';
|
import isDocker from 'is-docker';
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import { serverDirectory } from './src/server-directory.js';
|
import { serverDirectory } from './src/server-directory.js';
|
||||||
|
import { getVersion, color } from './src/util.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a cache version string based on the application version, Git revision, and Webpack version.
|
||||||
|
* @returns {string} The cache version string.
|
||||||
|
*/
|
||||||
|
function getWebpackCacheVersion() {
|
||||||
|
return crypto.createHash('shake256', { outputLength: 8 })
|
||||||
|
.update(JSON.stringify([appVersion.pkgVersion, appVersion.gitRevision, webpack.version]))
|
||||||
|
.digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prune old Webpack cache directories that do not match the current cache version.
|
||||||
|
* @param {string} webpackRoot The root directory where Webpack caches are stored.
|
||||||
|
* @param {string} currentCacheVersion The current cache version to keep.
|
||||||
|
*/
|
||||||
|
function pruneWebpackCache(webpackRoot, currentCacheVersion) {
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(webpackRoot)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheDirectories = fs.readdirSync(webpackRoot, { withFileTypes: true })
|
||||||
|
.filter(dirent => dirent.isDirectory())
|
||||||
|
.map(dirent => dirent.name);
|
||||||
|
|
||||||
|
for (const dir of cacheDirectories) {
|
||||||
|
const dirPath = path.join(webpackRoot, dir);
|
||||||
|
if (dir !== currentCacheVersion) {
|
||||||
|
try {
|
||||||
|
fs.rmSync(dirPath, { recursive: true, force: true });
|
||||||
|
console.debug(`Removed outdated cache directory: ${color.yellow(dir)}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to remove Webpack cache directory: ${color.red(dir)}`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to read Webpack cache directories for pruning.', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const appVersion = await getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Webpack configuration for the public/lib.js file.
|
* Get the Webpack configuration for the public/lib.js file.
|
||||||
* 1. Docker has got cache and the output file pre-baked.
|
* 1. Docker has got cache and the output file pre-baked.
|
||||||
* 2. Non-Docker environments use the global DATA_ROOT variable to determine the cache and output directories.
|
* 2. Non-Docker environments use the global DATA_ROOT variable to determine the cache and output directories.
|
||||||
* @param {boolean} forceDist Whether to force the use the /dist folder.
|
* @param {object} options Configuration options.
|
||||||
|
* @param {boolean} [options.forceDist=false] Whether to force the use the /dist folder.
|
||||||
|
* @param {boolean} [options.pruneCache=false] Whether to prune old cache directories.
|
||||||
* @returns {import('webpack').Configuration}
|
* @returns {import('webpack').Configuration}
|
||||||
* @throws {Error} If the DATA_ROOT variable is not set.
|
* @throws {Error} If the DATA_ROOT variable is not set.
|
||||||
* */
|
* */
|
||||||
export default function getPublicLibConfig(forceDist = false) {
|
export default function getPublicLibConfig({ forceDist = false, pruneCache = false } = {}) {
|
||||||
function getCacheDirectory() {
|
function getWebpackRoot() {
|
||||||
if (forceDist || isDocker()) {
|
if (forceDist || isDocker()) {
|
||||||
return path.resolve(process.cwd(), 'dist', '_webpack', webpack.version, 'cache');
|
return path.resolve(process.cwd(), 'dist', '_webpack');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof globalThis.DATA_ROOT === 'string') {
|
if (typeof globalThis.DATA_ROOT === 'string') {
|
||||||
return path.resolve(globalThis.DATA_ROOT, '_webpack', webpack.version, 'cache');
|
return path.resolve(globalThis.DATA_ROOT, '_webpack');
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('DATA_ROOT variable is not set.');
|
throw new Error('DATA_ROOT variable is not set.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCacheDirectory() {
|
||||||
|
return path.join(webpackRoot, cacheVersion, 'cache');
|
||||||
|
}
|
||||||
|
|
||||||
function getOutputDirectory() {
|
function getOutputDirectory() {
|
||||||
if (forceDist || isDocker()) {
|
return path.join(webpackRoot, cacheVersion, 'output');
|
||||||
return path.resolve(process.cwd(), 'dist', '_webpack', webpack.version, 'output');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof globalThis.DATA_ROOT === 'string') {
|
|
||||||
return path.resolve(globalThis.DATA_ROOT, '_webpack', webpack.version, 'output');
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('DATA_ROOT variable is not set.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const webpackRoot = getWebpackRoot();
|
||||||
|
const cacheVersion = getWebpackCacheVersion();
|
||||||
const cacheDirectory = getCacheDirectory();
|
const cacheDirectory = getCacheDirectory();
|
||||||
const outputDirectory = getOutputDirectory();
|
const outputDirectory = getOutputDirectory();
|
||||||
|
|
||||||
|
if (pruneCache) {
|
||||||
|
pruneWebpackCache(webpackRoot, cacheVersion);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
entry: path.join(serverDirectory, 'public/lib.js'),
|
entry: path.join(serverDirectory, 'public/lib.js'),
|
||||||
|
|||||||
Reference in New Issue
Block a user