147 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import * as chokidar from "chokidar";
 | 
						|
import esbuild from "esbuild";
 | 
						|
import fs from "fs";
 | 
						|
import { globSync } from "glob";
 | 
						|
import path from "path";
 | 
						|
import { cwd } from "process";
 | 
						|
import process from "process";
 | 
						|
import { fileURLToPath } from "url";
 | 
						|
 | 
						|
const __dirname = fileURLToPath(new URL(".", import.meta.url));
 | 
						|
 | 
						|
// eslint-disable-next-line no-undef
 | 
						|
const isProdBuild = process.env.NODE_ENV === "production";
 | 
						|
 | 
						|
// eslint-disable-next-line no-undef
 | 
						|
const apiBasePath = process.env.AK_API_BASE_PATH || "";
 | 
						|
 | 
						|
const definitions = {
 | 
						|
    "process.env.NODE_ENV": JSON.stringify(isProdBuild ? "production" : "development"),
 | 
						|
    "process.env.CWD": JSON.stringify(cwd()),
 | 
						|
    "process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath),
 | 
						|
};
 | 
						|
 | 
						|
// 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.
 | 
						|
 | 
						|
const otherFiles = [
 | 
						|
    ["node_modules/@patternfly/patternfly/patternfly.min.css", "."],
 | 
						|
    ["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"],
 | 
						|
    ["src/custom.css", "."],
 | 
						|
    ["src/common/styles/**", "."],
 | 
						|
    ["src/assets/images/**", "./assets/images"],
 | 
						|
    ["./icons/*", "./assets/icons"],
 | 
						|
];
 | 
						|
 | 
						|
const isFile = (filePath) => fs.statSync(filePath).isFile();
 | 
						|
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 otherFiles) {
 | 
						|
    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)) {
 | 
						|
            fs.mkdirSync(path.dirname(dest), { recursive: true });
 | 
						|
            fs.copyFileSync(src, dest);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// This starts the definitions used for esbuild: Our targets, our arguments, the function for running a build, and three
 | 
						|
// options for building: watching, building, and building the proxy.
 | 
						|
 | 
						|
const interfaces = [
 | 
						|
    ["polyfill/poly.ts", "."],
 | 
						|
    ["standalone/loading/index.ts", "standalone/loading"],
 | 
						|
    ["flow/FlowInterface.ts", "flow"],
 | 
						|
    ["user/UserInterface.ts", "user"],
 | 
						|
    ["enterprise/rac/index.ts", "enterprise/rac"],
 | 
						|
    ["standalone/api-browser/index.ts", "standalone/api-browser"],
 | 
						|
    ["admin/AdminInterface/AdminInterface.ts", "admin"],
 | 
						|
];
 | 
						|
 | 
						|
const baseArgs = {
 | 
						|
    bundle: true,
 | 
						|
    write: true,
 | 
						|
    sourcemap: !isProdBuild,
 | 
						|
    minify: isProdBuild,
 | 
						|
    splitting: true,
 | 
						|
    treeShaking: true,
 | 
						|
    external: ["*.woff", "*.woff2"],
 | 
						|
    tsconfig: "./tsconfig.json",
 | 
						|
    loader: { ".css": "text", ".md": "text" },
 | 
						|
    define: definitions,
 | 
						|
    format: "esm",
 | 
						|
};
 | 
						|
 | 
						|
function buildAuthentik(interfaces) {
 | 
						|
    for (const [source, dest] of interfaces) {
 | 
						|
        const DIST = path.join(__dirname, "./dist", dest);
 | 
						|
        console.log(`[${new Date(Date.now()).toISOString()}] Starting build for target ${source}`);
 | 
						|
        try {
 | 
						|
            const start = Date.now();
 | 
						|
            esbuild.buildSync({
 | 
						|
                ...baseArgs,
 | 
						|
                entryPoints: [`./src/${source}`],
 | 
						|
                outdir: DIST,
 | 
						|
            });
 | 
						|
            const end = Date.now();
 | 
						|
            console.log(
 | 
						|
                `[${new Date(end).toISOString()}] Finished build for target ${source} in ${Date.now() - start}ms`,
 | 
						|
            );
 | 
						|
        } catch (exc) {
 | 
						|
            console.error(
 | 
						|
                `[${new Date(Date.now()).toISOString()}] Failed to build ${source}: ${exc}`,
 | 
						|
            );
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
let timeoutId = null;
 | 
						|
function debouncedBuild() {
 | 
						|
    if (timeoutId !== null) {
 | 
						|
        clearTimeout(timeoutId);
 | 
						|
    }
 | 
						|
    timeoutId = setTimeout(() => {
 | 
						|
        console.clear();
 | 
						|
        buildAuthentik(interfaces);
 | 
						|
    }, 250);
 | 
						|
}
 | 
						|
 | 
						|
if (process.argv.length > 2 && (process.argv[2] === "-h" || process.argv[2] === "--help")) {
 | 
						|
    console.log(`Build the authentikUI
 | 
						|
 | 
						|
options:
 | 
						|
  -w, --watch: Build all ${interfaces.length} interfaces
 | 
						|
  -p, --proxy: Build only the polyfills and the loading application
 | 
						|
  -h, --help: This help message
 | 
						|
`);
 | 
						|
    process.exit(0);
 | 
						|
}
 | 
						|
 | 
						|
if (process.argv.length > 2 && (process.argv[2] === "-w" || process.argv[2] === "--watch")) {
 | 
						|
    console.log("Watching ./src for changes");
 | 
						|
    chokidar.watch("./src").on("all", (event, path) => {
 | 
						|
        if (!["add", "change", "unlink"].includes(event)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        if (!/(\.css|\.ts|\.js)$/.test(path)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        debouncedBuild();
 | 
						|
    });
 | 
						|
} else if (process.argv.length > 2 && (process.argv[2] === "-p" || process.argv[2] === "--proxy")) {
 | 
						|
    // There's no watch-for-proxy, sorry.
 | 
						|
    buildAuthentik(interfaces.slice(0, 2));
 | 
						|
    process.exit(0);
 | 
						|
} else {
 | 
						|
    // And the fallback: just build it.
 | 
						|
    buildAuthentik(interfaces);
 | 
						|
}
 |