 0d18c1d797
			
		
	
	0d18c1d797
	
	
	
		
			
			* web: fix regression in subpath support, part 1 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix media path in subpath Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
		
			
				
	
	
		
			248 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			248 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /// <reference types="../types/esbuild.js" />
 | |
| /**
 | |
|  * @file ESBuild script for building the authentik web UI.
 | |
|  *
 | |
|  * @import { BuildOptions } from "esbuild";
 | |
|  */
 | |
| import { mdxPlugin } from "#bundler/mdx-plugin/node";
 | |
| import { createBundleDefinitions } from "#bundler/utils/node";
 | |
| import { DistDirectory, EntryPoint, PackageRoot } from "#paths/node";
 | |
| import { NodeEnvironment } from "@goauthentik/core/environment/node";
 | |
| import { MonoRepoRoot, resolvePackage } from "@goauthentik/core/paths/node";
 | |
| import { readBuildIdentifier } from "@goauthentik/core/version/node";
 | |
| import { deepmerge } from "deepmerge-ts";
 | |
| import esbuild from "esbuild";
 | |
| import copy from "esbuild-plugin-copy";
 | |
| import { polyfillNode } from "esbuild-plugin-polyfill-node";
 | |
| import * as fs from "node:fs/promises";
 | |
| import * as path from "node:path";
 | |
| 
 | |
| const logPrefix = "[Build]";
 | |
| 
 | |
| const patternflyPath = resolvePackage("@patternfly/patternfly", import.meta);
 | |
| 
 | |
| /**
 | |
|  * @type {Readonly<BuildOptions>}
 | |
|  */
 | |
| const BASE_ESBUILD_OPTIONS = {
 | |
|     entryNames: `[dir]/[name]-${readBuildIdentifier()}`,
 | |
|     chunkNames: "[dir]/chunks/[hash]",
 | |
|     assetNames: "assets/[dir]/[name]-[hash]",
 | |
|     outdir: DistDirectory,
 | |
|     bundle: true,
 | |
|     write: true,
 | |
|     sourcemap: true,
 | |
|     minify: NodeEnvironment === "production",
 | |
|     legalComments: "external",
 | |
|     splitting: true,
 | |
|     treeShaking: true,
 | |
|     external: ["*.woff", "*.woff2"],
 | |
|     tsconfig: path.resolve(PackageRoot, "tsconfig.build.json"),
 | |
|     loader: {
 | |
|         ".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: MonoRepoRoot,
 | |
|         }),
 | |
|     ],
 | |
|     define: createBundleDefinitions(),
 | |
|     format: "esm",
 | |
|     logOverride: {
 | |
|         /**
 | |
|          * HACK: Silences issue originating in ESBuild.
 | |
|          *
 | |
|          * @see {@link https://github.com/evanw/esbuild/blob/b914dd30294346aa15fcc04278f4b4b51b8b43b5/internal/logger/msg_ids.go#L211 ESBuild source}
 | |
|          * @expires 2025-08-11
 | |
|          */
 | |
|         "invalid-source-url": "silent",
 | |
|     },
 | |
| };
 | |
| 
 | |
