From 4ee387671050527a658dabaf794a4d9cf00e6259 Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Sat, 21 Mar 2026 16:35:30 +0100 Subject: [PATCH] Update bundler. Handle non-existent file error. --- bun.lock | 3 + dist/commands/index.js | 5 +- dist/functions/bundler/all-pages-bundler.js | 24 ++- dist/functions/server/watcher.d.ts | 2 +- dist/functions/server/watcher.js | 17 +- .../server/web-pages/grab-page-component.js | 6 +- .../grab-web-page-hydration-script.js | 7 +- .../server/web-pages/handle-web-pages.js | 3 +- .../web-pages/tailwind-esbuild-plugin.js | 41 ++++- package.json | 3 +- src/build/build.ts | 156 ------------------ src/commands/index.ts | 9 +- src/functions/bundler/all-pages-bundler.ts | 29 +++- src/functions/server/watcher.ts | 20 ++- .../server/web-pages/grab-page-component.tsx | 6 +- .../grab-web-page-hydration-script.tsx | 8 +- .../server/web-pages/handle-web-pages.tsx | 3 +- .../web-pages/tailwind-esbuild-plugin.tsx | 52 +++++- 18 files changed, 194 insertions(+), 200 deletions(-) delete mode 100644 src/build/build.ts diff --git a/bun.lock b/bun.lock index c31e1bc..26ecd91 100644 --- a/bun.lock +++ b/bun.lock @@ -9,6 +9,7 @@ "chalk": "^5.6.2", "commander": "^14.0.2", "esbuild": "^0.27.4", + "@moduletrace/bunext": "github:moduletrace/bunext", "lightningcss-wasm": "^1.32.0", "lodash": "^4.17.23", "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=="], + "@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-x64": ["@oven/bun-darwin-x64@1.3.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-Nhssuh7GBpP5PiDSOl3+qnoIG7PJo+ec2oomDevnl9pRY6x6aD2gRt0JE+uf+A8Om2D6gjeHCxjEdrw5ZHE8mA=="], diff --git a/dist/commands/index.js b/dist/commands/index.js index 22263ad..df5f98d 100644 --- a/dist/commands/index.js +++ b/dist/commands/index.js @@ -3,6 +3,7 @@ import { program } from "commander"; import start from "./start"; import dev from "./dev"; import build from "./build"; +import { log } from "../utils/log"; /** * # Describe Program */ @@ -20,7 +21,9 @@ program.addCommand(build()); * # Handle Unavailable Commands */ 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); }); /** diff --git a/dist/functions/bundler/all-pages-bundler.js b/dist/functions/bundler/all-pages-bundler.js index 93c30a0..da72dc5 100644 --- a/dist/functions/bundler/all-pages-bundler.js +++ b/dist/functions/bundler/all-pages-bundler.js @@ -1,4 +1,4 @@ -import { writeFileSync } from "fs"; +import { existsSync, statSync, writeFileSync } from "fs"; import * as esbuild from "esbuild"; import grabAllPages from "../../utils/grab-all-pages"; 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 grabClientHydrationScript from "./grab-client-hydration-script"; 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) { const pages = grabAllPages({ exclude_api: true }); const virtualEntries = {}; @@ -39,11 +42,25 @@ export default async function allPagesBundler(params) { setup(build) { let buildStart = 0; build.onStart(() => { + build_starts++; 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) => { - 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; + } const artifacts = grabArtifactsFromBundledResults({ pages, result, @@ -60,6 +77,7 @@ export default async function allPagesBundler(params) { if (params?.exit_after_first_build) { process.exit(); } + build_starts = 0; }); }, }; diff --git a/dist/functions/server/watcher.d.ts b/dist/functions/server/watcher.d.ts index ae39fb1..2d397af 100644 --- a/dist/functions/server/watcher.d.ts +++ b/dist/functions/server/watcher.d.ts @@ -1 +1 @@ -export default function watcher(): void; +export default function watcher(): Promise; diff --git a/dist/functions/server/watcher.js b/dist/functions/server/watcher.js index 795d900..b8f06c5 100644 --- a/dist/functions/server/watcher.js +++ b/dist/functions/server/watcher.js @@ -1,16 +1,26 @@ -import { watch, existsSync } from "fs"; +import { watch, existsSync, statSync } from "fs"; import path from "path"; import grabDirNames from "../../utils/grab-dir-names"; import rebuildBundler from "./rebuild-bundler"; import { log } from "../../utils/log"; const { ROOT_DIR } = grabDirNames(); -export default function watcher() { +export default async function watcher() { + await Bun.sleep(1000); const pages_src_watcher = watch(ROOT_DIR, { recursive: true, persistent: true, }, async (event, filename) => { 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 = /node_modules\/|^public\/|^\.bunext\/|^\.git\/|^dist\/|bun\.lockb$/; if (filename.match(excluded_match)) return; @@ -40,8 +50,7 @@ export default function watcher() { return; if (global.RECOMPILING) return; - const fullPath = path.join(ROOT_DIR, filename); - const action = existsSync(fullPath) ? "created" : "deleted"; + const action = existsSync(full_file_path) ? "created" : "deleted"; const type = filename.match(/\.css$/) ? "Sylesheet" : "Page"; await fullRebuild({ msg: `${type} ${action}: ${filename}. Rebuilding ...`, diff --git a/dist/functions/server/web-pages/grab-page-component.js b/dist/functions/server/web-pages/grab-page-component.js index fa9d42d..682e75e 100644 --- a/dist/functions/server/web-pages/grab-page-component.js +++ b/dist/functions/server/web-pages/grab-page-component.js @@ -30,13 +30,13 @@ export default async function grabPageComponent({ req, file_path: passed_file_pa } if (!file_path) { const errMsg = `No File Path (\`file_path\`) or Request Object (\`req\`) provided not found`; - // console.error(errMsg); + // log.error(errMsg); throw new Error(errMsg); } const bundledMap = global.BUNDLER_CTX_MAP?.find((m) => m.local_path == file_path); if (!bundledMap?.path) { const errMsg = `No Bundled File Path for this request path!`; - console.error(errMsg); + log.error(errMsg); throw new Error(errMsg); } if (debug) { @@ -127,7 +127,7 @@ export default async function grabPageComponent({ req, file_path: passed_file_pa }; } catch (error) { - console.error(`Error Grabbing Page Component: ${error.message}`); + log.error(`Error Grabbing Page Component: ${error.message}`); return await grabPageErrorComponent({ error, routeParams, diff --git a/dist/functions/server/web-pages/grab-web-page-hydration-script.js b/dist/functions/server/web-pages/grab-web-page-hydration-script.js index 1b9eab8..e0e7c96 100644 --- a/dist/functions/server/web-pages/grab-web-page-hydration-script.js +++ b/dist/functions/server/web-pages/grab-web-page-hydration-script.js @@ -27,13 +27,16 @@ export default async function (params) { script += ` try {\n`; script += ` document.getElementById("__bunext_error_overlay")?.remove();\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 += ` const oldLink = document.querySelector('link[rel="stylesheet"]');\n`; script += ` const newLink = document.createElement("link");\n`; script += ` newLink.rel = "stylesheet";\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 += ` } else if (oldCSSLink) {\n`; + script += ` oldCSSLink.remove();\n`; script += ` }\n`; script += ` const newScriptPath = \`/\${data.target_map.path}?t=\${Date.now()}\`;\n\n`; script += ` const oldScript = document.getElementById("${AppData["BunextClientHydrationScriptID"]}");\n`; diff --git a/dist/functions/server/web-pages/handle-web-pages.js b/dist/functions/server/web-pages/handle-web-pages.js index 41c9da3..cb1da75 100644 --- a/dist/functions/server/web-pages/handle-web-pages.js +++ b/dist/functions/server/web-pages/handle-web-pages.js @@ -1,4 +1,5 @@ import isDevelopment from "../../../utils/is-development"; +import { log } from "../../../utils/log"; import getCache from "../../cache/get-cache"; import generateWebPageResponseFromComponentReturn from "./generate-web-page-response-from-component-return"; import grabPageComponent from "./grab-page-component"; @@ -27,7 +28,7 @@ export default async function handleWebPages({ req, }) { }); } catch (error) { - console.error(`Error Handling Web Page: ${error.message}`); + log.error(`Error Handling Web Page: ${error.message}`); const componentRes = await grabPageErrorComponent({ error, }); diff --git a/dist/functions/server/web-pages/tailwind-esbuild-plugin.js b/dist/functions/server/web-pages/tailwind-esbuild-plugin.js index 1826508..fabd197 100644 --- a/dist/functions/server/web-pages/tailwind-esbuild-plugin.js +++ b/dist/functions/server/web-pages/tailwind-esbuild-plugin.js @@ -2,17 +2,46 @@ import * as esbuild from "esbuild"; import postcss from "postcss"; import tailwindcss from "@tailwindcss/postcss"; 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 = { name: "tailwindcss", setup(build) { build.onLoad({ filter: /\.css$/ }, async (args) => { - const source = await readFile(args.path, "utf-8"); - const result = await postcss([tailwindcss()]).process(source, { - from: args.path, - }); + try { + const source = await readFile(args.path, "utf-8"); + 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 { - contents: result.css, - loader: "css", + path: css_path, }; }); }, diff --git a/package.json b/package.json index 642fa20..a7c6538 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ ], "scripts": { "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", "build": "tsc", "test": "bun test --max-concurrency=1" @@ -54,6 +54,7 @@ "registry": "https://npm.pkg.github.com" }, "dependencies": { + "@moduletrace/bunext": "github:moduletrace/bunext", "@tailwindcss/postcss": "^4.2.2", "bun-plugin-tailwind": "^0.1.2", "chalk": "^5.6.2", diff --git a/src/build/build.ts b/src/build/build.ts deleted file mode 100644 index c7de0d7..0000000 --- a/src/build/build.ts +++ /dev/null @@ -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 Output directory (default: "dist") - --minify Enable minification (or --minify.whitespace, --minify.syntax, etc) - --sourcemap Sourcemap type: none|linked|inline|external - --target Build target: browser|bun|node - --format Output format: esm|cjs|iife - --splitting Enable code splitting - --packages Package handling: bundle|external - --public-path Public path for assets - --env Environment handling: inline|disable|prefix* - --conditions Package.json export conditions (comma separated) - --external External packages (comma separated) - --banner Add banner text to output - --footer Add footer text to output - --define 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 { - 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`); diff --git a/src/commands/index.ts b/src/commands/index.ts index 40bedb3..9bbe793 100755 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -4,6 +4,7 @@ import { program } from "commander"; import start from "./start"; import dev from "./dev"; import build from "./build"; +import { log } from "../utils/log"; /** * # Describe Program @@ -24,10 +25,12 @@ program.addCommand(build()); * # Handle Unavailable Commands */ 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); }); diff --git a/src/functions/bundler/all-pages-bundler.ts b/src/functions/bundler/all-pages-bundler.ts index 4782b53..d0dd4ab 100644 --- a/src/functions/bundler/all-pages-bundler.ts +++ b/src/functions/bundler/all-pages-bundler.ts @@ -1,4 +1,4 @@ -import { writeFileSync } from "fs"; +import { existsSync, statSync, writeFileSync } from "fs"; import * as esbuild from "esbuild"; import grabAllPages from "../../utils/grab-all-pages"; 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 grabClientHydrationScript from "./grab-client-hydration-script"; 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 = { watch?: boolean; @@ -56,11 +61,27 @@ export default async function allPagesBundler(params?: Params) { let buildStart = 0; build.onStart(() => { + build_starts++; 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) => { - 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({ pages, @@ -86,6 +107,8 @@ export default async function allPagesBundler(params?: Params) { if (params?.exit_after_first_build) { process.exit(); } + + build_starts = 0; }); }, }; diff --git a/src/functions/server/watcher.ts b/src/functions/server/watcher.ts index 53693c1..5177db3 100644 --- a/src/functions/server/watcher.ts +++ b/src/functions/server/watcher.ts @@ -1,4 +1,4 @@ -import { watch, existsSync } from "fs"; +import { watch, existsSync, statSync } from "fs"; import path from "path"; import grabDirNames from "../../utils/grab-dir-names"; import rebuildBundler from "./rebuild-bundler"; @@ -6,7 +6,9 @@ import { log } from "../../utils/log"; const { ROOT_DIR } = grabDirNames(); -export default function watcher() { +export default async function watcher() { + await Bun.sleep(1000); + const pages_src_watcher = watch( ROOT_DIR, { @@ -16,6 +18,17 @@ export default function watcher() { async (event, filename) => { 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 = /node_modules\/|^public\/|^\.bunext\/|^\.git\/|^dist\/|bun\.lockb$/; @@ -52,8 +65,7 @@ export default function watcher() { if (global.RECOMPILING) return; - const fullPath = path.join(ROOT_DIR, filename); - const action = existsSync(fullPath) ? "created" : "deleted"; + const action = existsSync(full_file_path) ? "created" : "deleted"; const type = filename.match(/\.css$/) ? "Sylesheet" : "Page"; await fullRebuild({ diff --git a/src/functions/server/web-pages/grab-page-component.tsx b/src/functions/server/web-pages/grab-page-component.tsx index 3e035e4..5bae761 100644 --- a/src/functions/server/web-pages/grab-page-component.tsx +++ b/src/functions/server/web-pages/grab-page-component.tsx @@ -58,7 +58,7 @@ export default async function grabPageComponent({ if (!file_path) { const errMsg = `No File Path (\`file_path\`) or Request Object (\`req\`) provided not found`; - // console.error(errMsg); + // log.error(errMsg); throw new Error(errMsg); } @@ -68,7 +68,7 @@ export default async function grabPageComponent({ if (!bundledMap?.path) { const errMsg = `No Bundled File Path for this request path!`; - console.error(errMsg); + log.error(errMsg); throw new Error(errMsg); } @@ -172,7 +172,7 @@ export default async function grabPageComponent({ head: Head, }; } catch (error: any) { - console.error(`Error Grabbing Page Component: ${error.message}`); + log.error(`Error Grabbing Page Component: ${error.message}`); return await grabPageErrorComponent({ error, diff --git a/src/functions/server/web-pages/grab-web-page-hydration-script.tsx b/src/functions/server/web-pages/grab-web-page-hydration-script.tsx index 7b1dbef..4bca438 100644 --- a/src/functions/server/web-pages/grab-web-page-hydration-script.tsx +++ b/src/functions/server/web-pages/grab-web-page-hydration-script.tsx @@ -36,14 +36,18 @@ export default async function (params?: Params) { script += ` try {\n`; script += ` document.getElementById("__bunext_error_overlay")?.remove();\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 += ` const oldLink = document.querySelector('link[rel="stylesheet"]');\n`; script += ` const newLink = document.createElement("link");\n`; script += ` newLink.rel = "stylesheet";\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 += ` } else if (oldCSSLink) {\n`; + script += ` oldCSSLink.remove();\n`; script += ` }\n`; script += ` const newScriptPath = \`/\${data.target_map.path}?t=\${Date.now()}\`;\n\n`; diff --git a/src/functions/server/web-pages/handle-web-pages.tsx b/src/functions/server/web-pages/handle-web-pages.tsx index 263195d..953a3ad 100644 --- a/src/functions/server/web-pages/handle-web-pages.tsx +++ b/src/functions/server/web-pages/handle-web-pages.tsx @@ -1,4 +1,5 @@ import isDevelopment from "../../../utils/is-development"; +import { log } from "../../../utils/log"; import getCache from "../../cache/get-cache"; import generateWebPageResponseFromComponentReturn from "./generate-web-page-response-from-component-return"; import grabPageComponent from "./grab-page-component"; @@ -38,7 +39,7 @@ export default async function handleWebPages({ ...componentRes, }); } catch (error: any) { - console.error(`Error Handling Web Page: ${error.message}`); + log.error(`Error Handling Web Page: ${error.message}`); const componentRes = await grabPageErrorComponent({ error, diff --git a/src/functions/server/web-pages/tailwind-esbuild-plugin.tsx b/src/functions/server/web-pages/tailwind-esbuild-plugin.tsx index 9e9a8e3..6983528 100644 --- a/src/functions/server/web-pages/tailwind-esbuild-plugin.tsx +++ b/src/functions/server/web-pages/tailwind-esbuild-plugin.tsx @@ -2,19 +2,59 @@ import * as esbuild from "esbuild"; import postcss from "postcss"; import tailwindcss from "@tailwindcss/postcss"; 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 = { name: "tailwindcss", setup(build) { build.onLoad({ filter: /\.css$/ }, async (args) => { - const source = await readFile(args.path, "utf-8"); - const result = await postcss([tailwindcss()]).process(source, { - from: args.path, - }); + try { + const source = await readFile(args.path, "utf-8"); + 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 { - contents: result.css, - loader: "css", + path: css_path, }; }); },