diff --git a/docs/.config/docs.yaml b/docs/.config/docs.yaml index 21b7243..a95109a 100644 --- a/docs/.config/docs.yaml +++ b/docs/.config/docs.yaml @@ -2,7 +2,7 @@ name: srvx shortDescription: Universal Server API -description: Based on web platform standards and works seamlessly with Deno, Bun and Node.js and more. +description: Built atop web platform standards to integrate seamlessly with Deno, Bun, Node.js, and more. github: h3js/srvx themeColor: red socials: diff --git a/docs/1.guide/.navigation.yml b/docs/1.guide/.navigation.yml new file mode 100644 index 0000000..a542600 --- /dev/null +++ b/docs/1.guide/.navigation.yml @@ -0,0 +1,2 @@ +icon: i-ph:book-open-duotone +title: Guide diff --git a/docs/1.guide/0.index.md b/docs/1.guide/0.index.md new file mode 100644 index 0000000..cd4ad11 --- /dev/null +++ b/docs/1.guide/0.index.md @@ -0,0 +1,56 @@ +--- +icon: pixel:play +--- + +# Getting Started + +> Get to know srvx and familiarize yourself with basic usage. + +Srvx provides a unified API for creating HTTP servers based on web standard primitives such as [fetch][fetch], [Request][Request], and [Response][Response], working seamlessly with [Deno][Deno], [Bun][Bun], [Node.js][Node.js], and more. + +:read-more{to="/guide/basics/why" title="Why srvx?"} + +## Quick Start + +First, create an HTTP server using the `serve` function from the `srvx` package. + +```js [server.mjs] +import { serve } from "srvx"; + +const server = serve({ + fetch(request) { + return new Response("👋 Hello there!"); + }, +}); +``` + +Then, install `srvx` as a dependency: + +:pm-install{name="srvx"} + +Finally, run the server using your favorite runtime: + +::code-group + +```bash [node] +node server.mjs +``` + +```bash [deno] +deno run --allow-env --allow-net server.mjs +``` + +```bash [bun] +bun run server.mjs +``` + +:: + +[Deno]: https://deno.com/ +[Bun]: https://bun.sh/ +[Node.js]: https://nodejs.org/ +[Fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API +[Request]: https://developer.mozilla.org/en-US/docs/Web/API/Request +[Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response +[IncomingMessage]: https://nodejs.org/api/http.html#http_class_http_incomingmessage +[ServerResponse]: https://nodejs.org/api/http.html#http_class_http_serverresponse diff --git a/docs/1.guide/1.basics/.navigation.yml b/docs/1.guide/1.basics/.navigation.yml new file mode 100644 index 0000000..290df7a --- /dev/null +++ b/docs/1.guide/1.basics/.navigation.yml @@ -0,0 +1,2 @@ +icon: ph:book-open-duotone +title: Guide diff --git a/docs/1.guide/1.basics/0.why.md b/docs/1.guide/1.basics/0.why.md new file mode 100644 index 0000000..8cdc159 --- /dev/null +++ b/docs/1.guide/1.basics/0.why.md @@ -0,0 +1,90 @@ +--- +icon: clarity:rack-server-outline-alerted +--- + +# Why srvx? + +> Why does srx exist and why would you want to use it? + +Srvx provides a unified API for creating HTTP servers based on web standard primitives such as [fetch][fetch], [Request][Request], and [Response][Response], working seamlessly with [Deno][Deno], [Bun][Bun], [Node.js][Node.js], and more. + +Usage is simple, low-level, and universal, and in most cases, introduces no or minimum overhead. + +The main use-case of srvx is for tools and frameworks that wish to be runtime agnostic. Instead of depending on idiosyncratic runtime APIs, and introducing adapters, using srvx as unified building block. + +**Example:** Same code working regardless of runtime. + +```js +import { serve } from "srvx"; + +const server = serve({ + port: 3000, + // tls: {} + fetch(request) { + return new Response(`👋 Your IP address is ${request.ip}`); + }, +}); +``` + +## Runtime APIs + +### Deno and Bun + +[Deno][Deno] and [Bun][Bun] use web standard APIs for HTTP servers, with slight differences and extensions on top of the standard. + +**Example:** [Deno][Deno] server ([learn more](https://docs.deno.com/api/deno/~/Deno.serve)): + +```js +Deno.serve( + { port: 3000 }, + (request, info) => + new Response(`👋 Your IP address is ${info.remoteAddr.hostname}`), +); +``` + +**Example:** [Bun][Bun] server ([learn more](https://bun.sh/docs/api/http)): + +```js +Bun.serve({ + port: 3000, + fetch: (request, server) => + new Response(`👋 Your IP address is ${server.requestIP(request).address}`), +}); +``` + +> [!TIP] +> Srvx unifies usage by adding [extensions directly to request](/guide/basics/handler#extended-request-serverrequest) and unified [options](/guide/basics/options). + +### Node.js + +[Node.js][Node.js], provides [`node:http`](https://nodejs.org/api/http.html), [`node:https`](https://nodejs.org/api/https.html) and [`node:http2`](https://nodejs.org/api/http2.html) to create HTTP servers. + +**Example:** Node.js HTTP server ([learn more](https://nodejs.org/en/learn/getting-started/introduction-to-nodejs)): + +```js +import { createServer } from "node:http"; + +createServer((req, res) => { + res.end(`👋 Your IP address is ${req.socket.remoteAddress}`); +}).listen(3000); +``` + +Whenever a new request is received, the request event is called with two Node objects: + +- Request (conventionally `req`), which is of the type [node:IncomingMessage][IncomingMessage], and passed in as the first argument of the event and enables access to the HTTP request details. +- Response (conventionally `res`), which is of the type [node:ServerResponse][ServerResponse], and passed in as the second argument of the event and allows preparing and sending of an HTTP response. + +Srvx uses a lightweight proxy layer to emulate web standard APIs for Node.js. + +:read-more{to="/guide/advanced/node" title="Node.js support"} + +[Node.js]: https://nodejs.org/ +[Deno]: https://deno.com/ +[Bun]: https://bun.sh/ +[Express]: https://expressjs.com/ +[Fastify]: https://fastify.dev/ +[Fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API +[Request]: https://developer.mozilla.org/en-US/docs/Web/API/Request +[Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response +[IncomingMessage]: https://nodejs.org/api/http.html#http_class_http_incomingmessage +[ServerResponse]: https://nodejs.org/api/http.html#http_class_http_serverresponse diff --git a/docs/1.guide/2.handler.md b/docs/1.guide/1.basics/1.handler.md similarity index 100% rename from docs/1.guide/2.handler.md rename to docs/1.guide/1.basics/1.handler.md diff --git a/docs/1.guide/3.server.md b/docs/1.guide/1.basics/2.server.md similarity index 100% rename from docs/1.guide/3.server.md rename to docs/1.guide/1.basics/2.server.md diff --git a/docs/1.guide/4.middleware.md b/docs/1.guide/1.basics/3.middleware.md similarity index 100% rename from docs/1.guide/4.middleware.md rename to docs/1.guide/1.basics/3.middleware.md diff --git a/docs/1.guide/5.options.md b/docs/1.guide/1.basics/4.options.md similarity index 100% rename from docs/1.guide/5.options.md rename to docs/1.guide/1.basics/4.options.md diff --git a/docs/1.guide/6.bundler.md b/docs/1.guide/1.basics/5.bundler.md similarity index 100% rename from docs/1.guide/6.bundler.md rename to docs/1.guide/1.basics/5.bundler.md diff --git a/docs/1.guide/1.index.md b/docs/1.guide/1.index.md deleted file mode 100644 index 6536a67..0000000 --- a/docs/1.guide/1.index.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -icon: ph:book-open-duotone ---- - -# Getting Started - -> Get familiar with srvx usage and why it exists. - -srvx provides a unified standard API to create HTTP servers based on the standard web platform primitives ([fetch][fetch], [Request][Request] and [Response][Response]) and works seamlessly with [Deno][Deno], [Bun][Bun], [Node.js][Node.js] and more. - -For [Deno][Deno] and [Bun][Bun], srvx unifies interface with zero overhead and for [Node.js][Node.js], creates a lightweight compatibility layer to wrap [node:IncomingMessage][IncomingMessage] as a standard [Request][Request] object and convert final state of [node:ServerResponse][ServerResponse] to a standard [Response][Response] object. - -## Quick Start - -Create an HTTP server using the `serve` function from `srvx` package. - -```js [server.mjs] -import { serve } from "srvx"; - -const server = serve({ - fetch(request) { - return new Response("👋 Hello there!"); - }, -}); -``` - -Install `srvx` as a dependency: - -:pm-install{name="srvx"} - -Then, run the server using your favorite runtime: - -::code-group - -```bash [node] -node server.mjs -``` - -```bash [deno] -deno run --allow-env --allow-net server.mjs -``` - -```bash [bun] -bun run server.mjs -``` - -:: - -## Why using srvx? - -When you want to create a HTTP server using [Node.js][Node.js], you have to use [node:http](https://nodejs.org/api/http.html) module (or a library based on it). - -**Example:** Node.js HTTP server ([learn more](https://nodejs.org/en/learn/getting-started/introduction-to-nodejs)): - -```js -import { createServer } from "node:http"; - -createServer((req, res) => { - res.end("Hello, Node.js!"); -}).listen(3000); -``` - -Whenever a new request is received, the request event is called with two objects: a request `req` object ([node:IncomingMessage][IncomingMessage]) to access HTTP request details and a response `res` object ([node:ServerResponse][ServerResponse]) that can be used to prepare and send a HTTP response. Popular framework such as [Express](https://expressjs.com/) and [Fastify](https://fastify.dev/) are also based on Node.js server API. - -:read-more{to="/guide/node" title="Node.js support"} - -Recent JavaScript server runtimes like [Deno][Deno] and [Bun][Bun] have a different way to define a server which is similar to web [fetch][fetch] API. - -**Example:** [Deno][Deno] HTTP server ([learn more](https://docs.deno.com/api/deno/~/Deno.serve)): - -```js -Deno.serve({ port: 3000 }, (_req, info) => new Response("Hello, Deno!")); -``` - -**Example:** [Bun][Bun] HTTP server ([learn more](https://bun.sh/docs/api/http)): - -```js -Bun.serve({ port: 3000, fetch: (req) => new Response("Hello, Bun!") }); -``` - -As you probably noticed, there is a difference between [Node.js][Node.js] and [Deno][Deno] and [Bun][Bun]. The incoming request is a web [Request][Request] object and server response is a web [Response][Response] object. Accessing headers, request path, and preparing response is completely different between [Node.js][Node.js] and other runtimes. - -While [Deno][Deno] and [Bun][Bun] servers are both based on web standards, There are differences between them. The way to provide options, server lifecycle, access to request info such as client IP which is not part of [Request][Request] standard are some examples. - -Main use-case of this library is for tools and frameworks that want to be runtime agnostic. By using srvx as standard server layer, instead of depending on of the individual runtime APIs, we push JavaScript ecosystem to be more consistent and moving towards web standards! - -### How is it Different? - -You might ask, what is the difference between srvx and other HTTP frameworks. - -Srvx provides a simple, low-level, and universal API, very similar to [Deno][Deno] and [Bun][Bun]. It has **no conventions**, utilities, or router, and in most cases, using srvx introduces no overhead. - -The core of srvx was extracted from the [h3](https://h3.dev/) v2 early development branch and opened to a broader ecosystem to encourage the adoption of Web platform standards without enforcing it's own conventions. - -[Deno]: https://deno.com/ -[Bun]: https://bun.sh/ -[Node.js]: https://nodejs.org/ -[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API -[Request]: https://developer.mozilla.org/en-US/docs/Web/API/Request -[Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response -[IncomingMessage]: https://nodejs.org/api/http.html#http_class_http_incomingmessage -[ServerResponse]: https://nodejs.org/api/http.html#http_class_http_serverresponse diff --git a/docs/1.guide/2.advanced/.navigation.yml b/docs/1.guide/2.advanced/.navigation.yml new file mode 100644 index 0000000..0e2980f --- /dev/null +++ b/docs/1.guide/2.advanced/.navigation.yml @@ -0,0 +1,2 @@ +icon: gis:cube-3d +title: Advanced diff --git a/docs/1.guide/7.node.md b/docs/1.guide/2.advanced/0.node.md similarity index 91% rename from docs/1.guide/7.node.md rename to docs/1.guide/2.advanced/0.node.md index d4b6ae6..a6a2dc4 100644 --- a/docs/1.guide/7.node.md +++ b/docs/1.guide/2.advanced/0.node.md @@ -6,12 +6,11 @@ icon: akar-icons:node-fill > Learn more about Node.js support with srvx. -> [!NOTE] -> This is an advanced section, explaining internal mechanism of srvx for Node.js support. +## View from Above -As explained in the [why srvx](/guide/why) section, [Node.js][Node.js] uses different API for handling incoming http requests and sending responses. +As explained in the [Why srvx?](/guide/basics/why) page, [Node.js][Node.js] uses different APIs for handling incoming http requests and sending responses. -srvx internally uses a lightweight proxy system that wraps [node:IncomingMessage][IncomingMessage] as [Request][Request] and converts the final state of [node:ServerResponse][ServerResponse] to a [Response][Response] object. +The internal mechanisms of **srvx** use a lightweight proxy system that wraps the [node:IncomingMessage][IncomingMessage] in a [Request][Request] and converts its final state of [node:ServerResponse][ServerResponse] to a [Response][Response] object. ## How Node.js Compatibility Works diff --git a/docs/1.guide/2.advanced/1.experimental.md b/docs/1.guide/2.advanced/1.experimental.md new file mode 100644 index 0000000..48427ba --- /dev/null +++ b/docs/1.guide/2.advanced/1.experimental.md @@ -0,0 +1,74 @@ +--- +icon: game-icons:soap-experiment +--- + +# Experimental Support + +> See what the team is working on to improve srvx's core offering. + +## Caution! Scientists at work! + +Currently, **srvx** provides support for two experimental adapters: [Cloudflare][Cloudflare] and the web [Service Worker API][Service Worker]. +The aim is to enable engineers to leverage **srvx** in any conceivable server environment, +even those that impose specific handling of requests/responses, such as Cloudflare's Edge Network or browser-based Service Workers. +**srvx**'s lean ergonomics and middleware are maintained to ensure the same experience across adapters. + +## Cloudflare + +The Cloudflare brand has rapidly established a name that developers trust, +so it only serves to reason that their Worker runtime environment would be a desirable target for **srvx** users. +The framework provides its universal compat layer for any requests in the Worker Environment by utilizing Cloudflare's Fetch Handler API, +ensuring that Cloudflare-specific properties, environment variables, and execution context are all accommodated. +Care is taken to preserve access to critical capabilities, like `waitUntil()` for background tasks, and +runtime metadata is attached to identify the execution context. This enables any application making use of **srvx** +to be deployed as a Cloudflare Worker while maintaining the niceties of the web standard API. + +Upcoming: Handling IP addresses + +**Ex.** - Cloudflare Workers ([learn more](https://www.cloudflare.com/developer-platform/products/workers/)): + +```js +import { serve } from "srvx/adapters/cloudflare"; + +export default serve({ + fetch(request) { + return new Response(`

