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.
@@ -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.0",
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.