This commit is contained in:
2026-03-18 17:37:24 +01:00
parent f6db3ab866
commit eec0df83cd
79 changed files with 2333 additions and 1 deletions
+47
View File
@@ -0,0 +1,47 @@
import plugin from "bun-plugin-tailwind";
import { execSync } from "child_process";
const BuildKeys = [
{ key: "production" },
{ key: "bytecode" },
{ key: "conditions" },
{ key: "format" },
{ key: "root" },
{ key: "splitting" },
{ key: "cdd-chunking" },
];
export default function bundle({ out_dir, src, minify = true, exec_options, debug, entry_naming, sourcemap, target, build_options, }) {
let cmd = `bun build`;
if (minify) {
cmd += ` --minify`;
}
if (entry_naming) {
cmd += ` --entry-naming "${entry_naming}"`;
}
if (sourcemap) {
cmd += ` --sourcemap`;
}
if (target) {
cmd += ` --target ${target}`;
}
if (build_options) {
const keys = Object.keys(build_options);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = build_options[key];
if (typeof value == "boolean" && value) {
cmd += ` --${key}`;
}
else if (key && value) {
cmd += ` --${key} ${value}`;
}
}
}
cmd += ` ${src} --outdir ${out_dir}`;
if (debug) {
console.log("cmd =>", cmd);
}
execSync(cmd, {
stdio: "inherit",
...exec_options,
});
}
+18
View File
@@ -0,0 +1,18 @@
import EJSON from "./ejson";
/**
* # Convert Serialized Query back to object
*/
export default function deserializeQuery(query) {
let queryObject = typeof query == "object" ? query : Object(EJSON.parse(query));
const keys = Object.keys(queryObject);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = queryObject[key];
if (typeof value == "string") {
if (value.match(/^\{|^\[/)) {
queryObject[key] = EJSON.parse(value);
}
}
}
return queryObject;
}
+33
View File
@@ -0,0 +1,33 @@
/**
* # EJSON parse string
*/
function parse(string, reviver) {
if (!string)
return undefined;
if (typeof string == "object")
return string;
if (typeof string !== "string")
return undefined;
try {
return JSON.parse(string, reviver);
}
catch (error) {
return undefined;
}
}
/**
* # EJSON stringify object
*/
function stringify(value, replacer, space) {
try {
return JSON.stringify(value, replacer || undefined, space);
}
catch (error) {
return undefined;
}
}
const EJSON = {
parse,
stringify,
};
export default EJSON;
+4
View File
@@ -0,0 +1,4 @@
export default function exitWithError(msg, code) {
console.error(msg);
process.exit(code || 1);
}
+64
View File
@@ -0,0 +1,64 @@
import { existsSync, readdirSync, statSync } from "fs";
import grabDirNames from "./grab-dir-names";
import path from "path";
import AppNames from "./grab-app-names";
export default function grabAllPages(params) {
const { PAGES_DIR } = grabDirNames();
const pages = grabPageDirRecursively({ page_dir: PAGES_DIR });
if (params?.exclude_api) {
return pages.filter((p) => !Boolean(p.url_path.startsWith("/api/")));
}
return pages;
}
function grabPageDirRecursively({ page_dir }) {
const pages = readdirSync(page_dir);
const pages_files = [];
const root_pages_file = grabPageFileObject({ file_path: `` });
if (root_pages_file) {
pages_files.push(root_pages_file);
}
for (let i = 0; i < pages.length; i++) {
const page = pages[i];
const full_page_path = path.join(page_dir, page);
if (!existsSync(full_page_path)) {
continue;
}
if (page.match(new RegExp(`${AppNames["RootPagesComponentName"]}`))) {
continue;
}
if (page.match(/\(|\)|--/)) {
continue;
}
const page_stat = statSync(full_page_path);
if (page_stat.isDirectory()) {
if (page.match(/\(|\)/))
continue;
const new_page_files = grabPageDirRecursively({
page_dir: full_page_path,
});
pages_files.push(...new_page_files);
}
else if (page.match(/\.(ts|js)x?$/)) {
const pages_file = grabPageFileObject({
file_path: full_page_path,
});
if (pages_file) {
pages_files.push(pages_file);
}
}
}
return pages_files;
}
function grabPageFileObject({ file_path, }) {
let url_path = file_path
.replace(/.*\/pages\//, "/")
?.replace(/\.(ts|js)x?$/, "");
let file_name = url_path.split("/").pop();
if (!file_name)
return;
return {
local_path: file_path,
url_path,
file_name,
};
}
+8
View File
@@ -0,0 +1,8 @@
const AppNames = {
defaultPort: 7000,
defaultAssetPrefix: "_bunext/static",
name: "Bunext",
defaultDistDir: ".bunext",
RootPagesComponentName: "__root",
};
export default AppNames;
+17
View File
@@ -0,0 +1,17 @@
import AppNames from "./grab-app-names";
import numberfy from "./numberfy";
export default function grabAppPort() {
const { defaultPort } = AppNames;
try {
if (process.env.PORT) {
return numberfy(process.env.PORT);
}
if (global.CONFIG.port) {
return global.CONFIG.port;
}
return numberfy(defaultPort);
}
catch (error) {
return numberfy(defaultPort);
}
}
+8
View File
@@ -0,0 +1,8 @@
import AppNames from "./grab-app-names";
export default function grabAssetsPrefix() {
if (global.CONFIG.assetsPrefix) {
return global.CONFIG.assetsPrefix;
}
const { defaultAssetPrefix } = AppNames;
return defaultAssetPrefix;
}
+18
View File
@@ -0,0 +1,18 @@
export default function grabConstants() {
const config = global.CONFIG;
const MB_IN_BYTES = 1024 * 1024;
const ClientWindowPagePropsName = "__PAGE_PROPS__";
const ClientRootElementIDName = "__bunext";
const ClientRootComponentWindowName = "BUNEXT_ROOT";
const ServerDefaultRequestBodyLimitBytes = MB_IN_BYTES * 10;
const MaxBundlerRebuilds = 5;
return {
ClientRootElementIDName,
ClientWindowPagePropsName,
MBInBytes: MB_IN_BYTES,
ServerDefaultRequestBodyLimitBytes,
ClientRootComponentWindowName,
MaxBundlerRebuilds,
config,
};
}
+43
View File
@@ -0,0 +1,43 @@
import path from "path";
export default function grabDirNames() {
const ROOT_DIR = process.cwd();
const SRC_DIR = path.join(ROOT_DIR, "src");
const PAGES_DIR = path.join(SRC_DIR, "pages");
const API_DIR = path.join(PAGES_DIR, "api");
const PUBLIC_DIR = path.join(ROOT_DIR, "public");
const BUNEXT_PUBLIC_DIR = path.join(PUBLIC_DIR, "__bunext");
const HYDRATION_DST_DIR = path.join(BUNEXT_PUBLIC_DIR, "pages");
const BUNEXT_CACHE_DIR = path.join(BUNEXT_PUBLIC_DIR, "cache");
const HYDRATION_DST_DIR_MAP_JSON_FILE = path.join(HYDRATION_DST_DIR, "map.json");
const CONFIG_FILE = path.join(ROOT_DIR, "bunext.config.ts");
const BUNX_CWD_DIR = path.resolve(ROOT_DIR, ".bunext");
const BUNX_TMP_DIR = path.resolve(BUNX_CWD_DIR, ".tmp");
const BUNX_HYDRATION_SRC_DIR = path.resolve(BUNX_CWD_DIR, "client", "hydration-src");
const BUNX_ROOT_DIR = path.resolve(__dirname, "../../");
const BUNX_ROOT_SRC_DIR = path.join(BUNX_ROOT_DIR, "src");
const BUNX_ROOT_PRESETS_DIR = path.join(BUNX_ROOT_SRC_DIR, "presets");
const BUNX_ROOT_500_FILE_NAME = `server-error`;
const BUNX_ROOT_500_PRESET_COMPONENT = path.join(BUNX_ROOT_PRESETS_DIR, `${BUNX_ROOT_500_FILE_NAME}.tsx`);
const BUNX_ROOT_404_FILE_NAME = `not-found`;
const BUNX_ROOT_404_PRESET_COMPONENT = path.join(BUNX_ROOT_PRESETS_DIR, `${BUNX_ROOT_404_FILE_NAME}.tsx`);
return {
ROOT_DIR,
SRC_DIR,
PAGES_DIR,
API_DIR,
PUBLIC_DIR,
HYDRATION_DST_DIR,
BUNX_ROOT_DIR,
CONFIG_FILE,
BUNX_TMP_DIR,
BUNX_HYDRATION_SRC_DIR,
BUNX_ROOT_SRC_DIR,
BUNX_ROOT_PRESETS_DIR,
BUNX_ROOT_500_PRESET_COMPONENT,
BUNX_ROOT_500_FILE_NAME,
BUNX_ROOT_404_PRESET_COMPONENT,
BUNX_ROOT_404_FILE_NAME,
HYDRATION_DST_DIR_MAP_JSON_FILE,
BUNEXT_CACHE_DIR,
};
}
+8
View File
@@ -0,0 +1,8 @@
import grabAppPort from "./grab-app-port";
export default function grabOrigin() {
if (global.CONFIG.origin) {
return global.CONFIG.origin;
}
const port = grabAppPort();
return `http://localhost:${port}`;
}
+17
View File
@@ -0,0 +1,17 @@
export default function grabPageName(params) {
const pathArr = params.path.split("/");
const routesIndex = pathArr.findIndex((p) => p == "pages");
const newPathArr = [...pathArr].slice(routesIndex + 1);
const filename = newPathArr
.filter((p) => Boolean(p.match(/./)))
.map((p) => p
.replace(/\.\w+$/, "")
.replace(/\[/g, "-")
.replace(/\.\.\./g, "-")
.replace(/[^a-z\-]/g, ""))
.join("-");
if (filename.endsWith(`-index`)) {
return filename.replace(/-index$/, "");
}
return filename;
}
+21
View File
@@ -0,0 +1,21 @@
import deserializeQuery from "./deserialize-query";
export default async function grabRouteParams({ req, }) {
const url = new URL(req.url);
const query = deserializeQuery(Object.fromEntries(url.searchParams));
const body = await (async () => {
try {
return req.method == "GET" ? undefined : await req.json();
}
catch (error) {
return {};
}
})();
const routeParams = {
req,
url,
query,
body,
server: global.SERVER,
};
return routeParams;
}
+6
View File
@@ -0,0 +1,6 @@
export default function grabRouter() {
// if (process.env.NODE_ENV !== "production") {
// global.ROUTER.reload();
// }
return global.ROUTER;
}
+10
View File
@@ -0,0 +1,10 @@
export default function isDevelopment() {
const config = global.CONFIG;
if (process.env.NODE_ENV == "production") {
return false;
}
if (config.development) {
return true;
}
return false;
}
+31
View File
@@ -0,0 +1,31 @@
export default function numberfy(num, decimals) {
try {
const numberString = String(num)
.replace(/[^0-9\.]/g, "")
.replace(/\.$/, "");
if (!numberString.match(/./))
return 0;
const existingDecimals = numberString.match(/\./)
? numberString.split(".").pop()?.length
: undefined;
const numberfiedNum = Number(numberString);
if (typeof numberfiedNum !== "number")
return 0;
if (isNaN(numberfiedNum))
return 0;
if (decimals == 0) {
return Math.round(Number(numberfiedNum));
}
else if (decimals) {
return Number(numberfiedNum.toFixed(decimals));
}
if (existingDecimals)
return Number(numberfiedNum.toFixed(existingDecimals));
return Math.round(numberfiedNum);
}
catch (error) {
console.log(`Numberfy ERROR: ${error.message}`);
return 0;
}
}
export const _n = numberfy;
+9
View File
@@ -0,0 +1,9 @@
import grabDirNames from "./grab-dir-names";
export default function refreshRouter() {
const { PAGES_DIR } = grabDirNames();
const router = new Bun.FileSystemRouter({
style: "nextjs",
dir: PAGES_DIR,
});
global.ROUTER = router;
}