summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-06-22 14:59:26 +0700
committerpolwex <polwex@sortug.com>2025-06-22 14:59:26 +0700
commitfe091178bbfc36352626c1a650c0fe6e56423541 (patch)
tree4e69c943fa06e585239b0806e0d84f2317e7e971
parent20cc3637c7268ceb8ca18ce55027ad8584e1cfd8 (diff)
client working LETS FUCKING GO
-rw-r--r--bs5/client/build.mjs113
-rw-r--r--bs5/server/server.ml3
2 files changed, 114 insertions, 2 deletions
diff --git a/bs5/client/build.mjs b/bs5/client/build.mjs
new file mode 100644
index 0000000..f98de63
--- /dev/null
+++ b/bs5/client/build.mjs
@@ -0,0 +1,113 @@
+import Esbuild from "esbuild";
+import Path from "path";
+import { plugin as extractClientComponents } from "../packages/extract-client-components/esbuild-plugin.mjs";
+
+async function build(entryPoints, { env, output, extract, mockWebpackRequire }) {
+ const outfile = output;
+ const outdir = Path.dirname(outfile);
+ const splitting = true;
+
+ const bootstrapOutput = Path.join(Path.dirname(outfile), "bootstrap.js");
+
+ let plugins = [];
+ if (extract) {
+ plugins.push(
+ extractClientComponents({
+ target: "app",
+ mockWebpackRequire,
+ bootstrapOutput,
+ }),
+ );
+ }
+
+ const isDev = env === "development";
+
+ try {
+ const result = await Esbuild.build({
+ entryPoints,
+ entryNames: "[name]",
+ bundle: true,
+ logLevel: "debug",
+ platform: "browser",
+ format: "esm",
+ splitting,
+ outdir,
+ plugins,
+ write: true,
+ treeShaking: isDev ? false : true,
+ minify: isDev ? false : true,
+ define: {
+ "process.env.NODE_ENV": `"${env}"`,
+ "__DEV__": `"${isDev}"`, /* __DEV__ is used by react-client code */
+ },
+ });
+
+ entryPoints.forEach((entryPoint) => {
+ console.log('Build completed successfully for "' + entryPoint + '"');
+ });
+ return result;
+ } catch (error) {
+ console.error("\nBuild failed:", error);
+ process.exit(1);
+ }
+}
+
+function parseArgv(argv) {
+ const args = argv.slice(2);
+ const result = { _: [] };
+
+ for (let i = 0; i < args.length; i++) {
+ const arg = args[i];
+
+ if (arg.startsWith("--")) {
+ const longArg = arg.slice(2);
+ if (longArg.includes("=")) {
+ const [key, value] = longArg.split("=");
+ result[key] = parseValue(value);
+ } else if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
+ result[longArg] = parseValue(args[++i]);
+ } else {
+ result[longArg] = true;
+ }
+ } else if (arg.startsWith("-")) {
+ const shortArg = arg.slice(1);
+ if (shortArg.includes("=")) {
+ const [key, value] = shortArg.split("=");
+ result[key] = parseValue(value);
+ } else if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
+ result[shortArg] = parseValue(args[++i]);
+ } else {
+ for (const char of shortArg) {
+ result[char] = true;
+ }
+ }
+ } else {
+ result._.push(parseValue(arg));
+ }
+ }
+
+ return result;
+}
+
+function parseValue(value) {
+ if (value === "true") return true;
+ if (value === "false") return false;
+ if (value === "null") return null;
+ if (!isNaN(value)) return Number(value);
+ return value;
+}
+
+function camelCaseKeys(obj) {
+ return Object.fromEntries(
+ Object.entries(obj).map(([key, value]) => [
+ key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()),
+ value,
+ ]),
+ );
+}
+
+const flags = parseArgv(process.argv);
+const options = camelCaseKeys(flags);
+const entryPoints = options._;
+
+build(entryPoints, options);
diff --git a/bs5/server/server.ml b/bs5/server/server.ml
index a58abc5..68b4367 100644
--- a/bs5/server/server.ml
+++ b/bs5/server/server.ml
@@ -14,8 +14,7 @@ let router =
(* rendering tricks *)
Dream.get "/output.css"
(Dream.from_filesystem "./_build/default" "output.css");
- Dream.get "/static/**"
- (Dream.static "./_build/default/client/app/client");
+ Dream.get "/static/**" (Dream.static "./_build/default/client/app");
getAndPost Router.demoRenderToString (fun _ ->
Dream.html Pages.Hydrate.toString);
getAndPost Router.demoRenderToStaticMarkup (fun _ ->