Merge pull request #34850 from overleaf/acf-ar-yarn-pnp-redux

[monorepo] yarn pnp redux

GitOrigin-RevId: fb04cab879b04ead2665b5e985a44053ceea33f3
This commit is contained in:
Andrew Rumble
2026-09-17 11:35:26 +00:00
committed by Copybot
parent 44f053129f
commit da3adace36
47 changed files with 1057 additions and 57 deletions
+2
View File
@@ -28,10 +28,12 @@
},
"devDependencies": {
"@overleaf/migrations": "workspace:*",
"@types/node": "^24.5.2",
"acorn": "^7.1.1",
"ajv": "^6.12.0",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"eslint": "^10.4.0",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
+2
View File
@@ -40,8 +40,10 @@
},
"devDependencies": {
"@istanbuljs/esm-loader-hook": "^0.3.0",
"@types/node": "^24.5.2",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"eslint": "^10.4.0",
"form-data": "^4.0.5",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
+3
View File
@@ -30,14 +30,17 @@
"bunyan": "^1.8.15",
"express": "4.22.1",
"lodash": "^4.18.1",
"mongodb": "6.12.0",
"mongodb-legacy": "6.1.3",
"p-map": "^4.0.0"
},
"devDependencies": {
"@google-cloud/storage": "^7.19.0",
"@overleaf/migrations": "workspace:*",
"@types/node": "^24.5.2",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"eslint": "^10.4.0",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
+5
View File
@@ -33,15 +33,20 @@
"express": "4.22.1",
"lodash": "^4.18.1",
"minimist": "^1.2.8",
"mongodb": "6.12.0",
"mongodb-legacy": "6.1.3",
"overleaf-editor-core": "workspace:*"
},
"devDependencies": {
"@overleaf/migrations": "workspace:*",
"@types/ioredis": "^4.28.10",
"@types/mocha": "^10.0.6",
"@types/node": "^24.5.2",
"basic-auth": "^2.0.1",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"cluster-key-slot": "^1.0.5",
"eslint": "^10.4.0",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
@@ -204,7 +204,10 @@ async function scanNodes(nodes, batchSize = 1000) {
}
}
logger.info({ scanned, server: node.serverInfo.role }, 'Scanned node')
logger.info(
{ scanned, server: /** @type {any} */ (node).serverInfo.role },
'Scanned node'
)
}
}
+2
View File
@@ -35,8 +35,10 @@
},
"devDependencies": {
"@google-cloud/storage": "^7.19.0",
"@types/node": "^24.5.2",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"eslint": "^10.4.0",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
+6
View File
@@ -7,6 +7,7 @@
"private": true,
"dependencies": {
"@google-cloud/secret-manager": "^5.6.0",
"@google-cloud/storage": "^7.19.0",
"@overleaf/fetch-utils": "workspace:*",
"@overleaf/logger": "workspace:*",
"@overleaf/metrics": "workspace:*",
@@ -47,11 +48,16 @@
"zip-stream": "^7.0.2"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.994.0",
"@overleaf/migrations": "workspace:*",
"@types/chai-as-promised": "^7.1.8",
"@types/mocha": "^10.0.6",
"@types/node": "^24.5.2",
"benny": "^3.7.1",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"chai-exclude": "^2.1.1",
"eslint": "^10.4.0",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
@@ -316,8 +316,9 @@ if (OUTPUT_FILE !== '-') {
logger.initialize('file-migration', {
streams: [
{
stream:
OUTPUT_FILE === '-'
stream: DISPLAY_REPORT
? process.stderr
: OUTPUT_FILE === '-'
? process.stdout
: fs.createWriteStream(OUTPUT_FILE, { flags: 'a' }),
},
@@ -1,9 +1,11 @@
// @ts-check
import { backedUpBlobs } from '../lib/mongodb.js'
import { mongoId } from '../lib/assert.js'
import assert from '../lib/assert.js'
import { ObjectId } from 'mongodb'
import commandLineArgs from 'command-line-args'
const { mongoId } = assert
const STATS = {
total: 0,
replaced: 0,
@@ -485,7 +485,7 @@ describe('back_fill_file_hash script', function () {
* @param {Array<string>} args
* @return {Promise<{result: { stdout: string, stderr: string, status: number }, stats: any}>}
*/
async function rawRunScript(args = []) {
async function rawRunScript(args = [], env = {}) {
let result
try {
result = await promisify(execFile)(
@@ -502,6 +502,7 @@ describe('back_fill_file_hash script', function () {
...process.env,
AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE: '1',
LOG_LEVEL: 'warn', // Override LOG_LEVEL of acceptance tests
...env,
},
}
)
@@ -1120,7 +1121,7 @@ describe('back_fill_file_hash script', function () {
let output
before('prepare environment', prepareEnvironment)
before('run script', async function () {
output = await rawRunScript(['--report'])
output = await rawRunScript(['--report'], { LOG_LEVEL: 'error' })
})
it('should print the report', () => {
expect(output.status).to.equal(0)
@@ -140,7 +140,7 @@ async function runRecoverZipScript(args) {
try {
result = await promisify(execFile)(
'node',
['storage/scripts/recover_zip.js', ...args],
['--no-deprecation', 'storage/scripts/recover_zip.js', ...args],
{
encoding: 'utf-8',
timeout: TIMEOUT,
+3
View File
@@ -29,14 +29,17 @@
"async": "^3.2.5",
"bunyan": "^1.8.15",
"express": "4.22.1",
"mongodb": "6.12.0",
"mongodb-legacy": "6.1.3",
"zod": "^4.1.7",
"zod-validation-error": "^4.0.1"
},
"devDependencies": {
"@overleaf/migrations": "workspace:*",
"@types/node": "^24.5.2",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"eslint": "^10.4.0",
"mocha": "^11.1.0",
"typescript": "^5.0.4",
"vitest": "4.1.5"
+5 -1
View File
@@ -32,18 +32,22 @@
"express": "4.22.1",
"lodash": "^4.18.1",
"minimist": "^1.2.8",
"mongodb": "6.12.0",
"mongodb-legacy": "6.1.3",
"overleaf-editor-core": "workspace:*",
"p-queue": "^8.1.0"
},
"devDependencies": {
"@overleaf/migrations": "workspace:*",
"@types/node": "^24.5.2",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"esmock": "^2.7.3",
"eslint": "^10.4.0",
"esmock": "patch:esmock@npm%3A2.7.3#~/.yarn/patches/esmock-npm-2.7.3-83624b28f6.patch",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
"mongodb": "6.12.0",
"nock": "^13.5.3",
"sinon": "~9.0.1",
"sinon-chai": "^3.7.0",
+3
View File
@@ -36,12 +36,15 @@
"proxy-addr": "^2.0.7",
"socket.io": "github:overleaf/socket.io#0.9.19-overleaf-12",
"socket.io-client": "https://github.com/overleaf/socket.io-client/archive/refs/tags/0.9.17-overleaf-6.tar.gz",
"zod": "^4.0.0",
"zod-validation-error": "^4.0.1"
},
"devDependencies": {
"@types/node": "^24.5.2",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"cookie-signature": "^1.1.0",
"eslint": "^10.4.0",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
+1
View File
@@ -22,6 +22,7 @@ cypress/screenshots/
cypress/videos/
cypress/downloads/
cypress/results/
cypress/reporter/
# Ace themes for conversion
frontend/js/features/source-editor/themes/ace/
+4 -1
View File
@@ -1,10 +1,13 @@
import { defineConfig } from 'cypress'
import { webpackConfig } from './cypress/support/webpack.cypress'
// Cypress's Electron process uses PackherdModuleLoader which doesn't go through
// PnP hooks. Reporter packages are materialized into /tmp/cypress-reporter by
// scripts/materialize-cypress-reporter.js at container startup.
let reporterOptions = {}
if (process.env.CI) {
reporterOptions = {
reporter: 'cypress-multi-reporters',
reporter: '/tmp/cypress-reporter/node_modules/cypress-multi-reporters',
reporterOptions: {
configFile: 'cypress/cypress-multi-reporters.json',
},
+25 -3
View File
@@ -3,6 +3,10 @@
"description": "The HTTP front end for Overleaf",
"private": true,
"main": "app.mjs",
"exports": {
".": "./app.mjs",
"./*": "./*"
},
"directories": {
"public": "./public"
},
@@ -36,8 +40,9 @@
"type-check:backend": "tsc -p tsconfig.backend.json --noEmit",
"extract-translations": "i18next-scanner",
"convert-themes": "node frontend/js/features/source-editor/themes/scripts/convert.js",
"cypress:open-ct": "OVERLEAF_CONFIG=$(pwd)/config/settings.webpack.js cypress open --component",
"cypress:run-ct": "OVERLEAF_CONFIG=$(pwd)/config/settings.webpack.js cypress run --component --browser chrome",
"materialize-reporter": "node ../../bin/shared/materialize-cypress-reporter.js /tmp/cypress-reporter",
"cypress:open-ct": "yarn run materialize-reporter && OVERLEAF_CONFIG=$(pwd)/config/settings.webpack.js cypress open --component",
"cypress:run-ct": "yarn run materialize-reporter && OVERLEAF_CONFIG=$(pwd)/config/settings.webpack.js cypress run --component --browser chrome",
"cypress:docker:open-ct": "USER_UID=$(id -u) USER_GID=$(id -g) docker compose -f docker-compose.cypress.yml run --rm cypress yarn run cypress:open-ct",
"cypress:docker:run-ct": "USER_UID=$(id -u) USER_GID=$(id -g) docker compose -f docker-compose.cypress.yml run --rm cypress yarn run cypress:run-ct --browser chrome",
"lezer-latex:generate": "node scripts/lezer-latex/generate.mjs",
@@ -151,6 +156,7 @@
"minimist": "^1.2.7",
"mmmagic": "^0.5.3",
"moment": "^2.29.4",
"mongodb": "6.12.0",
"mongodb-legacy": "6.1.3",
"mongoose": "8.22.1",
"multer": "2.2.0",
@@ -197,6 +203,7 @@
"@ai-sdk/react": "^3.0.172",
"@babel/core": "^7.28.5",
"@babel/plugin-proposal-decorators": "^7.28.0",
"@babel/plugin-transform-typescript": "^7.28.0",
"@babel/preset-env": "^7.28.5",
"@babel/preset-react": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
@@ -234,6 +241,7 @@
"@replit/codemirror-indentation-markers": "overleaf/codemirror-indentation-markers#371ce3b56f453a392eb0d3b85ab019c185c68e1f",
"@replit/codemirror-vim": "overleaf/codemirror-vim#1bef138382d948018f3f9b8a4d7a70ab61774e4b",
"@sentry/browser": "7.46.0",
"@sentry/types": "7.46.0",
"@storybook/addon-a11y": "10.3.5",
"@storybook/addon-designs": "^11.1.3",
"@storybook/addon-docs": "10.3.5",
@@ -255,15 +263,19 @@
"@types/async": "^3.2.25",
"@types/bootstrap": "^5.2.10",
"@types/chai": "^4.3.0",
"@types/chai-as-promised": "^8.0.2",
"@types/dateformat": "^5.0.3",
"@types/diff": "^5.2.3",
"@types/dom-speech-recognition": "^0.0.7",
"@types/events": "^3.0.3",
"@types/express": "^4.17.23",
"@types/lodash": "^4.17.24",
"@types/mdast": "^4.0.4",
"@types/minimist": "^1.2.5",
"@types/mocha": "^9.1.0",
"@types/mocha-each": "^2.0.4",
"@types/node": "^24.5.2",
"@types/path-browserify": "^1.0.3",
"@types/react": "^18.3.20",
"@types/react-color": "^3.0.13",
"@types/react-dom": "^18.3.6",
@@ -272,15 +284,19 @@
"@types/react-syntax-highlighter": "^15.5.11",
"@types/recurly__recurly-js": "^4.38.0",
"@types/sanitize-html": "^2.14.0",
"@types/sinon": "^21.0.1",
"@types/sinon-chai": "^3.2.12",
"@types/utf-8-validate": "^5.0.2",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^8.59.4",
"@typescript-eslint/parser": "^8.59.4",
"@uppy/core": "^3.8.0",
"@uppy/dashboard": "3.7.1",
"@uppy/drag-drop": "3.0.3",
"@uppy/file-input": "3.0.4",
"@uppy/progress-bar": "3.0.4",
"@uppy/react": "3.2.1",
"@uppy/status-bar": "^3.2.5",
"@uppy/utils": "^5.7.0",
"@uppy/xhr-upload": "3.6.0",
"@vitest/coverage-istanbul": "^4.0.17",
@@ -315,6 +331,8 @@
"core-js": "~3.46.0",
"css-loader": "^7.1.4",
"css-minimizer-webpack-plugin": "^8.0.0",
"csv-parse": "^6.2.1",
"csv-stringify": "^6.7.0",
"cypress": "15.12.0",
"cypress-multi-reporters": "^2.0.5",
"cypress-plugin-tab": "^1.0.5",
@@ -325,9 +343,11 @@
"downshift": "^9.0.9",
"es6-promise": "^4.2.8",
"escodegen": "^2.0.0",
"eslint": "^10.4.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-chai-expect": "^4.1.0",
"eslint-plugin-chai-friendly": "^1.2.0",
"eslint-plugin-cypress": "^4.1.0",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-mocha": "^11.3.0",
@@ -343,6 +363,7 @@
"fake-indexeddb": "^6.0.0",
"fast-fuzzy": "^1.12.0",
"fetch-mock": "^12.6.0",
"focus-trap": "^8.2.1",
"formik": "^2.2.9",
"glob": "^12.0.0",
"globals": "^17.6.0",
@@ -418,8 +439,9 @@
"timekeeper": "^2.2.0",
"to-string-loader": "^1.2.0",
"ts-loader": "^9.5.7",
"tslib": "^2.8.1",
"tty-browserify": "^0.0.1",
"typescript": "^5.9.3",
"typescript": "^5.0.4",
"unified": "^11.0.5",
"unist-util-visit": "^5.0.0",
"use-stick-to-bottom": "^1.1.1",
+12
View File
@@ -1,3 +1,15 @@
// Register PnP ESM loader via module.register() for synchronous ESM resolution
// (--experimental-loader from yarn only works for async resolution)
const { register } = require('node:module')
const { pathToFileURL } = require('node:url')
const path = require('node:path')
const pnpRegister = path.resolve(__dirname, '../../.pnp.register.mjs')
try {
register(pathToFileURL(pnpRegister), pathToFileURL(__filename))
} catch {
// .pnp.register.mjs may not exist in non-PnP environments
}
const chai = require('chai')
chai.should()
chai.use(require('chai-as-promised'))
@@ -119,7 +119,8 @@ describe('DeleteOrphanedDocsOnlineCheck', function () {
// Hide verbose log messages `calling destroy for project in docstore`
'LOG_LEVEL=error',
// Hide deprecation warnings for calling `db.collection.count`
'NODE_OPTIONS=--no-deprecation',
// Preserve existing NODE_OPTIONS (e.g. PnP hooks) while adding --no-deprecation
`NODE_OPTIONS='${process.env.NODE_OPTIONS || ''} --no-deprecation'`,
])
.concat(['node', 'scripts/delete_orphaned_docs_online_check.mjs'])
.join(' ')
@@ -10,7 +10,9 @@ function clearSettingsCache() {
const settingsDeps = Object.keys(require.cache).filter(
x =>
x.includes('/@overleaf/settings') ||
x.includes('/@overleaf-settings-virtual') ||
x.includes(`${monorepoPath}/libraries/settings`) ||
x.includes('/libraries/settings/') ||
x.includes(`${monorepoPath}/services/web/config`)
)
settingsDeps.forEach(dep => delete require.cache[dep])
+3
View File
@@ -21,6 +21,9 @@
"@modules/*": ["./modules/*"],
"@overleaf/o-error": ["../../libraries/o-error"],
"@overleaf/ranges-tracker": ["../../libraries/ranges-tracker"],
"@overleaf/validation-tools": ["../../libraries/validation-tools"],
"overleaf-editor-core": ["../../libraries/overleaf-editor-core"],
"overleaf-editor-core/*": ["../../libraries/overleaf-editor-core/*"],
"@ol-types/*": ["./types/*"],
"@ol-storybook/*": ["./.storybook/*"],
+11
View File
@@ -0,0 +1,11 @@
// Ambient module declaration for @uppy/utils subpath imports.
// Under Yarn PnP, TypeScript cannot find the ambient declarations in
// @uppy/utils/types/index.d.ts for deep imports like
// @uppy/utils/lib/getDroppedFiles. Re-declare the subset we use here.
declare module '@uppy/utils/lib/getDroppedFiles' {
function getDroppedFiles(
dataTransfer: DataTransfer,
options?: Record<string, unknown>
): Promise<File[]>
export default getDroppedFiles
}
+19 -6
View File
@@ -51,13 +51,11 @@ globSync(
})
function getModuleDirectory(moduleName) {
const entrypointPath = require.resolve(moduleName)
const suffix = `node_modules/${moduleName}`
const idx = entrypointPath.indexOf(suffix)
if (idx === -1) {
throw new Error(`could not find Node module: ${moduleName}`)
try {
return path.dirname(require.resolve(`${moduleName}/package.json`))
} catch (err) {
throw new Error(`could not find Node module: ${moduleName}`, { cause: err })
}
return entrypointPath.slice(0, idx + suffix.length)
}
const mathjaxDir = getModuleDirectory('mathjax')
@@ -314,6 +312,21 @@ module.exports = {
// Ensure all packages use the same jQuery instance (prevents duplicate
// copies from Yarn hoisting breaking jQuery plugins like daterangepicker)
jquery: require.resolve('jquery'),
// Under Yarn PnP, babel-injected core-js polyfill imports cannot be
// resolved from third-party packages (e.g. @uppy, pdfjs-dist) because
// they don't declare core-js as a dependency. Alias to the web
// workspace's copy so all packages can resolve it.
'core-js': getModuleDirectory('core-js'),
// writefull's tsconfig uses importHelpers: true, which emits tslib
// imports that must be resolvable from the web workspace.
tslib: getModuleDirectory('tslib'),
// Under PnP, packages like cypress/react that import react/react-dom
// can't resolve them from their own scope. Alias to web's copies.
react: getModuleDirectory('react'),
'react-dom': getModuleDirectory('react-dom'),
// ai-sdk packages declare zod as a peer dep but PnP can't resolve it
// from their scope in the Docker build.
zod: getModuleDirectory('zod'),
},
// symlinks: false, // enable this while using `npm link`
extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.json'],