robuild 0.0.20 → 0.1.1
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/_chunks/build-BKisdK3B.mjs +3 -0
- package/dist/_chunks/{build-ZNO1BJMb.mjs → build-D6PKwgm3.mjs} +561 -510
- package/dist/_chunks/manager-CnmjrU85.mjs +3 -0
- package/dist/_chunks/{plugin-manager-CwMXjVtp.mjs → manager-DyYf90Z5.mjs} +1 -1
- package/dist/_chunks/{package-CspMOSID.mjs → package-BJHhPF4v.mjs} +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/config.d.mts +1 -1
- package/dist/index.d.mts +173 -13
- package/dist/index.mjs +387 -86
- package/package.json +1 -1
- package/dist/_chunks/build-B-lzI2ff.mjs +0 -3
- package/dist/_chunks/plugin-manager-pCQvlo7q.mjs +0 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as RobuildPluginManager } from "./
|
|
1
|
+
import { t as RobuildPluginManager } from "./manager-DyYf90Z5.mjs";
|
|
2
2
|
import { builtinModules } from "node:module";
|
|
3
3
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import { colors } from "consola/utils";
|
|
@@ -9,19 +9,19 @@ import { parseSync } from "oxc-parser";
|
|
|
9
9
|
import { rolldown, watch } from "rolldown";
|
|
10
10
|
import { dts } from "rolldown-plugin-dts";
|
|
11
11
|
import { existsSync, promises, readdirSync, statSync } from "node:fs";
|
|
12
|
-
import { consola } from "consola";
|
|
13
12
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
14
13
|
import { gzipSync } from "node:zlib";
|
|
15
14
|
import { minify } from "oxc-minify";
|
|
16
|
-
import {
|
|
15
|
+
import { consola } from "consola";
|
|
17
16
|
import { createHash } from "node:crypto";
|
|
17
|
+
import { glob } from "glob";
|
|
18
18
|
import MagicString from "magic-string";
|
|
19
19
|
import { transform } from "oxc-transform";
|
|
20
20
|
import { glob as glob$1 } from "tinyglobby";
|
|
21
21
|
import { exec } from "node:child_process";
|
|
22
22
|
import { promisify } from "node:util";
|
|
23
23
|
|
|
24
|
-
//#region src/
|
|
24
|
+
//#region src/core/logger.ts
|
|
25
25
|
/**
|
|
26
26
|
* Logger instance with configurable log level
|
|
27
27
|
*/
|
|
@@ -110,171 +110,199 @@ function shouldFailOnWarnings(failOnWarn) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
//#endregion
|
|
113
|
-
//#region src/
|
|
113
|
+
//#region src/utils/extensions.ts
|
|
114
114
|
/**
|
|
115
|
-
*
|
|
115
|
+
* Get file extension for a given format (with leading dot).
|
|
116
|
+
* This is the unified function used by bundle, watch, and transform modes.
|
|
117
|
+
*
|
|
118
|
+
* @param format - The module format (es, cjs, iife, umd, etc.)
|
|
119
|
+
* @param platform - The target platform
|
|
120
|
+
* @param fixedExtension - Whether to force .cjs/.mjs extensions
|
|
121
|
+
* @returns The file extension with leading dot (e.g., '.mjs', '.cjs', '.js')
|
|
116
122
|
*/
|
|
117
|
-
function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
resolveId: async (id, importer) => {
|
|
130
|
-
if (shouldInline(id)) return null;
|
|
131
|
-
if (!importer) return null;
|
|
132
|
-
if (id.includes("node_modules") || !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\\")) return {
|
|
133
|
-
id,
|
|
134
|
-
external: true
|
|
135
|
-
};
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
};
|
|
123
|
+
function getFormatExtension(format, platform = "node", fixedExtension = false) {
|
|
124
|
+
if (fixedExtension) return format === "cjs" || format === "commonjs" ? ".cjs" : ".mjs";
|
|
125
|
+
switch (format) {
|
|
126
|
+
case "es":
|
|
127
|
+
case "esm":
|
|
128
|
+
case "module": return ".mjs";
|
|
129
|
+
case "cjs":
|
|
130
|
+
case "commonjs": return platform === "node" ? ".cjs" : ".js";
|
|
131
|
+
case "iife":
|
|
132
|
+
case "umd": return ".js";
|
|
133
|
+
default: return ".js";
|
|
134
|
+
}
|
|
139
135
|
}
|
|
140
136
|
/**
|
|
141
|
-
*
|
|
137
|
+
* Resolve JavaScript output extension (without leading dot).
|
|
138
|
+
* @deprecated Use getFormatExtension() instead for consistency
|
|
142
139
|
*/
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
function resolveJsOutputExtension(format, platform = "node", fixedExtension = false) {
|
|
141
|
+
if (fixedExtension) return format === "cjs" ? "cjs" : "mjs";
|
|
142
|
+
switch (format) {
|
|
143
|
+
case "es": return platform === "browser" ? "js" : "mjs";
|
|
144
|
+
case "cjs": return platform === "browser" ? "js" : "cjs";
|
|
145
|
+
case "iife":
|
|
146
|
+
case "umd": return "js";
|
|
147
|
+
default: return "js";
|
|
148
|
+
}
|
|
145
149
|
}
|
|
146
150
|
/**
|
|
147
|
-
*
|
|
151
|
+
* Resolve DTS output extension
|
|
148
152
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (entry.skipNodeModules && dirEntry.name === "node_modules") continue;
|
|
156
|
-
await mkdir(dirname(outputPath), { recursive: true });
|
|
157
|
-
await processDirectoryUnbundled(inputPath, outputPath, entry);
|
|
158
|
-
} else if (dirEntry.isFile()) await processFileUnbundled(inputPath, outputPath, entry);
|
|
153
|
+
function resolveDtsOutputExtension(format, fixedExtension = false) {
|
|
154
|
+
if (fixedExtension) return format === "cjs" ? "d.cts" : "d.mts";
|
|
155
|
+
switch (format) {
|
|
156
|
+
case "es": return "d.mts";
|
|
157
|
+
case "cjs": return "d.cts";
|
|
158
|
+
default: return "d.ts";
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
/**
|
|
162
|
-
*
|
|
162
|
+
* Apply custom output extensions
|
|
163
163
|
*/
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
164
|
+
function applyOutExtensions(format, outExtensions) {
|
|
165
|
+
const defaultJs = resolveJsOutputExtension(format);
|
|
166
|
+
const defaultDts = resolveDtsOutputExtension(format);
|
|
167
|
+
if (!outExtensions) return {
|
|
168
|
+
js: defaultJs,
|
|
169
|
+
dts: defaultDts
|
|
170
|
+
};
|
|
171
|
+
const custom = outExtensions(format);
|
|
172
|
+
return {
|
|
173
|
+
js: custom.js || defaultJs,
|
|
174
|
+
dts: custom.dts || defaultDts
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Create filename with proper extension
|
|
179
|
+
*/
|
|
180
|
+
function createFilename(basename, format, isDts = false, options = {}) {
|
|
181
|
+
const { platform, fixedExtension, outExtensions } = options;
|
|
182
|
+
if (outExtensions) {
|
|
183
|
+
const extensions = applyOutExtensions(format, outExtensions);
|
|
184
|
+
return `${basename}.${isDts ? extensions.dts : extensions.js}`;
|
|
184
185
|
}
|
|
186
|
+
if (isDts) return `${basename}.${resolveDtsOutputExtension(format, fixedExtension)}`;
|
|
187
|
+
return `${basename}.${resolveJsOutputExtension(format, platform, fixedExtension)}`;
|
|
185
188
|
}
|
|
189
|
+
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/utils/hash.ts
|
|
186
192
|
/**
|
|
187
|
-
*
|
|
193
|
+
* Generate content hash for filename
|
|
188
194
|
*/
|
|
189
|
-
function
|
|
190
|
-
|
|
191
|
-
transformedContent = transformedContent.replace(/from\s+['"]([^'"]+)['"]/g, (match, importPath) => {
|
|
192
|
-
if (importPath.startsWith(".")) {
|
|
193
|
-
const newImportPath = updateImportExtension(importPath, entry);
|
|
194
|
-
return match.replace(importPath, newImportPath);
|
|
195
|
-
}
|
|
196
|
-
return match;
|
|
197
|
-
});
|
|
198
|
-
transformedContent = transformedContent.replace(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, (match, importPath) => {
|
|
199
|
-
if (importPath.startsWith(".")) {
|
|
200
|
-
const newImportPath = updateImportExtension(importPath, entry);
|
|
201
|
-
return match.replace(importPath, newImportPath);
|
|
202
|
-
}
|
|
203
|
-
return match;
|
|
204
|
-
});
|
|
205
|
-
return transformedContent;
|
|
195
|
+
function generateContentHash(content, length = 8) {
|
|
196
|
+
return createHash("sha256").update(content).digest("hex").slice(0, length);
|
|
206
197
|
}
|
|
207
198
|
/**
|
|
208
|
-
*
|
|
199
|
+
* Add hash to filename
|
|
209
200
|
*/
|
|
210
|
-
function
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
if (
|
|
214
|
-
|
|
215
|
-
".tsx",
|
|
216
|
-
".mts",
|
|
217
|
-
".cts"
|
|
218
|
-
].includes(ext)) {
|
|
219
|
-
const newExt = getUnbundleOutputExtension(ext, entry);
|
|
220
|
-
return importPath.replace(ext, newExt);
|
|
221
|
-
}
|
|
222
|
-
return importPath;
|
|
201
|
+
function addHashToFilename(filename, content, hashLength = 8) {
|
|
202
|
+
const hash = generateContentHash(content, hashLength);
|
|
203
|
+
const dotIndex = filename.lastIndexOf(".");
|
|
204
|
+
if (dotIndex === -1) return `${filename}-${hash}`;
|
|
205
|
+
return `${filename.slice(0, dotIndex)}-${hash}${filename.slice(dotIndex)}`;
|
|
223
206
|
}
|
|
224
207
|
/**
|
|
225
|
-
*
|
|
208
|
+
* Check if filename already has hash
|
|
226
209
|
*/
|
|
227
|
-
function
|
|
228
|
-
|
|
229
|
-
switch (inputExt) {
|
|
230
|
-
case ".ts":
|
|
231
|
-
case ".tsx": return format === "cjs" ? ".cjs" : ".mjs";
|
|
232
|
-
case ".mts": return ".mjs";
|
|
233
|
-
case ".cts": return ".cjs";
|
|
234
|
-
case ".js":
|
|
235
|
-
case ".jsx": return format === "cjs" ? ".cjs" : ".mjs";
|
|
236
|
-
case ".mjs": return ".mjs";
|
|
237
|
-
case ".cjs": return ".cjs";
|
|
238
|
-
default: return ".js";
|
|
239
|
-
}
|
|
210
|
+
function hasHash(filename) {
|
|
211
|
+
return /-[a-f0-9]{8}(?:\.|$)/.test(filename);
|
|
240
212
|
}
|
|
241
213
|
|
|
242
214
|
//#endregion
|
|
243
|
-
//#region src/
|
|
215
|
+
//#region src/utils/node-protocol.ts
|
|
244
216
|
/**
|
|
245
|
-
*
|
|
217
|
+
* Node.js built-in modules that support the node: protocol
|
|
246
218
|
*/
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
219
|
+
const NODE_BUILTIN_MODULES = new Set([
|
|
220
|
+
"assert",
|
|
221
|
+
"async_hooks",
|
|
222
|
+
"buffer",
|
|
223
|
+
"child_process",
|
|
224
|
+
"cluster",
|
|
225
|
+
"console",
|
|
226
|
+
"constants",
|
|
227
|
+
"crypto",
|
|
228
|
+
"dgram",
|
|
229
|
+
"diagnostics_channel",
|
|
230
|
+
"dns",
|
|
231
|
+
"domain",
|
|
232
|
+
"events",
|
|
233
|
+
"fs",
|
|
234
|
+
"http",
|
|
235
|
+
"http2",
|
|
236
|
+
"https",
|
|
237
|
+
"inspector",
|
|
238
|
+
"module",
|
|
239
|
+
"net",
|
|
240
|
+
"os",
|
|
241
|
+
"path",
|
|
242
|
+
"perf_hooks",
|
|
243
|
+
"process",
|
|
244
|
+
"punycode",
|
|
245
|
+
"querystring",
|
|
246
|
+
"readline",
|
|
247
|
+
"repl",
|
|
248
|
+
"stream",
|
|
249
|
+
"string_decoder",
|
|
250
|
+
"sys",
|
|
251
|
+
"timers",
|
|
252
|
+
"tls",
|
|
253
|
+
"trace_events",
|
|
254
|
+
"tty",
|
|
255
|
+
"url",
|
|
256
|
+
"util",
|
|
257
|
+
"v8",
|
|
258
|
+
"vm",
|
|
259
|
+
"wasi",
|
|
260
|
+
"worker_threads",
|
|
261
|
+
"zlib"
|
|
262
|
+
]);
|
|
263
|
+
/**
|
|
264
|
+
* Check if a module is a Node.js built-in module
|
|
265
|
+
*/
|
|
266
|
+
function isNodeBuiltin(id) {
|
|
267
|
+
const cleanId = id.startsWith("node:") ? id.slice(5) : id;
|
|
268
|
+
return NODE_BUILTIN_MODULES.has(cleanId);
|
|
251
269
|
}
|
|
252
270
|
/**
|
|
253
|
-
* Add
|
|
271
|
+
* Add node: prefix to built-in modules
|
|
254
272
|
*/
|
|
255
|
-
function
|
|
256
|
-
if (
|
|
257
|
-
return
|
|
273
|
+
function addNodeProtocol(id) {
|
|
274
|
+
if (id.startsWith("node:")) return id;
|
|
275
|
+
if (isNodeBuiltin(id)) return `node:${id}`;
|
|
276
|
+
return id;
|
|
258
277
|
}
|
|
259
278
|
/**
|
|
260
|
-
*
|
|
279
|
+
* Remove node: prefix from modules
|
|
261
280
|
*/
|
|
262
|
-
function
|
|
263
|
-
if (
|
|
264
|
-
return
|
|
281
|
+
function stripNodeProtocol(id) {
|
|
282
|
+
if (id.startsWith("node:")) return id.slice(5);
|
|
283
|
+
return id;
|
|
265
284
|
}
|
|
266
285
|
/**
|
|
267
|
-
*
|
|
286
|
+
* Process module ID based on nodeProtocol setting
|
|
268
287
|
*/
|
|
269
|
-
function
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
288
|
+
function processNodeProtocol(id, nodeProtocol) {
|
|
289
|
+
if (nodeProtocol === "strip") return stripNodeProtocol(id);
|
|
290
|
+
if (nodeProtocol === true) return addNodeProtocol(id);
|
|
291
|
+
return id;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Transform import/export statements to handle node protocol
|
|
295
|
+
*/
|
|
296
|
+
function transformNodeProtocol(code, nodeProtocol) {
|
|
297
|
+
if (!nodeProtocol) return code;
|
|
298
|
+
return code.replace(/(?:import|export)(?:\s[^'"]*)?\s['"]([^'"]+)['"]/g, (match, moduleId) => {
|
|
299
|
+
const processedId = processNodeProtocol(moduleId, nodeProtocol);
|
|
300
|
+
return match.replace(moduleId, processedId);
|
|
301
|
+
});
|
|
274
302
|
}
|
|
275
303
|
|
|
276
304
|
//#endregion
|
|
277
|
-
//#region src/utils.ts
|
|
305
|
+
//#region src/utils/index.ts
|
|
278
306
|
/**
|
|
279
307
|
* Normalize a path to an absolute path.
|
|
280
308
|
* Handles string paths, URL objects, and undefined values.
|
|
@@ -334,7 +362,7 @@ async function distSize(dir, entry) {
|
|
|
334
362
|
plugins: [],
|
|
335
363
|
platform: "neutral",
|
|
336
364
|
external: (id) => id[0] !== "." && !id.startsWith(dir)
|
|
337
|
-
})).generate({
|
|
365
|
+
})).generate({ codeSplitting: false });
|
|
338
366
|
const code = output[0].code;
|
|
339
367
|
const { code: minified } = await minify(entry, code);
|
|
340
368
|
return {
|
|
@@ -361,212 +389,77 @@ async function sideEffectSize(dir, entry) {
|
|
|
361
389
|
if (id === "#entry") return `import * as _lib from "${join(dir, entry)}";`;
|
|
362
390
|
}
|
|
363
391
|
}]
|
|
364
|
-
})).generate({
|
|
365
|
-
if (process.env.INSPECT_BUILD) {
|
|
366
|
-
logger.debug("---------[side effects]---------");
|
|
367
|
-
logger.debug(entry);
|
|
368
|
-
logger.debug(output[0].code);
|
|
369
|
-
logger.debug("-------------------------------");
|
|
370
|
-
}
|
|
371
|
-
return Buffer.byteLength(output[0].code.trim());
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
//#endregion
|
|
375
|
-
//#region src/features/clean.ts
|
|
376
|
-
/**
|
|
377
|
-
* Clean output directory or specific paths.
|
|
378
|
-
* Used by both bundle and transform builders.
|
|
379
|
-
*
|
|
380
|
-
* @param projectRoot - The project root directory
|
|
381
|
-
* @param outDir - The output directory to clean
|
|
382
|
-
* @param cleanPaths - true to clean outDir, or array of specific paths to clean
|
|
383
|
-
*/
|
|
384
|
-
async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
|
|
385
|
-
if (!cleanPaths) return;
|
|
386
|
-
if (cleanPaths === true) {
|
|
387
|
-
if (existsSync(outDir)) {
|
|
388
|
-
logger.log(colors.dim(`Cleaning ${fmtPath(outDir)}`));
|
|
389
|
-
await rm(outDir, {
|
|
390
|
-
recursive: true,
|
|
391
|
-
force: true
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
} else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
|
|
395
|
-
const fullPath = resolve(projectRoot, path);
|
|
396
|
-
if (existsSync(fullPath)) {
|
|
397
|
-
logger.log(colors.dim(`Cleaning ${fmtPath(fullPath)}`));
|
|
398
|
-
await rm(fullPath, {
|
|
399
|
-
recursive: true,
|
|
400
|
-
force: true
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
//#endregion
|
|
407
|
-
//#region src/features/copy.ts
|
|
408
|
-
/**
|
|
409
|
-
* Copy files to output directory
|
|
410
|
-
*/
|
|
411
|
-
async function copyFiles(cwd, outDir, copyOptions) {
|
|
412
|
-
if (!copyOptions || copyOptions.length === 0) return;
|
|
413
|
-
logger.verbose("Copying files...");
|
|
414
|
-
await Promise.all(copyOptions.map(async (entry) => {
|
|
415
|
-
const from = typeof entry === "string" ? entry : entry.from;
|
|
416
|
-
const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
|
|
417
|
-
const fromPath = resolve(cwd, from);
|
|
418
|
-
try {
|
|
419
|
-
await cp(fromPath, to, {
|
|
420
|
-
recursive: true,
|
|
421
|
-
force: true
|
|
422
|
-
});
|
|
423
|
-
logger.verbose(` ${from} → ${to}`);
|
|
424
|
-
} catch (error) {
|
|
425
|
-
logger.warn(`Failed to copy ${from} to ${to}:`, error);
|
|
426
|
-
}
|
|
427
|
-
}));
|
|
428
|
-
logger.verbose("Files copied successfully");
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
//#endregion
|
|
432
|
-
//#region src/features/entry-resolver.ts
|
|
433
|
-
/**
|
|
434
|
-
* Parse a string entry format like "src/index.ts:dist" or "src/:dist"
|
|
435
|
-
*
|
|
436
|
-
* @param rawEntry - The raw string entry
|
|
437
|
-
* @returns Parsed entry object
|
|
438
|
-
*/
|
|
439
|
-
function parseEntryString(rawEntry) {
|
|
440
|
-
const [input, outDir] = rawEntry.split(":");
|
|
441
|
-
if (input.endsWith("/")) return {
|
|
442
|
-
type: "transform",
|
|
443
|
-
input,
|
|
444
|
-
outDir: outDir || "dist"
|
|
445
|
-
};
|
|
446
|
-
return {
|
|
447
|
-
type: "bundle",
|
|
448
|
-
input: input.includes(",") ? input.split(",") : input,
|
|
449
|
-
outDir: outDir || "dist"
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
* Normalize entry input paths to absolute paths.
|
|
454
|
-
* Handles string, array, and object (named entries) formats.
|
|
455
|
-
*
|
|
456
|
-
* @param entryInput - The entry input (string, array, or object)
|
|
457
|
-
* @param pkgDir - The package directory to resolve paths from
|
|
458
|
-
* @returns Normalized input
|
|
459
|
-
*/
|
|
460
|
-
function normalizeEntryInput(entryInput, pkgDir) {
|
|
461
|
-
if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
|
|
462
|
-
const normalizedInput = {};
|
|
463
|
-
for (const [key, value] of Object.entries(entryInput)) normalizedInput[key] = normalizePath(value, pkgDir);
|
|
464
|
-
return normalizedInput;
|
|
465
|
-
}
|
|
466
|
-
if (Array.isArray(entryInput)) return entryInput.map((p) => normalizePath(p, pkgDir));
|
|
467
|
-
return normalizePath(entryInput, pkgDir);
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Get the entry input from a BundleEntry, supporting both 'input' and 'entry' fields.
|
|
471
|
-
* This provides tsup compatibility.
|
|
472
|
-
*
|
|
473
|
-
* @param entry - The bundle entry
|
|
474
|
-
* @returns The entry input or undefined
|
|
475
|
-
*/
|
|
476
|
-
function getBundleEntryInput(entry) {
|
|
477
|
-
return entry.input || entry.entry;
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Check if an entry has valid input.
|
|
481
|
-
*
|
|
482
|
-
* @param entry - The entry to check
|
|
483
|
-
* @returns true if the entry has valid input
|
|
484
|
-
*/
|
|
485
|
-
function hasValidInput(entry) {
|
|
486
|
-
if (entry.type === "transform") return !!entry.input;
|
|
487
|
-
return !!getBundleEntryInput(entry);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
//#endregion
|
|
491
|
-
//#region src/features/extensions.ts
|
|
492
|
-
/**
|
|
493
|
-
* Get file extension for a given format (with leading dot).
|
|
494
|
-
* This is the unified function used by bundle, watch, and transform modes.
|
|
495
|
-
*
|
|
496
|
-
* @param format - The module format (es, cjs, iife, umd, etc.)
|
|
497
|
-
* @param platform - The target platform
|
|
498
|
-
* @param fixedExtension - Whether to force .cjs/.mjs extensions
|
|
499
|
-
* @returns The file extension with leading dot (e.g., '.mjs', '.cjs', '.js')
|
|
500
|
-
*/
|
|
501
|
-
function getFormatExtension(format, platform = "node", fixedExtension = false) {
|
|
502
|
-
if (fixedExtension) return format === "cjs" || format === "commonjs" ? ".cjs" : ".mjs";
|
|
503
|
-
switch (format) {
|
|
504
|
-
case "es":
|
|
505
|
-
case "esm":
|
|
506
|
-
case "module": return ".mjs";
|
|
507
|
-
case "cjs":
|
|
508
|
-
case "commonjs": return platform === "node" ? ".cjs" : ".js";
|
|
509
|
-
case "iife":
|
|
510
|
-
case "umd": return ".js";
|
|
511
|
-
default: return ".js";
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Resolve JavaScript output extension (without leading dot).
|
|
516
|
-
* @deprecated Use getFormatExtension() instead for consistency
|
|
517
|
-
*/
|
|
518
|
-
function resolveJsOutputExtension(format, platform = "node", fixedExtension = false) {
|
|
519
|
-
if (fixedExtension) return format === "cjs" ? "cjs" : "mjs";
|
|
520
|
-
switch (format) {
|
|
521
|
-
case "es": return platform === "browser" ? "js" : "mjs";
|
|
522
|
-
case "cjs": return platform === "browser" ? "js" : "cjs";
|
|
523
|
-
case "iife":
|
|
524
|
-
case "umd": return "js";
|
|
525
|
-
default: return "js";
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
/**
|
|
529
|
-
* Resolve DTS output extension
|
|
530
|
-
*/
|
|
531
|
-
function resolveDtsOutputExtension(format, fixedExtension = false) {
|
|
532
|
-
if (fixedExtension) return format === "cjs" ? "d.cts" : "d.mts";
|
|
533
|
-
switch (format) {
|
|
534
|
-
case "es": return "d.mts";
|
|
535
|
-
case "cjs": return "d.cts";
|
|
536
|
-
default: return "d.ts";
|
|
392
|
+
})).generate({ codeSplitting: false });
|
|
393
|
+
if (process.env.INSPECT_BUILD) {
|
|
394
|
+
logger.debug("---------[side effects]---------");
|
|
395
|
+
logger.debug(entry);
|
|
396
|
+
logger.debug(output[0].code);
|
|
397
|
+
logger.debug("-------------------------------");
|
|
537
398
|
}
|
|
399
|
+
return Buffer.byteLength(output[0].code.trim());
|
|
538
400
|
}
|
|
401
|
+
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/config/entry-resolver.ts
|
|
539
404
|
/**
|
|
540
|
-
*
|
|
405
|
+
* Parse a string entry format like "src/index.ts:dist" or "src/:dist"
|
|
406
|
+
*
|
|
407
|
+
* @param rawEntry - The raw string entry
|
|
408
|
+
* @returns Parsed entry object
|
|
541
409
|
*/
|
|
542
|
-
function
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
410
|
+
function parseEntryString(rawEntry) {
|
|
411
|
+
const [input, outDir] = rawEntry.split(":");
|
|
412
|
+
if (input.endsWith("/")) return {
|
|
413
|
+
type: "transform",
|
|
414
|
+
input,
|
|
415
|
+
outDir: outDir || "dist"
|
|
548
416
|
};
|
|
549
|
-
const custom = outExtensions(format);
|
|
550
417
|
return {
|
|
551
|
-
|
|
552
|
-
|
|
418
|
+
type: "bundle",
|
|
419
|
+
input: input.includes(",") ? input.split(",") : input,
|
|
420
|
+
outDir: outDir || "dist"
|
|
553
421
|
};
|
|
554
422
|
}
|
|
555
423
|
/**
|
|
556
|
-
*
|
|
424
|
+
* Normalize entry input paths to absolute paths.
|
|
425
|
+
* Handles string, array, and object (named entries) formats.
|
|
426
|
+
*
|
|
427
|
+
* @param entryInput - The entry input (string, array, or object)
|
|
428
|
+
* @param pkgDir - The package directory to resolve paths from
|
|
429
|
+
* @returns Normalized input
|
|
557
430
|
*/
|
|
558
|
-
function
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
const
|
|
562
|
-
return
|
|
431
|
+
function normalizeEntryInput(entryInput, pkgDir) {
|
|
432
|
+
if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
|
|
433
|
+
const normalizedInput = {};
|
|
434
|
+
for (const [key, value] of Object.entries(entryInput)) normalizedInput[key] = normalizePath(value, pkgDir);
|
|
435
|
+
return normalizedInput;
|
|
563
436
|
}
|
|
564
|
-
if (
|
|
565
|
-
return
|
|
437
|
+
if (Array.isArray(entryInput)) return entryInput.map((p) => normalizePath(p, pkgDir));
|
|
438
|
+
return normalizePath(entryInput, pkgDir);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Get the entry input from a BundleEntry, supporting both 'input' and 'entry' fields.
|
|
442
|
+
* This provides tsup compatibility.
|
|
443
|
+
*
|
|
444
|
+
* @param entry - The bundle entry
|
|
445
|
+
* @returns The entry input or undefined
|
|
446
|
+
*/
|
|
447
|
+
function getBundleEntryInput(entry) {
|
|
448
|
+
return entry.input || entry.entry;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Check if an entry has valid input.
|
|
452
|
+
*
|
|
453
|
+
* @param entry - The entry to check
|
|
454
|
+
* @returns true if the entry has valid input
|
|
455
|
+
*/
|
|
456
|
+
function hasValidInput(entry) {
|
|
457
|
+
if (entry.type === "transform") return !!entry.input;
|
|
458
|
+
return !!getBundleEntryInput(entry);
|
|
566
459
|
}
|
|
567
460
|
|
|
568
461
|
//#endregion
|
|
569
|
-
//#region src/
|
|
462
|
+
//#region src/config/external.ts
|
|
570
463
|
/**
|
|
571
464
|
* Build external dependencies list from package.json dependencies and peerDependencies.
|
|
572
465
|
* This is the shared logic used by both bundle and watch modes.
|
|
@@ -648,7 +541,36 @@ function resolveExternalConfig(ctx, options) {
|
|
|
648
541
|
}
|
|
649
542
|
|
|
650
543
|
//#endregion
|
|
651
|
-
//#region src/
|
|
544
|
+
//#region src/plugins/builtin/glob-import.ts
|
|
545
|
+
/**
|
|
546
|
+
* Core transform logic for glob imports
|
|
547
|
+
*/
|
|
548
|
+
async function transformGlobImportCode(code, id, options) {
|
|
549
|
+
const { patterns, asUrls, eager } = options;
|
|
550
|
+
const globImportRegex = /import\.meta\.glob\s*\(\s*(['"`])(.*?)\1\s*(?:,\s*(\{[^}]*\})\s*)?\)/g;
|
|
551
|
+
let match;
|
|
552
|
+
let hasGlobImports = false;
|
|
553
|
+
let transformedCode = code;
|
|
554
|
+
while ((match = globImportRegex.exec(code)) !== null) {
|
|
555
|
+
hasGlobImports = true;
|
|
556
|
+
const [fullMatch, , pattern, optionsStr] = match;
|
|
557
|
+
let globOptions = {};
|
|
558
|
+
if (optionsStr) try {
|
|
559
|
+
globOptions = parseGlobOptions(optionsStr);
|
|
560
|
+
} catch {
|
|
561
|
+
logger.warn("Failed to parse glob options:", optionsStr);
|
|
562
|
+
}
|
|
563
|
+
const isEager = globOptions.eager ?? eager;
|
|
564
|
+
const isAsUrls = globOptions.as === "url" || asUrls;
|
|
565
|
+
try {
|
|
566
|
+
const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
|
|
567
|
+
transformedCode = transformedCode.replace(fullMatch, replacement);
|
|
568
|
+
} catch (error) {
|
|
569
|
+
logger.error(`Failed to process glob import ${pattern}:`, error);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return hasGlobImports ? transformedCode : null;
|
|
573
|
+
}
|
|
652
574
|
/**
|
|
653
575
|
* Create a glob import plugin for robuild
|
|
654
576
|
*/
|
|
@@ -657,30 +579,12 @@ function createGlobImportPlugin(options = {}) {
|
|
|
657
579
|
if (!enabled) return { name: "glob-import-disabled" };
|
|
658
580
|
return {
|
|
659
581
|
name: "glob-import",
|
|
660
|
-
transform: async (code, id) => {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
hasGlobImports = true;
|
|
667
|
-
const [fullMatch, , pattern, optionsStr] = match;
|
|
668
|
-
let globOptions = {};
|
|
669
|
-
if (optionsStr) try {
|
|
670
|
-
globOptions = parseGlobOptions(optionsStr);
|
|
671
|
-
} catch {
|
|
672
|
-
logger.warn("Failed to parse glob options:", optionsStr);
|
|
673
|
-
}
|
|
674
|
-
const isEager = globOptions.eager ?? eager;
|
|
675
|
-
const isAsUrls = globOptions.as === "url" || asUrls;
|
|
676
|
-
try {
|
|
677
|
-
const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
|
|
678
|
-
transformedCode = transformedCode.replace(fullMatch, replacement);
|
|
679
|
-
} catch (error) {
|
|
680
|
-
logger.error(`Failed to process glob import ${pattern}:`, error);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
return hasGlobImports ? transformedCode : null;
|
|
582
|
+
transform: async (code, id, _meta) => {
|
|
583
|
+
return transformGlobImportCode(code, id, {
|
|
584
|
+
patterns,
|
|
585
|
+
asUrls,
|
|
586
|
+
eager
|
|
587
|
+
});
|
|
684
588
|
}
|
|
685
589
|
};
|
|
686
590
|
}
|
|
@@ -753,33 +657,54 @@ function parseGlobOptions(optionsStr) {
|
|
|
753
657
|
if (asMatch) options.as = asMatch[1];
|
|
754
658
|
return options;
|
|
755
659
|
}
|
|
756
|
-
|
|
757
|
-
//#endregion
|
|
758
|
-
//#region src/features/hash.ts
|
|
759
660
|
/**
|
|
760
|
-
*
|
|
661
|
+
* Check if code contains glob imports
|
|
761
662
|
*/
|
|
762
|
-
function
|
|
763
|
-
return
|
|
663
|
+
function hasGlobImports(code) {
|
|
664
|
+
return /import\.meta\.glob\s*\(/.test(code);
|
|
764
665
|
}
|
|
666
|
+
|
|
667
|
+
//#endregion
|
|
668
|
+
//#region src/plugins/builtin/node-protocol.ts
|
|
765
669
|
/**
|
|
766
|
-
*
|
|
670
|
+
* Rolldown plugin for Node.js protocol handling
|
|
767
671
|
*/
|
|
768
|
-
function
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
672
|
+
function nodeProtocolPlugin(nodeProtocol) {
|
|
673
|
+
if (!nodeProtocol) return { name: "node-protocol-noop" };
|
|
674
|
+
return {
|
|
675
|
+
name: "node-protocol",
|
|
676
|
+
renderChunk(code) {
|
|
677
|
+
return {
|
|
678
|
+
code: transformNodeProtocol(code, nodeProtocol),
|
|
679
|
+
map: null
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
};
|
|
773
683
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
684
|
+
|
|
685
|
+
//#endregion
|
|
686
|
+
//#region src/plugins/builtin/shebang.ts
|
|
687
|
+
const SHEBANG_RE = /^#![^\n]*/;
|
|
688
|
+
function shebangPlugin() {
|
|
689
|
+
return {
|
|
690
|
+
name: "robuild-shebang",
|
|
691
|
+
async writeBundle(options, bundle) {
|
|
692
|
+
for (const [fileName, output] of Object.entries(bundle)) {
|
|
693
|
+
if (output.type !== "chunk") continue;
|
|
694
|
+
if (hasShebang(output.code)) await makeExecutable(resolve(options.dir, fileName));
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
function hasShebang(code) {
|
|
700
|
+
return SHEBANG_RE.test(code);
|
|
701
|
+
}
|
|
702
|
+
async function makeExecutable(filePath) {
|
|
703
|
+
await promises.chmod(filePath, 493).catch(() => {});
|
|
779
704
|
}
|
|
780
705
|
|
|
781
706
|
//#endregion
|
|
782
|
-
//#region src/
|
|
707
|
+
//#region src/plugins/builtin/shims.ts
|
|
783
708
|
/**
|
|
784
709
|
* Default shims configuration
|
|
785
710
|
*/
|
|
@@ -893,134 +818,155 @@ function createShimsPlugin(config = true) {
|
|
|
893
818
|
}
|
|
894
819
|
};
|
|
895
820
|
}
|
|
896
|
-
|
|
897
|
-
//#endregion
|
|
898
|
-
//#region src/features/node-protocol.ts
|
|
899
821
|
/**
|
|
900
|
-
*
|
|
822
|
+
* Create browser-specific shims plugin
|
|
901
823
|
*/
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
"diagnostics_channel",
|
|
913
|
-
"dns",
|
|
914
|
-
"domain",
|
|
915
|
-
"events",
|
|
916
|
-
"fs",
|
|
917
|
-
"http",
|
|
918
|
-
"http2",
|
|
919
|
-
"https",
|
|
920
|
-
"inspector",
|
|
921
|
-
"module",
|
|
922
|
-
"net",
|
|
923
|
-
"os",
|
|
924
|
-
"path",
|
|
925
|
-
"perf_hooks",
|
|
926
|
-
"process",
|
|
927
|
-
"punycode",
|
|
928
|
-
"querystring",
|
|
929
|
-
"readline",
|
|
930
|
-
"repl",
|
|
931
|
-
"stream",
|
|
932
|
-
"string_decoder",
|
|
933
|
-
"sys",
|
|
934
|
-
"timers",
|
|
935
|
-
"tls",
|
|
936
|
-
"trace_events",
|
|
937
|
-
"tty",
|
|
938
|
-
"url",
|
|
939
|
-
"util",
|
|
940
|
-
"v8",
|
|
941
|
-
"vm",
|
|
942
|
-
"wasi",
|
|
943
|
-
"worker_threads",
|
|
944
|
-
"zlib"
|
|
945
|
-
]);
|
|
824
|
+
function createBrowserShimsPlugin() {
|
|
825
|
+
return {
|
|
826
|
+
name: "browser-shims",
|
|
827
|
+
transform: async (code, id) => {
|
|
828
|
+
if (!/\.(?:js|mjs|jsx|tsx?)$/.test(id)) return null;
|
|
829
|
+
if (detectShimNeeds(code).needsEnv) return `${PROCESS_ENV_SHIM}\n${code}`;
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
}
|
|
946
834
|
/**
|
|
947
|
-
*
|
|
835
|
+
* Create Node.js-specific shims plugin
|
|
948
836
|
*/
|
|
949
|
-
function
|
|
950
|
-
|
|
951
|
-
|
|
837
|
+
function createNodeShimsPlugin() {
|
|
838
|
+
return {
|
|
839
|
+
name: "node-shims",
|
|
840
|
+
transform: async (code, id) => {
|
|
841
|
+
if (!/\.mjs$/.test(id) && !/\.js$/.test(id)) return null;
|
|
842
|
+
const needs = detectShimNeeds(code);
|
|
843
|
+
const shims = [];
|
|
844
|
+
if (needs.needsDirname || needs.needsRequire) shims.push(NODE_GLOBALS_SHIM);
|
|
845
|
+
if (needs.needsExports) shims.push(MODULE_EXPORTS_SHIM);
|
|
846
|
+
if (shims.length === 0) return null;
|
|
847
|
+
return `${shims.join("\n")}\n${code}`;
|
|
848
|
+
}
|
|
849
|
+
};
|
|
952
850
|
}
|
|
851
|
+
|
|
852
|
+
//#endregion
|
|
853
|
+
//#region src/plugins/builtin/skip-node-modules.ts
|
|
953
854
|
/**
|
|
954
|
-
*
|
|
855
|
+
* Create skip node_modules plugin
|
|
955
856
|
*/
|
|
956
|
-
function
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
857
|
+
function createSkipNodeModulesPlugin(options) {
|
|
858
|
+
const noExternalPatterns = options?.noExternal || [];
|
|
859
|
+
const shouldInline = (id) => {
|
|
860
|
+
for (const pattern of noExternalPatterns) if (typeof pattern === "string") {
|
|
861
|
+
if (id === pattern || id.startsWith(`${pattern}/`)) return true;
|
|
862
|
+
} else if (pattern instanceof RegExp) {
|
|
863
|
+
if (pattern.test(id)) return true;
|
|
864
|
+
}
|
|
865
|
+
return false;
|
|
866
|
+
};
|
|
867
|
+
return {
|
|
868
|
+
name: "skip-node-modules",
|
|
869
|
+
resolveId: async (id, importer) => {
|
|
870
|
+
if (shouldInline(id)) return null;
|
|
871
|
+
if (!importer) return null;
|
|
872
|
+
if (id.includes("node_modules") || !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\\")) return {
|
|
873
|
+
id,
|
|
874
|
+
external: true
|
|
875
|
+
};
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
};
|
|
960
879
|
}
|
|
880
|
+
|
|
881
|
+
//#endregion
|
|
882
|
+
//#region src/transforms/banner.ts
|
|
961
883
|
/**
|
|
962
|
-
*
|
|
884
|
+
* Resolve banner/footer addon for specific format
|
|
963
885
|
*/
|
|
964
|
-
function
|
|
965
|
-
if (
|
|
966
|
-
return
|
|
886
|
+
function resolveChunkAddon(addon, format) {
|
|
887
|
+
if (!addon) return;
|
|
888
|
+
if (typeof addon === "string") return addon;
|
|
889
|
+
return addon[format === "es" ? "js" : format] || addon.js;
|
|
967
890
|
}
|
|
968
891
|
/**
|
|
969
|
-
*
|
|
892
|
+
* Add banner to content
|
|
970
893
|
*/
|
|
971
|
-
function
|
|
972
|
-
if (
|
|
973
|
-
|
|
974
|
-
return id;
|
|
894
|
+
function addBanner(content, banner) {
|
|
895
|
+
if (!banner) return content;
|
|
896
|
+
return `${banner}\n${content}`;
|
|
975
897
|
}
|
|
976
898
|
/**
|
|
977
|
-
*
|
|
899
|
+
* Add footer to content
|
|
978
900
|
*/
|
|
979
|
-
function
|
|
980
|
-
if (!
|
|
981
|
-
return
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
901
|
+
function addFooter(content, footer) {
|
|
902
|
+
if (!footer) return content;
|
|
903
|
+
return `${content}\n${footer}`;
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Add both banner and footer to content
|
|
907
|
+
*/
|
|
908
|
+
function addBannerFooter(content, banner, footer) {
|
|
909
|
+
let result = content;
|
|
910
|
+
result = addBanner(result, banner);
|
|
911
|
+
result = addFooter(result, footer);
|
|
912
|
+
return result;
|
|
985
913
|
}
|
|
986
914
|
|
|
987
915
|
//#endregion
|
|
988
|
-
//#region src/
|
|
916
|
+
//#region src/transforms/clean.ts
|
|
989
917
|
/**
|
|
990
|
-
*
|
|
918
|
+
* Clean output directory or specific paths.
|
|
919
|
+
* Used by both bundle and transform builders.
|
|
920
|
+
*
|
|
921
|
+
* @param projectRoot - The project root directory
|
|
922
|
+
* @param outDir - The output directory to clean
|
|
923
|
+
* @param cleanPaths - true to clean outDir, or array of specific paths to clean
|
|
991
924
|
*/
|
|
992
|
-
function
|
|
993
|
-
if (!
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
};
|
|
925
|
+
async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
|
|
926
|
+
if (!cleanPaths) return;
|
|
927
|
+
if (cleanPaths === true) {
|
|
928
|
+
if (existsSync(outDir)) {
|
|
929
|
+
logger.log(colors.dim(`Cleaning ${fmtPath(outDir)}`));
|
|
930
|
+
await rm(outDir, {
|
|
931
|
+
recursive: true,
|
|
932
|
+
force: true
|
|
933
|
+
});
|
|
1001
934
|
}
|
|
1002
|
-
}
|
|
935
|
+
} else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
|
|
936
|
+
const fullPath = resolve(projectRoot, path);
|
|
937
|
+
if (existsSync(fullPath)) {
|
|
938
|
+
logger.log(colors.dim(`Cleaning ${fmtPath(fullPath)}`));
|
|
939
|
+
await rm(fullPath, {
|
|
940
|
+
recursive: true,
|
|
941
|
+
force: true
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
}
|
|
1003
945
|
}
|
|
1004
946
|
|
|
1005
947
|
//#endregion
|
|
1006
|
-
//#region src/
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
948
|
+
//#region src/transforms/copy.ts
|
|
949
|
+
/**
|
|
950
|
+
* Copy files to output directory
|
|
951
|
+
*/
|
|
952
|
+
async function copyFiles(cwd, outDir, copyOptions) {
|
|
953
|
+
if (!copyOptions || copyOptions.length === 0) return;
|
|
954
|
+
logger.verbose("Copying files...");
|
|
955
|
+
await Promise.all(copyOptions.map(async (entry) => {
|
|
956
|
+
const from = typeof entry === "string" ? entry : entry.from;
|
|
957
|
+
const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
|
|
958
|
+
const fromPath = resolve(cwd, from);
|
|
959
|
+
try {
|
|
960
|
+
await cp(fromPath, to, {
|
|
961
|
+
recursive: true,
|
|
962
|
+
force: true
|
|
963
|
+
});
|
|
964
|
+
logger.verbose(` ${from} → ${to}`);
|
|
965
|
+
} catch (error) {
|
|
966
|
+
logger.warn(`Failed to copy ${from} to ${to}:`, error);
|
|
1016
967
|
}
|
|
1017
|
-
};
|
|
1018
|
-
|
|
1019
|
-
function hasShebang(code) {
|
|
1020
|
-
return SHEBANG_RE.test(code);
|
|
1021
|
-
}
|
|
1022
|
-
async function makeExecutable(filePath) {
|
|
1023
|
-
await promises.chmod(filePath, 493).catch(() => {});
|
|
968
|
+
}));
|
|
969
|
+
logger.verbose("Files copied successfully");
|
|
1024
970
|
}
|
|
1025
971
|
|
|
1026
972
|
//#endregion
|
|
@@ -1253,6 +1199,110 @@ function normalizeBundleInputs(input, ctx) {
|
|
|
1253
1199
|
return inputs;
|
|
1254
1200
|
}
|
|
1255
1201
|
|
|
1202
|
+
//#endregion
|
|
1203
|
+
//#region src/builders/unbundle.ts
|
|
1204
|
+
/**
|
|
1205
|
+
* Unbundle mode: preserve file structure without bundling
|
|
1206
|
+
*/
|
|
1207
|
+
async function unbundleTransform(ctx, entry) {
|
|
1208
|
+
await processDirectoryUnbundled(isAbsolute(entry.input) ? entry.input : join(ctx.pkgDir, entry.input), join(ctx.pkgDir, entry.outDir || "dist"), entry);
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Process directory in unbundle mode
|
|
1212
|
+
*/
|
|
1213
|
+
async function processDirectoryUnbundled(inputDir, outputDir, entry) {
|
|
1214
|
+
const entries = await readdir(inputDir, { withFileTypes: true });
|
|
1215
|
+
for (const dirEntry of entries) {
|
|
1216
|
+
const inputPath = join(inputDir, dirEntry.name);
|
|
1217
|
+
const outputPath = join(outputDir, dirEntry.name);
|
|
1218
|
+
if (dirEntry.isDirectory()) {
|
|
1219
|
+
if (entry.skipNodeModules && dirEntry.name === "node_modules") continue;
|
|
1220
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
1221
|
+
await processDirectoryUnbundled(inputPath, outputPath, entry);
|
|
1222
|
+
} else if (dirEntry.isFile()) await processFileUnbundled(inputPath, outputPath, entry);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Process individual file in unbundle mode
|
|
1227
|
+
*/
|
|
1228
|
+
async function processFileUnbundled(inputPath, outputPath, entry) {
|
|
1229
|
+
const ext = extname(inputPath);
|
|
1230
|
+
if (![
|
|
1231
|
+
".js",
|
|
1232
|
+
".ts",
|
|
1233
|
+
".jsx",
|
|
1234
|
+
".tsx",
|
|
1235
|
+
".mjs",
|
|
1236
|
+
".mts",
|
|
1237
|
+
".cjs",
|
|
1238
|
+
".cts"
|
|
1239
|
+
].includes(ext)) return;
|
|
1240
|
+
try {
|
|
1241
|
+
const transformedContent = transformImportsForUnbundle(await readFile(inputPath, "utf-8"), inputPath, entry);
|
|
1242
|
+
const outputExt = getUnbundleOutputExtension(ext, entry);
|
|
1243
|
+
const finalOutputPath = outputPath.replace(ext, outputExt);
|
|
1244
|
+
await mkdir(dirname(finalOutputPath), { recursive: true });
|
|
1245
|
+
await writeFile(finalOutputPath, transformedContent, "utf-8");
|
|
1246
|
+
} catch (error) {
|
|
1247
|
+
logger.warn(`Failed to process file ${inputPath}:`, error);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Transform imports for unbundle mode
|
|
1252
|
+
*/
|
|
1253
|
+
function transformImportsForUnbundle(content, _filePath, entry) {
|
|
1254
|
+
let transformedContent = content;
|
|
1255
|
+
transformedContent = transformedContent.replace(/from\s+['"]([^'"]+)['"]/g, (match, importPath) => {
|
|
1256
|
+
if (importPath.startsWith(".")) {
|
|
1257
|
+
const newImportPath = updateImportExtension(importPath, entry);
|
|
1258
|
+
return match.replace(importPath, newImportPath);
|
|
1259
|
+
}
|
|
1260
|
+
return match;
|
|
1261
|
+
});
|
|
1262
|
+
transformedContent = transformedContent.replace(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, (match, importPath) => {
|
|
1263
|
+
if (importPath.startsWith(".")) {
|
|
1264
|
+
const newImportPath = updateImportExtension(importPath, entry);
|
|
1265
|
+
return match.replace(importPath, newImportPath);
|
|
1266
|
+
}
|
|
1267
|
+
return match;
|
|
1268
|
+
});
|
|
1269
|
+
return transformedContent;
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Update import extension for unbundle mode
|
|
1273
|
+
*/
|
|
1274
|
+
function updateImportExtension(importPath, entry) {
|
|
1275
|
+
const ext = extname(importPath);
|
|
1276
|
+
if (!ext) return `${importPath}.js`;
|
|
1277
|
+
if ([
|
|
1278
|
+
".ts",
|
|
1279
|
+
".tsx",
|
|
1280
|
+
".mts",
|
|
1281
|
+
".cts"
|
|
1282
|
+
].includes(ext)) {
|
|
1283
|
+
const newExt = getUnbundleOutputExtension(ext, entry);
|
|
1284
|
+
return importPath.replace(ext, newExt);
|
|
1285
|
+
}
|
|
1286
|
+
return importPath;
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Get output extension for unbundle mode
|
|
1290
|
+
*/
|
|
1291
|
+
function getUnbundleOutputExtension(inputExt, entry) {
|
|
1292
|
+
const format = Array.isArray(entry.format) ? entry.format[0] : entry.format || "es";
|
|
1293
|
+
switch (inputExt) {
|
|
1294
|
+
case ".ts":
|
|
1295
|
+
case ".tsx": return format === "cjs" ? ".cjs" : ".mjs";
|
|
1296
|
+
case ".mts": return ".mjs";
|
|
1297
|
+
case ".cts": return ".cjs";
|
|
1298
|
+
case ".js":
|
|
1299
|
+
case ".jsx": return format === "cjs" ? ".cjs" : ".mjs";
|
|
1300
|
+
case ".mjs": return ".mjs";
|
|
1301
|
+
case ".cjs": return ".cjs";
|
|
1302
|
+
default: return ".js";
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1256
1306
|
//#endregion
|
|
1257
1307
|
//#region src/builders/transform.ts
|
|
1258
1308
|
/**
|
|
@@ -1415,44 +1465,7 @@ async function transformModule(entryPath, entry) {
|
|
|
1415
1465
|
}
|
|
1416
1466
|
|
|
1417
1467
|
//#endregion
|
|
1418
|
-
//#region src/
|
|
1419
|
-
const execAsync = promisify(exec);
|
|
1420
|
-
/**
|
|
1421
|
-
* Execute onSuccess callback after successful build
|
|
1422
|
-
*/
|
|
1423
|
-
async function executeOnSuccess(onSuccess, result, cwd) {
|
|
1424
|
-
if (!onSuccess) return;
|
|
1425
|
-
try {
|
|
1426
|
-
if (typeof onSuccess === "string") {
|
|
1427
|
-
logger.verbose(`Executing onSuccess command: ${onSuccess}`);
|
|
1428
|
-
const { stdout, stderr } = await execAsync(onSuccess, { cwd });
|
|
1429
|
-
if (stdout) logger.verbose(`onSuccess stdout: ${stdout.trim()}`);
|
|
1430
|
-
if (stderr) logger.warn(`onSuccess stderr: ${stderr.trim()}`);
|
|
1431
|
-
} else {
|
|
1432
|
-
logger.verbose("Executing onSuccess callback function");
|
|
1433
|
-
await onSuccess(result);
|
|
1434
|
-
}
|
|
1435
|
-
logger.verbose("onSuccess callback completed successfully");
|
|
1436
|
-
} catch (error) {
|
|
1437
|
-
logger.error("onSuccess callback failed:", error);
|
|
1438
|
-
throw error;
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
/**
|
|
1442
|
-
* Create build result object
|
|
1443
|
-
*/
|
|
1444
|
-
function createBuildResult(entries, startTime) {
|
|
1445
|
-
return {
|
|
1446
|
-
entries: entries.map((entry) => ({
|
|
1447
|
-
...entry,
|
|
1448
|
-
format: entry.format
|
|
1449
|
-
})),
|
|
1450
|
-
duration: Date.now() - startTime
|
|
1451
|
-
};
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
//#endregion
|
|
1455
|
-
//#region src/features/vite-config.ts
|
|
1468
|
+
//#region src/config/vite-config.ts
|
|
1456
1469
|
/**
|
|
1457
1470
|
* Load Vite configuration and convert to robuild config
|
|
1458
1471
|
*/
|
|
@@ -1562,13 +1575,50 @@ function convertExternal(external) {
|
|
|
1562
1575
|
return external;
|
|
1563
1576
|
}
|
|
1564
1577
|
|
|
1578
|
+
//#endregion
|
|
1579
|
+
//#region src/transforms/on-success.ts
|
|
1580
|
+
const execAsync = promisify(exec);
|
|
1581
|
+
/**
|
|
1582
|
+
* Execute onSuccess callback after successful build
|
|
1583
|
+
*/
|
|
1584
|
+
async function executeOnSuccess(onSuccess, result, cwd) {
|
|
1585
|
+
if (!onSuccess) return;
|
|
1586
|
+
try {
|
|
1587
|
+
if (typeof onSuccess === "string") {
|
|
1588
|
+
logger.verbose(`Executing onSuccess command: ${onSuccess}`);
|
|
1589
|
+
const { stdout, stderr } = await execAsync(onSuccess, { cwd });
|
|
1590
|
+
if (stdout) logger.verbose(`onSuccess stdout: ${stdout.trim()}`);
|
|
1591
|
+
if (stderr) logger.warn(`onSuccess stderr: ${stderr.trim()}`);
|
|
1592
|
+
} else {
|
|
1593
|
+
logger.verbose("Executing onSuccess callback function");
|
|
1594
|
+
await onSuccess(result);
|
|
1595
|
+
}
|
|
1596
|
+
logger.verbose("onSuccess callback completed successfully");
|
|
1597
|
+
} catch (error) {
|
|
1598
|
+
logger.error("onSuccess callback failed:", error);
|
|
1599
|
+
throw error;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Create build result object
|
|
1604
|
+
*/
|
|
1605
|
+
function createBuildResult(entries, startTime) {
|
|
1606
|
+
return {
|
|
1607
|
+
entries: entries.map((entry) => ({
|
|
1608
|
+
...entry,
|
|
1609
|
+
format: entry.format
|
|
1610
|
+
})),
|
|
1611
|
+
duration: Date.now() - startTime
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1565
1615
|
//#endregion
|
|
1566
1616
|
//#region src/watch.ts
|
|
1567
1617
|
/**
|
|
1568
1618
|
* Perform watch build using rolldown's built-in watch mode
|
|
1569
1619
|
*/
|
|
1570
1620
|
async function performWatchBuild(config, ctx, startTime) {
|
|
1571
|
-
const { performBuild } = await import("./build-
|
|
1621
|
+
const { performBuild } = await import("./build-BKisdK3B.mjs");
|
|
1572
1622
|
await performBuild(config, ctx, startTime);
|
|
1573
1623
|
const bundleEntries = (config.entries || []).filter((entry) => {
|
|
1574
1624
|
if (typeof entry === "string") return !entry.endsWith("/");
|
|
@@ -1589,7 +1639,7 @@ async function performWatchBuild(config, ctx, startTime) {
|
|
|
1589
1639
|
*/
|
|
1590
1640
|
async function startRolldownWatch(config, ctx, bundleEntries) {
|
|
1591
1641
|
logger.info("Watching for changes...");
|
|
1592
|
-
const { RobuildPluginManager } = await import("./
|
|
1642
|
+
const { RobuildPluginManager } = await import("./manager-CnmjrU85.mjs");
|
|
1593
1643
|
const watchConfigs = [];
|
|
1594
1644
|
for (const rawEntry of bundleEntries) {
|
|
1595
1645
|
const entry = typeof rawEntry === "string" ? parseEntryString(rawEntry) : rawEntry;
|
|
@@ -1684,7 +1734,8 @@ const SHARED_CONFIG_FIELDS = [
|
|
|
1684
1734
|
"footer",
|
|
1685
1735
|
"shims",
|
|
1686
1736
|
"rolldown",
|
|
1687
|
-
"loaders"
|
|
1737
|
+
"loaders",
|
|
1738
|
+
"clean"
|
|
1688
1739
|
];
|
|
1689
1740
|
/**
|
|
1690
1741
|
* Inherit configuration from parent config to entry
|
|
@@ -1786,4 +1837,4 @@ async function readJSON(specifier) {
|
|
|
1786
1837
|
}
|
|
1787
1838
|
|
|
1788
1839
|
//#endregion
|
|
1789
|
-
export {
|
|
1840
|
+
export { createBrowserShimsPlugin as a, SHEBANG_RE as c, shebangPlugin as d, nodeProtocolPlugin as f, logger as g, configureLogger as h, DEFAULT_SHIMS_CONFIG as i, hasShebang as l, hasGlobImports as m, performBuild as n, createNodeShimsPlugin as o, createGlobImportPlugin as p, createSkipNodeModulesPlugin as r, createShimsPlugin as s, build as t, makeExecutable as u };
|