robuild 0.1.0 → 0.1.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/README.md +31 -5
- package/dist/_chunks/build-DsVOIGdc.mjs +3 -0
- package/dist/_chunks/{build-DbAuaVYJ.mjs → build-ZPgEqYgE.mjs} +562 -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-05zYHSH0.mjs → package-Cq3r5Qfx.mjs} +26 -26
- package/dist/cli.mjs +2 -2
- package/dist/config.d.mts +1 -2
- package/dist/index.d.mts +173 -14
- package/dist/index.mjs +387 -86
- package/package.json +26 -26
- package/dist/_chunks/build-tpynh1ZI.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.
|
|
@@ -362,219 +390,85 @@ async function sideEffectSize(dir, entry) {
|
|
|
362
390
|
}
|
|
363
391
|
}]
|
|
364
392
|
})).generate({ codeSplitting: false });
|
|
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";
|
|
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.
|
|
573
466
|
*/
|
|
574
467
|
function buildExternalDeps(ctx) {
|
|
468
|
+
const excludedBuiltins = new Set(["module"]);
|
|
575
469
|
return [
|
|
576
|
-
...builtinModules,
|
|
577
|
-
...builtinModules.map((m) => `node:${m}`),
|
|
470
|
+
...builtinModules.filter((m) => !excludedBuiltins.has(m)),
|
|
471
|
+
...builtinModules.filter((m) => !excludedBuiltins.has(m)).map((m) => `node:${m}`),
|
|
578
472
|
...[...Object.keys(ctx.pkg.dependencies || {}), ...Object.keys(ctx.pkg.peerDependencies || {})].flatMap((p) => [p, new RegExp(`^${p}/`)])
|
|
579
473
|
];
|
|
580
474
|
}
|
|
@@ -648,7 +542,36 @@ function resolveExternalConfig(ctx, options) {
|
|
|
648
542
|
}
|
|
649
543
|
|
|
650
544
|
//#endregion
|
|
651
|
-
//#region src/
|
|
545
|
+
//#region src/plugins/builtin/glob-import.ts
|
|
546
|
+
/**
|
|
547
|
+
* Core transform logic for glob imports
|
|
548
|
+
*/
|
|
549
|
+
async function transformGlobImportCode(code, id, options) {
|
|
550
|
+
const { patterns, asUrls, eager } = options;
|
|
551
|
+
const globImportRegex = /import\.meta\.glob\s*\(\s*(['"`])(.*?)\1\s*(?:,\s*(\{[^}]*\})\s*)?\)/g;
|
|
552
|
+
let match;
|
|
553
|
+
let hasGlobImports = false;
|
|
554
|
+
let transformedCode = code;
|
|
555
|
+
while ((match = globImportRegex.exec(code)) !== null) {
|
|
556
|
+
hasGlobImports = true;
|
|
557
|
+
const [fullMatch, , pattern, optionsStr] = match;
|
|
558
|
+
let globOptions = {};
|
|
559
|
+
if (optionsStr) try {
|
|
560
|
+
globOptions = parseGlobOptions(optionsStr);
|
|
561
|
+
} catch {
|
|
562
|
+
logger.warn("Failed to parse glob options:", optionsStr);
|
|
563
|
+
}
|
|
564
|
+
const isEager = globOptions.eager ?? eager;
|
|
565
|
+
const isAsUrls = globOptions.as === "url" || asUrls;
|
|
566
|
+
try {
|
|
567
|
+
const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
|
|
568
|
+
transformedCode = transformedCode.replace(fullMatch, replacement);
|
|
569
|
+
} catch (error) {
|
|
570
|
+
logger.error(`Failed to process glob import ${pattern}:`, error);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return hasGlobImports ? transformedCode : null;
|
|
574
|
+
}
|
|
652
575
|
/**
|
|
653
576
|
* Create a glob import plugin for robuild
|
|
654
577
|
*/
|
|
@@ -657,30 +580,12 @@ function createGlobImportPlugin(options = {}) {
|
|
|
657
580
|
if (!enabled) return { name: "glob-import-disabled" };
|
|
658
581
|
return {
|
|
659
582
|
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;
|
|
583
|
+
transform: async (code, id, _meta) => {
|
|
584
|
+
return transformGlobImportCode(code, id, {
|
|
585
|
+
patterns,
|
|
586
|
+
asUrls,
|
|
587
|
+
eager
|
|
588
|
+
});
|
|
684
589
|
}
|
|
685
590
|
};
|
|
686
591
|
}
|
|
@@ -753,33 +658,54 @@ function parseGlobOptions(optionsStr) {
|
|
|
753
658
|
if (asMatch) options.as = asMatch[1];
|
|
754
659
|
return options;
|
|
755
660
|
}
|
|
756
|
-
|
|
757
|
-
//#endregion
|
|
758
|
-
//#region src/features/hash.ts
|
|
759
661
|
/**
|
|
760
|
-
*
|
|
662
|
+
* Check if code contains glob imports
|
|
761
663
|
*/
|
|
762
|
-
function
|
|
763
|
-
return
|
|
664
|
+
function hasGlobImports(code) {
|
|
665
|
+
return /import\.meta\.glob\s*\(/.test(code);
|
|
764
666
|
}
|
|
667
|
+
|
|
668
|
+
//#endregion
|
|
669
|
+
//#region src/plugins/builtin/node-protocol.ts
|
|
765
670
|
/**
|
|
766
|
-
*
|
|
671
|
+
* Rolldown plugin for Node.js protocol handling
|
|
767
672
|
*/
|
|
768
|
-
function
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
673
|
+
function nodeProtocolPlugin(nodeProtocol) {
|
|
674
|
+
if (!nodeProtocol) return { name: "node-protocol-noop" };
|
|
675
|
+
return {
|
|
676
|
+
name: "node-protocol",
|
|
677
|
+
renderChunk(code) {
|
|
678
|
+
return {
|
|
679
|
+
code: transformNodeProtocol(code, nodeProtocol),
|
|
680
|
+
map: null
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
};
|
|
773
684
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
685
|
+
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region src/plugins/builtin/shebang.ts
|
|
688
|
+
const SHEBANG_RE = /^#![^\n]*/;
|
|
689
|
+
function shebangPlugin() {
|
|
690
|
+
return {
|
|
691
|
+
name: "robuild-shebang",
|
|
692
|
+
async writeBundle(options, bundle) {
|
|
693
|
+
for (const [fileName, output] of Object.entries(bundle)) {
|
|
694
|
+
if (output.type !== "chunk") continue;
|
|
695
|
+
if (hasShebang(output.code)) await makeExecutable(resolve(options.dir, fileName));
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
function hasShebang(code) {
|
|
701
|
+
return SHEBANG_RE.test(code);
|
|
702
|
+
}
|
|
703
|
+
async function makeExecutable(filePath) {
|
|
704
|
+
await promises.chmod(filePath, 493).catch(() => {});
|
|
779
705
|
}
|
|
780
706
|
|
|
781
707
|
//#endregion
|
|
782
|
-
//#region src/
|
|
708
|
+
//#region src/plugins/builtin/shims.ts
|
|
783
709
|
/**
|
|
784
710
|
* Default shims configuration
|
|
785
711
|
*/
|
|
@@ -893,134 +819,155 @@ function createShimsPlugin(config = true) {
|
|
|
893
819
|
}
|
|
894
820
|
};
|
|
895
821
|
}
|
|
896
|
-
|
|
897
|
-
//#endregion
|
|
898
|
-
//#region src/features/node-protocol.ts
|
|
899
822
|
/**
|
|
900
|
-
*
|
|
823
|
+
* Create browser-specific shims plugin
|
|
901
824
|
*/
|
|
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
|
-
]);
|
|
825
|
+
function createBrowserShimsPlugin() {
|
|
826
|
+
return {
|
|
827
|
+
name: "browser-shims",
|
|
828
|
+
transform: async (code, id) => {
|
|
829
|
+
if (!/\.(?:js|mjs|jsx|tsx?)$/.test(id)) return null;
|
|
830
|
+
if (detectShimNeeds(code).needsEnv) return `${PROCESS_ENV_SHIM}\n${code}`;
|
|
831
|
+
return null;
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
}
|
|
946
835
|
/**
|
|
947
|
-
*
|
|
836
|
+
* Create Node.js-specific shims plugin
|
|
948
837
|
*/
|
|
949
|
-
function
|
|
950
|
-
|
|
951
|
-
|
|
838
|
+
function createNodeShimsPlugin() {
|
|
839
|
+
return {
|
|
840
|
+
name: "node-shims",
|
|
841
|
+
transform: async (code, id) => {
|
|
842
|
+
if (!/\.mjs$/.test(id) && !/\.js$/.test(id)) return null;
|
|
843
|
+
const needs = detectShimNeeds(code);
|
|
844
|
+
const shims = [];
|
|
845
|
+
if (needs.needsDirname || needs.needsRequire) shims.push(NODE_GLOBALS_SHIM);
|
|
846
|
+
if (needs.needsExports) shims.push(MODULE_EXPORTS_SHIM);
|
|
847
|
+
if (shims.length === 0) return null;
|
|
848
|
+
return `${shims.join("\n")}\n${code}`;
|
|
849
|
+
}
|
|
850
|
+
};
|
|
952
851
|
}
|
|
852
|
+
|
|
853
|
+
//#endregion
|
|
854
|
+
//#region src/plugins/builtin/skip-node-modules.ts
|
|
953
855
|
/**
|
|
954
|
-
*
|
|
856
|
+
* Create skip node_modules plugin
|
|
955
857
|
*/
|
|
956
|
-
function
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
858
|
+
function createSkipNodeModulesPlugin(options) {
|
|
859
|
+
const noExternalPatterns = options?.noExternal || [];
|
|
860
|
+
const shouldInline = (id) => {
|
|
861
|
+
for (const pattern of noExternalPatterns) if (typeof pattern === "string") {
|
|
862
|
+
if (id === pattern || id.startsWith(`${pattern}/`)) return true;
|
|
863
|
+
} else if (pattern instanceof RegExp) {
|
|
864
|
+
if (pattern.test(id)) return true;
|
|
865
|
+
}
|
|
866
|
+
return false;
|
|
867
|
+
};
|
|
868
|
+
return {
|
|
869
|
+
name: "skip-node-modules",
|
|
870
|
+
resolveId: async (id, importer) => {
|
|
871
|
+
if (shouldInline(id)) return null;
|
|
872
|
+
if (!importer) return null;
|
|
873
|
+
if (id.includes("node_modules") || !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\\")) return {
|
|
874
|
+
id,
|
|
875
|
+
external: true
|
|
876
|
+
};
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
};
|
|
960
880
|
}
|
|
881
|
+
|
|
882
|
+
//#endregion
|
|
883
|
+
//#region src/transforms/banner.ts
|
|
961
884
|
/**
|
|
962
|
-
*
|
|
885
|
+
* Resolve banner/footer addon for specific format
|
|
963
886
|
*/
|
|
964
|
-
function
|
|
965
|
-
if (
|
|
966
|
-
return
|
|
887
|
+
function resolveChunkAddon(addon, format) {
|
|
888
|
+
if (!addon) return;
|
|
889
|
+
if (typeof addon === "string") return addon;
|
|
890
|
+
return addon[format === "es" ? "js" : format] || addon.js;
|
|
967
891
|
}
|
|
968
892
|
/**
|
|
969
|
-
*
|
|
893
|
+
* Add banner to content
|
|
970
894
|
*/
|
|
971
|
-
function
|
|
972
|
-
if (
|
|
973
|
-
|
|
974
|
-
return id;
|
|
895
|
+
function addBanner(content, banner) {
|
|
896
|
+
if (!banner) return content;
|
|
897
|
+
return `${banner}\n${content}`;
|
|
975
898
|
}
|
|
976
899
|
/**
|
|
977
|
-
*
|
|
900
|
+
* Add footer to content
|
|
978
901
|
*/
|
|
979
|
-
function
|
|
980
|
-
if (!
|
|
981
|
-
return
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
902
|
+
function addFooter(content, footer) {
|
|
903
|
+
if (!footer) return content;
|
|
904
|
+
return `${content}\n${footer}`;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Add both banner and footer to content
|
|
908
|
+
*/
|
|
909
|
+
function addBannerFooter(content, banner, footer) {
|
|
910
|
+
let result = content;
|
|
911
|
+
result = addBanner(result, banner);
|
|
912
|
+
result = addFooter(result, footer);
|
|
913
|
+
return result;
|
|
985
914
|
}
|
|
986
915
|
|
|
987
916
|
//#endregion
|
|
988
|
-
//#region src/
|
|
917
|
+
//#region src/transforms/clean.ts
|
|
989
918
|
/**
|
|
990
|
-
*
|
|
919
|
+
* Clean output directory or specific paths.
|
|
920
|
+
* Used by both bundle and transform builders.
|
|
921
|
+
*
|
|
922
|
+
* @param projectRoot - The project root directory
|
|
923
|
+
* @param outDir - The output directory to clean
|
|
924
|
+
* @param cleanPaths - true to clean outDir, or array of specific paths to clean
|
|
991
925
|
*/
|
|
992
|
-
function
|
|
993
|
-
if (!
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
};
|
|
926
|
+
async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
|
|
927
|
+
if (!cleanPaths) return;
|
|
928
|
+
if (cleanPaths === true) {
|
|
929
|
+
if (existsSync(outDir)) {
|
|
930
|
+
logger.log(colors.dim(`Cleaning ${fmtPath(outDir)}`));
|
|
931
|
+
await rm(outDir, {
|
|
932
|
+
recursive: true,
|
|
933
|
+
force: true
|
|
934
|
+
});
|
|
1001
935
|
}
|
|
1002
|
-
}
|
|
936
|
+
} else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
|
|
937
|
+
const fullPath = resolve(projectRoot, path);
|
|
938
|
+
if (existsSync(fullPath)) {
|
|
939
|
+
logger.log(colors.dim(`Cleaning ${fmtPath(fullPath)}`));
|
|
940
|
+
await rm(fullPath, {
|
|
941
|
+
recursive: true,
|
|
942
|
+
force: true
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
}
|
|
1003
946
|
}
|
|
1004
947
|
|
|
1005
948
|
//#endregion
|
|
1006
|
-
//#region src/
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
949
|
+
//#region src/transforms/copy.ts
|
|
950
|
+
/**
|
|
951
|
+
* Copy files to output directory
|
|
952
|
+
*/
|
|
953
|
+
async function copyFiles(cwd, outDir, copyOptions) {
|
|
954
|
+
if (!copyOptions || copyOptions.length === 0) return;
|
|
955
|
+
logger.verbose("Copying files...");
|
|
956
|
+
await Promise.all(copyOptions.map(async (entry) => {
|
|
957
|
+
const from = typeof entry === "string" ? entry : entry.from;
|
|
958
|
+
const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
|
|
959
|
+
const fromPath = resolve(cwd, from);
|
|
960
|
+
try {
|
|
961
|
+
await cp(fromPath, to, {
|
|
962
|
+
recursive: true,
|
|
963
|
+
force: true
|
|
964
|
+
});
|
|
965
|
+
logger.verbose(` ${from} → ${to}`);
|
|
966
|
+
} catch (error) {
|
|
967
|
+
logger.warn(`Failed to copy ${from} to ${to}:`, error);
|
|
1016
968
|
}
|
|
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(() => {});
|
|
969
|
+
}));
|
|
970
|
+
logger.verbose("Files copied successfully");
|
|
1024
971
|
}
|
|
1025
972
|
|
|
1026
973
|
//#endregion
|
|
@@ -1253,6 +1200,110 @@ function normalizeBundleInputs(input, ctx) {
|
|
|
1253
1200
|
return inputs;
|
|
1254
1201
|
}
|
|
1255
1202
|
|
|
1203
|
+
//#endregion
|
|
1204
|
+
//#region src/builders/unbundle.ts
|
|
1205
|
+
/**
|
|
1206
|
+
* Unbundle mode: preserve file structure without bundling
|
|
1207
|
+
*/
|
|
1208
|
+
async function unbundleTransform(ctx, entry) {
|
|
1209
|
+
await processDirectoryUnbundled(isAbsolute(entry.input) ? entry.input : join(ctx.pkgDir, entry.input), join(ctx.pkgDir, entry.outDir || "dist"), entry);
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Process directory in unbundle mode
|
|
1213
|
+
*/
|
|
1214
|
+
async function processDirectoryUnbundled(inputDir, outputDir, entry) {
|
|
1215
|
+
const entries = await readdir(inputDir, { withFileTypes: true });
|
|
1216
|
+
for (const dirEntry of entries) {
|
|
1217
|
+
const inputPath = join(inputDir, dirEntry.name);
|
|
1218
|
+
const outputPath = join(outputDir, dirEntry.name);
|
|
1219
|
+
if (dirEntry.isDirectory()) {
|
|
1220
|
+
if (entry.skipNodeModules && dirEntry.name === "node_modules") continue;
|
|
1221
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
1222
|
+
await processDirectoryUnbundled(inputPath, outputPath, entry);
|
|
1223
|
+
} else if (dirEntry.isFile()) await processFileUnbundled(inputPath, outputPath, entry);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Process individual file in unbundle mode
|
|
1228
|
+
*/
|
|
1229
|
+
async function processFileUnbundled(inputPath, outputPath, entry) {
|
|
1230
|
+
const ext = extname(inputPath);
|
|
1231
|
+
if (![
|
|
1232
|
+
".js",
|
|
1233
|
+
".ts",
|
|
1234
|
+
".jsx",
|
|
1235
|
+
".tsx",
|
|
1236
|
+
".mjs",
|
|
1237
|
+
".mts",
|
|
1238
|
+
".cjs",
|
|
1239
|
+
".cts"
|
|
1240
|
+
].includes(ext)) return;
|
|
1241
|
+
try {
|
|
1242
|
+
const transformedContent = transformImportsForUnbundle(await readFile(inputPath, "utf-8"), inputPath, entry);
|
|
1243
|
+
const outputExt = getUnbundleOutputExtension(ext, entry);
|
|
1244
|
+
const finalOutputPath = outputPath.replace(ext, outputExt);
|
|
1245
|
+
await mkdir(dirname(finalOutputPath), { recursive: true });
|
|
1246
|
+
await writeFile(finalOutputPath, transformedContent, "utf-8");
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
logger.warn(`Failed to process file ${inputPath}:`, error);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* Transform imports for unbundle mode
|
|
1253
|
+
*/
|
|
1254
|
+
function transformImportsForUnbundle(content, _filePath, entry) {
|
|
1255
|
+
let transformedContent = content;
|
|
1256
|
+
transformedContent = transformedContent.replace(/from\s+['"]([^'"]+)['"]/g, (match, importPath) => {
|
|
1257
|
+
if (importPath.startsWith(".")) {
|
|
1258
|
+
const newImportPath = updateImportExtension(importPath, entry);
|
|
1259
|
+
return match.replace(importPath, newImportPath);
|
|
1260
|
+
}
|
|
1261
|
+
return match;
|
|
1262
|
+
});
|
|
1263
|
+
transformedContent = transformedContent.replace(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, (match, importPath) => {
|
|
1264
|
+
if (importPath.startsWith(".")) {
|
|
1265
|
+
const newImportPath = updateImportExtension(importPath, entry);
|
|
1266
|
+
return match.replace(importPath, newImportPath);
|
|
1267
|
+
}
|
|
1268
|
+
return match;
|
|
1269
|
+
});
|
|
1270
|
+
return transformedContent;
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Update import extension for unbundle mode
|
|
1274
|
+
*/
|
|
1275
|
+
function updateImportExtension(importPath, entry) {
|
|
1276
|
+
const ext = extname(importPath);
|
|
1277
|
+
if (!ext) return `${importPath}.js`;
|
|
1278
|
+
if ([
|
|
1279
|
+
".ts",
|
|
1280
|
+
".tsx",
|
|
1281
|
+
".mts",
|
|
1282
|
+
".cts"
|
|
1283
|
+
].includes(ext)) {
|
|
1284
|
+
const newExt = getUnbundleOutputExtension(ext, entry);
|
|
1285
|
+
return importPath.replace(ext, newExt);
|
|
1286
|
+
}
|
|
1287
|
+
return importPath;
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Get output extension for unbundle mode
|
|
1291
|
+
*/
|
|
1292
|
+
function getUnbundleOutputExtension(inputExt, entry) {
|
|
1293
|
+
const format = Array.isArray(entry.format) ? entry.format[0] : entry.format || "es";
|
|
1294
|
+
switch (inputExt) {
|
|
1295
|
+
case ".ts":
|
|
1296
|
+
case ".tsx": return format === "cjs" ? ".cjs" : ".mjs";
|
|
1297
|
+
case ".mts": return ".mjs";
|
|
1298
|
+
case ".cts": return ".cjs";
|
|
1299
|
+
case ".js":
|
|
1300
|
+
case ".jsx": return format === "cjs" ? ".cjs" : ".mjs";
|
|
1301
|
+
case ".mjs": return ".mjs";
|
|
1302
|
+
case ".cjs": return ".cjs";
|
|
1303
|
+
default: return ".js";
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1256
1307
|
//#endregion
|
|
1257
1308
|
//#region src/builders/transform.ts
|
|
1258
1309
|
/**
|
|
@@ -1415,44 +1466,7 @@ async function transformModule(entryPath, entry) {
|
|
|
1415
1466
|
}
|
|
1416
1467
|
|
|
1417
1468
|
//#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
|
|
1469
|
+
//#region src/config/vite-config.ts
|
|
1456
1470
|
/**
|
|
1457
1471
|
* Load Vite configuration and convert to robuild config
|
|
1458
1472
|
*/
|
|
@@ -1562,13 +1576,50 @@ function convertExternal(external) {
|
|
|
1562
1576
|
return external;
|
|
1563
1577
|
}
|
|
1564
1578
|
|
|
1579
|
+
//#endregion
|
|
1580
|
+
//#region src/transforms/on-success.ts
|
|
1581
|
+
const execAsync = promisify(exec);
|
|
1582
|
+
/**
|
|
1583
|
+
* Execute onSuccess callback after successful build
|
|
1584
|
+
*/
|
|
1585
|
+
async function executeOnSuccess(onSuccess, result, cwd) {
|
|
1586
|
+
if (!onSuccess) return;
|
|
1587
|
+
try {
|
|
1588
|
+
if (typeof onSuccess === "string") {
|
|
1589
|
+
logger.verbose(`Executing onSuccess command: ${onSuccess}`);
|
|
1590
|
+
const { stdout, stderr } = await execAsync(onSuccess, { cwd });
|
|
1591
|
+
if (stdout) logger.verbose(`onSuccess stdout: ${stdout.trim()}`);
|
|
1592
|
+
if (stderr) logger.warn(`onSuccess stderr: ${stderr.trim()}`);
|
|
1593
|
+
} else {
|
|
1594
|
+
logger.verbose("Executing onSuccess callback function");
|
|
1595
|
+
await onSuccess(result);
|
|
1596
|
+
}
|
|
1597
|
+
logger.verbose("onSuccess callback completed successfully");
|
|
1598
|
+
} catch (error) {
|
|
1599
|
+
logger.error("onSuccess callback failed:", error);
|
|
1600
|
+
throw error;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Create build result object
|
|
1605
|
+
*/
|
|
1606
|
+
function createBuildResult(entries, startTime) {
|
|
1607
|
+
return {
|
|
1608
|
+
entries: entries.map((entry) => ({
|
|
1609
|
+
...entry,
|
|
1610
|
+
format: entry.format
|
|
1611
|
+
})),
|
|
1612
|
+
duration: Date.now() - startTime
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1565
1616
|
//#endregion
|
|
1566
1617
|
//#region src/watch.ts
|
|
1567
1618
|
/**
|
|
1568
1619
|
* Perform watch build using rolldown's built-in watch mode
|
|
1569
1620
|
*/
|
|
1570
1621
|
async function performWatchBuild(config, ctx, startTime) {
|
|
1571
|
-
const { performBuild } = await import("./build-
|
|
1622
|
+
const { performBuild } = await import("./build-DsVOIGdc.mjs");
|
|
1572
1623
|
await performBuild(config, ctx, startTime);
|
|
1573
1624
|
const bundleEntries = (config.entries || []).filter((entry) => {
|
|
1574
1625
|
if (typeof entry === "string") return !entry.endsWith("/");
|
|
@@ -1589,7 +1640,7 @@ async function performWatchBuild(config, ctx, startTime) {
|
|
|
1589
1640
|
*/
|
|
1590
1641
|
async function startRolldownWatch(config, ctx, bundleEntries) {
|
|
1591
1642
|
logger.info("Watching for changes...");
|
|
1592
|
-
const { RobuildPluginManager } = await import("./
|
|
1643
|
+
const { RobuildPluginManager } = await import("./manager-CnmjrU85.mjs");
|
|
1593
1644
|
const watchConfigs = [];
|
|
1594
1645
|
for (const rawEntry of bundleEntries) {
|
|
1595
1646
|
const entry = typeof rawEntry === "string" ? parseEntryString(rawEntry) : rawEntry;
|
|
@@ -1684,7 +1735,8 @@ const SHARED_CONFIG_FIELDS = [
|
|
|
1684
1735
|
"footer",
|
|
1685
1736
|
"shims",
|
|
1686
1737
|
"rolldown",
|
|
1687
|
-
"loaders"
|
|
1738
|
+
"loaders",
|
|
1739
|
+
"clean"
|
|
1688
1740
|
];
|
|
1689
1741
|
/**
|
|
1690
1742
|
* Inherit configuration from parent config to entry
|
|
@@ -1786,4 +1838,4 @@ async function readJSON(specifier) {
|
|
|
1786
1838
|
}
|
|
1787
1839
|
|
|
1788
1840
|
//#endregion
|
|
1789
|
-
export {
|
|
1841
|
+
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 };
|