From 621b0e642ca00a1d5b9d31f0d3d79e5980d241e1 Mon Sep 17 00:00:00 2001 From: Teffen Ellis Date: Tue, 22 Apr 2025 01:14:22 +0200 Subject: [PATCH] web: Use monorepo utilities when building. --- web/package-lock.json | 284 +++++++++++++++++++++++++++----------- web/package.json | 2 +- web/scripts/build-web.mjs | 134 ++++++------------ 3 files changed, 247 insertions(+), 173 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 1f6ee4b51e..8546e912a4 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -106,13 +106,13 @@ "@wdio/spec-reporter": "^9.1.2", "chromedriver": "^131.0.1", "esbuild": "^0.25.0", + "esbuild-plugin-copy": "^2.1.1", "esbuild-plugin-polyfill-node": "^0.3.0", "esbuild-plugins-node-modules-polyfill": "^1.7.0", "eslint": "^9.11.1", "eslint-plugin-lit": "^1.15.0", "eslint-plugin-wc": "^2.1.1", "github-slugger": "^2.0.0", - "glob": "^11.0.0", "globals": "^15.10.0", "knip": "^5.30.6", "lit-analyzer": "^2.0.3", @@ -12054,6 +12054,193 @@ "node": ">=12" } }, + "node_modules/esbuild-plugin-copy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/esbuild-plugin-copy/-/esbuild-plugin-copy-2.1.1.tgz", + "integrity": "sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "fs-extra": "^10.0.1", + "globby": "^11.0.3" + }, + "peerDependencies": { + "esbuild": ">= 0.14.0" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild-plugin-copy/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esbuild-plugin-copy/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/esbuild-plugin-polyfill-node": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/esbuild-plugin-polyfill-node/-/esbuild-plugin-polyfill-node-0.3.0.tgz", @@ -13836,29 +14023,6 @@ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "dev": true }, - "node_modules/glob": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", - "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -13871,21 +14035,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "15.10.0", "resolved": "https://registry.npmjs.org/globals/-/globals-15.10.0.tgz", @@ -15357,21 +15506,6 @@ "node": ">=8" } }, - "node_modules/jackspeak": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", - "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/jake": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", @@ -16734,15 +16868,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/lru-cache": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz", - "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==", - "dev": true, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/magic-string": { "version": "0.30.15", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.15.tgz", @@ -19805,22 +19930,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "dev": true, - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/path-to-regexp": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", @@ -26302,6 +26411,23 @@ "node": ">=20.11" } }, + "packages/monorepo/node_modules/@types/node": { + "version": "22.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", + "integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "packages/monorepo/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, "packages/sfe": { "name": "@goauthentik/web-sfe", "version": "0.0.0", diff --git a/web/package.json b/web/package.json index 6d0842e3b2..c5f701c938 100644 --- a/web/package.json +++ b/web/package.json @@ -133,13 +133,13 @@ "@wdio/spec-reporter": "^9.1.2", "chromedriver": "^131.0.1", "esbuild": "^0.25.0", + "esbuild-plugin-copy": "^2.1.1", "esbuild-plugin-polyfill-node": "^0.3.0", "esbuild-plugins-node-modules-polyfill": "^1.7.0", "eslint": "^9.11.1", "eslint-plugin-lit": "^1.15.0", "eslint-plugin-wc": "^2.1.1", "github-slugger": "^2.0.0", - "glob": "^11.0.0", "globals": "^15.10.0", "knip": "^5.30.6", "lit-analyzer": "^2.0.3", diff --git a/web/scripts/build-web.mjs b/web/scripts/build-web.mjs index d985a0c13f..3b1f329e23 100644 --- a/web/scripts/build-web.mjs +++ b/web/scripts/build-web.mjs @@ -4,99 +4,38 @@ * @import { BuildOptions } from "esbuild"; */ import { liveReloadPlugin } from "@goauthentik/esbuild-plugin-live-reload/plugin"; +import { + MonoRepoRoot, + NodeEnvironment, + readBuildIdentifier, + resolvePackage, + serializeEnvironmentVars, +} from "@goauthentik/monorepo"; import { DistDirectory, DistDirectoryName, EntryPoint, PackageRoot } from "@goauthentik/web/paths"; import { deepmerge } from "deepmerge-ts"; import esbuild from "esbuild"; +import copy from "esbuild-plugin-copy"; import { polyfillNode } from "esbuild-plugin-polyfill-node"; -import { globSync } from "glob"; -import { execFileSync } from "node:child_process"; -import { copyFileSync, mkdirSync, readFileSync, statSync } from "node:fs"; import * as fs from "node:fs/promises"; import * as path from "node:path"; -import process, { cwd } from "node:process"; import { mdxPlugin } from "./esbuild/build-mdx-plugin.mjs"; const logPrefix = "[Build]"; -let authentikProjectRoot = path.join(__dirname, "..", ".."); +const definitions = serializeEnvironmentVars({ + NODE_ENV: NodeEnvironment, + CWD: process.cwd(), + AK_API_BASE_PATH: process.env.AK_API_BASE_PATH, +}); -try { - // Use the package.json file in the root folder, as it has the current version information. - authentikProjectRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], { - encoding: "utf8", - }).replace("\n", ""); -} catch (_error) { - // We probably don't have a .git folder, which could happen in container builds. -} - -const packageJSONPath = path.join(authentikProjectRoot, "./package.json"); -const rootPackage = JSON.parse(readFileSync(packageJSONPath, "utf8")); - -const NODE_ENV = process.env.NODE_ENV || "development"; -const AK_API_BASE_PATH = process.env.AK_API_BASE_PATH || ""; - -const environmentVars = new Map([ - ["NODE_ENV", NODE_ENV], - ["CWD", cwd()], - ["AK_API_BASE_PATH", AK_API_BASE_PATH], -]); - -const definitions = Object.fromEntries( - Array.from(environmentVars).map(([key, value]) => { - return [`process.env.${key}`, JSON.stringify(value)]; - }), -); -/** - * All is magic is just to make sure the assets are copied into the right places. This is a very - * stripped down version of what the rollup-copy-plugin does, without any of the features we don't - * use, and using globSync instead of globby since we already had globSync lying around thanks to - * Typescript. If there's a third argument in an array entry, it's used to replace the internal path - * before concatenating it all together as the destination target. - * @type {Array<[string, string, string?]>} - */ -const assetsFileMappings = [ - ["node_modules/@patternfly/patternfly/patternfly.min.css", "."], - ["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"], - ["src/common/styles/**", "."], - ["src/assets/images/**", "./assets/images"], - ["./icons/*", "./assets/icons"], -]; - -/** - * @param {string} filePath - */ -const isFile = (filePath) => statSync(filePath).isFile(); - -/** - * @param {string} src Source file - * @param {string} dest Destination folder - * @param {string} [strip] Path to strip from the source file - */ -function nameCopyTarget(src, dest, strip) { - const target = path.join(dest, strip ? src.replace(strip, "") : path.parse(src).base); - return [src, target]; -} - -for (const [source, rawdest, strip] of assetsFileMappings) { - const matchedPaths = globSync(source); - const dest = path.join("dist", rawdest); - - const copyTargets = matchedPaths.map((path) => nameCopyTarget(path, dest, strip)); - - for (const [src, dest] of copyTargets) { - if (isFile(src)) { - mkdirSync(path.dirname(dest), { recursive: true }); - copyFileSync(src, dest); - } - } -} +const patternflyPath = resolvePackage("@patternfly/patternfly"); /** * @type {Readonly} */ const BASE_ESBUILD_OPTIONS = { - entryNames: `[dir]/[name]-${composeVersionID()}`, + entryNames: `[dir]/[name]-${readBuildIdentifier()}`, chunkNames: "[dir]/chunks/[name]-[hash]", assetNames: "assets/[dir]/[name]-[hash]", publicPath: path.join("/static", DistDirectoryName), @@ -104,7 +43,7 @@ const BASE_ESBUILD_OPTIONS = { bundle: true, write: true, sourcemap: true, - minify: NODE_ENV === "production", + minify: NodeEnvironment === "production", legalComments: "external", splitting: true, treeShaking: true, @@ -114,13 +53,37 @@ const BASE_ESBUILD_OPTIONS = { ".css": "text", }, plugins: [ + copy({ + assets: [ + { + from: path.join(patternflyPath, "patternfly.min.css"), + to: ".", + }, + { + from: path.join(patternflyPath, "assets", "**"), + to: "./assets", + }, + { + from: path.resolve(PackageRoot, "src", "common", "styles", "**"), + to: ".", + }, + { + from: path.resolve(PackageRoot, "src", "assets", "images", "**"), + to: "./assets/images", + }, + { + from: path.resolve(PackageRoot, "icons", "*"), + to: "./assets/icons", + }, + ], + }), polyfillNode({ polyfills: { path: true, }, }), mdxPlugin({ - root: authentikProjectRoot, + root: MonoRepoRoot, }), ], define: definitions, @@ -136,21 +99,6 @@ const BASE_ESBUILD_OPTIONS = { }, }; -/** - * Creates a version ID for the build. - * @returns {string} - */ -function composeVersionID() { - const { version } = rootPackage; - const buildHash = process.env.GIT_BUILD_HASH; - - if (buildHash) { - return `${version}+${buildHash}`; - } - - return version; -} - async function cleanDistDirectory() { const timerLabel = `${logPrefix} ♻️ Cleaning previous builds...`;