From 39f798a4b8ba93e3e9d6b2adb06365f2038d22f8 Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Tue, 16 Sep 2025 12:12:09 +0200 Subject: [PATCH] chore(compass-web): add new script that combines together sync, mms start, and a special browser extension that does the redirect This new script is basically packaging all sync logic in one step task doing all the pre-setup work required to see compass-web running in latest mms. We will be adapting compass-e2e-tests to use this instead of sandbox for atlas cloud tests. To try this out locally: MMS_HOME= node --experimental-strip-types ./packages/compass-web/scripts/web-mms.mts --- package-lock.json | 3 + packages/compass-web/package.json | 1 + .../scripts/redirect-extension/.gitignore | 2 + .../scripts/redirect-extension/manifest.json | 17 ++ .../redirect-extension/redirect-rules.json | 15 ++ packages/compass-web/scripts/web-mms.mts | 151 ++++++++++++++++++ 6 files changed, 189 insertions(+) create mode 100644 packages/compass-web/scripts/redirect-extension/.gitignore create mode 100644 packages/compass-web/scripts/redirect-extension/manifest.json create mode 100644 packages/compass-web/scripts/redirect-extension/redirect-rules.json create mode 100644 packages/compass-web/scripts/web-mms.mts diff --git a/package-lock.json b/package-lock.json index 3c70dd2e93d..d125314f8df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30100,6 +30100,7 @@ "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -51641,6 +51642,7 @@ "express": "^4.21.1", "express-http-proxy": "^2.0.0", "is-ip": "^5.0.1", + "jszip": "^3.10.1", "lodash": "^4.17.21", "mocha": "^10.2.0", "mongodb": "^6.19.0", @@ -64292,6 +64294,7 @@ "express": "^4.21.1", "express-http-proxy": "^2.0.0", "is-ip": "^5.0.1", + "jszip": "^3.10.1", "lodash": "^4.17.21", "mocha": "^10.2.0", "mongodb": "^6.19.0", diff --git a/packages/compass-web/package.json b/packages/compass-web/package.json index d469088fe06..feca3627638 100644 --- a/packages/compass-web/package.json +++ b/packages/compass-web/package.json @@ -126,6 +126,7 @@ "express": "^4.21.1", "express-http-proxy": "^2.0.0", "is-ip": "^5.0.1", + "jszip": "^3.10.1", "lodash": "^4.17.21", "mocha": "^10.2.0", "mongodb": "^6.19.0", diff --git a/packages/compass-web/scripts/redirect-extension/.gitignore b/packages/compass-web/scripts/redirect-extension/.gitignore new file mode 100644 index 00000000000..8b1461fe0bf --- /dev/null +++ b/packages/compass-web/scripts/redirect-extension/.gitignore @@ -0,0 +1,2 @@ +# generated by browsers when extension is loaded +_metadata \ No newline at end of file diff --git a/packages/compass-web/scripts/redirect-extension/manifest.json b/packages/compass-web/scripts/redirect-extension/manifest.json new file mode 100644 index 00000000000..66d9cdd9442 --- /dev/null +++ b/packages/compass-web/scripts/redirect-extension/manifest.json @@ -0,0 +1,17 @@ +{ + "manifest_version": 3, + "name": "Redirect MMS", + "description": "Redirect MMS assets requests to the locally running dev server", + "version": "0.2", + "permissions": ["declarativeNetRequestWithHostAccess"], + "host_permissions": ["*://*/*"], + "declarative_net_request": { + "rule_resources": [ + { + "id": "ruleset", + "enabled": true, + "path": "redirect-rules.json" + } + ] + } +} diff --git a/packages/compass-web/scripts/redirect-extension/redirect-rules.json b/packages/compass-web/scripts/redirect-extension/redirect-rules.json new file mode 100644 index 00000000000..abbb5482bd6 --- /dev/null +++ b/packages/compass-web/scripts/redirect-extension/redirect-rules.json @@ -0,0 +1,15 @@ +[ + { + "id": 1, + "condition": { + "regexFilter": "^https:\\/\\/assets(?:-\\w+?)?\\.mongodb-cdn\\.com\\/mms(.+?)(?:\\.[\\w\\d]+(\\.min)?)?\\.js$", + "resourceTypes": ["script"] + }, + "action": { + "type": "redirect", + "redirect": { + "regexSubstitution": "http://localhost:8081\\1\\2.js" + } + } + } +] diff --git a/packages/compass-web/scripts/web-mms.mts b/packages/compass-web/scripts/web-mms.mts new file mode 100644 index 00000000000..8159f8c37e2 --- /dev/null +++ b/packages/compass-web/scripts/web-mms.mts @@ -0,0 +1,151 @@ +import path from 'path'; +import fs from 'fs'; +import util from 'util'; +import child_process from 'child_process'; +import stream from 'stream'; +import * as wdio from 'webdriverio'; +import JSZip from 'jszip'; +import os from 'os'; + +const redirectExtensionPath = path.join( + import.meta.dirname, + 'redirect-extension' +); + +function getZippedExtension() { + const zip = new JSZip(); + for (const file of ['manifest.json', 'redirect-rules.json']) { + zip.file(file, fs.createReadStream(path.join(redirectExtensionPath, file))); + } + return zip.generateAsync({ type: 'base64' }); +} + +async function startBrowserWithPreloadedRedirectExtension() { + const browser = await wdio.remote({ + capabilities: { + // TODO: arugments for browser, infer default one (if firefox installed ? firefox : chrome) + browserName: 'firefox', + 'goog:chromeOptions': { + args: [ + `--load-extension=${redirectExtensionPath}`, + // load-extension is deprecated in chrome, but available in chromium / + // chrome-for-testing, for now in chrome you can enable the flag by + // disabling the "disable" feature flag + '--disable-features=DisableLoadExtensionCommandLineSwitch', + ], + }, + }, + }); + // In firefox you have to load a zip archive + if (browser.capabilities.browserName === 'firefox') { + await browser.installAddOn(await getZippedExtension(), true); + } + // TODO: arguments for default env to open + await browser.url('https://cloud-dev.mongodb.com'); +} + +const defualtMmsDir = path.join(os.tmpdir(), '.mms'); +const mmsDir = process.env.MMS_HOME || defualtMmsDir; + +const execFileAsync = util.promisify(child_process.execFile); + +async function pathExists(path: string) { + try { + await fs.promises.stat(path); + return true; + } catch { + return false; + } +} + +async function runMmsDevServer() { + // TODO: if something running on 8081, assume it's devserver and skip + if (!process.env.MMS_HOME && !(await pathExists(defualtMmsDir))) { + console.warn(); + console.warn( + 'WARN: Environmental variable MMS_HOME is not set. Assuming mms repo is not cloned, cloning from remote to %s. This is slow, to speed up dev build, clone mms repo locally and set MMS_HOME env variable to the mms root directory.', + defualtMmsDir + ); + console.warn(); + await execFileAsync('git', [ + 'clone', + '--depth=1', + 'git@github.com:10gen/mms.git', + defualtMmsDir, + ]); + } + const { + default: { engines }, + } = await import(path.join(mmsDir, 'package.json'), { + with: { type: 'json' }, + }); + const pnpmVersion = engines.pnpm ?? 'latest'; + console.log('Installing mms dependencies via pnpm...'); + await execFileAsync( + 'npx', + [ + `pnpm@${pnpmVersion}`, + // mms requires exact Node.js version, Compass might be slightly off, this + // doesn't matter that much if we're in the same range + '--engine-strict=false', + 'install', + ], + { cwd: mmsDir } + ); + console.log('Starting mms dev server...'); + return new Promise((resolve) => { + const mmsDevServerProcess = child_process.execFile( + 'npx', + [ + `pnpm@${pnpmVersion}`, + '--engine-strict=false', + 'compile:js:apps', + // TODO: production mode + '--serve', + ], + { cwd: mmsDir, maxBuffer: Infinity } + ); + function resolveOnReady(chunk: any) { + if (/webpack .+? compiled (successfully|with \d warnings?)/.test(chunk)) { + mmsDevServerProcess.stdout?.off('data', resolveOnReady); + resolve(mmsDevServerProcess); + } + } + // TODO: super noisy, better logging + mmsDevServerProcess.stdout?.pipe(process.stdout); + mmsDevServerProcess.stderr?.pipe(process.stderr); + mmsDevServerProcess.stdout?.on('data', resolveOnReady); + }); +} + +async function runCompassWebSync() { + // TODO: check if this is already running, skip if it is + return new Promise((resolve) => { + const compassWebSyncBuild = child_process.execFile( + 'npm', + ['run', 'sync', '--workspace', '@mongodb-js/compass-web'], + { maxBuffer: Infinity, env: { ...process.env, MMS_HOME: mmsDir } } + ); + + function resolveOnReady(chunk: any) { + if (/webpack .+? compiled (successfully|with \d warnings?)/.test(chunk)) { + compassWebSyncBuild.stdout?.off('data', resolveOnReady); + resolve(compassWebSyncBuild); + } + } + // TODO: super noisy, better logging + compassWebSyncBuild.stdout?.pipe(process.stdout); + compassWebSyncBuild.stderr?.pipe(process.stderr); + compassWebSyncBuild.stdout?.on('data', resolveOnReady); + }); +} + +async function main() { + await runCompassWebSync(); + console.log('>>> compass-web ready'); + await runMmsDevServer(); + console.log('>>> mms ready'); + startBrowserWithPreloadedRedirectExtension(); +} + +main();