nuxt-devkit-server 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +192 -0
- package/dist/index.d.mts +51 -0
- package/dist/index.mjs +88 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 lonewolfyx
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# nuxt-devkit-server
|
|
2
|
+
|
|
3
|
+
A lightweight Node.js library for creating a local HTTP server that runs Nitro/Nuxt build outputs in CLI tools.
|
|
4
|
+
|
|
5
|
+
It dynamically imports the Nitro server entry point from a build output directory, wraps it in a `node:http` server, and optionally sets up WebSocket support via `crossws`.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add nuxt-devkit-server
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
If you need WebSocket support, install `crossws` as well:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add crossws
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createRuntimeServer } from 'nuxt-devkit-server'
|
|
25
|
+
|
|
26
|
+
const app = await createRuntimeServer({
|
|
27
|
+
path: '.output',
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
console.log(`Server running at ${app.url}`) // http://127.0.0.1:7777
|
|
31
|
+
|
|
32
|
+
// Close the server when done
|
|
33
|
+
await app.close()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Custom Host and Port
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
const app = await createRuntimeServer({
|
|
40
|
+
path: '.output/server/index.mjs',
|
|
41
|
+
host: '0.0.0.0',
|
|
42
|
+
port: 3000,
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Using the `onReady` Callback
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const app = await createRuntimeServer({
|
|
50
|
+
path: 'dist',
|
|
51
|
+
onReady({ info, app, port }) {
|
|
52
|
+
console.log(`Listening on ${info.address}:${port}`)
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Direct Path to Server Entry
|
|
58
|
+
|
|
59
|
+
You can pass either a Nitro build output directory or a direct path to `server/index.mjs`:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
// Directory — automatically resolves to <path>/server/index.mjs
|
|
63
|
+
const app = await createRuntimeServer({ path: '.output' })
|
|
64
|
+
|
|
65
|
+
// Direct file path
|
|
66
|
+
const app = await createRuntimeServer({ path: 'dist/server/index.mjs' })
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## API Reference
|
|
70
|
+
|
|
71
|
+
### `createRuntimeServer(options): Promise<RuntimeServer>`
|
|
72
|
+
|
|
73
|
+
Creates and starts an HTTP server backed by a Nitro/Nuxt build output.
|
|
74
|
+
|
|
75
|
+
| Parameter | Type | Required | Default | Description |
|
|
76
|
+
|---|---|---|---|---|
|
|
77
|
+
| `options` | `CreateRuntimeServerOptions` | Yes | — | Configuration options |
|
|
78
|
+
|
|
79
|
+
Returns a `Promise<RuntimeServer>` that resolves once the server is listening.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
### `CreateRuntimeServerOptions`
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
interface CreateRuntimeServerOptions {
|
|
87
|
+
/**
|
|
88
|
+
* Nitro / Nuxt build output directory, or the direct path to server/index.mjs.
|
|
89
|
+
*
|
|
90
|
+
* Supported:
|
|
91
|
+
* - dist
|
|
92
|
+
* - .output
|
|
93
|
+
* - dist/server/index.mjs
|
|
94
|
+
* - .output/server/index.mjs
|
|
95
|
+
*/
|
|
96
|
+
path: string
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Server port.
|
|
100
|
+
* Defaults to a dynamic port in the range [7777, 9000].
|
|
101
|
+
*/
|
|
102
|
+
port?: number
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Server listen address.
|
|
106
|
+
* Defaults to '127.0.0.1'.
|
|
107
|
+
*/
|
|
108
|
+
host?: string
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Callback fired once the server is listening.
|
|
112
|
+
*/
|
|
113
|
+
onReady?: (info: {
|
|
114
|
+
info: AddressInfo
|
|
115
|
+
app: RuntimeServer
|
|
116
|
+
port: number
|
|
117
|
+
}) => void
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `RuntimeServer`
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
interface RuntimeServer {
|
|
125
|
+
/** The underlying Node.js HTTP server instance. */
|
|
126
|
+
server: Server
|
|
127
|
+
|
|
128
|
+
/** The full URL of the running server (e.g. http://127.0.0.1:7777). */
|
|
129
|
+
url: string
|
|
130
|
+
|
|
131
|
+
/** Gracefully shuts down the server. */
|
|
132
|
+
close: () => Promise<void>
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### `NitroModule`
|
|
137
|
+
|
|
138
|
+
The shape of a dynamically imported Nitro server module.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
interface NitroModule {
|
|
142
|
+
listener?: unknown
|
|
143
|
+
middleware?: unknown
|
|
144
|
+
handler?: unknown
|
|
145
|
+
default?: unknown
|
|
146
|
+
websocket?: unknown
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The library resolves the HTTP handler in priority order: `listener` > `middleware` > `handler` > `default`.
|
|
151
|
+
|
|
152
|
+
### `NitroNodeListener`
|
|
153
|
+
|
|
154
|
+
The type of a Nitro HTTP handler function.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
type NitroNodeListener = (
|
|
158
|
+
req: IncomingMessage,
|
|
159
|
+
res: ServerResponse,
|
|
160
|
+
) => MaybePromise<void>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### `MaybePromise<T>`
|
|
164
|
+
|
|
165
|
+
A value that may or may not be a promise.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
type MaybePromise<T> = T | Promise<T>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Development
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Install dependencies
|
|
175
|
+
pnpm install
|
|
176
|
+
|
|
177
|
+
# Start development with watch mode
|
|
178
|
+
pnpm dev
|
|
179
|
+
|
|
180
|
+
# Run tests
|
|
181
|
+
pnpm test
|
|
182
|
+
|
|
183
|
+
# Lint
|
|
184
|
+
pnpm lint
|
|
185
|
+
|
|
186
|
+
# Build for production
|
|
187
|
+
pnpm build
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
[MIT](./LICENSE) © [lonewolfyx](https://github.com/lonewolfyx)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { IncomingMessage, Server, ServerResponse } from "node:http";
|
|
2
|
+
import { AddressInfo } from "node:net";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
6
|
+
type NitroNodeListener = (req: IncomingMessage, res: ServerResponse) => MaybePromise<void>;
|
|
7
|
+
interface NitroModule {
|
|
8
|
+
listener?: unknown;
|
|
9
|
+
middleware?: unknown;
|
|
10
|
+
handler?: unknown;
|
|
11
|
+
default?: unknown;
|
|
12
|
+
websocket?: unknown;
|
|
13
|
+
}
|
|
14
|
+
interface CreateRuntimeServerOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Nitro / Nuxt build output directory, or the direct path to server/index.mjs.
|
|
17
|
+
*
|
|
18
|
+
* Supported:
|
|
19
|
+
* - dist
|
|
20
|
+
* - .output
|
|
21
|
+
* - dist/server/index.mjs
|
|
22
|
+
* - .output/server/index.mjs
|
|
23
|
+
*/
|
|
24
|
+
path: string;
|
|
25
|
+
/**
|
|
26
|
+
* Server port, defaults to 7777
|
|
27
|
+
*/
|
|
28
|
+
port?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Server listen address, defaults to 127.0.0.1
|
|
31
|
+
*/
|
|
32
|
+
host?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Callback fired once the server is listening.
|
|
35
|
+
*/
|
|
36
|
+
onReady?: (info: {
|
|
37
|
+
info: AddressInfo;
|
|
38
|
+
app: RuntimeServer;
|
|
39
|
+
port: number;
|
|
40
|
+
}) => void;
|
|
41
|
+
}
|
|
42
|
+
interface RuntimeServer {
|
|
43
|
+
server: Server;
|
|
44
|
+
url: string;
|
|
45
|
+
close: () => Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/runtime.d.ts
|
|
49
|
+
declare function createRuntimeServer(options: CreateRuntimeServerOptions): Promise<RuntimeServer>;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { type CreateRuntimeServerOptions, type MaybePromise, type NitroModule, type NitroNodeListener, type RuntimeServer, createRuntimeServer };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { existsSync, statSync } from "node:fs";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { isAbsolute, resolve } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { getPort } from "get-port-please";
|
|
6
|
+
//#region src/runtime.ts
|
|
7
|
+
function toAbsolutePath(path) {
|
|
8
|
+
return isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
9
|
+
}
|
|
10
|
+
function resolveNitroEntry(inputPath) {
|
|
11
|
+
const absolutePath = toAbsolutePath(inputPath);
|
|
12
|
+
if (!existsSync(absolutePath)) throw new Error(`Runtime path does not exist: ${absolutePath}`);
|
|
13
|
+
const entryPath = statSync(absolutePath).isDirectory() ? resolve(absolutePath, "server/index.mjs") : absolutePath;
|
|
14
|
+
if (!existsSync(entryPath)) throw new Error(`Nitro entry not found: ${entryPath}`);
|
|
15
|
+
return entryPath;
|
|
16
|
+
}
|
|
17
|
+
function pickNitroListener(mod) {
|
|
18
|
+
const listener = mod.listener ?? mod.middleware ?? mod.handler ?? mod.default;
|
|
19
|
+
if (typeof listener !== "function") throw new TypeError("Cannot find a valid Nitro node listener export. Expected one of: listener, middleware, handler, default.");
|
|
20
|
+
return listener;
|
|
21
|
+
}
|
|
22
|
+
async function loadNitroEntrypoint(path) {
|
|
23
|
+
const mod = await import(pathToFileURL(resolveNitroEntry(path)).href);
|
|
24
|
+
return {
|
|
25
|
+
listener: pickNitroListener(mod),
|
|
26
|
+
websocket: mod.websocket
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function listen(server, host, port) {
|
|
30
|
+
return new Promise((res, rej) => {
|
|
31
|
+
server.once("error", rej);
|
|
32
|
+
server.listen(port, host, () => {
|
|
33
|
+
server.off("error", rej);
|
|
34
|
+
res(server.address().port);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function closeServer(server) {
|
|
39
|
+
return new Promise((res, rej) => {
|
|
40
|
+
server.close((error) => {
|
|
41
|
+
if (error) {
|
|
42
|
+
rej(error);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
res();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async function setupWebSocket(server, websocket) {
|
|
50
|
+
if (!websocket) return;
|
|
51
|
+
const { default: nodeAdapter } = await import("crossws/adapters/node");
|
|
52
|
+
const { handleUpgrade } = nodeAdapter(websocket);
|
|
53
|
+
server.on("upgrade", (req, socket, head) => {
|
|
54
|
+
handleUpgrade(req, socket, head);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async function createRuntimeServer(options) {
|
|
58
|
+
const port = options.port ?? await getPort({ portRange: [7777, 9e3] });
|
|
59
|
+
const host = options.host ?? "127.0.0.1";
|
|
60
|
+
const nitro = await loadNitroEntrypoint(options.path);
|
|
61
|
+
const server = createServer(async (req, res) => {
|
|
62
|
+
try {
|
|
63
|
+
await nitro.listener(req, res);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (!res.headersSent) {
|
|
66
|
+
res.statusCode = 500;
|
|
67
|
+
res.setHeader("content-type", "text/plain; charset=utf-8");
|
|
68
|
+
}
|
|
69
|
+
const message = error instanceof Error ? error.stack ?? error.message : String(error);
|
|
70
|
+
res.end(message);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
await setupWebSocket(server, nitro.websocket);
|
|
74
|
+
const actualPort = await listen(server, host, port);
|
|
75
|
+
const app = {
|
|
76
|
+
server,
|
|
77
|
+
url: `http://${host}:${actualPort}`,
|
|
78
|
+
close: () => closeServer(server)
|
|
79
|
+
};
|
|
80
|
+
if (options.onReady) options.onReady({
|
|
81
|
+
info: server.address(),
|
|
82
|
+
app,
|
|
83
|
+
port: actualPort
|
|
84
|
+
});
|
|
85
|
+
return app;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { createRuntimeServer };
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nuxt-devkit-server",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"packageManager": "pnpm@10.33.2",
|
|
6
|
+
"description": "Create a local server for running Nuxt outputs in CLI tools.",
|
|
7
|
+
"author": "lonewolfyx",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"homepage": "https://github.com/lonewolfyx/nuxt-devkit-server",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/lonewolfyx/nuxt-devkit-server/issues"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"nuxt",
|
|
15
|
+
"dev",
|
|
16
|
+
"server"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.mjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"main": "./dist/index.mjs",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"dev": "tsdown --watch",
|
|
31
|
+
"build": "tsdown",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"lint": "eslint .",
|
|
35
|
+
"lint:fix": "eslint --fix",
|
|
36
|
+
"prepare": "simple-git-hooks",
|
|
37
|
+
"prepublishOnly": "pnpm build"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"registry": "https://registry.npmjs.org",
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"crossws": ">=0.4"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"crossws": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"get-port-please": "^3.2.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@antfu/eslint-config": "^9.0.0",
|
|
56
|
+
"@lonewolfyx/tsconfig": "^0.0.6",
|
|
57
|
+
"@types/node": "^25.9.1",
|
|
58
|
+
"crossws": "^0.4.5",
|
|
59
|
+
"eslint": "^10.4.0",
|
|
60
|
+
"jiti": "^2.7.0",
|
|
61
|
+
"nano-staged": "^1.0.2",
|
|
62
|
+
"picocolors": "^1.1.1",
|
|
63
|
+
"simple-git-hooks": "^2.13.1",
|
|
64
|
+
"tsdown": "^0.22.0",
|
|
65
|
+
"tsx": "^4.22.3",
|
|
66
|
+
"typescript": "^6.0.3",
|
|
67
|
+
"vitest": "^4.1.7"
|
|
68
|
+
},
|
|
69
|
+
"simple-git-hooks": {
|
|
70
|
+
"pre-commit": "npx nano-staged",
|
|
71
|
+
"commit-msg": "node scripts/verify-commit.js"
|
|
72
|
+
},
|
|
73
|
+
"nano-staged": {
|
|
74
|
+
"*": "eslint --fix"
|
|
75
|
+
}
|
|
76
|
+
}
|