vite-plugin-rebundle 1.2.0 → 1.2.2
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/dist/rebundle.d.ts +6 -0
- package/dist/rebundle.js +44 -17
- package/package.json +5 -2
- package/readme.md +90 -0
package/dist/rebundle.d.ts
CHANGED
|
@@ -10,14 +10,20 @@ export declare class Rebundle extends $utils.Unit {
|
|
|
10
10
|
private config;
|
|
11
11
|
private chunkFiles;
|
|
12
12
|
private rebundledContent;
|
|
13
|
+
private hasError;
|
|
14
|
+
private port;
|
|
15
|
+
private ws;
|
|
13
16
|
constructor(options: OptionsInput);
|
|
14
17
|
get vite(): Plugin;
|
|
18
|
+
private onConfig;
|
|
15
19
|
private onConfigResolved;
|
|
20
|
+
private onBuildEnd;
|
|
16
21
|
private onWriteBundle;
|
|
17
22
|
private get outDir();
|
|
18
23
|
private outPath;
|
|
19
24
|
private outRead;
|
|
20
25
|
private outWrite;
|
|
26
|
+
private ensureWs;
|
|
21
27
|
private getOptions;
|
|
22
28
|
private readChunkFiles;
|
|
23
29
|
private removeDirectoryIfEmpty;
|
package/dist/rebundle.js
CHANGED
|
@@ -2,12 +2,17 @@ import * as $esbuild from 'esbuild';
|
|
|
2
2
|
import * as $fs from 'node:fs/promises';
|
|
3
3
|
import * as $path from 'node:path';
|
|
4
4
|
import * as $utils from '@eposlabs/utils';
|
|
5
|
+
import * as $ws from 'ws';
|
|
5
6
|
import $chalk from 'chalk';
|
|
7
|
+
import $portfinder from 'portfinder';
|
|
6
8
|
export class Rebundle extends $utils.Unit {
|
|
7
9
|
options;
|
|
8
10
|
config = null;
|
|
9
11
|
chunkFiles = {};
|
|
10
12
|
rebundledContent = {};
|
|
13
|
+
hasError = false;
|
|
14
|
+
port = null;
|
|
15
|
+
ws = null;
|
|
11
16
|
constructor(options) {
|
|
12
17
|
super();
|
|
13
18
|
this.options = options;
|
|
@@ -17,13 +22,23 @@ export class Rebundle extends $utils.Unit {
|
|
|
17
22
|
name: 'vite-plugin-rebundle',
|
|
18
23
|
apply: 'build',
|
|
19
24
|
enforce: 'post',
|
|
25
|
+
config: this.onConfig,
|
|
20
26
|
configResolved: this.onConfigResolved,
|
|
27
|
+
buildEnd: this.onBuildEnd,
|
|
21
28
|
writeBundle: this.onWriteBundle,
|
|
22
29
|
};
|
|
23
30
|
}
|
|
24
31
|
// ---------------------------------------------------------------------------
|
|
25
32
|
// HOOKS
|
|
26
33
|
// ---------------------------------------------------------------------------
|
|
34
|
+
onConfig = async () => {
|
|
35
|
+
this.port = await $portfinder.getPort({ port: 3100 });
|
|
36
|
+
return {
|
|
37
|
+
define: {
|
|
38
|
+
'import.meta.env.REBUNDLE_PORT': JSON.stringify(this.port),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
};
|
|
27
42
|
onConfigResolved = async (config) => {
|
|
28
43
|
// Save resolved config
|
|
29
44
|
this.config = config;
|
|
@@ -36,8 +51,15 @@ export class Rebundle extends $utils.Unit {
|
|
|
36
51
|
info(message, options);
|
|
37
52
|
};
|
|
38
53
|
};
|
|
54
|
+
onBuildEnd = (error) => {
|
|
55
|
+
this.hasError = !!error;
|
|
56
|
+
};
|
|
39
57
|
onWriteBundle = async (_output, bundle) => {
|
|
58
|
+
if (this.hasError)
|
|
59
|
+
return;
|
|
60
|
+
const ws = await this.ensureWs();
|
|
40
61
|
const options = await this.getOptions();
|
|
62
|
+
const changedChunkNames = [];
|
|
41
63
|
// Get entry js chunks
|
|
42
64
|
const entryJsChunks = Object.values(bundle)
|
|
43
65
|
.filter(chunkOrAsset => chunkOrAsset.type === 'chunk')
|
|
@@ -56,7 +78,7 @@ export class Rebundle extends $utils.Unit {
|
|
|
56
78
|
// Modified? -> Rebundle
|
|
57
79
|
if (chunkChanged) {
|
|
58
80
|
// Build with esbuild
|
|
59
|
-
await $esbuild.build({
|
|
81
|
+
const result = await $esbuild.build({
|
|
60
82
|
sourcemap: Boolean(this.config.build.sourcemap),
|
|
61
83
|
...chunkBuildOptions,
|
|
62
84
|
outfile: chunkPath,
|
|
@@ -64,23 +86,16 @@ export class Rebundle extends $utils.Unit {
|
|
|
64
86
|
bundle: true,
|
|
65
87
|
minify: false,
|
|
66
88
|
allowOverwrite: true,
|
|
67
|
-
plugins: [
|
|
68
|
-
...(chunkBuildOptions.plugins ?? []),
|
|
69
|
-
{
|
|
70
|
-
name: 'logger',
|
|
71
|
-
setup: build => {
|
|
72
|
-
build.onEnd(result => {
|
|
73
|
-
if (result.errors.length > 0)
|
|
74
|
-
return;
|
|
75
|
-
const outDir = $chalk.dim(`${this.outDir}/`);
|
|
76
|
-
const fileName = $chalk.cyan(chunk.fileName);
|
|
77
|
-
const rebundleTag = $chalk.dim.cyan('rebundle');
|
|
78
|
-
console.log(`${outDir}${fileName} ${rebundleTag}`);
|
|
79
|
-
});
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
89
|
});
|
|
90
|
+
if (result.errors.length > 0)
|
|
91
|
+
return;
|
|
92
|
+
// Log successful build
|
|
93
|
+
const _outDir_ = $chalk.dim(`${this.outDir}/`);
|
|
94
|
+
const _fileName_ = $chalk.cyan(chunk.fileName);
|
|
95
|
+
const _rebundle_ = $chalk.dim.cyan('rebundle');
|
|
96
|
+
console.log(`${_outDir_}${_fileName_} ${_rebundle_}`);
|
|
97
|
+
// Mark chunk as changed
|
|
98
|
+
changedChunkNames.push(chunk.name);
|
|
84
99
|
// Save chunk content
|
|
85
100
|
this.rebundledContent[chunk.fileName] = await this.outRead(chunk.fileName);
|
|
86
101
|
// Save sourcemap content
|
|
@@ -118,6 +133,10 @@ export class Rebundle extends $utils.Unit {
|
|
|
118
133
|
const dir = $path.dirname(this.outPath(chunk.fileName));
|
|
119
134
|
await this.removeDirectoryIfEmpty(dir);
|
|
120
135
|
}
|
|
136
|
+
// Notify about changed chunks
|
|
137
|
+
if (changedChunkNames.length > 0) {
|
|
138
|
+
ws.clients.forEach(client => client.send(JSON.stringify(changedChunkNames)));
|
|
139
|
+
}
|
|
121
140
|
};
|
|
122
141
|
// ---------------------------------------------------------------------------
|
|
123
142
|
// HELPERS
|
|
@@ -136,6 +155,14 @@ export class Rebundle extends $utils.Unit {
|
|
|
136
155
|
async outWrite(path, content) {
|
|
137
156
|
await $fs.writeFile(this.outPath(path), content, 'utf-8');
|
|
138
157
|
}
|
|
158
|
+
async ensureWs() {
|
|
159
|
+
if (this.ws)
|
|
160
|
+
return this.ws;
|
|
161
|
+
if (!this.port)
|
|
162
|
+
throw this.never;
|
|
163
|
+
this.ws = new $ws.WebSocketServer({ port: this.port });
|
|
164
|
+
return this.ws;
|
|
165
|
+
}
|
|
139
166
|
async getOptions() {
|
|
140
167
|
if (typeof this.options !== 'function')
|
|
141
168
|
return this.options;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-rebundle",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "imkost",
|
|
@@ -24,7 +24,10 @@
|
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
+
"@types/ws": "^8.18.1",
|
|
27
28
|
"chalk": "^5.6.0",
|
|
28
|
-
"esbuild": "^0.25.9"
|
|
29
|
+
"esbuild": "^0.25.9",
|
|
30
|
+
"portfinder": "^1.0.37",
|
|
31
|
+
"ws": "^8.18.3"
|
|
29
32
|
}
|
|
30
33
|
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# vite-plugin-rebundle
|
|
2
|
+
|
|
3
|
+
A Vite plugin that guarantees **one standalone file per entry point**. Each entry is bundled into a single file with no code-splitting or dynamic imports.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
Sometimes you need bundles without dynamic imports. Vite/Rollup don’t provide this option when building with multiple entries. This plugin solves it by rebundling Vite’s output with esbuild to enforce single-file output.
|
|
8
|
+
|
|
9
|
+
> ℹ️ Useful when targeting environments that require standalone files (e.g., browser extensions, legacy systems, or file-based distribution).
|
|
10
|
+
|
|
11
|
+
> ⚠️ This plugin runs **only during** `vite build`. It does not affect the Vite dev server.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -D vite-plugin-rebundle
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
import { defineConfig } from 'vite'
|
|
23
|
+
import rebundle from 'vite-plugin-rebundle'
|
|
24
|
+
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
plugins: [rebundle()],
|
|
27
|
+
build: {
|
|
28
|
+
rollupOptions: {
|
|
29
|
+
input: {
|
|
30
|
+
app: 'src/app.js',
|
|
31
|
+
libs: 'src/libs.js',
|
|
32
|
+
},
|
|
33
|
+
output: {
|
|
34
|
+
entryFileNames: '[name].js',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Options
|
|
42
|
+
|
|
43
|
+
You can provide **esbuild options per entry point**. This is useful, for example, to inject custom define variables into specific bundles:
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
export default defineConfig({
|
|
47
|
+
plugins: [
|
|
48
|
+
rebundle({
|
|
49
|
+
app: {
|
|
50
|
+
define: {
|
|
51
|
+
BUNDLE_NAME: JSON.stringify('app'),
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
libs: {
|
|
55
|
+
define: {
|
|
56
|
+
BUNDLE_NAME: JSON.stringify('libs'),
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
],
|
|
61
|
+
build: {
|
|
62
|
+
rollupOptions: {
|
|
63
|
+
input: {
|
|
64
|
+
app: 'src/app.js',
|
|
65
|
+
libs: 'src/libs.js',
|
|
66
|
+
},
|
|
67
|
+
output: {
|
|
68
|
+
entryFileNames: '[name].js',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## How it works
|
|
76
|
+
|
|
77
|
+
When you run `vite build`, Rollup normally outputs multiple chunks per entry if code-splitting is needed.
|
|
78
|
+
`vite-plugin-rebundle` hooks into the build and **rebundles each entry’s output with esbuild**, forcing a single self-contained file per entry.
|
|
79
|
+
|
|
80
|
+
- Rollup still handles the initial build (tree-shaking, asset pipeline, etc.).
|
|
81
|
+
- Afterward, each entry is passed through esbuild.
|
|
82
|
+
- The final result is one .js file per entry with no dynamic imports or shared chunks.
|
|
83
|
+
- If sourcemaps are enabled, they are preserved — the rebundled files include correct mappings.
|
|
84
|
+
|
|
85
|
+
## Limitations
|
|
86
|
+
|
|
87
|
+
- **Build only** — this plugin affects only vite build, not the dev server.
|
|
88
|
+
- **Bundle size** — since all shared chunks are inlined, resulting files can be larger than Rollup’s default output.
|
|
89
|
+
- **Dynamic imports** — intentionally disabled; any import() calls are bundled inline.
|
|
90
|
+
- **Code-splitting features** — manual chunks and vendor splitting are ignored.
|