Update bundler. Handle non-existent file error.
This commit is contained in:
parent
632c70fc90
commit
4ee3876710
3
bun.lock
3
bun.lock
@ -9,6 +9,7 @@
|
|||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"commander": "^14.0.2",
|
"commander": "^14.0.2",
|
||||||
"esbuild": "^0.27.4",
|
"esbuild": "^0.27.4",
|
||||||
|
"@moduletrace/bunext": "github:moduletrace/bunext",
|
||||||
"lightningcss-wasm": "^1.32.0",
|
"lightningcss-wasm": "^1.32.0",
|
||||||
"lodash": "^4.17.23",
|
"lodash": "^4.17.23",
|
||||||
"micromatch": "^4.0.8",
|
"micromatch": "^4.0.8",
|
||||||
@ -106,6 +107,8 @@
|
|||||||
|
|
||||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||||
|
|
||||||
|
"@moduletrace/bunext": ["@moduletrace/bunext@github:moduletrace/bunext#632c70f", { "dependencies": { "@tailwindcss/postcss": "^4.2.2", "bun-plugin-tailwind": "^0.1.2", "chalk": "^5.6.2", "commander": "^14.0.2", "esbuild": "^0.27.4", "lightningcss-wasm": "^1.32.0", "lodash": "^4.17.23", "micromatch": "^4.0.8", "ora": "^9.0.0", "postcss": "^8.5.8" }, "peerDependencies": { "react": "^19.0.0", "react-dom": "^19.0.0", "typescript": "^5.0.0" }, "bin": { "bunext": "dist/commands/index.js" } }, "Moduletrace-bunext-632c70f"],
|
||||||
|
|
||||||
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PXgg5gqcS/rHwa1hF0JdM1y5TiyejVrMHoBmWY/DjtfYZoFTXie1RCFOkoG0b5diOOmUcuYarMpH7CSNTqwj+w=="],
|
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PXgg5gqcS/rHwa1hF0JdM1y5TiyejVrMHoBmWY/DjtfYZoFTXie1RCFOkoG0b5diOOmUcuYarMpH7CSNTqwj+w=="],
|
||||||
|
|
||||||
"@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.3.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-Nhssuh7GBpP5PiDSOl3+qnoIG7PJo+ec2oomDevnl9pRY6x6aD2gRt0JE+uf+A8Om2D6gjeHCxjEdrw5ZHE8mA=="],
|
"@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.3.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-Nhssuh7GBpP5PiDSOl3+qnoIG7PJo+ec2oomDevnl9pRY6x6aD2gRt0JE+uf+A8Om2D6gjeHCxjEdrw5ZHE8mA=="],
|
||||||
|
|||||||
5
dist/commands/index.js
vendored
5
dist/commands/index.js
vendored
@ -3,6 +3,7 @@ import { program } from "commander";
|
|||||||
import start from "./start";
|
import start from "./start";
|
||||||
import dev from "./dev";
|
import dev from "./dev";
|
||||||
import build from "./build";
|
import build from "./build";
|
||||||
|
import { log } from "../utils/log";
|
||||||
/**
|
/**
|
||||||
* # Describe Program
|
* # Describe Program
|
||||||
*/
|
*/
|
||||||
@ -20,7 +21,9 @@ program.addCommand(build());
|
|||||||
* # Handle Unavailable Commands
|
* # Handle Unavailable Commands
|
||||||
*/
|
*/
|
||||||
program.on("command:*", () => {
|
program.on("command:*", () => {
|
||||||
console.error("Invalid command: %s\nSee --help for a list of available commands.", program.args.join(" "));
|
log.error("Invalid command: %s\nSee --help for a list of available commands." +
|
||||||
|
" " +
|
||||||
|
program.args.join(" "));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
/**
|
/**
|
||||||
|
|||||||
24
dist/functions/bundler/all-pages-bundler.js
vendored
24
dist/functions/bundler/all-pages-bundler.js
vendored
@ -1,4 +1,4 @@
|
|||||||
import { writeFileSync } from "fs";
|
import { existsSync, statSync, writeFileSync } from "fs";
|
||||||
import * as esbuild from "esbuild";
|
import * as esbuild from "esbuild";
|
||||||
import grabAllPages from "../../utils/grab-all-pages";
|
import grabAllPages from "../../utils/grab-all-pages";
|
||||||
import grabDirNames from "../../utils/grab-dir-names";
|
import grabDirNames from "../../utils/grab-dir-names";
|
||||||
@ -8,7 +8,10 @@ import { log } from "../../utils/log";
|
|||||||
import tailwindEsbuildPlugin from "../server/web-pages/tailwind-esbuild-plugin";
|
import tailwindEsbuildPlugin from "../server/web-pages/tailwind-esbuild-plugin";
|
||||||
import grabClientHydrationScript from "./grab-client-hydration-script";
|
import grabClientHydrationScript from "./grab-client-hydration-script";
|
||||||
import grabArtifactsFromBundledResults from "./grab-artifacts-from-bundled-result";
|
import grabArtifactsFromBundledResults from "./grab-artifacts-from-bundled-result";
|
||||||
const { HYDRATION_DST_DIR, HYDRATION_DST_DIR_MAP_JSON_FILE } = grabDirNames();
|
import path from "path";
|
||||||
|
const { HYDRATION_DST_DIR, HYDRATION_DST_DIR_MAP_JSON_FILE, ROOT_DIR } = grabDirNames();
|
||||||
|
let build_starts = 0;
|
||||||
|
const MAX_BUILD_STARTS = 10;
|
||||||
export default async function allPagesBundler(params) {
|
export default async function allPagesBundler(params) {
|
||||||
const pages = grabAllPages({ exclude_api: true });
|
const pages = grabAllPages({ exclude_api: true });
|
||||||
const virtualEntries = {};
|
const virtualEntries = {};
|
||||||
@ -39,11 +42,25 @@ export default async function allPagesBundler(params) {
|
|||||||
setup(build) {
|
setup(build) {
|
||||||
let buildStart = 0;
|
let buildStart = 0;
|
||||||
build.onStart(() => {
|
build.onStart(() => {
|
||||||
|
build_starts++;
|
||||||
buildStart = performance.now();
|
buildStart = performance.now();
|
||||||
|
if (build_starts == MAX_BUILD_STARTS) {
|
||||||
|
const error_msg = `Build Failed. Please check all your components and imports.`;
|
||||||
|
log.error(error_msg);
|
||||||
|
// process.exit(1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
build.onEnd((result) => {
|
build.onEnd((result) => {
|
||||||
if (result.errors.length > 0)
|
if (result.errors.length > 0) {
|
||||||
|
for (const error of result.errors) {
|
||||||
|
const loc = error.location;
|
||||||
|
const location = loc
|
||||||
|
? ` ${loc.file}:${loc.line}:${loc.column}`
|
||||||
|
: "";
|
||||||
|
log.error(`[Build]${location} ${error.text}`);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
const artifacts = grabArtifactsFromBundledResults({
|
const artifacts = grabArtifactsFromBundledResults({
|
||||||
pages,
|
pages,
|
||||||
result,
|
result,
|
||||||
@ -60,6 +77,7 @@ export default async function allPagesBundler(params) {
|
|||||||
if (params?.exit_after_first_build) {
|
if (params?.exit_after_first_build) {
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
build_starts = 0;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
2
dist/functions/server/watcher.d.ts
vendored
2
dist/functions/server/watcher.d.ts
vendored
@ -1 +1 @@
|
|||||||
export default function watcher(): void;
|
export default function watcher(): Promise<void>;
|
||||||
|
|||||||
17
dist/functions/server/watcher.js
vendored
17
dist/functions/server/watcher.js
vendored
@ -1,16 +1,26 @@
|
|||||||
import { watch, existsSync } from "fs";
|
import { watch, existsSync, statSync } from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import grabDirNames from "../../utils/grab-dir-names";
|
import grabDirNames from "../../utils/grab-dir-names";
|
||||||
import rebuildBundler from "./rebuild-bundler";
|
import rebuildBundler from "./rebuild-bundler";
|
||||||
import { log } from "../../utils/log";
|
import { log } from "../../utils/log";
|
||||||
const { ROOT_DIR } = grabDirNames();
|
const { ROOT_DIR } = grabDirNames();
|
||||||
export default function watcher() {
|
export default async function watcher() {
|
||||||
|
await Bun.sleep(1000);
|
||||||
const pages_src_watcher = watch(ROOT_DIR, {
|
const pages_src_watcher = watch(ROOT_DIR, {
|
||||||
recursive: true,
|
recursive: true,
|
||||||
persistent: true,
|
persistent: true,
|
||||||
}, async (event, filename) => {
|
}, async (event, filename) => {
|
||||||
if (!filename)
|
if (!filename)
|
||||||
return;
|
return;
|
||||||
|
const full_file_path = path.join(ROOT_DIR, filename);
|
||||||
|
if (full_file_path.match(/\/styles$/)) {
|
||||||
|
global.RECOMPILING = true;
|
||||||
|
await Bun.sleep(1000);
|
||||||
|
await fullRebuild({
|
||||||
|
msg: `Detected new \`styles\` directory. Rebuilding ...`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
const excluded_match = /node_modules\/|^public\/|^\.bunext\/|^\.git\/|^dist\/|bun\.lockb$/;
|
const excluded_match = /node_modules\/|^public\/|^\.bunext\/|^\.git\/|^dist\/|bun\.lockb$/;
|
||||||
if (filename.match(excluded_match))
|
if (filename.match(excluded_match))
|
||||||
return;
|
return;
|
||||||
@ -40,8 +50,7 @@ export default function watcher() {
|
|||||||
return;
|
return;
|
||||||
if (global.RECOMPILING)
|
if (global.RECOMPILING)
|
||||||
return;
|
return;
|
||||||
const fullPath = path.join(ROOT_DIR, filename);
|
const action = existsSync(full_file_path) ? "created" : "deleted";
|
||||||
const action = existsSync(fullPath) ? "created" : "deleted";
|
|
||||||
const type = filename.match(/\.css$/) ? "Sylesheet" : "Page";
|
const type = filename.match(/\.css$/) ? "Sylesheet" : "Page";
|
||||||
await fullRebuild({
|
await fullRebuild({
|
||||||
msg: `${type} ${action}: ${filename}. Rebuilding ...`,
|
msg: `${type} ${action}: ${filename}. Rebuilding ...`,
|
||||||
|
|||||||
@ -30,13 +30,13 @@ export default async function grabPageComponent({ req, file_path: passed_file_pa
|
|||||||
}
|
}
|
||||||
if (!file_path) {
|
if (!file_path) {
|
||||||
const errMsg = `No File Path (\`file_path\`) or Request Object (\`req\`) provided not found`;
|
const errMsg = `No File Path (\`file_path\`) or Request Object (\`req\`) provided not found`;
|
||||||
// console.error(errMsg);
|
// log.error(errMsg);
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
const bundledMap = global.BUNDLER_CTX_MAP?.find((m) => m.local_path == file_path);
|
const bundledMap = global.BUNDLER_CTX_MAP?.find((m) => m.local_path == file_path);
|
||||||
if (!bundledMap?.path) {
|
if (!bundledMap?.path) {
|
||||||
const errMsg = `No Bundled File Path for this request path!`;
|
const errMsg = `No Bundled File Path for this request path!`;
|
||||||
console.error(errMsg);
|
log.error(errMsg);
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
if (debug) {
|
if (debug) {
|
||||||
@ -127,7 +127,7 @@ export default async function grabPageComponent({ req, file_path: passed_file_pa
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error(`Error Grabbing Page Component: ${error.message}`);
|
log.error(`Error Grabbing Page Component: ${error.message}`);
|
||||||
return await grabPageErrorComponent({
|
return await grabPageErrorComponent({
|
||||||
error,
|
error,
|
||||||
routeParams,
|
routeParams,
|
||||||
|
|||||||
@ -27,13 +27,16 @@ export default async function (params) {
|
|||||||
script += ` try {\n`;
|
script += ` try {\n`;
|
||||||
script += ` document.getElementById("__bunext_error_overlay")?.remove();\n`;
|
script += ` document.getElementById("__bunext_error_overlay")?.remove();\n`;
|
||||||
script += ` const data = JSON.parse(event.data);\n`;
|
script += ` const data = JSON.parse(event.data);\n`;
|
||||||
|
// script += ` console.log("data", data);\n`;
|
||||||
|
script += ` const oldCSSLink = document.querySelector('link[rel="stylesheet"]');\n`;
|
||||||
script += ` if (data.target_map.css_path) {\n`;
|
script += ` if (data.target_map.css_path) {\n`;
|
||||||
script += ` const oldLink = document.querySelector('link[rel="stylesheet"]');\n`;
|
|
||||||
script += ` const newLink = document.createElement("link");\n`;
|
script += ` const newLink = document.createElement("link");\n`;
|
||||||
script += ` newLink.rel = "stylesheet";\n`;
|
script += ` newLink.rel = "stylesheet";\n`;
|
||||||
script += ` newLink.href = \`/\${data.target_map.css_path}?t=\${Date.now()}\`;\n`;
|
script += ` newLink.href = \`/\${data.target_map.css_path}?t=\${Date.now()}\`;\n`;
|
||||||
script += ` newLink.onload = () => oldLink?.remove();\n`;
|
script += ` newLink.onload = () => oldCSSLink?.remove();\n`;
|
||||||
script += ` document.head.appendChild(newLink);\n`;
|
script += ` document.head.appendChild(newLink);\n`;
|
||||||
|
script += ` } else if (oldCSSLink) {\n`;
|
||||||
|
script += ` oldCSSLink.remove();\n`;
|
||||||
script += ` }\n`;
|
script += ` }\n`;
|
||||||
script += ` const newScriptPath = \`/\${data.target_map.path}?t=\${Date.now()}\`;\n\n`;
|
script += ` const newScriptPath = \`/\${data.target_map.path}?t=\${Date.now()}\`;\n\n`;
|
||||||
script += ` const oldScript = document.getElementById("${AppData["BunextClientHydrationScriptID"]}");\n`;
|
script += ` const oldScript = document.getElementById("${AppData["BunextClientHydrationScriptID"]}");\n`;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import isDevelopment from "../../../utils/is-development";
|
import isDevelopment from "../../../utils/is-development";
|
||||||
|
import { log } from "../../../utils/log";
|
||||||
import getCache from "../../cache/get-cache";
|
import getCache from "../../cache/get-cache";
|
||||||
import generateWebPageResponseFromComponentReturn from "./generate-web-page-response-from-component-return";
|
import generateWebPageResponseFromComponentReturn from "./generate-web-page-response-from-component-return";
|
||||||
import grabPageComponent from "./grab-page-component";
|
import grabPageComponent from "./grab-page-component";
|
||||||
@ -27,7 +28,7 @@ export default async function handleWebPages({ req, }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error(`Error Handling Web Page: ${error.message}`);
|
log.error(`Error Handling Web Page: ${error.message}`);
|
||||||
const componentRes = await grabPageErrorComponent({
|
const componentRes = await grabPageErrorComponent({
|
||||||
error,
|
error,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,17 +2,46 @@ import * as esbuild from "esbuild";
|
|||||||
import postcss from "postcss";
|
import postcss from "postcss";
|
||||||
import tailwindcss from "@tailwindcss/postcss";
|
import tailwindcss from "@tailwindcss/postcss";
|
||||||
import { readFile } from "fs/promises";
|
import { readFile } from "fs/promises";
|
||||||
|
import path from "path";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
import grabDirNames from "../../../utils/grab-dir-names";
|
||||||
|
import { log } from "../../../utils/log";
|
||||||
|
const { ROOT_DIR } = grabDirNames();
|
||||||
|
let error_logged = false;
|
||||||
const tailwindEsbuildPlugin = {
|
const tailwindEsbuildPlugin = {
|
||||||
name: "tailwindcss",
|
name: "tailwindcss",
|
||||||
setup(build) {
|
setup(build) {
|
||||||
build.onLoad({ filter: /\.css$/ }, async (args) => {
|
build.onLoad({ filter: /\.css$/ }, async (args) => {
|
||||||
const source = await readFile(args.path, "utf-8");
|
try {
|
||||||
const result = await postcss([tailwindcss()]).process(source, {
|
const source = await readFile(args.path, "utf-8");
|
||||||
from: args.path,
|
const result = await postcss([tailwindcss()]).process(source, {
|
||||||
});
|
from: args.path,
|
||||||
|
});
|
||||||
|
error_logged = false;
|
||||||
|
return { contents: result.css, loader: "css" };
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
return { errors: [{ text: error.message }] };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
build.onResolve({ filter: /\.css$/ }, async (args) => {
|
||||||
|
const css_path = path.resolve(args.resolveDir, args.path.replace(/\@\//g, ROOT_DIR + "/"));
|
||||||
|
const does_path_exist = existsSync(css_path);
|
||||||
|
if (!does_path_exist && !error_logged) {
|
||||||
|
const err_msg = `CSS Error: ${css_path} file does not exist.`;
|
||||||
|
log.error(err_msg);
|
||||||
|
error_logged = true;
|
||||||
|
// return {
|
||||||
|
// errors: [
|
||||||
|
// {
|
||||||
|
// text: err_msg,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// pluginName: "tailwindcss",
|
||||||
|
// };
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
contents: result.css,
|
path: css_path,
|
||||||
loader: "css",
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "tsc --watch",
|
"dev": "tsc --watch",
|
||||||
"git:push": "tsc --noEmit && tsc && git add . && git commit -m 'Update watcher function. Add .css files to the rebuild pipeline' && git push",
|
"git:push": "tsc --noEmit && tsc && git add . && git commit -m 'Update bundler. Handle non-existent file error.' && git push",
|
||||||
"compile": "bun build ./src/commands/index.ts --compile --outfile bin/bunext",
|
"compile": "bun build ./src/commands/index.ts --compile --outfile bin/bunext",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"test": "bun test --max-concurrency=1"
|
"test": "bun test --max-concurrency=1"
|
||||||
@ -54,6 +54,7 @@
|
|||||||
"registry": "https://npm.pkg.github.com"
|
"registry": "https://npm.pkg.github.com"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@moduletrace/bunext": "github:moduletrace/bunext",
|
||||||
"@tailwindcss/postcss": "^4.2.2",
|
"@tailwindcss/postcss": "^4.2.2",
|
||||||
"bun-plugin-tailwind": "^0.1.2",
|
"bun-plugin-tailwind": "^0.1.2",
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
|
|||||||
@ -1,156 +0,0 @@
|
|||||||
#!/usr/bin/env bun
|
|
||||||
import type { BuildConfig } from "bun";
|
|
||||||
import plugin from "bun-plugin-tailwind";
|
|
||||||
import { existsSync } from "fs";
|
|
||||||
import { rm } from "fs/promises";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
||||||
console.log(`
|
|
||||||
🏗️ Bun Build Script
|
|
||||||
|
|
||||||
Usage: bun run build.ts [options]
|
|
||||||
|
|
||||||
Common Options:
|
|
||||||
--outdir <path> Output directory (default: "dist")
|
|
||||||
--minify Enable minification (or --minify.whitespace, --minify.syntax, etc)
|
|
||||||
--sourcemap <type> Sourcemap type: none|linked|inline|external
|
|
||||||
--target <target> Build target: browser|bun|node
|
|
||||||
--format <format> Output format: esm|cjs|iife
|
|
||||||
--splitting Enable code splitting
|
|
||||||
--packages <type> Package handling: bundle|external
|
|
||||||
--public-path <path> Public path for assets
|
|
||||||
--env <mode> Environment handling: inline|disable|prefix*
|
|
||||||
--conditions <list> Package.json export conditions (comma separated)
|
|
||||||
--external <list> External packages (comma separated)
|
|
||||||
--banner <text> Add banner text to output
|
|
||||||
--footer <text> Add footer text to output
|
|
||||||
--define <obj> Define global constants (e.g. --define.VERSION=1.0.0)
|
|
||||||
--help, -h Show this help message
|
|
||||||
|
|
||||||
Example:
|
|
||||||
bun run build.ts --outdir=dist --minify --sourcemap=linked --external=react,react-dom
|
|
||||||
`);
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const toCamelCase = (str: string): string =>
|
|
||||||
str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
||||||
|
|
||||||
const parseValue = (value: string): any => {
|
|
||||||
if (value === "true") return true;
|
|
||||||
if (value === "false") return false;
|
|
||||||
|
|
||||||
if (/^\d+$/.test(value)) return parseInt(value, 10);
|
|
||||||
if (/^\d*\.\d+$/.test(value)) return parseFloat(value);
|
|
||||||
|
|
||||||
if (value.includes(",")) return value.split(",").map((v) => v.trim());
|
|
||||||
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
function parseArgs(): Partial<BuildConfig> {
|
|
||||||
const config: any = {};
|
|
||||||
const args = process.argv.slice(2);
|
|
||||||
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
const arg = args[i];
|
|
||||||
if (arg === undefined) continue;
|
|
||||||
if (!arg.startsWith("--")) continue;
|
|
||||||
|
|
||||||
if (arg.startsWith("--no-")) {
|
|
||||||
const key = toCamelCase(arg.slice(5));
|
|
||||||
config[key] = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!arg.includes("=") &&
|
|
||||||
(i === args.length - 1 || args[i + 1]?.startsWith("--"))
|
|
||||||
) {
|
|
||||||
const key = toCamelCase(arg.slice(2));
|
|
||||||
config[key] = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let key: string;
|
|
||||||
let value: string;
|
|
||||||
|
|
||||||
if (arg.includes("=")) {
|
|
||||||
[key, value] = arg.slice(2).split("=", 2) as [string, string];
|
|
||||||
} else {
|
|
||||||
key = arg.slice(2);
|
|
||||||
value = args[++i] ?? "";
|
|
||||||
}
|
|
||||||
|
|
||||||
key = toCamelCase(key);
|
|
||||||
|
|
||||||
if (key.includes(".")) {
|
|
||||||
const [parentKey, childKey] = key.split(".");
|
|
||||||
config[parentKey] = config[parentKey] || {};
|
|
||||||
config[parentKey][childKey] = parseValue(value);
|
|
||||||
} else {
|
|
||||||
config[key] = parseValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatFileSize = (bytes: number): string => {
|
|
||||||
const units = ["B", "KB", "MB", "GB"];
|
|
||||||
let size = bytes;
|
|
||||||
let unitIndex = 0;
|
|
||||||
|
|
||||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
||||||
size /= 1024;
|
|
||||||
unitIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${size.toFixed(2)} ${units[unitIndex]}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log("\n🚀 Starting build process...\n");
|
|
||||||
|
|
||||||
const cliConfig = parseArgs();
|
|
||||||
const outdir = cliConfig.outdir || path.join(process.cwd(), "dist");
|
|
||||||
|
|
||||||
if (existsSync(outdir)) {
|
|
||||||
console.log(`🗑️ Cleaning previous build at ${outdir}`);
|
|
||||||
await rm(outdir, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
const start = performance.now();
|
|
||||||
|
|
||||||
const entrypoints = [...new Bun.Glob("**.html").scanSync("src/app")]
|
|
||||||
.map((a) => path.resolve("src/app", a))
|
|
||||||
.filter((dir) => !dir.includes("node_modules"));
|
|
||||||
console.log(
|
|
||||||
`📄 Found ${entrypoints.length} HTML ${entrypoints.length === 1 ? "file" : "files"} to process\n`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await Bun.build({
|
|
||||||
entrypoints,
|
|
||||||
outdir,
|
|
||||||
plugins: [plugin],
|
|
||||||
minify: true,
|
|
||||||
target: "browser",
|
|
||||||
sourcemap: "linked",
|
|
||||||
define: {
|
|
||||||
"process.env.NODE_ENV": JSON.stringify("production"),
|
|
||||||
},
|
|
||||||
...cliConfig,
|
|
||||||
});
|
|
||||||
|
|
||||||
const end = performance.now();
|
|
||||||
|
|
||||||
const outputTable = result.outputs.map((output) => ({
|
|
||||||
File: path.relative(process.cwd(), output.path),
|
|
||||||
Type: output.kind,
|
|
||||||
Size: formatFileSize(output.size),
|
|
||||||
}));
|
|
||||||
|
|
||||||
console.table(outputTable);
|
|
||||||
const buildTime = (end - start).toFixed(2);
|
|
||||||
|
|
||||||
console.log(`\n✅ Build completed in ${buildTime}ms\n`);
|
|
||||||
@ -4,6 +4,7 @@ import { program } from "commander";
|
|||||||
import start from "./start";
|
import start from "./start";
|
||||||
import dev from "./dev";
|
import dev from "./dev";
|
||||||
import build from "./build";
|
import build from "./build";
|
||||||
|
import { log } from "../utils/log";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* # Describe Program
|
* # Describe Program
|
||||||
@ -24,10 +25,12 @@ program.addCommand(build());
|
|||||||
* # Handle Unavailable Commands
|
* # Handle Unavailable Commands
|
||||||
*/
|
*/
|
||||||
program.on("command:*", () => {
|
program.on("command:*", () => {
|
||||||
console.error(
|
log.error(
|
||||||
"Invalid command: %s\nSee --help for a list of available commands.",
|
"Invalid command: %s\nSee --help for a list of available commands." +
|
||||||
program.args.join(" "),
|
" " +
|
||||||
|
program.args.join(" "),
|
||||||
);
|
);
|
||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { writeFileSync } from "fs";
|
import { existsSync, statSync, writeFileSync } from "fs";
|
||||||
import * as esbuild from "esbuild";
|
import * as esbuild from "esbuild";
|
||||||
import grabAllPages from "../../utils/grab-all-pages";
|
import grabAllPages from "../../utils/grab-all-pages";
|
||||||
import grabDirNames from "../../utils/grab-dir-names";
|
import grabDirNames from "../../utils/grab-dir-names";
|
||||||
@ -9,8 +9,13 @@ import { log } from "../../utils/log";
|
|||||||
import tailwindEsbuildPlugin from "../server/web-pages/tailwind-esbuild-plugin";
|
import tailwindEsbuildPlugin from "../server/web-pages/tailwind-esbuild-plugin";
|
||||||
import grabClientHydrationScript from "./grab-client-hydration-script";
|
import grabClientHydrationScript from "./grab-client-hydration-script";
|
||||||
import grabArtifactsFromBundledResults from "./grab-artifacts-from-bundled-result";
|
import grabArtifactsFromBundledResults from "./grab-artifacts-from-bundled-result";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
const { HYDRATION_DST_DIR, HYDRATION_DST_DIR_MAP_JSON_FILE } = grabDirNames();
|
const { HYDRATION_DST_DIR, HYDRATION_DST_DIR_MAP_JSON_FILE, ROOT_DIR } =
|
||||||
|
grabDirNames();
|
||||||
|
|
||||||
|
let build_starts = 0;
|
||||||
|
const MAX_BUILD_STARTS = 10;
|
||||||
|
|
||||||
type Params = {
|
type Params = {
|
||||||
watch?: boolean;
|
watch?: boolean;
|
||||||
@ -56,11 +61,27 @@ export default async function allPagesBundler(params?: Params) {
|
|||||||
let buildStart = 0;
|
let buildStart = 0;
|
||||||
|
|
||||||
build.onStart(() => {
|
build.onStart(() => {
|
||||||
|
build_starts++;
|
||||||
buildStart = performance.now();
|
buildStart = performance.now();
|
||||||
|
|
||||||
|
if (build_starts == MAX_BUILD_STARTS) {
|
||||||
|
const error_msg = `Build Failed. Please check all your components and imports.`;
|
||||||
|
log.error(error_msg);
|
||||||
|
// process.exit(1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
build.onEnd((result) => {
|
build.onEnd((result) => {
|
||||||
if (result.errors.length > 0) return;
|
if (result.errors.length > 0) {
|
||||||
|
for (const error of result.errors) {
|
||||||
|
const loc = error.location;
|
||||||
|
const location = loc
|
||||||
|
? ` ${loc.file}:${loc.line}:${loc.column}`
|
||||||
|
: "";
|
||||||
|
log.error(`[Build]${location} ${error.text}`);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const artifacts = grabArtifactsFromBundledResults({
|
const artifacts = grabArtifactsFromBundledResults({
|
||||||
pages,
|
pages,
|
||||||
@ -86,6 +107,8 @@ export default async function allPagesBundler(params?: Params) {
|
|||||||
if (params?.exit_after_first_build) {
|
if (params?.exit_after_first_build) {
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build_starts = 0;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { watch, existsSync } from "fs";
|
import { watch, existsSync, statSync } from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import grabDirNames from "../../utils/grab-dir-names";
|
import grabDirNames from "../../utils/grab-dir-names";
|
||||||
import rebuildBundler from "./rebuild-bundler";
|
import rebuildBundler from "./rebuild-bundler";
|
||||||
@ -6,7 +6,9 @@ import { log } from "../../utils/log";
|
|||||||
|
|
||||||
const { ROOT_DIR } = grabDirNames();
|
const { ROOT_DIR } = grabDirNames();
|
||||||
|
|
||||||
export default function watcher() {
|
export default async function watcher() {
|
||||||
|
await Bun.sleep(1000);
|
||||||
|
|
||||||
const pages_src_watcher = watch(
|
const pages_src_watcher = watch(
|
||||||
ROOT_DIR,
|
ROOT_DIR,
|
||||||
{
|
{
|
||||||
@ -16,6 +18,17 @@ export default function watcher() {
|
|||||||
async (event, filename) => {
|
async (event, filename) => {
|
||||||
if (!filename) return;
|
if (!filename) return;
|
||||||
|
|
||||||
|
const full_file_path = path.join(ROOT_DIR, filename);
|
||||||
|
|
||||||
|
if (full_file_path.match(/\/styles$/)) {
|
||||||
|
global.RECOMPILING = true;
|
||||||
|
await Bun.sleep(1000);
|
||||||
|
await fullRebuild({
|
||||||
|
msg: `Detected new \`styles\` directory. Rebuilding ...`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const excluded_match =
|
const excluded_match =
|
||||||
/node_modules\/|^public\/|^\.bunext\/|^\.git\/|^dist\/|bun\.lockb$/;
|
/node_modules\/|^public\/|^\.bunext\/|^\.git\/|^dist\/|bun\.lockb$/;
|
||||||
|
|
||||||
@ -52,8 +65,7 @@ export default function watcher() {
|
|||||||
|
|
||||||
if (global.RECOMPILING) return;
|
if (global.RECOMPILING) return;
|
||||||
|
|
||||||
const fullPath = path.join(ROOT_DIR, filename);
|
const action = existsSync(full_file_path) ? "created" : "deleted";
|
||||||
const action = existsSync(fullPath) ? "created" : "deleted";
|
|
||||||
const type = filename.match(/\.css$/) ? "Sylesheet" : "Page";
|
const type = filename.match(/\.css$/) ? "Sylesheet" : "Page";
|
||||||
|
|
||||||
await fullRebuild({
|
await fullRebuild({
|
||||||
|
|||||||
@ -58,7 +58,7 @@ export default async function grabPageComponent({
|
|||||||
|
|
||||||
if (!file_path) {
|
if (!file_path) {
|
||||||
const errMsg = `No File Path (\`file_path\`) or Request Object (\`req\`) provided not found`;
|
const errMsg = `No File Path (\`file_path\`) or Request Object (\`req\`) provided not found`;
|
||||||
// console.error(errMsg);
|
// log.error(errMsg);
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ export default async function grabPageComponent({
|
|||||||
|
|
||||||
if (!bundledMap?.path) {
|
if (!bundledMap?.path) {
|
||||||
const errMsg = `No Bundled File Path for this request path!`;
|
const errMsg = `No Bundled File Path for this request path!`;
|
||||||
console.error(errMsg);
|
log.error(errMsg);
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ export default async function grabPageComponent({
|
|||||||
head: Head,
|
head: Head,
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(`Error Grabbing Page Component: ${error.message}`);
|
log.error(`Error Grabbing Page Component: ${error.message}`);
|
||||||
|
|
||||||
return await grabPageErrorComponent({
|
return await grabPageErrorComponent({
|
||||||
error,
|
error,
|
||||||
|
|||||||
@ -36,14 +36,18 @@ export default async function (params?: Params) {
|
|||||||
script += ` try {\n`;
|
script += ` try {\n`;
|
||||||
script += ` document.getElementById("__bunext_error_overlay")?.remove();\n`;
|
script += ` document.getElementById("__bunext_error_overlay")?.remove();\n`;
|
||||||
script += ` const data = JSON.parse(event.data);\n`;
|
script += ` const data = JSON.parse(event.data);\n`;
|
||||||
|
// script += ` console.log("data", data);\n`;
|
||||||
|
|
||||||
|
script += ` const oldCSSLink = document.querySelector('link[rel="stylesheet"]');\n`;
|
||||||
|
|
||||||
script += ` if (data.target_map.css_path) {\n`;
|
script += ` if (data.target_map.css_path) {\n`;
|
||||||
script += ` const oldLink = document.querySelector('link[rel="stylesheet"]');\n`;
|
|
||||||
script += ` const newLink = document.createElement("link");\n`;
|
script += ` const newLink = document.createElement("link");\n`;
|
||||||
script += ` newLink.rel = "stylesheet";\n`;
|
script += ` newLink.rel = "stylesheet";\n`;
|
||||||
script += ` newLink.href = \`/\${data.target_map.css_path}?t=\${Date.now()}\`;\n`;
|
script += ` newLink.href = \`/\${data.target_map.css_path}?t=\${Date.now()}\`;\n`;
|
||||||
script += ` newLink.onload = () => oldLink?.remove();\n`;
|
script += ` newLink.onload = () => oldCSSLink?.remove();\n`;
|
||||||
script += ` document.head.appendChild(newLink);\n`;
|
script += ` document.head.appendChild(newLink);\n`;
|
||||||
|
script += ` } else if (oldCSSLink) {\n`;
|
||||||
|
script += ` oldCSSLink.remove();\n`;
|
||||||
script += ` }\n`;
|
script += ` }\n`;
|
||||||
|
|
||||||
script += ` const newScriptPath = \`/\${data.target_map.path}?t=\${Date.now()}\`;\n\n`;
|
script += ` const newScriptPath = \`/\${data.target_map.path}?t=\${Date.now()}\`;\n\n`;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import isDevelopment from "../../../utils/is-development";
|
import isDevelopment from "../../../utils/is-development";
|
||||||
|
import { log } from "../../../utils/log";
|
||||||
import getCache from "../../cache/get-cache";
|
import getCache from "../../cache/get-cache";
|
||||||
import generateWebPageResponseFromComponentReturn from "./generate-web-page-response-from-component-return";
|
import generateWebPageResponseFromComponentReturn from "./generate-web-page-response-from-component-return";
|
||||||
import grabPageComponent from "./grab-page-component";
|
import grabPageComponent from "./grab-page-component";
|
||||||
@ -38,7 +39,7 @@ export default async function handleWebPages({
|
|||||||
...componentRes,
|
...componentRes,
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(`Error Handling Web Page: ${error.message}`);
|
log.error(`Error Handling Web Page: ${error.message}`);
|
||||||
|
|
||||||
const componentRes = await grabPageErrorComponent({
|
const componentRes = await grabPageErrorComponent({
|
||||||
error,
|
error,
|
||||||
|
|||||||
@ -2,19 +2,59 @@ import * as esbuild from "esbuild";
|
|||||||
import postcss from "postcss";
|
import postcss from "postcss";
|
||||||
import tailwindcss from "@tailwindcss/postcss";
|
import tailwindcss from "@tailwindcss/postcss";
|
||||||
import { readFile } from "fs/promises";
|
import { readFile } from "fs/promises";
|
||||||
|
import path from "path";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
import grabDirNames from "../../../utils/grab-dir-names";
|
||||||
|
import { log } from "../../../utils/log";
|
||||||
|
|
||||||
|
const { ROOT_DIR } = grabDirNames();
|
||||||
|
|
||||||
|
let error_logged = false;
|
||||||
|
|
||||||
const tailwindEsbuildPlugin: esbuild.Plugin = {
|
const tailwindEsbuildPlugin: esbuild.Plugin = {
|
||||||
name: "tailwindcss",
|
name: "tailwindcss",
|
||||||
setup(build) {
|
setup(build) {
|
||||||
build.onLoad({ filter: /\.css$/ }, async (args) => {
|
build.onLoad({ filter: /\.css$/ }, async (args) => {
|
||||||
const source = await readFile(args.path, "utf-8");
|
try {
|
||||||
const result = await postcss([tailwindcss()]).process(source, {
|
const source = await readFile(args.path, "utf-8");
|
||||||
from: args.path,
|
const result = await postcss([tailwindcss()]).process(source, {
|
||||||
});
|
from: args.path,
|
||||||
|
});
|
||||||
|
|
||||||
|
error_logged = false;
|
||||||
|
|
||||||
|
return { contents: result.css, loader: "css" };
|
||||||
|
} catch (error: any) {
|
||||||
|
return { errors: [{ text: error.message }] };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
build.onResolve({ filter: /\.css$/ }, async (args) => {
|
||||||
|
const css_path = path.resolve(
|
||||||
|
args.resolveDir,
|
||||||
|
args.path.replace(/\@\//g, ROOT_DIR + "/"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const does_path_exist = existsSync(css_path);
|
||||||
|
|
||||||
|
if (!does_path_exist && !error_logged) {
|
||||||
|
const err_msg = `CSS Error: ${css_path} file does not exist.`;
|
||||||
|
|
||||||
|
log.error(err_msg);
|
||||||
|
error_logged = true;
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// errors: [
|
||||||
|
// {
|
||||||
|
// text: err_msg,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// pluginName: "tailwindcss",
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
contents: result.css,
|
path: css_path,
|
||||||
loader: "css",
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user