vite-plugin-rebundle 1.15.0 → 1.16.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/dist/rebundle.d.ts +8 -4
- package/dist/rebundle.js +65 -62
- package/package.json +1 -1
- package/src/rebundle.ts +85 -79
package/dist/rebundle.d.ts
CHANGED
|
@@ -13,18 +13,22 @@ declare class Rebundle {
|
|
|
13
13
|
private bundleOptions;
|
|
14
14
|
private config;
|
|
15
15
|
private originals;
|
|
16
|
-
private rebundled;
|
|
17
16
|
private port;
|
|
18
17
|
private ws;
|
|
18
|
+
private isRollupVite;
|
|
19
|
+
private isRolldownVite;
|
|
20
|
+
private ORIGINALS_DIR;
|
|
19
21
|
constructor(commonOptions?: RolldownOptions | null, bundleOptions?: BundleOptions);
|
|
20
22
|
get vite(): Plugin;
|
|
21
23
|
private onConfig;
|
|
22
24
|
private onConfigResolved;
|
|
25
|
+
private onGenerateBundle;
|
|
23
26
|
private onWriteBundle;
|
|
24
27
|
private get dist();
|
|
25
|
-
private
|
|
26
|
-
private
|
|
27
|
-
private
|
|
28
|
+
private prefixed;
|
|
29
|
+
private unprefixed;
|
|
30
|
+
private getChunks;
|
|
31
|
+
private getEntryChunks;
|
|
28
32
|
private merge;
|
|
29
33
|
}
|
|
30
34
|
declare function rebundle(commonOptions?: RolldownOptions | null, bundleOptions?: BundleOptions): Plugin<any>;
|
package/dist/rebundle.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/rebundle.ts
|
|
2
|
-
import { is
|
|
2
|
+
import { is } from "@eposlabs/utils";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { filesize } from "filesize";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { rm, stat } from "fs/promises";
|
|
6
|
+
import { extname, join } from "path";
|
|
7
7
|
import { getPort } from "portfinder";
|
|
8
8
|
import { rolldown } from "rolldown";
|
|
9
9
|
import { WebSocketServer } from "ws";
|
|
@@ -12,9 +12,11 @@ var Rebundle = class {
|
|
|
12
12
|
bundleOptions;
|
|
13
13
|
config = null;
|
|
14
14
|
originals = {};
|
|
15
|
-
rebundled = {};
|
|
16
15
|
port = null;
|
|
17
16
|
ws = null;
|
|
17
|
+
isRollupVite = false;
|
|
18
|
+
isRolldownVite = false;
|
|
19
|
+
ORIGINALS_DIR = "__originals__";
|
|
18
20
|
constructor(commonOptions, bundleOptions) {
|
|
19
21
|
this.commonOptions = commonOptions ?? {};
|
|
20
22
|
this.bundleOptions = bundleOptions ?? {};
|
|
@@ -26,74 +28,81 @@ var Rebundle = class {
|
|
|
26
28
|
enforce: "post",
|
|
27
29
|
config: this.onConfig,
|
|
28
30
|
configResolved: this.onConfigResolved,
|
|
31
|
+
generateBundle: this.onGenerateBundle,
|
|
29
32
|
writeBundle: this.onWriteBundle
|
|
30
33
|
};
|
|
31
34
|
}
|
|
32
35
|
// ---------------------------------------------------------------------------
|
|
33
36
|
// VITE HOOKS
|
|
34
37
|
// ---------------------------------------------------------------------------
|
|
35
|
-
onConfig = async () => {
|
|
36
|
-
|
|
38
|
+
onConfig = async (config) => {
|
|
39
|
+
if (config.build?.watch) {
|
|
40
|
+
this.port = await getPort({ port: 3100 });
|
|
41
|
+
this.ws = new WebSocketServer({ port: this.port });
|
|
42
|
+
}
|
|
37
43
|
return {
|
|
38
44
|
define: { "import.meta.env.REBUNDLE_PORT": JSON.stringify(this.port) },
|
|
39
45
|
build: { sourcemap: false }
|
|
40
46
|
};
|
|
41
47
|
};
|
|
42
48
|
onConfigResolved = async (config) => {
|
|
49
|
+
this.isRollupVite = !("oxc" in config);
|
|
50
|
+
this.isRolldownVite = !this.isRollupVite;
|
|
43
51
|
this.config = config;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
if (this.isRollupVite) {
|
|
53
|
+
const info = this.config.logger.info;
|
|
54
|
+
this.config.logger.info = (message, options) => {
|
|
55
|
+
const path = message.split(/\s+/)[0];
|
|
56
|
+
if (extname(path) === ".js") return;
|
|
57
|
+
info(message, options);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
onGenerateBundle = async (_options, bundle) => {
|
|
62
|
+
for (const chunk of this.getChunks(bundle)) {
|
|
63
|
+
const originalFileName = chunk.fileName;
|
|
64
|
+
chunk.fileName = this.prefixed(originalFileName);
|
|
65
|
+
chunk.imports = chunk.imports.map((name) => this.prefixed(name));
|
|
66
|
+
if (this.isRollupVite) {
|
|
67
|
+
bundle[chunk.fileName] = chunk;
|
|
68
|
+
delete bundle[originalFileName];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
50
71
|
};
|
|
51
72
|
onWriteBundle = async (_output, bundle) => {
|
|
52
|
-
const
|
|
73
|
+
const modifiedEntryChunks = this.getEntryChunks(bundle).filter((chunk) => {
|
|
74
|
+
const usedPaths = [chunk.fileName, ...chunk.imports];
|
|
75
|
+
return usedPaths.some((path) => "code" in bundle[path] && bundle[path].code !== this.originals[path]);
|
|
76
|
+
});
|
|
77
|
+
if (modifiedEntryChunks.length === 0) return;
|
|
53
78
|
await Promise.all(
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
if (!chunk) return;
|
|
57
|
-
const chunkFilePath = join(this.dist, chunk.fileName);
|
|
58
|
-
const modified = [chunk.fileName, ...chunk.imports].some((name) => {
|
|
59
|
-
return bundle[name].type === "chunk" && bundle[name].code !== this.originals[name];
|
|
60
|
-
});
|
|
61
|
-
if (!modified) {
|
|
62
|
-
await writeFile(chunkFilePath, this.rebundled[chunk.fileName]);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
79
|
+
modifiedEntryChunks.map(async (chunk) => {
|
|
80
|
+
const originalFileName = this.unprefixed(chunk.fileName);
|
|
65
81
|
const build = await rolldown({
|
|
66
82
|
...this.merge(this.commonOptions.input ?? {}, this.bundleOptions[chunk.name]?.input ?? {}),
|
|
67
|
-
input:
|
|
83
|
+
input: join(this.dist, chunk.fileName)
|
|
68
84
|
});
|
|
69
|
-
|
|
85
|
+
await build.write({
|
|
70
86
|
...this.merge(this.commonOptions.output ?? {}, this.bundleOptions[chunk.name]?.output ?? {}),
|
|
71
87
|
sourcemap: false,
|
|
72
|
-
file:
|
|
88
|
+
file: join(this.dist, originalFileName)
|
|
73
89
|
});
|
|
74
|
-
const { size } = await stat(join(this.dist,
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
console.log(`${
|
|
80
|
-
modifiedChunkNames.push(chunk.name);
|
|
81
|
-
this.rebundled[chunk.fileName] = result.output[0].code;
|
|
90
|
+
const { size } = await stat(join(this.dist, originalFileName));
|
|
91
|
+
const $dist = chalk.dim(`${this.dist}/`);
|
|
92
|
+
const $fileName = chalk.cyan(originalFileName);
|
|
93
|
+
const $rebundle = chalk.dim.cyan("[rebundle]");
|
|
94
|
+
const $size = chalk.bold.dim(`${filesize(size)}`);
|
|
95
|
+
console.log(`${$dist}${$fileName} ${$rebundle} ${$size}`);
|
|
82
96
|
})
|
|
83
97
|
);
|
|
84
|
-
for (const
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
this.originals[chunk.fileName] = chunk.code;
|
|
88
|
-
delete bundle[chunk.fileName];
|
|
89
|
-
if (!chunk.isEntry) {
|
|
90
|
-
await this.removeFromDist(chunk.fileName);
|
|
91
|
-
}
|
|
98
|
+
for (const chunk of this.getChunks(bundle)) {
|
|
99
|
+
this.originals[this.unprefixed(chunk.fileName)] = chunk.code;
|
|
100
|
+
if (this.isRolldownVite) delete bundle[chunk.fileName];
|
|
92
101
|
}
|
|
93
|
-
|
|
94
|
-
if (this.
|
|
95
|
-
const
|
|
96
|
-
ws.clients.forEach((client) => client.send(JSON.stringify(
|
|
102
|
+
await rm(join(this.dist, this.ORIGINALS_DIR), { recursive: true });
|
|
103
|
+
if (this.ws && modifiedEntryChunks.length > 0) {
|
|
104
|
+
const names = modifiedEntryChunks.map((chunk) => chunk.name);
|
|
105
|
+
this.ws.clients.forEach((client) => client.send(JSON.stringify(names)));
|
|
97
106
|
}
|
|
98
107
|
};
|
|
99
108
|
// ---------------------------------------------------------------------------
|
|
@@ -103,23 +112,17 @@ var Rebundle = class {
|
|
|
103
112
|
if (!this.config) throw "never";
|
|
104
113
|
return this.config.build.outDir;
|
|
105
114
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
prefixed(path) {
|
|
116
|
+
return join(this.ORIGINALS_DIR, path);
|
|
117
|
+
}
|
|
118
|
+
unprefixed(path) {
|
|
119
|
+
return path.replace(`${this.ORIGINALS_DIR}/`, "");
|
|
111
120
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!this.port) throw "never";
|
|
115
|
-
this.ws = new WebSocketServer({ port: this.port });
|
|
116
|
-
return this.ws;
|
|
121
|
+
getChunks(bundle) {
|
|
122
|
+
return Object.values(bundle).filter((item) => item.type === "chunk");
|
|
117
123
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (files.length > 0) return;
|
|
121
|
-
await rmdir(dir);
|
|
122
|
-
await this.removeDirectoryIfEmpty(dirname(dir));
|
|
124
|
+
getEntryChunks(bundle) {
|
|
125
|
+
return Object.values(bundle).filter((item) => item.type === "chunk").filter((chunk) => chunk.isEntry);
|
|
123
126
|
}
|
|
124
127
|
merge(obj1, obj2) {
|
|
125
128
|
const result = { ...obj1 };
|
package/package.json
CHANGED
package/src/rebundle.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { is
|
|
1
|
+
import { is } from '@eposlabs/utils'
|
|
2
2
|
import chalk from 'chalk'
|
|
3
3
|
import { filesize } from 'filesize'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { rm, stat } from 'node:fs/promises'
|
|
5
|
+
import { extname, join } from 'node:path'
|
|
6
6
|
import { getPort } from 'portfinder'
|
|
7
7
|
import { rolldown, type InputOptions, type OutputOptions } from 'rolldown'
|
|
8
8
|
import type { NormalizedOutputOptions, OutputBundle } from 'rollup'
|
|
9
|
-
import type { Plugin, ResolvedConfig } from 'vite'
|
|
9
|
+
import type { Plugin, ResolvedConfig, UserConfig } from 'vite'
|
|
10
10
|
import { WebSocketServer } from 'ws'
|
|
11
11
|
|
|
12
12
|
export type RolldownOptions = {
|
|
@@ -23,9 +23,11 @@ export class Rebundle {
|
|
|
23
23
|
private bundleOptions: BundleOptions
|
|
24
24
|
private config: ResolvedConfig | null = null
|
|
25
25
|
private originals: Record<string, string> = {}
|
|
26
|
-
private rebundled: Record<string, string> = {}
|
|
27
26
|
private port: number | null = null
|
|
28
27
|
private ws: WebSocketServer | null = null
|
|
28
|
+
private isRollupVite = false
|
|
29
|
+
private isRolldownVite = false
|
|
30
|
+
private ORIGINALS_DIR = '__originals__'
|
|
29
31
|
|
|
30
32
|
constructor(commonOptions?: RolldownOptions | null, bundleOptions?: BundleOptions) {
|
|
31
33
|
this.commonOptions = commonOptions ?? {}
|
|
@@ -39,6 +41,7 @@ export class Rebundle {
|
|
|
39
41
|
enforce: 'post',
|
|
40
42
|
config: this.onConfig,
|
|
41
43
|
configResolved: this.onConfigResolved,
|
|
44
|
+
generateBundle: this.onGenerateBundle,
|
|
42
45
|
writeBundle: this.onWriteBundle,
|
|
43
46
|
}
|
|
44
47
|
}
|
|
@@ -47,8 +50,12 @@ export class Rebundle {
|
|
|
47
50
|
// VITE HOOKS
|
|
48
51
|
// ---------------------------------------------------------------------------
|
|
49
52
|
|
|
50
|
-
private onConfig = async () => {
|
|
51
|
-
|
|
53
|
+
private onConfig = async (config: UserConfig) => {
|
|
54
|
+
if (config.build?.watch) {
|
|
55
|
+
this.port = await getPort({ port: 3100 })
|
|
56
|
+
this.ws = new WebSocketServer({ port: this.port })
|
|
57
|
+
}
|
|
58
|
+
|
|
52
59
|
return {
|
|
53
60
|
define: { 'import.meta.env.REBUNDLE_PORT': JSON.stringify(this.port) },
|
|
54
61
|
build: { sourcemap: false },
|
|
@@ -56,89 +63,91 @@ export class Rebundle {
|
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
private onConfigResolved = async (config: ResolvedConfig) => {
|
|
66
|
+
// Detect Vite variant
|
|
67
|
+
this.isRollupVite = !('oxc' in config)
|
|
68
|
+
this.isRolldownVite = !this.isRollupVite
|
|
69
|
+
|
|
59
70
|
// Save resolved config
|
|
60
71
|
this.config = config
|
|
61
72
|
|
|
62
|
-
// Hide js files from output logs
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
// Hide js files from output logs for rollup Vite
|
|
74
|
+
if (this.isRollupVite) {
|
|
75
|
+
const info = this.config.logger.info
|
|
76
|
+
this.config.logger.info = (message, options) => {
|
|
77
|
+
const path = message.split(/\s+/)[0]
|
|
78
|
+
if (extname(path) === '.js') return
|
|
79
|
+
info(message, options)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private onGenerateBundle = async (_options: NormalizedOutputOptions, bundle: OutputBundle) => {
|
|
85
|
+
for (const chunk of this.getChunks(bundle)) {
|
|
86
|
+
const originalFileName = chunk.fileName
|
|
87
|
+
|
|
88
|
+
// Move all chunks to a temporary subfolder
|
|
89
|
+
chunk.fileName = this.prefixed(originalFileName)
|
|
90
|
+
chunk.imports = chunk.imports.map(name => this.prefixed(name))
|
|
91
|
+
|
|
92
|
+
// Use prefixed names as bundle keys for rollup Vite (rolldown Vite does this automatically)
|
|
93
|
+
if (this.isRollupVite) {
|
|
94
|
+
bundle[chunk.fileName] = chunk
|
|
95
|
+
delete bundle[originalFileName]
|
|
96
|
+
}
|
|
68
97
|
}
|
|
69
98
|
}
|
|
70
99
|
|
|
71
100
|
private onWriteBundle = async (_output: NormalizedOutputOptions, bundle: OutputBundle) => {
|
|
72
|
-
|
|
101
|
+
// Get modified entry chunks
|
|
102
|
+
const modifiedEntryChunks = this.getEntryChunks(bundle).filter(chunk => {
|
|
103
|
+
const usedPaths = [chunk.fileName, ...chunk.imports]
|
|
104
|
+
return usedPaths.some(path => 'code' in bundle[path] && bundle[path].code !== this.originals[path])
|
|
105
|
+
})
|
|
73
106
|
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
Object.values(bundle).map(async chunkOrAsset => {
|
|
77
|
-
// Only process entry chunks
|
|
78
|
-
const chunk = chunkOrAsset.type === 'chunk' && chunkOrAsset.isEntry ? chunkOrAsset : null
|
|
79
|
-
if (!chunk) return
|
|
80
|
-
const chunkFilePath = join(this.dist, chunk.fileName)
|
|
81
|
-
|
|
82
|
-
// Check if chunk is modified
|
|
83
|
-
const modified = [chunk.fileName, ...chunk.imports].some(name => {
|
|
84
|
-
return bundle[name].type === 'chunk' && bundle[name].code !== this.originals[name]
|
|
85
|
-
})
|
|
107
|
+
// No modified entry chunks? -> Skip rebundle
|
|
108
|
+
if (modifiedEntryChunks.length === 0) return
|
|
86
109
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
110
|
+
// Rebundle modified entry chunks
|
|
111
|
+
await Promise.all(
|
|
112
|
+
modifiedEntryChunks.map(async chunk => {
|
|
113
|
+
const originalFileName = this.unprefixed(chunk.fileName)
|
|
92
114
|
|
|
93
|
-
//
|
|
115
|
+
// Build with rolldown
|
|
94
116
|
const build = await rolldown({
|
|
95
117
|
...this.merge(this.commonOptions.input ?? {}, this.bundleOptions[chunk.name]?.input ?? {}),
|
|
96
|
-
input:
|
|
118
|
+
input: join(this.dist, chunk.fileName),
|
|
97
119
|
})
|
|
98
|
-
|
|
120
|
+
await build.write({
|
|
99
121
|
...this.merge(this.commonOptions.output ?? {}, this.bundleOptions[chunk.name]?.output ?? {}),
|
|
100
122
|
sourcemap: false,
|
|
101
|
-
file:
|
|
123
|
+
file: join(this.dist, originalFileName),
|
|
102
124
|
})
|
|
103
125
|
|
|
104
126
|
// Log successful build
|
|
105
|
-
const { size } = await stat(join(this.dist,
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
console.log(`${
|
|
111
|
-
|
|
112
|
-
// Keep track of modified chunks
|
|
113
|
-
modifiedChunkNames.push(chunk.name)
|
|
114
|
-
|
|
115
|
-
// Cache rebundled code
|
|
116
|
-
this.rebundled[chunk.fileName] = result.output[0].code
|
|
127
|
+
const { size } = await stat(join(this.dist, originalFileName))
|
|
128
|
+
const $dist = chalk.dim(`${this.dist}/`)
|
|
129
|
+
const $fileName = chalk.cyan(originalFileName)
|
|
130
|
+
const $rebundle = chalk.dim.cyan('[rebundle]')
|
|
131
|
+
const $size = chalk.bold.dim(`${filesize(size)}`)
|
|
132
|
+
console.log(`${$dist}${$fileName} ${$rebundle} ${$size}`)
|
|
117
133
|
}),
|
|
118
134
|
)
|
|
119
135
|
|
|
120
|
-
for (const
|
|
121
|
-
// Process chunks only
|
|
122
|
-
const chunk = chunkOrAsset.type === 'chunk' ? chunkOrAsset : null
|
|
123
|
-
if (!chunk) continue
|
|
124
|
-
|
|
136
|
+
for (const chunk of this.getChunks(bundle)) {
|
|
125
137
|
// Save original chunk code
|
|
126
|
-
this.originals[chunk.fileName] = chunk.code
|
|
127
|
-
|
|
128
|
-
// Delete chunk from the `bundle` to hide log for `rolldown-vite`. Call for `rollup` for consistency.
|
|
129
|
-
delete bundle[chunk.fileName]
|
|
138
|
+
this.originals[this.unprefixed(chunk.fileName)] = chunk.code
|
|
130
139
|
|
|
131
|
-
//
|
|
132
|
-
if (
|
|
133
|
-
await this.removeFromDist(chunk.fileName)
|
|
134
|
-
}
|
|
140
|
+
// Delete chunk from the bundle to hide Vite's output log
|
|
141
|
+
if (this.isRolldownVite) delete bundle[chunk.fileName]
|
|
135
142
|
}
|
|
136
143
|
|
|
144
|
+
// Remove folder with original chunks
|
|
145
|
+
await rm(join(this.dist, this.ORIGINALS_DIR), { recursive: true })
|
|
146
|
+
|
|
137
147
|
// Notify about modified chunks
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
ws.clients.forEach(client => client.send(JSON.stringify(modifiedChunkNames)))
|
|
148
|
+
if (this.ws && modifiedEntryChunks.length > 0) {
|
|
149
|
+
const names = modifiedEntryChunks.map(chunk => chunk.name)
|
|
150
|
+
this.ws.clients.forEach(client => client.send(JSON.stringify(names)))
|
|
142
151
|
}
|
|
143
152
|
}
|
|
144
153
|
|
|
@@ -151,25 +160,22 @@ export class Rebundle {
|
|
|
151
160
|
return this.config.build.outDir
|
|
152
161
|
}
|
|
153
162
|
|
|
154
|
-
private
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
163
|
+
private prefixed(path: string) {
|
|
164
|
+
return join(this.ORIGINALS_DIR, path)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private unprefixed(path: string) {
|
|
168
|
+
return path.replace(`${this.ORIGINALS_DIR}/`, '')
|
|
159
169
|
}
|
|
160
170
|
|
|
161
|
-
private
|
|
162
|
-
|
|
163
|
-
if (!this.port) throw 'never'
|
|
164
|
-
this.ws = new WebSocketServer({ port: this.port })
|
|
165
|
-
return this.ws
|
|
171
|
+
private getChunks(bundle: OutputBundle) {
|
|
172
|
+
return Object.values(bundle).filter(item => item.type === 'chunk')
|
|
166
173
|
}
|
|
167
174
|
|
|
168
|
-
private
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
await this.removeDirectoryIfEmpty(dirname(dir))
|
|
175
|
+
private getEntryChunks(bundle: OutputBundle) {
|
|
176
|
+
return Object.values(bundle)
|
|
177
|
+
.filter(item => item.type === 'chunk')
|
|
178
|
+
.filter(chunk => chunk.isEntry)
|
|
173
179
|
}
|
|
174
180
|
|
|
175
181
|
private merge(obj1: Record<string, any>, obj2: Record<string, any>) {
|