Skip to content

Commit

Permalink
Merge pull request #89 from magne4000/server-support/express
Browse files Browse the repository at this point in the history
Support for servers like express
  • Loading branch information
magne4000 authored Jul 4, 2024
2 parents fdf24bf + f768d15 commit 5d7edcd
Show file tree
Hide file tree
Showing 17 changed files with 1,241 additions and 87 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ jobs:

steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion examples/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.4.5",
"vike": "^0.4.160",
"vike": "^0.4.178",
"vite": "^5.2.9",
"vite-plugin-vercel": "workspace:*"
},
Expand Down
188 changes: 188 additions & 0 deletions examples/express/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# vite-plugin-vercel-simple

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@6.0.1

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@6.0.0

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@5.0.5

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@5.0.4

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@5.0.3

## null

### Patch Changes

- vite-plugin-vercel@5.0.2

## null

### Patch Changes

- vite-plugin-vercel@5.0.1

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@5.0.0

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@4.0.2

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@4.0.1

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@4.0.0

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@3.0.2

## null

### Patch Changes

- Updated dependencies [8e7cad4]
- vite-plugin-vercel@3.0.1

## null

### Patch Changes

- Updated dependencies [ec8dcba]
- vite-plugin-vercel@3.0.0

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@2.0.1

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@2.0.0

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@1.0.0

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.3.7

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.3.6

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.3.5

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@1.0.0

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.3.3

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.3.2

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.3.1

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.3.0

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.2.2

## null

### Patch Changes

- Updated dependencies
- vite-plugin-vercel@0.2.1
96 changes: 96 additions & 0 deletions examples/express/express-entry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

import { vikeHandler } from './server/vike-handler';
import { createMiddleware } from '@universal-middleware/express';
import express from 'express';

const __filename = globalThis.__filename ?? fileURLToPath(import.meta.url);
const __dirname = globalThis.__dirname ?? dirname(__filename);
const root = __dirname;
const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
const hmrPort = process.env.HMR_PORT
? parseInt(process.env.HMR_PORT, 10)
: 24678;

interface Middleware<
Context extends Record<string | number | symbol, unknown>,
> {
(
request: Request,
context: Context,
): Response | void | Promise<Response> | Promise<void>;
}

export function handlerAdapter<
Context extends Record<string | number | symbol, unknown>,
>(handler: Middleware<Context>) {
return createMiddleware(
async (context) => {
const rawRequest = context.platform.request as unknown as Record<
string,
unknown
>;
rawRequest.context ??= {};
const response = await handler(
context.request,
rawRequest.context as Context,
);

if (!response) {
context.passThrough();
return new Response('', {
status: 404,
});
}

return response;
},
{
alwaysCallNext: false,
},
);
}

export default await startServer();

async function startServer() {
const app = express();

if (process.env.NODE_ENV === 'production') {
app.use(express.static(`${root}/dist/client`));
} else {
// Instantiate Vite's development server and integrate its middleware to our server.
// ⚠️ We should instantiate it *only* in development. (It isn't needed in production
// and would unnecessarily bloat our server in production.)
const vite = await import('vite');
const viteDevMiddleware = (
await vite.createServer({
root,
server: { middlewareMode: true, hmr: { port: hmrPort } },
})
).middlewares;
app.use(viteDevMiddleware);
}

app.get(
'/hello',
handlerAdapter(() => {
console.log('HELLO');
return new Response('Hello');
}),
);

/**
* Vike route
*
* @link {@see https://vike.dev}
**/
app.all('*', handlerAdapter(vikeHandler));

app.listen(port, () => {
console.log(`Server listening on http://localhost:${port}`);
});

return app;
}
33 changes: 33 additions & 0 deletions examples/express/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "vite-plugin-vercel-simple",
"private": true,
"version": null,
"description": "",
"type": "module",
"scripts": {
"dev": "tsx ./express-entry.ts",
"build": "vite build",
"typecheck": "tsc -p tsconfig.json --noEmit"
},
"keywords": [],
"author": "",
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^18.19.31",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
"@universal-middleware/express": "^0.0.2",
"@vercel/node": "^3.0.26",
"@vitejs/plugin-react-swc": "^3.6.0",
"express": "^4.19.2",
"react": "^18.2.0",
"tsx": "^4.16.2",
"typescript": "^5.4.5",
"vike": "^0.4.178",
"vike-react": "^0.4.16",
"vite": "^5.2.9"
},
"dependencies": {
"vite-plugin-vercel": "workspace:*"
}
}
8 changes: 8 additions & 0 deletions examples/express/pages/+config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import vikeReact from 'vike-react/config';
import type { Config } from 'vike/types';

// Default config (can be overridden by pages)
export default {
title: 'My Vike App',
extends: vikeReact,
} satisfies Config;
17 changes: 17 additions & 0 deletions examples/express/pages/index/+Page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { Counter } from './Counter.js';

export default function Page() {
return (
<>
<h1>Welcome</h1>
This page is:
<ul>
<li>Rendered to HTML.</li>
<li>
Interactive. <Counter />
</li>
</ul>
</>
);
}
12 changes: 12 additions & 0 deletions examples/express/pages/index/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React, { useState } from 'react';

export { Counter };

function Counter() {
const [count, setCount] = useState(0);
return (
<button type="button" onClick={() => setCount((count) => count + 1)}>
Counter {count}
</button>
);
}
19 changes: 19 additions & 0 deletions examples/express/server/vike-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/// <reference lib="webworker" />
import { renderPage } from 'vike/server';

export async function vikeHandler<
Context extends Record<string | number | symbol, unknown>,
>(request: Request, context?: Context): Promise<Response> {
const pageContextInit = { ...context, urlOriginal: request.url };
const pageContext = await renderPage(pageContextInit);
const response = pageContext.httpResponse;

const { readable, writable } = new TransformStream();

response?.pipe(writable);

return new Response(readable, {
status: response?.statusCode,
headers: response?.headers,
});
}
Loading

0 comments on commit 5d7edcd

Please sign in to comment.