web/packages: NPM workspace: Mini Cleanup (#14767)
* web: Move non-workspace package. * web: Update ESBuild package version. * web: Use NPM link to alias local package. * web: Update lock. * web: Fix regression where bundler is expected.
This commit is contained in:
59
packages/esbuild-plugin-live-reload/.github/README.md
vendored
Normal file
59
packages/esbuild-plugin-live-reload/.github/README.md
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
_An ESBuild development plugin that watches for file changes and triggers automatic browser refreshes._
|
||||
|
||||
## Quick start
|
||||
|
||||
```sh
|
||||
npm install -D @goauthentik/esbuild-plugin-live-reload
|
||||
# Or with Yarn:
|
||||
yarn add -D @goauthentik/esbuild-plugin-live-reload
|
||||
```
|
||||
|
||||
### 1. Configure ESBuild
|
||||
|
||||
```js
|
||||
import { liveReloadPlugin } from "@goauthentik/esbuild-plugin-live-reload";
|
||||
import esbuild from "esbuild";
|
||||
|
||||
const NodeEnvironment = process.env.NODE_ENV || "development";
|
||||
|
||||
/**
|
||||
* @type {esbuild.BuildOptions}
|
||||
*/
|
||||
const buildOptions = {
|
||||
// ... Your build options.
|
||||
define: {
|
||||
"process.env.NODE_ENV": JSON.stringify(NodeEnvironment),
|
||||
},
|
||||
plugins: [
|
||||
/** @see {@link LiveReloadPluginOptions} */
|
||||
liveReloadPlugin(),
|
||||
],
|
||||
};
|
||||
|
||||
const buildContext = await esbuild.context(buildOptions);
|
||||
|
||||
await buildContext.rebuild();
|
||||
await buildContext.watch();
|
||||
```
|
||||
|
||||
### 2. Connect your browser
|
||||
|
||||
Add the following import near the beginning of your application's entry point.
|
||||
|
||||
```js
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
await import("@goauthentik/esbuild-plugin-live-reload/client");
|
||||
}
|
||||
```
|
||||
|
||||
That's it! Your browser will now automatically refresh whenever ESBuild finishes rebuilding your code.
|
||||
|
||||
## About authentik
|
||||
|
||||
[authentik](https://goauthentik.io) is an open source Identity Provider that unifies your identity needs into a single platform, replacing Okta, Active Directory, and Auth0.
|
||||
|
||||
We built this plugin to streamline our development workflow, and we're sharing it with the community. If you have any questions, feature requests, or bug reports, please [open an issue](https://github.com/goauthentik/authentik/issues/new/choose).
|
||||
|
||||
## License
|
||||
|
||||
This code is licensed under the [MIT License](https://www.tldrlegal.com/license/mit-license)
|
4
packages/esbuild-plugin-live-reload/.gitignore
vendored
Normal file
4
packages/esbuild-plugin-live-reload/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
README.md
|
||||
node_modules
|
||||
_media
|
||||
!.github/README.md
|
3
packages/esbuild-plugin-live-reload/.prettierignore
Normal file
3
packages/esbuild-plugin-live-reload/.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
./README.md
|
||||
out
|
18
packages/esbuild-plugin-live-reload/LICENSE.txt
Normal file
18
packages/esbuild-plugin-live-reload/LICENSE.txt
Normal file
@ -0,0 +1,18 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2025 Authentik Security, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
221
packages/esbuild-plugin-live-reload/client/ESBuildObserver.js
Normal file
221
packages/esbuild-plugin-live-reload/client/ESBuildObserver.js
Normal file
@ -0,0 +1,221 @@
|
||||
/// <reference types="./types.js" />
|
||||
|
||||
/**
|
||||
* @file Client-side observer for ESBuild events.
|
||||
*
|
||||
* @import { Message as ESBuildMessage } from "esbuild";
|
||||
*/
|
||||
|
||||
const logPrefix = "authentik/dev/web: ";
|
||||
const log = console.debug.bind(console, logPrefix);
|
||||
|
||||
/**
|
||||
* @template {unknown} [Data=unknown]
|
||||
* @typedef {(event: MessageEvent) => void} BuildEventListener
|
||||
*/
|
||||
|
||||
/**
|
||||
* A client-side watcher for ESBuild.
|
||||
*
|
||||
* Note that this should be conditionally imported in your code, so that
|
||||
* ESBuild may tree-shake it out of production builds.
|
||||
*
|
||||
* ```ts
|
||||
* if (process.env.NODE_ENV === "development") {
|
||||
* await import("@goauthentik/esbuild-plugin-live-reload/client")
|
||||
* .catch(() => console.warn("Failed to import watcher"))
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @implements {Disposable}
|
||||
* @category Plugin
|
||||
* runtime browser
|
||||
*/
|
||||
export class ESBuildObserver extends EventSource {
|
||||
/**
|
||||
* Whether the watcher has a recent connection to the server.
|
||||
*/
|
||||
alive = true;
|
||||
|
||||
/**
|
||||
* The number of errors that have occurred since the watcher started.
|
||||
*/
|
||||
errorCount = 0;
|
||||
|
||||
/**
|
||||
* Whether a reload has been requested while offline.
|
||||
*/
|
||||
deferredReload = false;
|
||||
|
||||
/**
|
||||
* The last time a message was received from the server.
|
||||
*/
|
||||
lastUpdatedAt = Date.now();
|
||||
|
||||
/**
|
||||
* Whether the browser considers itself online.
|
||||
*/
|
||||
online = true;
|
||||
|
||||
/**
|
||||
* The ID of the animation frame for the reload.
|
||||
*/
|
||||
#reloadFrameID = -1;
|
||||
|
||||
/**
|
||||
* The interval for the keep-alive check.
|
||||
* @type {ReturnType<typeof setInterval> | undefined}
|
||||
*/
|
||||
#keepAliveInterval;
|
||||
|
||||
#trackActivity = () => {
|
||||
this.lastUpdatedAt = Date.now();
|
||||
this.alive = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {BuildEventListener}
|
||||
*/
|
||||
#startListener = () => {
|
||||
this.#trackActivity();
|
||||
log("⏰ Build started...");
|
||||
};
|
||||
|
||||
#internalErrorListener = () => {
|
||||
this.errorCount += 1;
|
||||
|
||||
if (this.errorCount > 100) {
|
||||
clearTimeout(this.#keepAliveInterval);
|
||||
|
||||
this.close();
|
||||
log("⛔️ Closing connection");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {BuildEventListener<string>}
|
||||
*/
|
||||
#errorListener = (event) => {
|
||||
this.#trackActivity();
|
||||
|
||||
console.group(logPrefix, "⛔️⛔️⛔️ Build error...");
|
||||
|
||||
/**
|
||||
* @type {ESBuildMessage[]}
|
||||
*/
|
||||
const esbuildErrorMessages = JSON.parse(event.data);
|
||||
|
||||
for (const error of esbuildErrorMessages) {
|
||||
console.warn(error.text);
|
||||
|
||||
if (error.location) {
|
||||
console.debug(
|
||||
`file://${error.location.file}:${error.location.line}:${error.location.column}`,
|
||||
);
|
||||
console.debug(error.location.lineText);
|
||||
}
|
||||
}
|
||||
|
||||
console.groupEnd();
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {BuildEventListener}
|
||||
*/
|
||||
#endListener = () => {
|
||||
cancelAnimationFrame(this.#reloadFrameID);
|
||||
|
||||
this.#trackActivity();
|
||||
|
||||
if (!this.online) {
|
||||
log("🚫 Build finished while offline.");
|
||||
this.deferredReload = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
log("🛎️ Build completed! Reloading...");
|
||||
|
||||
// We use an animation frame to keep the reload from happening before the
|
||||
// event loop has a chance to process the message.
|
||||
this.#reloadFrameID = requestAnimationFrame(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {BuildEventListener}
|
||||
*/
|
||||
#keepAliveListener = () => {
|
||||
this.#trackActivity();
|
||||
log("🏓 Keep-alive");
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the ESBuild observer.
|
||||
* This should be called once in your application.
|
||||
*
|
||||
* @param {string | URL} [url]
|
||||
* @returns {ESBuildObserver}
|
||||
*/
|
||||
static initialize = (url) => {
|
||||
const esbuildObserver = new ESBuildObserver(url);
|
||||
|
||||
return esbuildObserver;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string | URL} [url]
|
||||
*/
|
||||
constructor(url) {
|
||||
if (!url) {
|
||||
throw new TypeError("ESBuildObserver: Cannot construct without a URL");
|
||||
}
|
||||
|
||||
super(url);
|
||||
|
||||
this.addEventListener("esbuild:start", this.#startListener);
|
||||
this.addEventListener("esbuild:end", this.#endListener);
|
||||
this.addEventListener("esbuild:error", this.#errorListener);
|
||||
this.addEventListener("esbuild:keep-alive", this.#keepAliveListener);
|
||||
|
||||
this.addEventListener("error", this.#internalErrorListener);
|
||||
|
||||
window.addEventListener("offline", () => {
|
||||
this.online = false;
|
||||
});
|
||||
|
||||
window.addEventListener("online", () => {
|
||||
this.online = true;
|
||||
|
||||
if (!this.deferredReload) return;
|
||||
|
||||
log("🛎️ Reloading after offline build...");
|
||||
this.deferredReload = false;
|
||||
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
log("🛎️ Listening for build changes...");
|
||||
|
||||
this.#keepAliveInterval = setInterval(() => {
|
||||
const now = Date.now();
|
||||
|
||||
if (now - this.lastUpdatedAt < 10_000) return;
|
||||
|
||||
this.alive = false;
|
||||
log("👋 Waiting for build to start...");
|
||||
}, 15_000);
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
return this.close();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
return this[Symbol.dispose]();
|
||||
}
|
||||
}
|
||||
|
||||
export default ESBuildObserver;
|
13
packages/esbuild-plugin-live-reload/client/index.js
Normal file
13
packages/esbuild-plugin-live-reload/client/index.js
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference types="./types.js" />
|
||||
/**
|
||||
* @file Entry point for the ESBuild client-side observer.
|
||||
*/
|
||||
import { ESBuildObserver } from "./ESBuildObserver.js";
|
||||
|
||||
if (import.meta.env?.ESBUILD_WATCHER_URL) {
|
||||
const buildObserver = new ESBuildObserver(import.meta.env.ESBUILD_WATCHER_URL);
|
||||
|
||||
window.addEventListener("beforeunload", () => {
|
||||
buildObserver.dispose();
|
||||
});
|
||||
}
|
23
packages/esbuild-plugin-live-reload/client/types.d.ts
vendored
Normal file
23
packages/esbuild-plugin-live-reload/client/types.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @file Import meta environment variables available via ESBuild.
|
||||
*/
|
||||
|
||||
export {};
|
||||
declare global {
|
||||
/**
|
||||
* Environment variables injected by ESBuild.
|
||||
*/
|
||||
interface ImportMetaEnv {
|
||||
/**
|
||||
* The injected watcher URL for ESBuild.
|
||||
* This is used for live reloading in development mode.
|
||||
*
|
||||
* @format url
|
||||
*/
|
||||
readonly ESBUILD_WATCHER_URL?: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
}
|
6
packages/esbuild-plugin-live-reload/index.js
Normal file
6
packages/esbuild-plugin-live-reload/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @remarks Live reload plugin for ESBuild.
|
||||
*/
|
||||
|
||||
export * from "./client/index.js";
|
||||
export * from "./plugin/index.js";
|
1283
packages/esbuild-plugin-live-reload/package-lock.json
generated
Normal file
1283
packages/esbuild-plugin-live-reload/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
75
packages/esbuild-plugin-live-reload/package.json
Normal file
75
packages/esbuild-plugin-live-reload/package.json
Normal file
@ -0,0 +1,75 @@
|
||||
{
|
||||
"name": "@goauthentik/esbuild-plugin-live-reload",
|
||||
"version": "1.0.6",
|
||||
"description": "ESBuild + browser refresh. Build completes, page reloads.",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "npm run build:types && npm run build:docs",
|
||||
"build:docs": "typedoc",
|
||||
"build:types": "tsc -p .",
|
||||
"prettier": "prettier --cache --write -u .",
|
||||
"prettier-check": "prettier --cache --check -u ."
|
||||
},
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"types": "./out/index.d.ts",
|
||||
"import": "./index.js"
|
||||
},
|
||||
"./client": {
|
||||
"types": "./out/client/index.d.ts",
|
||||
"import": "./client/index.js"
|
||||
},
|
||||
"./plugin": {
|
||||
"types": "./out/plugin/index.d.ts",
|
||||
"import": "./plugin/index.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"find-free-ports": "^3.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@goauthentik/prettier-config": "^1.0.5",
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/node": "^22.15.21",
|
||||
"esbuild": "^0.25.5",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-packagejson": "^2.5.14",
|
||||
"typedoc": "^0.28.5",
|
||||
"typedoc-plugin-markdown": "^4.6.3",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"esbuild": "^0.25.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
},
|
||||
"keywords": [
|
||||
"esbuild",
|
||||
"live-reload",
|
||||
"browser",
|
||||
"refresh",
|
||||
"reload",
|
||||
"authentik"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/goauthentik/authentik.git",
|
||||
"directory": "web/packages/esbuild-plugin-live-reload"
|
||||
},
|
||||
"types": "./out/index.d.ts",
|
||||
"files": [
|
||||
"./index.js",
|
||||
"client/**/*",
|
||||
"plugin/**/*",
|
||||
"out/**/*"
|
||||
],
|
||||
"prettier": "@goauthentik/prettier-config",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
265
packages/esbuild-plugin-live-reload/plugin/index.js
Normal file
265
packages/esbuild-plugin-live-reload/plugin/index.js
Normal file
@ -0,0 +1,265 @@
|
||||
/**
|
||||
* @file Live reload plugin for ESBuild.
|
||||
*
|
||||
* @import { ListenOptions } from "node:net";
|
||||
* @import {Server as HTTPServer} from "node:http";
|
||||
* @import {Server as HTTPSServer} from "node:https";
|
||||
*/
|
||||
import { findFreePorts } from "find-free-ports";
|
||||
import * as http from "node:http";
|
||||
import { resolve as resolvePath } from "node:path";
|
||||
|
||||
/**
|
||||
* Serializes a custom event to a text stream.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @returns {string}
|
||||
*
|
||||
* @category Server API
|
||||
* @ignore
|
||||
* @internal
|
||||
* @runtime node
|
||||
*/
|
||||
export function serializeCustomEventToStream(event) {
|
||||
// @ts-expect-error - TS doesn't know about the detail property
|
||||
const data = event.detail ?? {};
|
||||
|
||||
const eventContent = [`event: ${event.type}`, `data: ${JSON.stringify(data)}`];
|
||||
|
||||
return eventContent.join("\n") + "\n\n";
|
||||
}
|
||||
|
||||
const MIN_PORT = 1025;
|
||||
const MAX_PORT = 65535;
|
||||
|
||||
/**
|
||||
* Find a random port that is not in use, sufficiently far from the default port.
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
async function findDisparatePort() {
|
||||
const startPort = Math.floor(Math.random() * (MAX_PORT - MIN_PORT + 1)) + MIN_PORT;
|
||||
|
||||
const wathcherPorts = await findFreePorts(1, {
|
||||
startPort,
|
||||
});
|
||||
|
||||
const [port] = wathcherPorts;
|
||||
|
||||
if (!port) {
|
||||
throw new Error("No free ports available");
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event server initialization options.
|
||||
*
|
||||
* @typedef {Object} EventServerInit
|
||||
*
|
||||
* @property {string} pathname
|
||||
* @property {EventTarget} dispatcher
|
||||
* @property {string} [logPrefix]
|
||||
*
|
||||
* @category Server API
|
||||
* @runtime node
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {(req: http.IncomingMessage, res: http.ServerResponse) => void} RequestHandler
|
||||
*
|
||||
* @category Server API
|
||||
* @runtime node
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create an event request handler.
|
||||
*
|
||||
* @param {EventServerInit} options
|
||||
* @returns {RequestHandler}
|
||||
*
|
||||
* @category Server API
|
||||
* @runtime node
|
||||
*/
|
||||
export function createRequestHandler({ pathname, dispatcher, logPrefix = "Build Observer" }) {
|
||||
const log = console.log.bind(console, `[${logPrefix}]`);
|
||||
|
||||
/**
|
||||
* @type {RequestHandler}
|
||||
*/
|
||||
const requestHandler = (req, res) => {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
||||
|
||||
if (req.url !== pathname) {
|
||||
log(`🚫 Invalid request to ${req.url}`);
|
||||
res.writeHead(404);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
log("🔌 Client connected");
|
||||
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive",
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
const listener = (event) => {
|
||||
const body = serializeCustomEventToStream(event);
|
||||
|
||||
res.write(body);
|
||||
};
|
||||
|
||||
dispatcher.addEventListener("esbuild:start", listener);
|
||||
dispatcher.addEventListener("esbuild:error", listener);
|
||||
dispatcher.addEventListener("esbuild:end", listener);
|
||||
|
||||
req.on("close", () => {
|
||||
log("🔌 Client disconnected");
|
||||
|
||||
clearInterval(keepAliveInterval);
|
||||
|
||||
dispatcher.removeEventListener("esbuild:start", listener);
|
||||
dispatcher.removeEventListener("esbuild:error", listener);
|
||||
dispatcher.removeEventListener("esbuild:end", listener);
|
||||
});
|
||||
|
||||
const keepAliveInterval = setInterval(() => {
|
||||
console.timeStamp("🏓 Keep-alive");
|
||||
|
||||
res.write("event: keep-alive\n\n");
|
||||
res.write(serializeCustomEventToStream(new CustomEvent("esbuild:keep-alive")));
|
||||
}, 15_000);
|
||||
};
|
||||
|
||||
return requestHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for the build observer plugin.
|
||||
*
|
||||
* @category Plugin API
|
||||
* @runtime node
|
||||
*
|
||||
* @typedef {object} LiveReloadPluginOptions
|
||||
*
|
||||
* @property {HTTPServer | HTTPSServer} [server] A server to listen on. If not provided, a new server will be created.
|
||||
* @property {ListenOptions} [listenOptions] Options for the server's listen method.
|
||||
* @property {string | URL} [publicURL] A URL to listen on. If not provided, a random port will be used.
|
||||
* @property {string} [logPrefix] A prefix to use for log messages.
|
||||
* @property {string} [relativeRoot] A relative path to the root of the project. This is used to resolve build errors, line numbers, and file paths.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a plugin that listens for build events and sends them to a server-sent event stream.
|
||||
*
|
||||
* @param {LiveReloadPluginOptions} [options]
|
||||
* @returns {import('esbuild').Plugin}
|
||||
*/
|
||||
export function liveReloadPlugin(options = {}) {
|
||||
return {
|
||||
name: "build-watcher",
|
||||
setup: async (build) => {
|
||||
const logPrefix = options.logPrefix || "Build Observer";
|
||||
|
||||
const timerLabel = `[${logPrefix}] 🏁`;
|
||||
const relativeRoot = options.relativeRoot || process.cwd();
|
||||
|
||||
const dispatcher = new EventTarget();
|
||||
|
||||
/**
|
||||
* @type {URL}
|
||||
*/
|
||||
let publicURL;
|
||||
|
||||
if (!options.publicURL) {
|
||||
const port = await findDisparatePort();
|
||||
|
||||
publicURL = new URL(`http://localhost:${port}/events`);
|
||||
} else {
|
||||
publicURL =
|
||||
typeof options.publicURL === "string"
|
||||
? new URL(options.publicURL)
|
||||
: options.publicURL;
|
||||
}
|
||||
|
||||
build.initialOptions.define = {
|
||||
...build.initialOptions.define,
|
||||
"import.meta.env.ESBUILD_WATCHER_URL": JSON.stringify(publicURL.href),
|
||||
};
|
||||
|
||||
build.initialOptions.define["process.env.NODE_ENV"] ??= JSON.stringify(
|
||||
process.env.NODE_ENV || "development",
|
||||
);
|
||||
|
||||
const requestHandler = createRequestHandler({
|
||||
pathname: publicURL.pathname,
|
||||
dispatcher,
|
||||
logPrefix,
|
||||
});
|
||||
|
||||
const server = options.server || http.createServer(requestHandler);
|
||||
|
||||
const listenOptions = options.listenOptions || {
|
||||
port: parseInt(publicURL.port, 10),
|
||||
host: publicURL.hostname,
|
||||
};
|
||||
|
||||
server.listen(listenOptions, () => {
|
||||
console.log(`[${logPrefix}] Listening`);
|
||||
});
|
||||
|
||||
build.onDispose(() => {
|
||||
server?.close();
|
||||
});
|
||||
|
||||
build.onStart(() => {
|
||||
console.time(timerLabel);
|
||||
|
||||
dispatcher.dispatchEvent(
|
||||
new CustomEvent("esbuild:start", {
|
||||
detail: new Date().toISOString(),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
build.onEnd((buildResult) => {
|
||||
console.timeEnd(timerLabel);
|
||||
|
||||
if (!buildResult.errors.length) {
|
||||
dispatcher.dispatchEvent(
|
||||
new CustomEvent("esbuild:end", {
|
||||
detail: new Date().toISOString(),
|
||||
}),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn(`Build ended with ${buildResult.errors.length} errors`);
|
||||
|
||||
dispatcher.dispatchEvent(
|
||||
new CustomEvent("esbuild:error", {
|
||||
detail: buildResult.errors.map((error) => ({
|
||||
...error,
|
||||
location: error.location
|
||||
? {
|
||||
...error.location,
|
||||
file: resolvePath(relativeRoot, error.location.file),
|
||||
}
|
||||
: null,
|
||||
})),
|
||||
}),
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default liveReloadPlugin;
|
14
packages/esbuild-plugin-live-reload/tsconfig.json
Normal file
14
packages/esbuild-plugin-live-reload/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "@goauthentik/tsconfig",
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"resolveJsonModule": true,
|
||||
"baseUrl": ".",
|
||||
"checkJs": true,
|
||||
"emitDeclarationOnly": true
|
||||
},
|
||||
"exclude": [
|
||||
// ---
|
||||
"**/out/**/*"
|
||||
]
|
||||
}
|
66
packages/esbuild-plugin-live-reload/typedoc.json
Normal file
66
packages/esbuild-plugin-live-reload/typedoc.json
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
"$schema": "https://typedoc-plugin-markdown.org/schema.json",
|
||||
"entryPoints": ["./plugin/index.js"],
|
||||
"plugin": ["typedoc-plugin-markdown"],
|
||||
"name": "ESBuild Plugin Live Reload",
|
||||
"formatWithPrettier": true,
|
||||
"prettierConfigFile": "@goauthentik/prettier-config",
|
||||
"flattenOutputFiles": true,
|
||||
"readme": ".github/README.md",
|
||||
"mergeReadme": true,
|
||||
"enumMembersFormat": "table",
|
||||
"parametersFormat": "table",
|
||||
"interfacePropertiesFormat": "table",
|
||||
"typeDeclarationFormat": "table",
|
||||
"indexFormat": "table",
|
||||
"router": "module",
|
||||
"jsDocCompatibility": true,
|
||||
"defaultCategory": "Plugin API",
|
||||
"disableSources": true,
|
||||
"out": ".",
|
||||
"cleanOutputDir": false,
|
||||
"blockTags": [
|
||||
"@runtime",
|
||||
"@file",
|
||||
"@defaultValue",
|
||||
"@deprecated",
|
||||
"@example",
|
||||
"@param",
|
||||
"@privateRemarks",
|
||||
"@remarks",
|
||||
"@returns",
|
||||
"@see",
|
||||
"@throws",
|
||||
"@typeParam",
|
||||
"@author",
|
||||
"@callback",
|
||||
"@category",
|
||||
"@categoryDescription",
|
||||
"@default",
|
||||
"@document",
|
||||
"@extends",
|
||||
"@augments",
|
||||
"@yields",
|
||||
"@group",
|
||||
"@groupDescription",
|
||||
"@import",
|
||||
"@inheritDoc",
|
||||
"@jsx",
|
||||
"@license",
|
||||
"@module",
|
||||
"@mergeModuleWith",
|
||||
"@prop",
|
||||
"@property",
|
||||
"@return",
|
||||
"@satisfies",
|
||||
"@since",
|
||||
"@template",
|
||||
"@type",
|
||||
"@typedef",
|
||||
"@summary",
|
||||
"@preventInline",
|
||||
"@inlineType",
|
||||
"@preventExpand",
|
||||
"@expandType"
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user