Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions esbuild.dev.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Import Node.js Dependencies
import fs from "node:fs";
import fsAsync from "node:fs/promises";
import http from "node:http";
import path from "node:path";
import { fileURLToPath } from "node:url";

// Import Third-party Dependencies
import { getBuildConfiguration } from "@nodesecure/documentation-ui/node";
import * as i18n from "@nodesecure/i18n";
import esbuild from "esbuild";
import router from "find-my-way";
import open from "open";
import sirv from "sirv";

// Import Internal Dependencies
import english from "./i18n/english.js";
import french from "./i18n/french.js";
import { context as alsContext } from "./workspaces/server/src/ALS.ts";
import { ViewBuilder } from "./workspaces/server/src/ViewBuilder.class.ts";
import { cache } from "./workspaces/server/src/cache.ts";
import * as bundle from "./workspaces/server/src/endpoints/bundle.ts";
import * as config from "./workspaces/server/src/endpoints/config.ts";
import * as data from "./workspaces/server/src/endpoints/data.ts";
import * as flags from "./workspaces/server/src/endpoints/flags.ts";
import * as locali18n from "./workspaces/server/src/endpoints/i18n.ts";
import * as npmDownloads from "./workspaces/server/src/endpoints/npm-downloads.ts";
import * as scorecard from "./workspaces/server/src/endpoints/ossf-scorecard.ts";
import * as report from "./workspaces/server/src/endpoints/report.ts";
import * as root from "./workspaces/server/src/endpoints/root.ts";
import * as search from "./workspaces/server/src/endpoints/search.ts";
import { logger } from "./workspaces/server/src/logger.ts";
import { WebSocketServerInstanciator } from "./workspaces/server/src/websocket/index.ts";

// CONSTANTS
const __dirname = path.dirname(fileURLToPath(import.meta.url));

const kPublicDir = path.join(__dirname, "public");
const kOutDir = path.join(__dirname, "dist");
const kImagesDir = path.join(kPublicDir, "img");
const kNodeModulesDir = path.join(__dirname, "node_modules");
const kComponentsDir = path.join(kPublicDir, "components");
const kDefaultPayloadPath = path.join(process.cwd(), "nsecure-result.json");

const kDevPort = Number(process.env.DEV_PORT ?? 8080);

await i18n.getLocalLang();
await i18n.extendFromSystemPath(path.join(__dirname, "i18n"));

const imagesFiles = await fsAsync.readdir(kImagesDir);

await Promise.all([
...imagesFiles
.map((name) => fsAsync.copyFile(path.join(kImagesDir, name), path.join(kOutDir, name))),
fsAsync.copyFile(path.join(kPublicDir, "favicon.ico"), path.join(kOutDir, "favicon.ico"))
]);

const buildContext = await esbuild.context({
entryPoints: [
path.join(kPublicDir, "main.js"),
path.join(kPublicDir, "main.css"),
path.join(kNodeModulesDir, "highlight.js", "styles", "github.css"),
...getBuildConfiguration().entryPoints
],

loader: {
".jpg": "file",
".png": "file",
".woff": "file",
".woff2": "file",
".eot": "file",
".ttf": "file",
".svg": "file"
},
platform: "browser",
bundle: true,
sourcemap: true,
treeShaking: true,
outdir: kOutDir
});

await buildContext.watch();

const { hosts: esbuildHosts, port: esbuildPort } = await buildContext.serve({
servedir: kOutDir
});

const dataFilePath = fs.existsSync(kDefaultPayloadPath) ? kDefaultPayloadPath : undefined;

if (dataFilePath === undefined) {
cache.startFromZero = true;
}

const store = {
i18n: { english: { ui: english.ui }, french: { ui: french.ui } },
viewBuilder: new ViewBuilder({
autoReload: true,
projectRootDir: __dirname,
componentsDir: kComponentsDir
}),
dataFilePath
};

const serving = sirv(kOutDir, { dev: true });

const apiRouter = router({
ignoreTrailingSlash: true,
defaultRoute: (req: http.IncomingMessage, res: http.ServerResponse) => {
if (req.url === "/esbuild") {
const proxyReq = http.request(
{ hostname: esbuildHosts[0], port: esbuildPort, path: req.url, method: req.method, headers: req.headers },
(proxyRes) => {
res.writeHead(proxyRes.statusCode!, proxyRes.headers);
proxyRes.pipe(res);
}
);

proxyReq.on("error", (err) => {
console.error(`[proxy/esbuild] ${err.message}`);
res.writeHead(502);
res.end("Bad Gateway");
});

req.pipe(proxyReq);

return;
}

serving(req, res, () => {
res.writeHead(404);
res.end("Not Found");
});
}
});