| async function cleanDistDirectory() {
 | |
|     const timerLabel = `${logPrefix} ♻️ Cleaning previous builds...`;
 | |
| 
 | |
|     console.time(timerLabel);
 | |
| 
 | |
|     await fs.rm(DistDirectory, {
 | |
|         recursive: true,
 | |
|         force: true,
 | |
|     });
 | |
| 
 | |
|     await fs.mkdir(DistDirectory, {
 | |
|         recursive: true,
 | |
|     });
 | |
| 
 | |
|     console.timeEnd(timerLabel);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Creates an ESBuild options, extending the base options with the given overrides.
 | |
|  *
 | |
|  * @param {BuildOptions} overrides
 | |
|  * @returns {BuildOptions}
 | |
|  */
 | |
| export function createESBuildOptions(overrides) {
 | |
|     /**
 | |
|      * @type {BuildOptions}
 | |
|      */
 | |
|     const mergedOptions = deepmerge(BASE_ESBUILD_OPTIONS, overrides);
 | |
| 
 | |
|     return mergedOptions;
 | |
| }
 | |
| 
 | |
| function doHelp() {
 | |
|     console.log(`Build the authentik UI
 | |
| 
 | |
|         options:
 | |
|             -w, --watch: Build all interfaces
 | |
|             -p, --proxy: Build only the polyfills and the loading application
 | |
|             -h, --help: This help message
 | |
| `);
 | |
| 
 | |
|     process.exit(0);
 | |
| }
 | |
| 
 | |
| async function doWatch() {
 | |
|     console.group(`${logPrefix} 🤖 Watching entry points`);
 | |
| 
 | |
|     const entryPoints = Object.entries(EntryPoint).map(([entrypointID, target]) => {
 | |
|         console.log(entrypointID);
 | |
| 
 | |
|         return target;
 | |
|     });
 | |
| 
 | |
|     console.groupEnd();
 | |
| 
 | |
|     const developmentPlugins = await import("@goauthentik/esbuild-plugin-live-reload/plugin")
 | |
|         .then(({ liveReloadPlugin }) => [
 | |
|             liveReloadPlugin({
 | |
|                 relativeRoot: PackageRoot,
 | |
|             }),
 | |
|         ])
 | |
|         .catch(() => []);
 | |
| 
 | |
|     const buildOptions = createESBuildOptions({
 | |
|         entryPoints,
 | |
|         plugins: developmentPlugins,
 | |
|     });
 | |
| 
 | |
|     const buildContext = await esbuild.context(buildOptions);
 | |
| 
 | |
|     await buildContext.rebuild();
 | |
|     await buildContext.watch();
 | |
| 
 | |
|     const httpURL = new URL("http://localhost");
 | |
|     httpURL.port = process.env.COMPOSE_PORT_HTTP ?? "9000";
 | |
| 
 | |
|     const httpsURL = new URL("https://localhost");
 | |
|     httpsURL.port = process.env.COMPOSE_PORT_HTTPS ?? "9443";
 | |
| 
 | |
|     console.log(`\n${logPrefix} 🚀 Server running\n\n`);
 | |
| 
 | |
|     console.log(`  🔓 ${httpURL.href}`);
 | |
|     console.log(`  🔒 ${httpsURL.href}`);
 | |
| 
 | |
|     console.log(`\n---`);
 | |
| 
 | |
|     return /** @type {Promise<void>} */ (
 | |
|         new Promise((resolve) => {
 | |
|             process.on("SIGINT", () => {
 | |
|                 resolve();
 | |
|             });
 | |
|         })
 | |
|     );
 | |
| }
 | |
| 
 | |
| async function doBuild() {
 | |
|     console.group(`${logPrefix} 🚀 Building entry points:`);
 | |
| 
 | |
|     const entryPoints = Object.entries(EntryPoint).map(([entrypointID, target]) => {
 | |
|         console.log(entrypointID);
 | |
| 
 | |
|         return target;
 | |
|     });
 | |
| 
 | |
|     console.groupEnd();
 | |
| 
 | |
|     const buildOptions = createESBuildOptions({
 | |
|         entryPoints,
 | |
|     });
 | |
| 
 | |
|     await esbuild.build(buildOptions);
 | |
| 
 | |
|     console.log("Build complete");
 | |
| }
 | |
| 
 | |
| async function doProxy() {
 | |
|     const entryPoints = [EntryPoint.StandaloneLoading];
 | |
| 
 | |
|     const buildOptions = createESBuildOptions({
 | |
|         entryPoints,
 | |
|     });
 | |
| 
 | |
|     await esbuild.build(buildOptions);
 | |
|     console.log("Proxy build complete");
 | |
| }
 | |
| 
 | |
| async function delegateCommand() {
 | |
|     const command = process.argv[2];
 | |
| 
 | |
|     switch (command) {
 | |
|         case "-h":
 | |
|         case "--help":
 | |
|             return doHelp();
 | |
|         case "-w":
 | |
|         case "--watch":
 | |
|             return doWatch();
 | |
|         // There's no watch-for-proxy, sorry.
 | |
|         case "-p":
 | |
|         case "--proxy":
 | |
|             return doProxy();
 | |
|         default:
 | |
|             return doBuild();
 | |
|     }
 | |
| }
 | |
| 
 | |
| await cleanDistDirectory()
 | |
|     // ---
 | |
|     .then(() =>
 | |
|         delegateCommand()
 | |
|             .then(() => {
 | |
|                 process.exit(0);
 | |
|             })
 | |
|             .catch((error) => {
 | |
|                 console.error(error);
 | |
|                 process.exit(1);
 | |
|             }),
 | |
|     );
 |