Hello from Cloudflare!

`, { + headers: { "Content-Type": "text/html; charset=UTF-8" }, + }); + }, +}); +``` + +## Service Workers + +Anytime a Browser application has need for a proxy server to act in the absence of network availability, Service Workers are turned to. Whether completing computationally intensive tasks, +intercepting network requests, creating offline experiences, sending push notifications, or running background sync APIs, these are the purview of the +Service Worker. Retaining this core functionality is of crucial importance as any dev reaching for a Service Worker solution will expect consistency. +To this end, **srvx** smartly detects if it's running in a Browser or Service Worker context and delivers the commensurate behavior for each environment. +The entire Service Worker lifecycle is supported and managed as **srvx** self-registers, activates, and unregisters automatically. Critical features, +such as `waitUntil` capability for background operations, "claim immediately" behavior, and per-update page reloads so that new clients can be claimed. +During self-registration scenarios, any heavier application logic should be lazy loaded when performance implications are a concern (but when aren't they...? :smirk:). + +> [!NOTE] +> As a safety measure, 404 responses and requests for static assets (i.e. URLs with file extensions) are skipped to avoid breaking normal browser behaviors. + +Upcoming: An option for 404 handling will be explored + +**Ex.** - Service Workers ([learn more](https://stackblitz.com/github/h3js/srvx/tree/main/playground?file=app.mjs)): + +```js +import { serve } from "../node_modules/srvx/dist/adapters/service-worker.mjs"; + +// Internally the service worker is implemented by passing it as an option to the `serve()` function alongside `fetch()` +serve({ + serviceWorker: { url: import.meta.url }, + fetch(_request) { + return new Response(`