// same as workspaces/server/src/endpoints/index.ts ---
apiRouter.get("/", root.get);
apiRouter.get("/data", data.get);
apiRouter.get("/config", config.get);
apiRouter.put("/config", config.save);
apiRouter.get("/i18n", locali18n.get);
apiRouter.get("/search/:packageName", search.get);
apiRouter.get("/search-versions/:packageName", search.versions);
apiRouter.get("/flags", flags.getAll);
apiRouter.get("/flags/description/:title", flags.get);
apiRouter.get("/bundle/:packageName", bundle.get);
apiRouter.get("/bundle/:packageName/:version", bundle.get);
apiRouter.get("/downloads/:packageName", npmDownloads.get);
apiRouter.get("/scorecard/:org/:packageName", scorecard.get);
apiRouter.post("/report", report.post);

http.createServer((req, res) => alsContext.run(store, () => apiRouter.lookup(req, res)))
.listen(kDevPort, () => {
console.log(`Dev server: http://localhost:${kDevPort}`);
open(`http://localhost:${kDevPort}`);
});

new WebSocketServerInstanciator({ cache, logger });

console.log("Watching...");
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"lint-fix": "npm run lint -- --fix",
"prepublishOnly": "rimraf ./dist && npm run build && pkg-ok",
"build": "npm run build:front && npm run build:workspaces",
"build:dev": "npm run build:front:dev && npm run build:workspaces",
"build:front": "node ./esbuild.config.js",
"build:front:dev": "node --experimental-strip-types ./esbuild.dev.config.ts",
"build:workspaces": "npm run build --ws --if-present",
"test": "npm run test:cli && npm run lint && npm run lint:css",
"test:cli": "node --no-warnings --test test/**/*.test.js",
Expand Down
3 changes: 3 additions & 0 deletions public/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,6 @@ function onSettingsSaved(defaultConfig = null) {
networkView.classList.remove("locked");
});
}

new EventSource("/esbuild").addEventListener("change", () => location.reload());

66 changes: 36 additions & 30 deletions src/commands/http.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Import Node.js Dependencies
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import crypto from "node:crypto";

// Import Third-party Dependencies
import open from "open";
import * as SemVer from "semver";
import * as i18n from "@nodesecure/i18n";
import {
buildServer,
cache,
logger,
buildServer,
WebSocketServerInstanciator
} from "@nodesecure/server";
import open from "open";
import * as SemVer from "semver";

// Import Internal Dependencies
import english from "../../i18n/english.js";
Expand Down Expand Up @@ -51,37 +51,43 @@ export async function start(
cache.prefix = crypto.randomBytes(4).toString("hex");
}

const httpServer = buildServer(dataFilePath, {
port: httpPort,
hotReload: enableDeveloperMode,
runFromPayload,
projectRootDir: kProjectRootDir,
componentsDir: kComponentsDir,
i18n: {
english,
french
}
});
if (enableDeveloperMode) {
// todo: ping/warn if dev server is not up & running
open("http://127.0.0.1:8080");
}
else {
const httpServer = buildServer(dataFilePath, {
port: httpPort,
hotReload: enableDeveloperMode,
runFromPayload,
projectRootDir: kProjectRootDir,
componentsDir: kComponentsDir,
i18n: {
english,
french
}
});

httpServer.listen(httpPort, async() => {
const link = `http://localhost:${httpServer.address().port}`;
console.log(kleur.magenta().bold(await i18n.getToken("cli.http_server_started")), kleur.cyan().bold(link));
httpServer.listen(httpPort, async() => {
const link = `http://localhost:${httpServer.address().port}`;
console.log(kleur.magenta().bold(await i18n.getToken("cli.http_server_started")), kleur.cyan().bold(link));

open(link);
});
open(link);
});

new WebSocketServerInstanciator({
cache,
logger
});
new WebSocketServerInstanciator({
cache,
logger
});

for (const eventName of ["SIGINT", "SIGTERM"]) {
process.on(eventName, () => {
httpServer.close();
for (const eventName of ["SIGINT", "SIGTERM"]) {
process.on(eventName, () => {
httpServer.close();

console.log(kleur.red().bold(`${eventName} signal received.`));
process.exit(0);
});
console.log(kleur.red().bold(`${eventName} signal received.`));
process.exit(0);
});
}
}
}

Expand Down
Loading