@rollup-extras/plugin-serve 2.0.1 → 2.1.0
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/README.md +39 -0
- package/exports.d.ts +1 -0
- package/index.d.ts +1 -0
- package/index.js +49 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,6 +60,20 @@ Optional, `boolean`, default: `true`.
|
|
|
60
60
|
|
|
61
61
|
Option to use `writeBundle` hook instead of `generateBundle`.
|
|
62
62
|
|
|
63
|
+
### inMemory
|
|
64
|
+
|
|
65
|
+
Optional, `boolean`, default: `false`.
|
|
66
|
+
|
|
67
|
+
When enabled, serves all emitted assets directly from memory instead of from disk. This is similar to how webpack-dev-server works — Rollup output never needs to hit the filesystem.
|
|
68
|
+
|
|
69
|
+
When `inMemory` is `true`, the plugin automatically uses the `generateBundle` hook (regardless of `useWriteBundle`) to capture all chunks and assets in memory. A custom Hono middleware serves these files before falling through to any disk-based static serving configured via `dirs`.
|
|
70
|
+
|
|
71
|
+
For a fully disk-free dev server, set `watch: { skipWrite: true }` in your Rollup config to prevent Rollup from writing files to disk. The plugin does not force this — you control it.
|
|
72
|
+
|
|
73
|
+
**Limitations:**
|
|
74
|
+
- Only covers Rollup's own output. Other plugins (e.g., plugin-copy, plugin-html) may still perform disk I/O independently.
|
|
75
|
+
- Plugins that only use the `writeBundle` hook won't participate when `skipWrite` is enabled.
|
|
76
|
+
|
|
63
77
|
### dirs
|
|
64
78
|
|
|
65
79
|
Optional, `string` | `string[]`, default: `output.dir`.
|
|
@@ -108,12 +122,37 @@ Optional, `(server: Server) => void | true`
|
|
|
108
122
|
|
|
109
123
|
Extension point after the server is live. Please return true to suppress the default banner.
|
|
110
124
|
|
|
125
|
+
## In-Memory Serving
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
import serve from "@rollup-extras/plugin-serve";
|
|
129
|
+
|
|
130
|
+
export default {
|
|
131
|
+
input: "src/index.js",
|
|
132
|
+
output: {
|
|
133
|
+
format: "es",
|
|
134
|
+
dir: "dest",
|
|
135
|
+
},
|
|
136
|
+
watch: {
|
|
137
|
+
skipWrite: true, // recommended: avoid writing files to disk
|
|
138
|
+
},
|
|
139
|
+
plugins: [serve({ inMemory: true })],
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Hybrid mode — bundle from memory, static assets from disk:
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
serve({ inMemory: true, dirs: ["public"] })
|
|
147
|
+
```
|
|
148
|
+
|
|
111
149
|
## Configuration
|
|
112
150
|
|
|
113
151
|
```typescript
|
|
114
152
|
type ServePluginOptions = {
|
|
115
153
|
pluginName?: string;
|
|
116
154
|
useWriteBundle?: boolean;
|
|
155
|
+
inMemory?: boolean;
|
|
117
156
|
dirs?: string | string[];
|
|
118
157
|
port?: number;
|
|
119
158
|
useLogger?: boolean;
|
package/exports.d.ts
CHANGED
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createAdaptorServer } from '@hono/node-server';
|
|
|
4
4
|
import { serveStatic } from '@hono/node-server/serve-static';
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
6
|
import { logger as honoLogger } from 'hono/logger';
|
|
7
|
+
import { getMimeType } from 'hono/utils/mime';
|
|
7
8
|
|
|
8
9
|
import { LogLevel } from '@niceties/logger';
|
|
9
10
|
import logger from '@rollup-extras/utils/logger';
|
|
@@ -26,8 +27,13 @@ export default function (options = {}) {
|
|
|
26
27
|
'dirs',
|
|
27
28
|
factories
|
|
28
29
|
);
|
|
29
|
-
const { pluginName,
|
|
30
|
-
const
|
|
30
|
+
const { pluginName, port, host, https, useLogger, customize, staticOptions, onListen, logger, inMemory } = normalizedOptions;
|
|
31
|
+
const useWriteBundle = inMemory ? false : normalizedOptions.useWriteBundle;
|
|
32
|
+
const instance = inMemory
|
|
33
|
+
? multiConfigPluginBase(useWriteBundle, pluginName, serve, captureOutput)
|
|
34
|
+
: multiConfigPluginBase(useWriteBundle, pluginName, serve);
|
|
35
|
+
|
|
36
|
+
const memoryFiles = new Map();
|
|
31
37
|
|
|
32
38
|
let { dirs } = normalizedOptions,
|
|
33
39
|
collectDirs = false,
|
|
@@ -40,6 +46,8 @@ export default function (options = {}) {
|
|
|
40
46
|
dirs = [];
|
|
41
47
|
collectDirs = true;
|
|
42
48
|
pluginInstance.renderStart = renderStart;
|
|
49
|
+
} else if (inMemory) {
|
|
50
|
+
pluginInstance.renderStart = renderStart;
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
return (pluginInstance);
|
|
@@ -47,6 +55,9 @@ export default function (options = {}) {
|
|
|
47
55
|
function renderStart( outputOptions, inputOptions) {
|
|
48
56
|
|
|
49
57
|
( (instance).renderStart).call(this, outputOptions, inputOptions);
|
|
58
|
+
if (inMemory) {
|
|
59
|
+
memoryFiles.clear();
|
|
60
|
+
}
|
|
50
61
|
if (collectDirs) {
|
|
51
62
|
if (outputOptions.dir) {
|
|
52
63
|
(dirs).push(outputOptions.dir);
|
|
@@ -59,6 +70,23 @@ export default function (options = {}) {
|
|
|
59
70
|
return null;
|
|
60
71
|
}
|
|
61
72
|
|
|
73
|
+
function captureBundle(bundle) {
|
|
74
|
+
for (const key in bundle) {
|
|
75
|
+
const item = (bundle[key]);
|
|
76
|
+
const content = item.type === 'chunk' ? item.code : item.source;
|
|
77
|
+
memoryFiles.set(item.fileName, { content, type: getMimeType(item.fileName) || 'application/octet-stream' });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function captureOutput(
|
|
82
|
+
_options,
|
|
83
|
+
bundle,
|
|
84
|
+
_remainingConfigsCount,
|
|
85
|
+
_remainingOutputsCount
|
|
86
|
+
) {
|
|
87
|
+
captureBundle(bundle);
|
|
88
|
+
}
|
|
89
|
+
|
|
62
90
|
async function serve() {
|
|
63
91
|
if (!started && watchMode) {
|
|
64
92
|
started = true;
|
|
@@ -78,6 +106,10 @@ export default function (options = {}) {
|
|
|
78
106
|
app.use('*', honoLogger());
|
|
79
107
|
}
|
|
80
108
|
|
|
109
|
+
if (inMemory) {
|
|
110
|
+
app.use('*', inMemoryMiddleware(memoryFiles));
|
|
111
|
+
}
|
|
112
|
+
|
|
81
113
|
for (const dir of (dirs)) {
|
|
82
114
|
app.use('*', serveStatic({ root: dir, ...staticOptions }));
|
|
83
115
|
}
|
|
@@ -128,3 +160,18 @@ function linkFromAddressInfo({ address, port, family }, https) {
|
|
|
128
160
|
const protocol = `http${https ? 's' : ''}://`;
|
|
129
161
|
return `${protocol}${serverName}:${port}`;
|
|
130
162
|
}
|
|
163
|
+
|
|
164
|
+
function inMemoryMiddleware(files) {
|
|
165
|
+
return async (c, next) => {
|
|
166
|
+
let pathname = new URL(c.req.url).pathname;
|
|
167
|
+
if (pathname.endsWith('/')) {
|
|
168
|
+
pathname += 'index.html';
|
|
169
|
+
}
|
|
170
|
+
const fileName = pathname.startsWith('/') ? pathname.slice(1) : pathname;
|
|
171
|
+
const file = files.get(fileName);
|
|
172
|
+
if (file) {
|
|
173
|
+
return c.body(file.content, 200, { 'Content-Type': file.type });
|
|
174
|
+
}
|
|
175
|
+
await next();
|
|
176
|
+
};
|
|
177
|
+
}
|
package/package.json
CHANGED