👋 Hello there!

`, { + headers: { "Content-Type": "text/html; charset=UTF-8" }, + }); + }, +}); +``` + +[Cloudflare]: https://www.cloudflare.com/ +[Service Worker]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API diff --git a/docs/1.guide/2.advanced/2.plugins.md b/docs/1.guide/2.advanced/2.plugins.md new file mode 100644 index 0000000..40457f4 --- /dev/null +++ b/docs/1.guide/2.advanced/2.plugins.md @@ -0,0 +1,10 @@ +--- +icon: bi:plugin +--- + +# Plugins + +> Learn more about how we leverage plugins to extend the srvx foundation with new functionalities. + +> [!NOTE] +> More to come!! Keep watching this space... diff --git a/package.json b/package.json index c45fb4f..635ad5f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "srvx", "version": "0.8.0", - "description": "Universal Server API based on web platform standards. Works seamlessly with Deno, Bun and Node.js.", + "description": "Universal Server API built atop web platform standards to integrate seamlessly with Deno, Bun, Node.js, and more.", "homepage": "https://srvx.h3.dev", "repository": "h3js/srvx", "license": "MIT", diff --git a/test/bench-node/README.md b/test/bench-node/README.md index 8f488d9..42faf8d 100644 --- a/test/bench-node/README.md +++ b/test/bench-node/README.md @@ -1,4 +1,4 @@ -# Node.js Cmpatibility Benchmarks +# Node.js Compatibility Benchmarks Simple benchmarks primarily focus on how closely we can approach native `node:http` performance while using a web standards compatibility layer.