Update API routes function. Add middleware. Update README.md
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { Command } from "commander";
|
||||
import grabConfig from "../../functions/grab-config";
|
||||
import init from "../../functions/init";
|
||||
import type { BunextConfig } from "../../types";
|
||||
import allPagesBundler from "../../functions/bundler/all-pages-bundler";
|
||||
|
||||
export default function () {
|
||||
return new Command("build")
|
||||
.description("Build Project")
|
||||
.action(async () => {
|
||||
console.log(`Building Project ...`);
|
||||
|
||||
process.env.NODE_ENV = "production";
|
||||
|
||||
await init();
|
||||
|
||||
const config: BunextConfig = (await grabConfig()) || {};
|
||||
|
||||
global.CONFIG = {
|
||||
...config,
|
||||
development: true,
|
||||
};
|
||||
|
||||
allPagesBundler({
|
||||
exit_after_first_build: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Command } from "commander";
|
||||
import grabConfig from "../../functions/grab-config";
|
||||
import startServer from "../../functions/server/start-server";
|
||||
import init from "../../functions/init";
|
||||
import type { BunextConfig } from "../../types";
|
||||
|
||||
export default function () {
|
||||
return new Command("dev")
|
||||
.description("Run development server")
|
||||
.action(async () => {
|
||||
console.log(`Running development server ...`);
|
||||
|
||||
await init();
|
||||
|
||||
const config: BunextConfig = (await grabConfig()) || {};
|
||||
|
||||
global.CONFIG = {
|
||||
...config,
|
||||
development: true,
|
||||
};
|
||||
|
||||
await startServer({ dev: true });
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Command } from "commander";
|
||||
import grabConfig from "../../functions/grab-config";
|
||||
import startServer from "../../functions/server/start-server";
|
||||
import init from "../../functions/init";
|
||||
|
||||
export default function () {
|
||||
return new Command("start")
|
||||
.description("Start production server")
|
||||
.action(async () => {
|
||||
console.log(`Starting production server ...`);
|
||||
|
||||
await init();
|
||||
|
||||
const config = await grabConfig();
|
||||
|
||||
global.CONFIG = { ...config };
|
||||
|
||||
await startServer();
|
||||
});
|
||||
}
|
||||
@@ -41,7 +41,7 @@ type Params = {
|
||||
export default async function allPagesBundler(params?: Params) {
|
||||
const pages = grabAllPages({ exclude_api: true });
|
||||
const { ClientRootElementIDName, ClientRootComponentWindowName } =
|
||||
await grabConstants();
|
||||
grabConstants();
|
||||
|
||||
const virtualEntries: Record<string, string> = {};
|
||||
const dev = isDevelopment();
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import type { Server } from "bun";
|
||||
import type {
|
||||
APIResponseObject,
|
||||
BunextServerRouteConfig,
|
||||
BunxRouteParams,
|
||||
} from "../../types";
|
||||
import type { BunextServerRouteConfig, BunxRouteParams } from "../../types";
|
||||
import grabRouteParams from "../../utils/grab-route-params";
|
||||
import grabConstants from "../../utils/grab-constants";
|
||||
import grabRouter from "../../utils/grab-router";
|
||||
@@ -13,14 +9,10 @@ type Params = {
|
||||
server: Server;
|
||||
};
|
||||
|
||||
export default async function ({
|
||||
req,
|
||||
server,
|
||||
}: Params): Promise<APIResponseObject | undefined> {
|
||||
export default async function ({ req, server }: Params): Promise<Response> {
|
||||
const url = new URL(req.url);
|
||||
|
||||
const { MBInBytes, ServerDefaultRequestBodyLimitBytes } =
|
||||
await grabConstants();
|
||||
const { MBInBytes, ServerDefaultRequestBodyLimitBytes } = grabConstants();
|
||||
|
||||
const router = grabRouter();
|
||||
|
||||
@@ -28,13 +20,19 @@ export default async function ({
|
||||
|
||||
if (!match?.filePath) {
|
||||
const errMsg = `Route ${url.pathname} not found`;
|
||||
// console.error(errMsg);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
status: 401,
|
||||
msg: errMsg,
|
||||
};
|
||||
return Response.json(
|
||||
{
|
||||
success: false,
|
||||
msg: errMsg,
|
||||
},
|
||||
{
|
||||
status: 401,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const routeParams: BunxRouteParams = await grabRouteParams({ req });
|
||||
@@ -52,17 +50,25 @@ export default async function ({
|
||||
size > config.maxRequestBodyMB * MBInBytes) ||
|
||||
size > ServerDefaultRequestBodyLimitBytes
|
||||
) {
|
||||
return {
|
||||
success: false,
|
||||
status: 413,
|
||||
msg: "Request Body Too Large!",
|
||||
};
|
||||
return Response.json(
|
||||
{
|
||||
success: false,
|
||||
msg: "Request Body Too Large!",
|
||||
},
|
||||
{
|
||||
status: 413,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const res: APIResponseObject = await module["default"](
|
||||
routeParams as BunxRouteParams,
|
||||
);
|
||||
const res: Response = await module["default"]({
|
||||
...routeParams,
|
||||
server,
|
||||
} as BunxRouteParams);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import grabDirNames from "../../utils/grab-dir-names";
|
||||
import handleWebPages from "./web-pages/handle-web-pages";
|
||||
import handleRoutes from "./handle-routes";
|
||||
import isDevelopment from "../../utils/is-development";
|
||||
import grabConstants from "../../utils/grab-constants";
|
||||
|
||||
type Params = {
|
||||
dev?: boolean;
|
||||
@@ -19,6 +20,20 @@ export default async function (params?: Params): Promise<ServeOptions> {
|
||||
try {
|
||||
const url = new URL(req.url);
|
||||
|
||||
const { config } = grabConstants();
|
||||
|
||||
if (config?.middleware) {
|
||||
const middleware_res = await config.middleware({
|
||||
req,
|
||||
url,
|
||||
server,
|
||||
});
|
||||
|
||||
if (typeof middleware_res == "object") {
|
||||
return middleware_res;
|
||||
}
|
||||
}
|
||||
|
||||
if (url.pathname === "/__hmr" && isDevelopment()) {
|
||||
const referer_url = new URL(
|
||||
req.headers.get("referer") || "",
|
||||
@@ -69,14 +84,7 @@ export default async function (params?: Params): Promise<ServeOptions> {
|
||||
}
|
||||
|
||||
if (url.pathname.startsWith("/api/")) {
|
||||
const res = await handleRoutes({ req, server });
|
||||
|
||||
return new Response(JSON.stringify(res), {
|
||||
status: res?.status,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
return await handleRoutes({ req, server });
|
||||
}
|
||||
|
||||
if (url.pathname.startsWith("/public/")) {
|
||||
|
||||
@@ -5,8 +5,6 @@ import rebuildBundler from "./rebuild-bundler";
|
||||
|
||||
const { SRC_DIR } = grabDirNames();
|
||||
|
||||
const PAGE_FILE_RE = /\.(tsx?|jsx?|css)$/;
|
||||
|
||||
export default function watcher() {
|
||||
watch(
|
||||
SRC_DIR,
|
||||
@@ -16,12 +14,7 @@ export default function watcher() {
|
||||
},
|
||||
async (event, filename) => {
|
||||
if (!filename) return;
|
||||
const file_path = path.join(SRC_DIR, filename);
|
||||
// if (!PAGE_FILE_RE.test(filename)) return;
|
||||
|
||||
// "change" events (file content modified) are already handled by
|
||||
// esbuild's internal ctx.watch(). Only "rename" (create or delete)
|
||||
// requires a full rebuild because entry points have changed.
|
||||
if (event !== "rename") return;
|
||||
|
||||
if (global.RECOMPILING) return;
|
||||
|
||||
@@ -16,7 +16,7 @@ export default async function genWebHTML({
|
||||
routeParams,
|
||||
}: LivePageDistGenParams) {
|
||||
const { ClientRootElementIDName, ClientWindowPagePropsName } =
|
||||
await grabContants();
|
||||
grabContants();
|
||||
|
||||
const { renderToString } = await import(
|
||||
path.join(process.cwd(), "node_modules", "react-dom", "server")
|
||||
|
||||
@@ -125,7 +125,7 @@ export default async function grabPageComponent({
|
||||
: undefined;
|
||||
|
||||
const Component = module.default as FC<any>;
|
||||
const Head = module.head as FC<any>;
|
||||
const Head = module.Head as FC<any>;
|
||||
|
||||
const component = RootComponent ? (
|
||||
<RootComponent {...serverRes}>
|
||||
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
import { program } from "commander";
|
||||
import start from "./commands/start";
|
||||
import dev from "./commands/dev";
|
||||
import ora, { type Ora } from "ora";
|
||||
import type {
|
||||
BundlerCTXMap,
|
||||
BunextConfig,
|
||||
GlobalHMRControllerObject,
|
||||
} from "./types";
|
||||
import type { FileSystemRouter, Server } from "bun";
|
||||
import init from "./functions/init";
|
||||
import grabDirNames from "./utils/grab-dir-names";
|
||||
import build from "./commands/build";
|
||||
import type { BuildContext } from "esbuild";
|
||||
|
||||
/**
|
||||
* # Declare Global Variables
|
||||
*/
|
||||
declare global {
|
||||
var ORA_SPINNER: Ora;
|
||||
var CONFIG: BunextConfig;
|
||||
var SERVER: Server | undefined;
|
||||
var RECOMPILING: boolean;
|
||||
var WATCHER_TIMEOUT: any;
|
||||
var ROUTER: FileSystemRouter;
|
||||
var HMR_CONTROLLERS: GlobalHMRControllerObject[];
|
||||
var LAST_BUILD_TIME: number;
|
||||
var BUNDLER_CTX: BuildContext | undefined;
|
||||
var BUNDLER_CTX_MAP: BundlerCTXMap[] | undefined;
|
||||
var IS_FIRST_BUNDLE_READY: boolean;
|
||||
var BUNDLER_REBUILDS: 0;
|
||||
}
|
||||
|
||||
global.ORA_SPINNER = ora();
|
||||
global.ORA_SPINNER.clear();
|
||||
global.HMR_CONTROLLERS = [];
|
||||
global.IS_FIRST_BUNDLE_READY = false;
|
||||
global.BUNDLER_REBUILDS = 0;
|
||||
|
||||
await init();
|
||||
|
||||
const { PAGES_DIR } = grabDirNames();
|
||||
|
||||
const router = new Bun.FileSystemRouter({
|
||||
style: "nextjs",
|
||||
dir: PAGES_DIR,
|
||||
});
|
||||
|
||||
global.ROUTER = router;
|
||||
|
||||
/**
|
||||
* # Describe Program
|
||||
*/
|
||||
program
|
||||
.name(`bunext`)
|
||||
.description(`A React Next JS replacement built with bun JS`)
|
||||
.version(`1.0.0`);
|
||||
|
||||
/**
|
||||
* # Declare Commands
|
||||
*/
|
||||
program.addCommand(dev());
|
||||
program.addCommand(start());
|
||||
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(" "),
|
||||
);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
/**
|
||||
* # Parse Arguments
|
||||
*/
|
||||
program.parse(Bun.argv);
|
||||
@@ -0,0 +1,2 @@
|
||||
const config = {};
|
||||
export default config;
|
||||
+11
-1
@@ -48,6 +48,15 @@ export type BunextConfig = {
|
||||
globalVars?: { [k: string]: any };
|
||||
port?: number;
|
||||
development?: boolean;
|
||||
middleware?: (
|
||||
params: BunextConfigMiddlewareParams,
|
||||
) => Promise<Response | undefined> | Response | undefined;
|
||||
};
|
||||
|
||||
export type BunextConfigMiddlewareParams = {
|
||||
req: Request;
|
||||
url: URL;
|
||||
server: Server;
|
||||
};
|
||||
|
||||
export type GetRouteReturn = {
|
||||
@@ -69,6 +78,7 @@ export type BunxRouteParams = {
|
||||
* Intercept and Transform the response object
|
||||
*/
|
||||
resTransform?: (res: Response) => Promise<Response> | Response;
|
||||
server?: Server;
|
||||
};
|
||||
|
||||
export interface PostInsertReturn {
|
||||
@@ -146,7 +156,7 @@ export type BunextPageModule = {
|
||||
default: FC<any>;
|
||||
server?: BunextPageServerFn;
|
||||
meta?: BunextPageModuleMeta | BunextPageModuleMetaFn;
|
||||
head?: FC<BunextPageHeadFCProps>;
|
||||
Head?: FC<BunextPageHeadFCProps>;
|
||||
};
|
||||
|
||||
export type BunextPageModuleMetaFn = (params: {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import path from "path";
|
||||
import grabConfig from "../functions/grab-config";
|
||||
|
||||
export default async function grabConstants() {
|
||||
const config = await grabConfig();
|
||||
export default function grabConstants() {
|
||||
const config = global.CONFIG;
|
||||
const MB_IN_BYTES = 1024 * 1024;
|
||||
|
||||
const ClientWindowPagePropsName = "__PAGE_PROPS__";
|
||||
@@ -20,5 +17,6 @@ export default async function grabConstants() {
|
||||
ServerDefaultRequestBodyLimitBytes,
|
||||
ClientRootComponentWindowName,
|
||||
MaxBundlerRebuilds,
|
||||
config,
|
||||
} as const;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { Server } from "bun";
|
||||
import type { BunxRouteParams } from "../types";
|
||||
import deserializeQuery from "./deserialize-query";
|
||||
|
||||
@@ -26,6 +25,7 @@ export default async function grabRouteParams({
|
||||
url,
|
||||
query,
|
||||
body,
|
||||
server: global.SERVER,
|
||||
};
|
||||
|
||||
return routeParams;
|
||||
|
||||
Reference in New Issue
Block a user