Repository: unjs/h3
Pull request #663 (2024-02-24 05:43:37)

docs(examples/from-expressjs-to-h3): add node middleware usage
<!---
☝️ PR title should follow conventional commits (https://conventionalcommits.org) 
-->

### 🔗 Linked issue

<!-- Please ensure there is an open issue and mention its number as #123 -->

### ❓ Type of change

<!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply. -->

- [x] 📖 Documentation (updates to the documentation, readme, or JSdoc annotations)
- [ ] 🐞 Bug fix (a non-breaking change that fixes an issue)
- [ ] 👌 Enhancement (improving an existing functionality like performance)
- [ ] ✨ New feature (a non-breaking change that adds functionality)
- [ ] 🧹 Chore (updates to the build process or auxiliary tools and libraries)
- [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

### 📚 Description

I think we can add a guide on using middleware with h3 for users accustomed to Express, which would facilitate their migration. 

tip: This is also the confusion I have encountered in actual use; I believe they might face similar issues as well. 🤣

<!-- Describe your changes in detail -->
<!-- Why is this change required? What problem does it solve? -->
<!-- If it resolves an open issue, please link to the issue here. For example "Resolves #1337" -->

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [ ] I have linked an issue or discussion.
- [ ] I have updated the documentation accordingly.



Patch:
diff --git a/docs/1.guide/1.index.md b/docs/1.guide/1.index.md
index 5384cbd..c8e2b30 100644
--- a/docs/1.guide/1.index.md
+++ b/docs/1.guide/1.index.md
@@ -46,11 +46,11 @@ npx --yes listhen -w --open ./app.ts
 ```
 
 > [!TIP]
-> You don't need to install any additional dependency. Listhen has as preinstalled version of h3!
+> You don't need to install any additional dependency. Listhen has a preinstalled version of h3!
 
 And tadaa! We have a web server running locally.
 
-### What happend?
+### What happened?
 
 Okay, let's now break down our hello world example:
 
@@ -68,13 +68,13 @@ const router = createRouter();
 app.use(router);
 ```
 
-Now it it time to add our first endpoint. In h3, request handlers can be defined using `defineEventHandler` or `eventHandler` helpers (they are aliases). Using wrappers, h3 can supercharge your code with better typehints and future compatibility.
+Now it is time to add our first endpoint. In h3, request handlers can be defined using `defineEventHandler` or `eventHandler` helpers (they are aliases). Using wrappers, h3 can supercharge your code with better typehints and future compatibility.
 
 ```ts
 eventHandler((event) => {});
 ```
 
-What is beatiful in h3 is that all you have to do to make a reponse, is to simply return it! Responses can be simple string, JSON objects, data buffers, streams or standard [Web Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response).
+What is beautiful in h3 is that all you have to do to make a reponse, is to simply return it! Responses can be simple string, JSON objects, data buffers, streams or standard [Web Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response).
 
 ```ts
 return { message: "⚡️ Tadaa!" };
diff --git a/docs/1.guide/4.event.md b/docs/1.guide/4.event.md
index a07da98..4ed9772 100644
--- a/docs/1.guide/4.event.md
+++ b/docs/1.guide/4.event.md
@@ -13,7 +13,7 @@ An event is passed through all the lifecycle hooks and composable utils to use i
 **Example:**
 
 ```js
-import { defineEventHandler, readBody, query } from "h3";
+import { defineEventHandler, readBody, getQuery } from "h3";
 
 app.use(
   defineEventHandler((event) => {
@@ -114,7 +114,7 @@ app.use(
   defineEventHandler((event) => {
     await event.respondWith(new Response("Hello World"));
 
-    return "..."; // DOES NOT WORKS
+    return "..."; // DOES NOT WORK
   }),
 );
 ```
diff --git a/docs/4.examples/from-expressjs-to-h3.md b/docs/4.examples/from-expressjs-to-h3.md
index 4d73941..b6481c2 100644
--- a/docs/4.examples/from-expressjs-to-h3.md
+++ b/docs/4.examples/from-expressjs-to-h3.md
@@ -392,3 +392,45 @@ app.use(router);
 ```
 
 With h3, we do not have a `cookieParser` middleware. Instead, we use `getCookie` and `setCookie` to get and set cookies. It's more explicit and easier to use.
+
+## Middleware
+
+When using `express`, we usually handle requests with `middleware`.
+
+For instance, here we use `morgan` to handle request logging.
+
+```js [index.js]
+var express = require("express");
+var morgan = require("morgan");
+
+var app = express();
+
+app.use(morgan("combined"));
+
+app.get("/", function (req, res) {
+  res.send("hello, world!");
+});
+
+app.listen(3000);
+console.log("Express started on port 3000");
+```
+
+In `h3`, we can also directly use middleware from the `express` ecosystem.
+
+This can be easily achieved by wrapping with `fromNodeMiddleware`.
+
+```ts [app.ts]
+import morgan from "morgan";
+import { defineEventHandler, createApp, fromNodeMiddleware } from "h3";
+
+export const app = createApp();
+
+app.use(fromNodeMiddleware(morgan()));
+
+app.use(
+  "/",
+  defineEventHandler((event) => {
+    return "Hello World";
+  }),
+);
+```
diff --git a/src/utils/static.ts b/src/utils/static.ts
index 6a48637..aec9c7b 100644
--- a/src/utils/static.ts
+++ b/src/utils/static.ts
@@ -118,6 +118,10 @@ export async function serveStatic(
     return false;
   }
 
+  if (meta.etag && !getResponseHeader(event, "etag")) {
+    setResponseHeader(event, "etag", meta.etag);
+  }
+
   const ifNotMatch =
     meta.etag && getRequestHeader(event, "if-none-match") === meta.etag;
   if (ifNotMatch) {
@@ -143,10 +147,6 @@ export async function serveStatic(
     setResponseHeader(event, "content-type", meta.type);
   }
 
-  if (meta.etag && !getResponseHeader(event, "etag")) {
-    setResponseHeader(event, "etag", meta.etag);
-  }
-
   if (meta.encoding && !getResponseHeader(event, "content-encoding")) {
     setResponseHeader(event, "content-encoding", meta.encoding);
   }


Test patch:
diff --git a/test/static.test.ts b/test/static.test.ts
index 7446e20..e47f66f 100644
--- a/test/static.test.ts
+++ b/test/static.test.ts
@@ -83,6 +83,7 @@ describe("Serve Static", () => {
 
   it("Handles cache (if-none-match)", async () => {
     const res = await request.get("/test.png").set("if-none-match", "w/123");
+    expect(res.headers.etag).toBe(expectedHeaders.etag);
     expect(res.status).toEqual(304);
     expect(res.text).toBe("");
   });