@rollup-extras/plugin-serve 2.0.1 → 2.2.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 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
@@ -7,6 +7,7 @@ import type { Plugin } from 'rollup';
7
7
  export type ServePluginOptionsObject = {
8
8
  pluginName?: string;
9
9
  useWriteBundle?: boolean;
10
+ inMemory?: boolean;
10
11
  dirs?: string | string[];
11
12
  port?: number;
12
13
  useLogger?: boolean;
package/index.d.ts CHANGED
@@ -6,6 +6,7 @@ declare module '@rollup-extras/plugin-serve' {
6
6
  export type ServePluginOptionsObject = {
7
7
  pluginName?: string;
8
8
  useWriteBundle?: boolean;
9
+ inMemory?: boolean;
9
10
  dirs?: string | string[];
10
11
  port?: number;
11
12
  useLogger?: boolean;
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, useWriteBundle, port, host, https, useLogger, customize, staticOptions, onListen, logger } = normalizedOptions;
30
- const instance = multiConfigPluginBase(useWriteBundle, pluginName, serve);
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
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.0.1",
2
+ "version": "2.2.0",
3
3
  "license": "MIT",
4
4
  "name": "@rollup-extras/plugin-serve",
5
5
  "author": "Konstantin Shutkin",
@@ -33,7 +33,7 @@
33
33
  ],
34
34
  "dependencies": {
35
35
  "@niceties/logger": "^2.1.0",
36
- "@hono/node-server": "^1.19.11",
36
+ "@hono/node-server": "^2.0.0",
37
37
  "hono": "^4.12.8",
38
38
  "@rollup-extras/utils": "^2.0.0"
39
39
  },