From 9a35f8a6b47fe023e80e2ec23ecb950031a02ec9 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Mon, 8 Jul 2024 15:04:40 +0200 Subject: [PATCH 1/4] docs: initial migration guide for v2 --- MIGRATION.md | 143 ++++++++++++++++++++++++++++++++++++ docs/1.guide/6.websocket.md | 2 + docs/5.migration/0.index.md | 1 + 3 files changed, 146 insertions(+) create mode 100644 MIGRATION.md create mode 120000 docs/5.migration/0.index.md diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 00000000..63e92e5b --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,143 @@ +--- +icon: icons8:up-round +--- + +# Migration guide for v1 to v2 + +h3 v2 includes some behavior and API changes that you need to consider applying when migrating. + +> [!NOTE] +> Currently v2 is in beta stage You can try with [`h3-nightly@2x`](https://www.npmjs.com/package/h3-nightly?activeTab=versions) + +> [!NOTE] +> This is an undergoing migration guide and not finished yet. + +## Fully decoupled from Node.js + +We started migrating h3 towards Web standards since [v1.8](https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web). h3 apps are now fully decoupled from Node.js leveraging an adapter based abstraction layer to natively support Web and Node.js runtimes, equality fast and efficient! + +This migration significantly reduces your bundle sizes and overhead in Web native runtimes such as [Bun](https://bun.sh/), [Deno](https://deno.com) and [Cloudflare Workers](https://workers.cloudflare.com/). + +Sinve v2, Event properties `event.node.{req,res}` and `event.web` are not available anymore, instead you can use `getNodeContext(event)` and `getWebContext(event)` to access raw objects for each runtime (if you really have to!). + +## Response handling + +You should now always explicitly `return` or `throw` responses and errors from event handlers. + +Previously we had `send*` utils that could interop the response handling lifecycle **anywhere** in any utility or middleware causing unpredictable application state control. In order to mitigate edge cases, previously events had an `event.handler` property which is now gone! `event.respondWith` is also removed, you can directly return a `Response` object. + +If you were priously using these methods, you can simply replace them with `return` statements returning a text, json value, stream or web `Response` (h3 smatly detects and handles them): + +- `send(event, value)`: Use `return ` +- `sendNoContent(event)`: Use `return null` +- `sendError(event, error)`: Use `throw createError()` +- `sendStream(event, stream)`: Use `return steream` +- `sendWebResponse(event, response)`: Use `return response` + +Other send utils that renamed and need explicit `return`: + +- `sendIterable(event, value)`: Use `return iterable()` +- `sendRedirect(event, location, code)`: Use `return redirect(event, location, code)` +- `sendProxy(event, target)`: Use `return proxy(event, target)` +- `handleCors(event)`: Check return value (boolean) and early `return` if handled. +- `serveStatic(event, content)`: Make sure to add `return before. + +## Body utils + +The legacy `readBody` and `readRawBody`: Utils had been replaced with a new set of body utils which can leverage native runtime primitives better. + +- `readRawBody`: Returns body as [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) which is similar to Node.js `Buffer`. +- `readTextBody`: Returns body as text (`utf8`). +- `readJSONBody` / `readValidatedJSONBody`: Returns JSON value of the body using `JSON.parse` or `URLSearchParams` for `form-urlencoded` +- `readFormDataBody`: Returns body parsed as [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData). +- `getBodyStream`: Returns body as a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream), replacing older experimental `getRequestWebStream`: Util. + +**Behavior changes:** + +- Body utils won' throw an error if incoming request has no body (or is a `GET` method) but instead return `undefined` +- `readJSONBody` does not use [unjs/destr](https://destr.unjs.io) anymore. You should always filter and sanitize data coming from user to avoid [prototype-poisoning](https://medium.com/intrinsic-blog/javascript-prototype-poisoning-vulnerabilities-in-the-wild-7bc15347c96) + +## Router + +h3 migrated to a much faster rewrite of route matching engine [unjs/rou3](https://rou3.unjs.io/). + +You might experience slight behavior changes which should be more intuitive. + +- `router.use(path, handler)` is deprecated. Use `router.all(path, handler)` instead. +- `router.add(path, method: Method | Method[]` signature is changed to `router.add(method: Method, path)` (**important!**) +- `app.resolve` and `handler.__resolve` signature changed from `(path)` to `(method, path)`. + +## Cookie and Headers + +Most of the internals migrated to leverage standard web [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) and the Node.js adapter uses a lightweight proxy to translate Node.js incoming and outgoing headers to a Headers interface. + +Header values are always a plain `string` now (no `null` or `undefined` or `number` or `string[]`). + +For the [`Set-Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) header, you can use [`.getSetCookie`](https://developer.mozilla.org/en-US/docs/Web/API/Headers/getSetCookie) that always returns a string array. + +### Other deprecatons + +h3 v2 deprecated some legacy and aliased utilities. + +**Handler:** + +- `eventHandler`: Use `defineEventHandler` +- `toEventHandler`: (it is not required anymore) +- `lazyEventHandler`: Use `defineLazyEventHandler` + +**Request:** + +- `getHeader`: Use `getRequestHeader` +- `getHeaders`: Use `getRequestHeaders` +- `getRequestPath`: Use `event.path` + +**Response:** + +- `appendHeader`: Use `appendResponseHeader` +- `appendHeaders`: Use `appendResponseHeaders` +- `setHeader`: Use `setResponseHeader` +- `setHeaders` => Use `setResponseHeaders` + +**Node.js:** + +- `defineNodeListener`: Use `defineNodeHandler` +- `fromNodeMiddleware`: Use `fromNodeHandler` +- `createEvent`: Use `fromNodeRequest` +- `toNodeListener`: Use `toNodeHandler` +- `callNodeListener`: Use `callNodeHandler` +- `promisifyNodeListener` (removed) +- `callNodeHandler`: (internal) + +**Web:** + +- `callWithWebRequest`: (removed) + +**Body:** + +- `readBody`: Use `readJSONBody` +- `readFormData`: Use `readFormDataBody` +- `readValidatedBody`: Use `readValidatedJSONBody` +- `getRequestWebStream`: Use `getBodyStream` +- `readMultipartFormData`: Migrate to `readFormDataBody` + +**Types:** + +- `_RequestMiddleware`: Use `RequestMiddleware` +- `_ResponseMiddleware`: Use `ResponseMiddleware` +- `NodeListener`: Use `NodeHandler` +- `TypedHeaders`: Use `RequestHeaders` and `ResponseHeaders` +- `HTTPHeaderName`: Use `RequestHeaderName` and `ResponseHeaderName` +- `H3Headers`: Use native `Headers` +- `H3Response`: Use native `Response` +- `WebEventContext` +- `NodeEventContext` +- `NodePromisifiedHandler` +- `MultiPartData`: Use `FormData` +- `RouteNode`: Use `RouterEntry` + `CreateRouterOptions`: use `RouterOptions` + +- **Utils:** + +- `isStream`: Use `instanceof ReadableStream` and `.pipe` property for detecting Node.js `ReadableStream` +- `isWebResponse`: Use `use instanceof Response` +- `MIMES`: Removed internal map. diff --git a/docs/1.guide/6.websocket.md b/docs/1.guide/6.websocket.md index 7b830459..a4d55f4f 100644 --- a/docs/1.guide/6.websocket.md +++ b/docs/1.guide/6.websocket.md @@ -62,6 +62,7 @@ app.use( }, }), ); + ``` @@ -105,6 +106,7 @@ router.get( return eventStream.send(); }), ); + ``` diff --git a/docs/5.migration/0.index.md b/docs/5.migration/0.index.md new file mode 120000 index 00000000..dddda038 --- /dev/null +++ b/docs/5.migration/0.index.md @@ -0,0 +1 @@ +../../MIGRATION.md \ No newline at end of file From 2a76a96e10b8957f1ea944d3039bb3389e8100a2 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 13:05:27 +0000 Subject: [PATCH 2/4] chore: apply automated updates --- docs/1.guide/6.websocket.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/1.guide/6.websocket.md b/docs/1.guide/6.websocket.md index a4d55f4f..7b830459 100644 --- a/docs/1.guide/6.websocket.md +++ b/docs/1.guide/6.websocket.md @@ -62,7 +62,6 @@ app.use( }, }), ); - ``` @@ -106,7 +105,6 @@ router.get( return eventStream.send(); }), ); - ``` From a1573492c76e537f127d760e05ec38d393ba2658 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Mon, 8 Jul 2024 15:46:29 +0200 Subject: [PATCH 3/4] Update MIGRATION.md --- MIGRATION.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 63e92e5b..c3095f9d 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -10,31 +10,31 @@ h3 v2 includes some behavior and API changes that you need to consider applying > Currently v2 is in beta stage You can try with [`h3-nightly@2x`](https://www.npmjs.com/package/h3-nightly?activeTab=versions) > [!NOTE] -> This is an undergoing migration guide and not finished yet. +> This is an undergoing migration guide and is not finished yet. ## Fully decoupled from Node.js -We started migrating h3 towards Web standards since [v1.8](https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web). h3 apps are now fully decoupled from Node.js leveraging an adapter based abstraction layer to natively support Web and Node.js runtimes, equality fast and efficient! +We started migrating h3 towards Web standards since [v1.8](https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web). h3 apps are now fully decoupled from Node.js using an adapter-based abstraction layer to support Web and Node.js runtime features and performances natively. -This migration significantly reduces your bundle sizes and overhead in Web native runtimes such as [Bun](https://bun.sh/), [Deno](https://deno.com) and [Cloudflare Workers](https://workers.cloudflare.com/). +This migration significantly reduces your bundle sizes and overhead in Web-native runtimes such as [Bun](https://bun.sh/), [Deno](https://deno.com) and [Cloudflare Workers](https://workers.cloudflare.com/). -Sinve v2, Event properties `event.node.{req,res}` and `event.web` are not available anymore, instead you can use `getNodeContext(event)` and `getWebContext(event)` to access raw objects for each runtime (if you really have to!). +Since v2, Event properties `event.node.{req,res}` and `event.web` is not available anymore, instead, you can use `getNodeContext(event)` and `getWebContext(event)` to access raw objects for each runtime. ## Response handling -You should now always explicitly `return` or `throw` responses and errors from event handlers. +You should always explicitly `return` or `throw` responses and errors from event handlers. -Previously we had `send*` utils that could interop the response handling lifecycle **anywhere** in any utility or middleware causing unpredictable application state control. In order to mitigate edge cases, previously events had an `event.handler` property which is now gone! `event.respondWith` is also removed, you can directly return a `Response` object. +Previously h3 had `send*` utils that could interop the response handling lifecycle **anywhere** in any utility or middleware causing unpredictable application state control. To mitigate edge cases of this, previously h3 added `event.handler` property which is now gone! -If you were priously using these methods, you can simply replace them with `return` statements returning a text, json value, stream or web `Response` (h3 smatly detects and handles them): +If you were previously using these methods, you can replace them with `return` statements returning a text, JSON value, stream, or web `Response` (h3 smartly detects and handles them): - `send(event, value)`: Use `return ` - `sendNoContent(event)`: Use `return null` - `sendError(event, error)`: Use `throw createError()` -- `sendStream(event, stream)`: Use `return steream` +- `sendStream(event, stream)`: Use `return stream` - `sendWebResponse(event, response)`: Use `return response` -Other send utils that renamed and need explicit `return`: +Other send utils that are renamed and need explicit `return`: - `sendIterable(event, value)`: Use `return iterable()` - `sendRedirect(event, location, code)`: Use `return redirect(event, location, code)` @@ -44,7 +44,7 @@ Other send utils that renamed and need explicit `return`: ## Body utils -The legacy `readBody` and `readRawBody`: Utils had been replaced with a new set of body utils which can leverage native runtime primitives better. +The legacy `readBody` and `readRawBody` utils are replaced with a new set of body utils that can leverage native runtime primitives better. - `readRawBody`: Returns body as [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) which is similar to Node.js `Buffer`. - `readTextBody`: Returns body as text (`utf8`). @@ -54,28 +54,28 @@ The legacy `readBody` and `readRawBody`: Utils had been replaced with a new set **Behavior changes:** -- Body utils won' throw an error if incoming request has no body (or is a `GET` method) but instead return `undefined` +- Body utils won't throw an error if the incoming request has no body (or is a `GET` method for example) but instead, returns `undefined` - `readJSONBody` does not use [unjs/destr](https://destr.unjs.io) anymore. You should always filter and sanitize data coming from user to avoid [prototype-poisoning](https://medium.com/intrinsic-blog/javascript-prototype-poisoning-vulnerabilities-in-the-wild-7bc15347c96) ## Router -h3 migrated to a much faster rewrite of route matching engine [unjs/rou3](https://rou3.unjs.io/). +h3 migrated to a brand new route-matching engine [unjs/rou3](https://rou3.unjs.io/). -You might experience slight behavior changes which should be more intuitive. +You might experience slight (and more intuitive) behavior changes for matching patterns. - `router.use(path, handler)` is deprecated. Use `router.all(path, handler)` instead. -- `router.add(path, method: Method | Method[]` signature is changed to `router.add(method: Method, path)` (**important!**) +- `router.add(path, method: Method | Method[]` signature is changed to `router.add(method: Method, path)` (**important**) - `app.resolve` and `handler.__resolve` signature changed from `(path)` to `(method, path)`. ## Cookie and Headers -Most of the internals migrated to leverage standard web [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) and the Node.js adapter uses a lightweight proxy to translate Node.js incoming and outgoing headers to a Headers interface. +h3 migrated to leverage standard web [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) for all utils. Header values are always a plain `string` now (no `null` or `undefined` or `number` or `string[]`). -For the [`Set-Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) header, you can use [`.getSetCookie`](https://developer.mozilla.org/en-US/docs/Web/API/Headers/getSetCookie) that always returns a string array. +For the [`Set-Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) header, you can use [`headers.getSetCookie`](https://developer.mozilla.org/en-US/docs/Web/API/Headers/getSetCookie) that always returns a string array. -### Other deprecatons +### Other deprecations h3 v2 deprecated some legacy and aliased utilities. @@ -138,6 +138,6 @@ h3 v2 deprecated some legacy and aliased utilities. - **Utils:** -- `isStream`: Use `instanceof ReadableStream` and `.pipe` property for detecting Node.js `ReadableStream` +- `isStream`: Use `instanceof ReadableStream` and `.pipe` properties for detecting Node.js `ReadableStream` - `isWebResponse`: Use `use instanceof Response` - `MIMES`: Removed internal map. From ff7dc1e8077a807f49334425c6213604cb65ecf1 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Mon, 8 Jul 2024 15:49:02 +0200 Subject: [PATCH 4/4] Update MIGRATION.md --- MIGRATION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIGRATION.md b/MIGRATION.md index c3095f9d..64f06e53 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -40,7 +40,7 @@ Other send utils that are renamed and need explicit `return`: - `sendRedirect(event, location, code)`: Use `return redirect(event, location, code)` - `sendProxy(event, target)`: Use `return proxy(event, target)` - `handleCors(event)`: Check return value (boolean) and early `return` if handled. -- `serveStatic(event, content)`: Make sure to add `return before. +- `serveStatic(event, content)`: Make sure to add `return` before. ## Body utils