From 9d2fca7d591e0efe6edc91d2a13da086a6f26b0c Mon Sep 17 00:00:00 2001 From: DaxServer <7479937+DaxServer@users.noreply.github.com> Date: Fri, 24 Oct 2025 19:13:06 +0000 Subject: [PATCH] blog: improve grammar and flow in blof/elysia-06.md --- docs/blog/elysia-06.md | 186 ++++++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 86 deletions(-) diff --git a/docs/blog/elysia-06.md b/docs/blog/elysia-06.md index 7ec44554..fc16c319 100644 --- a/docs/blog/elysia-06.md +++ b/docs/blog/elysia-06.md @@ -40,27 +40,31 @@ head: Named after the opening of the legendary anime, **"No Game No Life"**, 「[This Game](https://youtu.be/kJ04dMmimn8)」composed by Konomi Suzuki. -This Game push the boundary of medium-size project to large-scale app with re-imagined plugin model, dynamic mode, pushing developer experience with declarative custom error, collecting more metric with 'onResponse', customizable loose and strict path mapping, TypeBox 0.30 and WinterCG framework interlop. +This Game pushes the boundary from medium-sized projects to large-scale apps with a reimagined plugin model, dynamic mode, improved developer experience via declarative custom errors, better metrics with `onResponse`, customizable loose and strict path mapping, TypeBox 0.30, and WinterCG framework interop. ###### (We are still waiting for No Game No Life season 2) ## New Plugin Model -This Game introduce a new syntax for plugin registration, and come up with a new plugin model internally. -Previously you can register plugin by defining a callback function for Elysia instance like this: +This Game introduces a new syntax for plugin registration and a new internal plugin model. + +Previously you could register a plugin by defining a callback function that receives the Elysia instance: + ```ts const plugin = (app: Elysia) => app.get('/', () => 'hello') ``` -With the new plugin, you can now turns and Elysia instance into a plugin: +With the new plugin model, you can turn an Elysia instance into a plugin directly: + ```ts const plugin = new Elysia() .get('/', () => 'hello') ``` -This allows any Elysia instance and even existing one to be used across application, removing any possible addition callback and tab spacing. +This allows any Elysia instance—even existing ones—to be reused across applications, removing extra callback boilerplate and redundant indentation. + +This significantly improves developer experience when working with nested groups: -This improved Developer Experience significantly when working and nested group ```ts // < 0.6 const group = (app: Elysia) => app @@ -73,33 +77,33 @@ const group = new Elysia({ prefix: '/v1' }) .get('/hello', () => 'Hello World') ``` -We encourage you to use the new model of Elysia plugin instance, as we can take advantage of Plugin Checksum and new possible features in the future. +We encourage you to use the new Elysia plugin-instance model so we can leverage Plugin Checksum and other future features. -However, we are **NOT deprecating** the callback function method as there's some case function model is useful like: -- Inline function -- Plugins that required an information of main instance (for example accessing OpenAPI schema) +However, we are **NOT deprecating** the callback function style; it remains useful in cases such as: +- Inline functions +- Plugins that require information from the main instance (for example, accessing OpenAPI schema) -With this new plugin model, we hope that you can make your codebase even easier to maintain. +With this new plugin model, your codebase should be easier to maintain. ## Plugin Checksum -By default, Elysia plugin use function callback to register plugin. -This means that if you register a plugin for type declaration, it will duplicate itself for just providing a type support, leading to duplication of plugin used in production. +By default, Elysia plugins use function callbacks to register. + +That can cause duplication: registering a plugin just for type declarations will duplicate the plugin at runtime for just type support. + +Plugin Checksum addresses this by deduplicating plugins registered for type declarations. -Which is why Plugin Checksum is introduced, to de-duplicated plugin registered for type declaration. +To opt-in to Plugin Checksum, use the new plugin model and provide a `name` property so Elysia can deduplicate plugins by name: -To opt-in to Plugin Checksum, you need to use a new plugin model, and provide a `name` property to tell Elysia to prevent the plugin from being deduplicate ```ts const plugin = new Elysia({ name: 'plugin' }) ``` -This allows Elysia to identify the plugin and deduplicated based on name. +Elysia will identify the plugin by name and register it only once. Type-safety is preserved even when a plugin is deduplicated. -Any duplicated name will be registered only once but type-safety will be provided after registration even if the plugin is deduplicated. - -In case your plugin needs configuration, you can provide the configuration into a **seed** property to generate a checksum for deduplicating the plugin. +If your plugin requires configuration, provide it as **seed** property to generate a checksum for deduplication: ```ts const plugin = (config) = new Elysia({ @@ -108,31 +112,34 @@ const plugin = (config) = new Elysia({ }) ``` -Name and seed will be used to generate a checksum to de-duplicated registration, which leads to even better performance improvement. +Name and seed properties are used to generate a checksum for deduplicated registrations, improving performance. -This update also fixed the deduplication of the plugin's lifecycle accidentally inline lifecycle when Elysia is not sure if plugin is local and global event. +This update also fixes accidental duplication of plugin lifecycle hooks when Elysia couldn't determine whether a plugin was local or global. -As always, means performance improvement for an app that's larger than "Hello World". +As always, this means performance improvements for apps larger than "Hello World". ## Mount and WinterCG Compliance -WinterCG is a standard for web-interoperable runtimes supports by Cloudflare, Deno, Vercel Edge Runtime, Netlify Function and various more. -WinterCG is a standard to allows web server to runs interoperable across runtime, which use Web Standard definitions like Fetch, Request, and Response. +WinterCG is a standard for web-interoperable runtimes supported by Cloudflare, Deno, Vercel Edge Runtime, Netlify Functions, and more. + +WinterCG enables web servers to run interoperably across runtimes using web-standard definitions like Fetch, Request, and Response. -By this, Elysia is partially follows WinterCG compliance as we are optimized to Bun but also openly support other runtime if possible. +Elysia partially follows WinterCG compliance: while optimized for Bun, it also supports other runtimes where possible. -This allows any framework and code that is WinterCG compliance to be run together in theory, an implementation is proved by [Hono](https://honojs.dev) which introduce the **.mount** method to [runs multiple framework together in one codebase](https://twitter.com/honojs/status/1684839623355490304), including Remix, Elysia, Itty Router, and Hono itself in a simple function. +This allows WinterCG-compliant frameworks and code to theoretically run together. Hono demonstrated this with its **.mount** method to [run multiple frameworks in one codebase](https://twitter.com/honojs/status/1684839623355490304), including Remix, Elysia, Itty Router, and Hono itself in a simple function. -By this, we implemented the same logic for Elysia by introducing `.mount` method to runs any framework or code that is WinterCG compliant. +We implemented similar functionality in Elysia by introducing a `.mount` method to run any WinterCG-compliant framework or code. To use `.mount`, [simply pass a `fetch` function](https://twitter.com/saltyAom/status/1684786233594290176): + ```ts const app = new Elysia() .get('/', () => 'Hello from Elysia') .mount('/hono', hono.fetch) ``` -A **fetch** function is a function that accept Web Standard Request and return Web Standard Response as the definition of: +A **fetch** function accepts a Web-standard Request and returns a Web-standard Response: + ```ts // Web Standard Request-like object // Web Standard Response @@ -147,9 +154,10 @@ By default, this declaration is used by: - Netlify Edge Function - Remix Function Handler -Which means you can run all of the above code to interlop with Elysia all in a single server, or re-used and existing function all in one deployment, no need to setting up Reverse Proxy for handling multiple server. +This means you can interoperate with multiple frameworks in a single server or reuse existing functions in one deployment—no reverse proxy required. + +If the mounted framework also supports **.mount**, frameworks can be nested arbitrarily: -If the framework also support a **.mount** function, you can deeply nested a framework that support it infinitely. ```ts const elysia = new Elysia() .get('/Hello from Elysia inside Hono inside Elysia') @@ -164,7 +172,7 @@ const main = new Elysia() .listen(3000) ``` -You can even re-used multiple existing Elysia project in your server. +You can even reuse multiple existing Elysia projects in your server: ```ts import A from 'project-a/elysia' @@ -177,49 +185,51 @@ new Elysia() .mount(C) ``` -If an instance passed to mount is an Elysia instance, it will resolve to `use` automatically, providing type-safety and support for Eden by default. +If an instance passed to `mount` is an Elysia instance, it resolves to `use` automatically, providing type-safety and Eden support by default. + +This makes interoperable frameworks and runtimes a practical reality. -This made the possibility of interlopable framework and runtime to a reality. +## Improved startup time -## Improved starts up time -Starts up time is an important metric in a serverless environment which Elysia excels it incredibly, but we have taken it even further. +Startup time is an important metric in serverless environments, and Elysia already excels here; we've pushed it even further. -By default, Elysia generates OpenAPI schema for every route automatically and stored it internally when if not used. +By default, Elysia generates OpenAPI schema for every route and stores it internally when not in use. -In this version, Elysia defers the compilation and moved to `@elysiajs/swagger` instead allowing Elysia starts up time to be even faster. +In this version, Elysia defers schema compilation to `@elysiajs/swagger`, allowing even faster startup times. -And with various micro-optimization, and made possible by new Plugin model, starts up time is now up to 35% faster. +With various micro-optimizations made possible by the new plugin model, startup time is now up to 35% faster. ## Dynamic Mode -Elysia introduces Static Code Analysis and Ahead of Time compilation to push the boundary of performance. -Static Code Analysis allow Elysia to read your code then produce the most optimized version code, allowing Elysia to push the performance to its limit. +Elysia introduces Static Code Analysis and Ahead-of-Time compilation to push the performance boundary. -Even if Elysia is WinterCG compliance, environment like Cloudflare worker doesn't support function composition. +Static Code Analysis lets Elysia read your code and produce highly optimized handlers. -This means that Ahead of Time Compliation isn't possible, leading us to create a dynamic mode which use JIT compilation instead of AoT, allowing Elysia to run in Cloudflare Worker as well. +However, some environments (for example Cloudflare Workers) don't support function composition, making Ahead-of-Time compilation impossible. + +For those cases, we created a dynamic mode, which uses JIT compilation instead of AoT and allows Elysia to run in those environments. + +To enable dynamic mode, set `aot` to false: -To enable dynamic mode, set `aot` to false. ```ts new Elysia({ aot: false }) ``` -Dynamic Mode is enabled by default in cloudflare worker. - -#### It's worth noting that, enabling Dynamic Mode will disable some feature like dynamic injected code like `t.Numeric` which parse strings to numbers automatically. +Dynamic Mode is enabled by default in Cloudflare Workers. -Ahead of Time compilation can read, detect and optimize your code in exchange for startup time in exchange for extra performance gain, while dynamic mode uses JIT compilation, allowing start up time to be even faster up to 6x. +It's worth noting that enabling Dynamic Mode will disable certain features that rely on Ahead-of-Time injection (for example, automatic parsing provided by `t.Numeric`). -But it should be noted that startup time in Elysia is fast enough by default. +Ahead-of-Time compilation trades startup time for runtime performance: it reads, detects, and optimizes your code for extra performance, while dynamic mode (JIT) favors faster startup (up to 6x faster in some scenarios). -Elysia is able to register 10,000 routes in just 78ms which means in an average of 0.0079 ms/route +Elysia is already fast by default: it can register 10,000 routes in just 78ms (about 0.0078 ms/route on average). -That being said, we are leaving a choice for you to decided yourself. +That said, we leave the choice to you. ## Declarative Custom Error -This update adds support for adding type support for handling custom error. + +This update adds support for declarative type-safe custom errors. ```ts class CustomError extends Error { @@ -243,30 +253,30 @@ new Elysia() }) ``` -This allows us to handle custom types with type narrowing for handling custom errors and auto-completion for error codes to narrow down the correct types, fully type-safe declaratively. - -This fulfills one of our main philosophies is focused on Developer Experience especially with types. +This enables type narrowing and autocompletion for error codes, making custom error handling fully type-safe and declarative. -Elysia Type System is complex, yet we try to refrained our users need to write a custom type or passing a custom generic, retaining all the code to look just like JavaScript. +This fulfills one of our core philosophies: focusing on developer experience, especially around types. -It just works, and all the code looks just like JavaScript. +Elysia's type system is complex, but we strive to avoid forcing users to write custom generics or verbose types—keeping code simple and JavaScript-like. ## TypeBox 0.30 -TypeBox is a core library that powers Elysia's strict type system known as **Elysia.t**. -In this update, we update TypeBox from 0.28 to 0.30 to make even more fine-grained Type System nearly strictly typed language. +TypeBox continues to power Elysia's strict type system (**Elysia.t**). + +In this update we upgrade TypeBox from 0.28 to 0.30 to provide even more fine-grained typing. -These updates introduce new features and many interesting changes, for example **Iterator** type, reducing packages size, TypeScript code generation. +These updates introduce new features such as an **Iterator** type, reduced package size, and TypeScript code generation. -And with support for Utility Types like: +This adds support for utility types like: - `t.Awaited` - `t.Uppercase` -- `t.Capitlized` +- `t.Capitalized` ## Strict Path -We got a lot of requests for handling loose path. -By default, Elysia handle path strictly, which means that if you have to support path with or without optional `/` , it will not be resolved and you have to duplicate the pathname twice. +We received many requests for handling loose paths. + +By default, Elysia handles path strictly, which means that if you have to support a path with or without optional `/`, it will not be resolved and you have to duplicate the pathname twice. ```ts new Elysia() @@ -278,9 +288,10 @@ new Elysia() ) ``` -By this, many have been requesting that `/v1/` should also resolved `/v1` as well. +Many requested that `/v1/` should also resolve to `/v1`. + +With this update we enable loose path matching by default so a single handler can handle both: -With this update, we add support for loose path matching by default, to opt-in into this feature automatically. ```ts new Elysia() .group('/v1', (app) => app @@ -289,17 +300,19 @@ new Elysia() ) ``` -To disable loosePath mapping, you can set `strictPath` to true to used the previous behavior: +To disable loose path mapping and use the previous strict behavior, set `strictPath` to true: + ```ts new Elysia({ strictPath: false }) ``` -We hope that this will clear any questions regards to path matching and its expected behavior +We hope this clears questions about path matching behavior. ## onResponse -This update introduce a new lifecycle hook called `onResponse`. + +This update introduces a new lifecycle hook called `onResponse` (proposal: [elysia#67](https://github.com/elysiajs/elysia/issues/67)). This is a proposal proposed by [elysia#67](https://github.com/elysiajs/elysia/issues/67) @@ -320,42 +333,43 @@ Quoted --- -### Notable Improvement: -- Added an error field to the Elysia type system for adding custom error messages -- Support Cloudflare worker with Dynamic Mode (and ENV) -- AfterHandle now automatically maps the value -- Using bun build to target Bun environment, improving the overall performance by 5-10% +### Notable Improvements: +- Added an error field to the Elysia type system for custom error messages +- Support Cloudflare Workers with Dynamic Mode (and ENV) +- AfterHandle now automatically maps values +- Using bun build to target Bun environment, improving performance by ~5-10% - Deduplicated inline lifecycle when using plugin registration - Support for setting `prefix` - Recursive path typing - Slightly improved type checking speed -- Recursive schema collision causing infinite types +- Fixed recursive schema collisions that caused infinite types -### Change: -- Moved **registerSchemaPath** to @elysiajs/swagger -- [Internal] Add qi (queryIndex) to context +### Changes: +- Moved **registerSchemaPath** to `@elysiajs/swagger` +- [Internal] Added `qi` (queryIndex) to context -### Breaking Change: +### Breaking Changes: - [Internal] Removed Elysia Symbol - [Internal] Refactored `getSchemaValidator`, `getResponseSchemaValidator` to named parameters - [Internal] Moved `registerSchemaPath` to `@elysiajs/swagger` ## Afterward -We have just passed a one year milestone, and really excited how Elysia and Bun have improved over the year! -Pushing the performance boundaries of JavaScript with Bun, and developer experience with Elysia, we are thrilled to have kept in touch with you and our community. +We just passed a one-year milestone and are excited by how Elysia and Bun have improved over the year! + +Pushing the performance boundaries of JavaScript with Bun and improving the developer experience with Elysia remain our priorities. We are thrilled to have kept in touch with you and our community. -Every updates, keeps making Elysia even more stable, and gradually providing a better developer experience without a drop in performance and features. +Each update makes Elysia more stable while maintaining performance and features, and gradually providing a better developer experience. -We're thrilled to see our community of open-source developers bringing Elysia to life with their projects like. -- [Elysia Vite Plugin SSR](https://github.com/timnghg/elysia-vite-plugin-ssr) allowing us to use Vite Server Side Rendering using Elysia as the server. -- [Elysia Connect](https://github.com/timnghg/elysia-connect) which made Connect's plugin compatible with Elysia +We're grateful to the open-source community for bringing Elysia to life with projects like: +- [Elysia Vite Plugin SSR](https://github.com/timnghg/elysia-vite-plugin-ssr) — allowing us to use Vite Server Side Rendering using Elysia as the server +- [Elysia Connect](https://github.com/timnghg/elysia-connect) — Connect plugin compatibility for Elysia -And much more developers that choose Elysia for their next big project. +And many more projects built with Elysia. With our commitment, we also recently introduced [Mobius](https://github.com/saltyaom/mobius), and open-source TypeScript library to parse GraphQL to TypeScript type without relying on code generation by using TypeScript template literal type entirely to be the very first framework to achieve end-to-end type safety without relying on code generation. -We incredibly thankful for your overwhelming continous support for Elysia, and we hope to see you pushing the boundaries together in the next release. +We are incredibly thankful for your continuous support of Elysia, and we hope you'll keep pushing the boundaries with us in the next release. > As this whole new world cheers my name >