Selaa lähdekoodia

[web] isolate cypress webpack caches (#33516)

GitOrigin-RevId: 65f8bf162df4fa3b67c8ac19f36fd578251e88f4
Kristina 3 kuukautta sitten
vanhempi
sitoutus
b3beca0e8d

+ 2 - 0
services/web/docker-compose.ci.yml

@@ -108,6 +108,8 @@ services:
     volumes:
       - /dev/shm/overleaf:/overleaf
       - ./data/reports:/overleaf/services/web/data/reports
+    tmpfs:
+      - /overleaf/services/web/node_modules/.cache:uid=1000,gid=1000
     entrypoint: yarn
     command:
       - "run"

+ 23 - 0
services/web/frontend/macros/cypress-cache-variant.js

@@ -0,0 +1,23 @@
+const path = require('path')
+
+// Returns the cache subdirectory name for the current Cypress CT variant,
+// or null when CYPRESS_RESULTS is not set.
+// Throws if the derived basename is unsafe to prevent path traversal or
+// absolute-path escapes.
+function cypressCacheVariant() {
+  if (!process.env.CYPRESS_RESULTS) return null
+  const variant = path.basename(process.env.CYPRESS_RESULTS)
+  if (
+    !variant ||
+    variant === '.' ||
+    variant === '..' ||
+    path.isAbsolute(variant)
+  ) {
+    throw new Error(
+      `CYPRESS_RESULTS must resolve to a safe basename; got "${process.env.CYPRESS_RESULTS}"`
+    )
+  }
+  return variant
+}
+
+module.exports = cypressCacheVariant

+ 5 - 1
services/web/frontend/macros/invalidate-babel-cache-if-needed.js

@@ -1,9 +1,13 @@
 const fs = require('fs')
 const Path = require('path')
 const Settings = require('@overleaf/settings')
+const cypressCacheVariant = require('./cypress-cache-variant')
 
 module.exports = function invalidateBabelCacheIfNeeded() {
-  const cacheDir = Path.join(__dirname, '../../node_modules/.cache')
+  // Use a unique subdirectory per Cypress CT variant to avoid parallel jobs
+  // racing on the shared babel cache and state file.
+  const suffix = cypressCacheVariant() ?? ''
+  const cacheDir = Path.join(__dirname, '../../node_modules/.cache', suffix)
   const cachePath = Path.join(cacheDir, 'babel-loader')
   const statePath = Path.join(cacheDir, 'last-overleafModuleImports.json')
   let lastState = ''

+ 14 - 0
services/web/webpack.config.dev.js

@@ -5,6 +5,9 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
 const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
 
 const base = require('./webpack.config')
+const cypressCacheVariant = require('./frontend/macros/cypress-cache-variant')
+
+const cypressVariant = cypressCacheVariant()
 
 // if WEBPACK_ENTRYPOINTS is defined, remove any entrypoints that aren't included
 if (process.env.WEBPACK_ENTRYPOINTS) {
@@ -26,6 +29,17 @@ module.exports = merge(base, {
 
   cache: {
     type: 'filesystem',
+    // Use a unique cache directory per Cypress CT variant to avoid
+    // parallel jobs corrupting the shared PackFileCacheStrategy pack files.
+    ...(cypressVariant
+      ? {
+          cacheDirectory: path.resolve(
+            __dirname,
+            'node_modules/.cache/webpack',
+            cypressVariant
+          ),
+        }
+      : {}),
     buildDependencies: {
       config: [
         __filename,

+ 10 - 2
services/web/webpack.config.js

@@ -10,10 +10,18 @@ const {
 
 const PackageVersions = require('./app/src/infrastructure/PackageVersions.js')
 const invalidateBabelCacheIfNeeded = require('./frontend/macros/invalidate-babel-cache-if-needed')
+const cypressCacheVariant = require('./frontend/macros/cypress-cache-variant')
 
 // Make sure that babel-macros are re-evaluated after changing the modules config
 invalidateBabelCacheIfNeeded()
 
+// Use a unique babel-loader cache directory per Cypress CT variant to avoid
+// parallel jobs corrupting the shared cache.
+const cypressVariant = cypressCacheVariant()
+const babelCacheDirectory = cypressVariant
+  ? path.join(__dirname, 'node_modules/.cache', cypressVariant, 'babel-loader')
+  : true
+
 // Generate a hash of entry points, including modules
 const entryPoints = {
   bootstrap: './frontend/js/bootstrap.ts',
@@ -123,7 +131,7 @@ module.exports = {
           {
             loader: 'babel-loader',
             options: {
-              cacheDirectory: true,
+              cacheDirectory: babelCacheDirectory,
               configFile: path.join(__dirname, './babel.config.json'),
             },
           },
@@ -156,7 +164,7 @@ module.exports = {
             options: {
               // Configure babel-loader to cache compiled output so that
               // subsequent compile runs are much faster
-              cacheDirectory: true,
+              cacheDirectory: babelCacheDirectory,
               configFile: path.join(__dirname, './babel.config.json'),
               plugins: [
                 process.env.REACT_REFRESH_ENABLED === 'true' &&