@rollup-extras/plugin-serve 2.3.1 → 2.4.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 +29 -6
- package/index.d.ts +11 -0
- package/index.js +13 -3
- package/package.json +5 -1
- package/watch-exports.d.ts +7 -0
- package/watch.js +93 -0
package/README.md
CHANGED
|
@@ -66,15 +66,15 @@ Option to use `writeBundle` hook instead of `generateBundle`.
|
|
|
66
66
|
|
|
67
67
|
Optional, `boolean`, default: `false`.
|
|
68
68
|
|
|
69
|
-
When enabled, serves all emitted assets directly from memory instead of from disk. This
|
|
69
|
+
When enabled, serves all emitted assets directly from memory instead of from disk. This controls how files are served; Rollup still writes output when run with `rollup -cw`.
|
|
70
70
|
|
|
71
71
|
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`.
|
|
72
72
|
|
|
73
|
-
For
|
|
73
|
+
For disk-free Rollup output, use the package's [`/watch` helper](#in-memory-serving). Setting `watch: { skipWrite: true }` with Rollup's ordinary watcher skips output generation as well as writing, so the plugin receives no files to serve.
|
|
74
74
|
|
|
75
75
|
**Limitations:**
|
|
76
76
|
- Only covers Rollup's own output. Other plugins (e.g., plugin-copy, plugin-html) may still perform disk I/O independently.
|
|
77
|
-
- Plugins that only use the `writeBundle` hook won't participate
|
|
77
|
+
- Plugins that only use the `writeBundle` hook won't participate with the `/watch` helper. Configure plugins such as plugin-html to use `generateBundle` when their output should be served from memory.
|
|
78
78
|
|
|
79
79
|
### dirs
|
|
80
80
|
|
|
@@ -138,6 +138,8 @@ Set to `false` (or leave unset) to disable both the endpoint and the script inje
|
|
|
138
138
|
|
|
139
139
|
## In-Memory Serving
|
|
140
140
|
|
|
141
|
+
Keep the Rollup configuration in `rollup.config.js`:
|
|
142
|
+
|
|
141
143
|
```javascript
|
|
142
144
|
import serve from "@rollup-extras/plugin-serve";
|
|
143
145
|
|
|
@@ -147,13 +149,34 @@ export default {
|
|
|
147
149
|
format: "es",
|
|
148
150
|
dir: "dest",
|
|
149
151
|
},
|
|
150
|
-
watch: {
|
|
151
|
-
skipWrite: true, // recommended: avoid writing files to disk
|
|
152
|
-
},
|
|
153
152
|
plugins: [serve({ inMemory: true })],
|
|
154
153
|
};
|
|
155
154
|
```
|
|
156
155
|
|
|
156
|
+
Create `dev.js` to start a watcher that generates output without writing it to disk:
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
import watch from "@rollup-extras/plugin-serve/watch";
|
|
160
|
+
import config from "./rollup.config.js";
|
|
161
|
+
|
|
162
|
+
const watcher = watch(config);
|
|
163
|
+
|
|
164
|
+
watcher.on("event", event => {
|
|
165
|
+
if (event.code === "ERROR") console.error(event.error);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
process.once("SIGINT", () => watcher.close());
|
|
169
|
+
process.once("SIGTERM", () => watcher.close());
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Run `node dev.js`. The helper accepts one Rollup configuration or an array, generates all configured outputs on each rebuild, and forces `watch.skipWrite` without mutating the supplied configuration. Configurations with `watch: false` are ignored.
|
|
173
|
+
|
|
174
|
+
It returns a Rollup watcher. Use its `END` event to observe completion of generation and build cleanup. The helper owns the build results, so consumers should not call `event.result.generate()` or `event.result.close()`. Output errors are reported through the usual `ERROR` event, and later file changes can trigger another build. `await watcher.close()` waits for pending generation and shuts down the server.
|
|
175
|
+
|
|
176
|
+
Register watched dependencies in build hooks, such as `buildStart` or `transform`. With `skipWrite`, Rollup collects watch files before `BUNDLE_END`; files first registered in output hooks during the helper's generation are not picked up by the watcher.
|
|
177
|
+
|
|
178
|
+
Running the same configuration with `rollup -cw` also serves from memory, while continuing to write the usual output files.
|
|
179
|
+
|
|
157
180
|
Hybrid mode — bundle from memory, static assets from disk:
|
|
158
181
|
|
|
159
182
|
```javascript
|
package/index.d.ts
CHANGED
|
@@ -41,3 +41,14 @@ declare module '@rollup-extras/plugin-serve' {
|
|
|
41
41
|
|
|
42
42
|
export {};
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
declare module '@rollup-extras/plugin-serve/watch' {
|
|
46
|
+
import type { RollupWatcher, RollupWatchOptions } from 'rollup';
|
|
47
|
+
/**
|
|
48
|
+
* Watch and generate Rollup output in memory, closing each build result automatically.
|
|
49
|
+
* Configure `serve({ inMemory: true })` in the supplied Rollup configuration.
|
|
50
|
+
*/
|
|
51
|
+
export default function watch(config: RollupWatchOptions | RollupWatchOptions[]): RollupWatcher;
|
|
52
|
+
|
|
53
|
+
export {};
|
|
54
|
+
}
|
package/index.js
CHANGED
|
@@ -43,12 +43,14 @@ export default function (options = {}) {
|
|
|
43
43
|
|
|
44
44
|
let currentInputOptions;
|
|
45
45
|
|
|
46
|
+
let server;
|
|
47
|
+
|
|
46
48
|
let { dirs } = normalizedOptions,
|
|
47
49
|
collectDirs = false,
|
|
48
50
|
started = false,
|
|
49
51
|
watchMode = true;
|
|
50
52
|
|
|
51
|
-
const pluginInstance = { ...instance, outputOptions };
|
|
53
|
+
const pluginInstance = { ...instance, outputOptions, closeWatcher };
|
|
52
54
|
|
|
53
55
|
if (!dirs) {
|
|
54
56
|
dirs = [];
|
|
@@ -138,13 +140,13 @@ export default function (options = {}) {
|
|
|
138
140
|
app.use('*', serveStatic({ root: dir, ...staticOptions }));
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
server = createAdaptorServer({
|
|
142
144
|
fetch: app.fetch,
|
|
143
145
|
...(https ? { createServer: createHttpsServer, serverOptions: https } : {}),
|
|
144
146
|
});
|
|
145
147
|
globalServer = server;
|
|
146
148
|
|
|
147
|
-
const listenCb = () => internalOnListen(server);
|
|
149
|
+
const listenCb = () => internalOnListen( (server));
|
|
148
150
|
|
|
149
151
|
if (host) {
|
|
150
152
|
server.listen(port, host, listenCb);
|
|
@@ -161,6 +163,14 @@ export default function (options = {}) {
|
|
|
161
163
|
});
|
|
162
164
|
}
|
|
163
165
|
|
|
166
|
+
async function closeWatcher() {
|
|
167
|
+
if (!server || globalServer !== server) return;
|
|
168
|
+
globalLiveReload?.close();
|
|
169
|
+
globalLiveReload = undefined;
|
|
170
|
+
globalServer = undefined;
|
|
171
|
+
await new Promise(resolve => (server).close(resolve));
|
|
172
|
+
}
|
|
173
|
+
|
|
164
174
|
function internalOnListen(server) {
|
|
165
175
|
if (!onListen?.( (server))) {
|
|
166
176
|
logger.finish(`listening on ${linkFromAddress(server.address(), !!https)}`, LogLevel.info);
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.4.0",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "@rollup-extras/plugin-serve",
|
|
5
5
|
"author": "Konstantin Shutkin",
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
"types": "./index.d.ts",
|
|
11
11
|
"default": "./index.js"
|
|
12
12
|
},
|
|
13
|
+
"./watch": {
|
|
14
|
+
"types": "./index.d.ts",
|
|
15
|
+
"default": "./watch.js"
|
|
16
|
+
},
|
|
13
17
|
"./package.json": "./package.json"
|
|
14
18
|
},
|
|
15
19
|
"main": "./index.js",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RollupWatcher, RollupWatchOptions } from 'rollup';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Watch and generate Rollup output in memory, closing each build result automatically.
|
|
5
|
+
* Configure `serve({ inMemory: true })` in the supplied Rollup configuration.
|
|
6
|
+
*/
|
|
7
|
+
export default function watch(config: RollupWatchOptions | RollupWatchOptions[]): RollupWatcher;
|
package/watch.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { watch as rollupWatch } from 'rollup';
|
|
2
|
+
|
|
3
|
+
export default function watch(config) {
|
|
4
|
+
|
|
5
|
+
let outputs = [];
|
|
6
|
+
let closing = false;
|
|
7
|
+
|
|
8
|
+
let finishBuild;
|
|
9
|
+
let pending = Promise.resolve();
|
|
10
|
+
|
|
11
|
+
let closed;
|
|
12
|
+
|
|
13
|
+
let ready;
|
|
14
|
+
const initialized = new Promise(resolve => {
|
|
15
|
+
ready = () => resolve(undefined);
|
|
16
|
+
});
|
|
17
|
+
const configs = Array.isArray(config) ? config : [config];
|
|
18
|
+
const watcher = rollupWatch(
|
|
19
|
+
configs.map(options => ({
|
|
20
|
+
...options,
|
|
21
|
+
watch: options.watch === false ? false : { ...options.watch, skipWrite: true },
|
|
22
|
+
plugins: [
|
|
23
|
+
options.plugins,
|
|
24
|
+
{
|
|
25
|
+
name: '@rollup-extras/plugin-serve/watch',
|
|
26
|
+
buildStart() {
|
|
27
|
+
outputs = Array.isArray(options.output) ? options.output : [options.output || {}];
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
}))
|
|
32
|
+
);
|
|
33
|
+
watcher.on('event', async event => {
|
|
34
|
+
if (event.code === 'BUNDLE_START') {
|
|
35
|
+
pending = new Promise(resolve => {
|
|
36
|
+
finishBuild = resolve;
|
|
37
|
+
});
|
|
38
|
+
ready?.();
|
|
39
|
+
} else if (event.code === 'BUNDLE_END') {
|
|
40
|
+
try {
|
|
41
|
+
await generate(event.result, outputs);
|
|
42
|
+
} finally {
|
|
43
|
+
finishBuild?.();
|
|
44
|
+
}
|
|
45
|
+
} else if (event.code === 'ERROR') {
|
|
46
|
+
try {
|
|
47
|
+
await event.result?.close();
|
|
48
|
+
} finally {
|
|
49
|
+
finishBuild?.();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function close() {
|
|
55
|
+
closing = true;
|
|
56
|
+
closed ||= (async () => {
|
|
57
|
+
|
|
58
|
+
await initialized;
|
|
59
|
+
await pending;
|
|
60
|
+
await watcher.close();
|
|
61
|
+
})();
|
|
62
|
+
return closed;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const managed = new Proxy(watcher, {
|
|
66
|
+
get(target, key) {
|
|
67
|
+
if (key === 'close') return close;
|
|
68
|
+
const value = Reflect.get(target, key);
|
|
69
|
+
if (typeof value !== 'function') return value;
|
|
70
|
+
|
|
71
|
+
function call(...args) {
|
|
72
|
+
const result = value.apply(target, args);
|
|
73
|
+
return result === target ? managed : result;
|
|
74
|
+
}
|
|
75
|
+
return call;
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
return managed;
|
|
79
|
+
|
|
80
|
+
async function generate(result, outputOptions) {
|
|
81
|
+
try {
|
|
82
|
+
if (!closing) {
|
|
83
|
+
|
|
84
|
+
const generated = await Promise.allSettled(outputOptions.map(output => result.generate(output)));
|
|
85
|
+
for (const output of generated) {
|
|
86
|
+
if (output.status === 'rejected') throw output.reason;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
await result.close();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|