robuild 0.0.5 → 0.0.7

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/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { build } from "./_chunks/build-eIjZ3Fk8.mjs";
2
+ import { build } from "./_chunks/build-5gEwHBbl.mjs";
3
3
  import { consola } from "consola";
4
4
  import { parseArgs } from "node:util";
5
5
  import { loadConfig } from "c12";
@@ -9,16 +9,105 @@ const args = parseArgs({
9
9
  args: process.argv.slice(2),
10
10
  allowPositionals: true,
11
11
  options: {
12
- dir: {
12
+ "dir": {
13
13
  type: "string",
14
14
  default: "."
15
15
  },
16
- stub: {
16
+ "stub": {
17
17
  type: "boolean",
18
18
  default: false
19
- }
19
+ },
20
+ "watch": {
21
+ type: "boolean",
22
+ default: false,
23
+ short: "w"
24
+ },
25
+ "format": {
26
+ type: "string",
27
+ multiple: true
28
+ },
29
+ "platform": { type: "string" },
30
+ "target": { type: "string" },
31
+ "global-name": { type: "string" },
32
+ "clean": {
33
+ type: "boolean",
34
+ default: true
35
+ },
36
+ "no-clean": { type: "boolean" },
37
+ "external": {
38
+ type: "string",
39
+ multiple: true
40
+ },
41
+ "no-external": {
42
+ type: "string",
43
+ multiple: true
44
+ },
45
+ "log-level": { type: "string" },
46
+ "on-success": { type: "string" },
47
+ "fail-on-warn": { type: "boolean" },
48
+ "ignore-watch": {
49
+ type: "string",
50
+ multiple: true
51
+ },
52
+ "from-vite": { type: "boolean" },
53
+ "workspace": { type: "boolean" },
54
+ "filter": {
55
+ type: "string",
56
+ multiple: true
57
+ },
58
+ "generate-exports": { type: "boolean" },
59
+ "cjs-default": { type: "string" },
60
+ "shims": { type: "boolean" },
61
+ "skip-node-modules": { type: "boolean" },
62
+ "unbundle": { type: "boolean" },
63
+ "help": { type: "boolean" },
64
+ "version": { type: "boolean" }
20
65
  }
21
66
  });
67
+ if (args.values.help) {
68
+ console.log(`
69
+ Usage: robuild [options] [entries...]
70
+
71
+ Options:
72
+ --dir <dir> Working directory (default: ".")
73
+ --stub Generate stub files instead of building
74
+ -w, --watch Enable watch mode
75
+ --format <format> Output format(s): esm, cjs, iife, umd (can be used multiple times)
76
+ --platform <platform> Target platform: browser, node, neutral
77
+ --target <target> Target ES version: es5, es2015, es2016, es2017, es2018, es2019, es2020, es2021, es2022, esnext
78
+ --global-name <name> Global variable name for IIFE/UMD formats
79
+ --clean Clean output directory before build (default: true)
80
+ --no-clean Disable cleaning output directory
81
+ --external <module> Mark dependencies as external (can be used multiple times)
82
+ --no-external <module> Force bundle dependencies (can be used multiple times)
83
+ --log-level <level> Log level: silent, error, warn, info, verbose (default: info)
84
+ --on-success <command> Command to run after successful build
85
+ --fail-on-warn Fail build on warnings
86
+ --ignore-watch <pattern> Ignore patterns in watch mode (can be used multiple times)
87
+ --from-vite Load configuration from Vite config file
88
+ --workspace Enable workspace mode for monorepo builds
89
+ --filter <pattern> Filter workspace packages by name or path pattern (can be used multiple times)
90
+ --generate-exports Generate package.json exports field
91
+ --cjs-default <mode> CommonJS default export handling: true, false, auto (default: auto)
92
+ --shims Enable CJS/ESM compatibility shims
93
+ --skip-node-modules Skip bundling node_modules dependencies
94
+ --unbundle Preserve file structure without bundling
95
+ --help Show this help message
96
+ --version Show version number
97
+
98
+ Examples:
99
+ robuild src/index.ts # Bundle single file
100
+ robuild src/index.ts --format esm cjs # Multiple formats
101
+ robuild src/ --watch # Transform directory in watch mode
102
+ robuild --help # Show help
103
+ `);
104
+ process.exit(0);
105
+ }
106
+ if (args.values.version) {
107
+ const pkg = await import("../package.json", { with: { type: "json" } });
108
+ console.log(pkg.default.version);
109
+ process.exit(0);
110
+ }
22
111
  const { config = {} } = await loadConfig({
23
112
  name: "robuild",
24
113
  configFile: "build.config",
@@ -28,15 +117,34 @@ const rawEntries = args.positionals.length > 0 ? args.positionals : config.entri
28
117
  const entries = rawEntries.map((entry) => {
29
118
  if (typeof entry === "string") {
30
119
  const [input, outDir] = entry.split(":");
31
- return input.endsWith("/") ? {
120
+ if (input.endsWith("/")) return {
32
121
  type: "transform",
33
122
  input,
34
123
  outDir
35
- } : {
36
- type: "bundle",
37
- input: input.split(","),
38
- outDir
39
124
  };
125
+ else {
126
+ const baseEntry = {
127
+ type: "bundle",
128
+ input: input.split(","),
129
+ outDir
130
+ };
131
+ if (args.values.format) baseEntry.format = args.values.format;
132
+ if (args.values.platform) baseEntry.platform = args.values.platform;
133
+ if (args.values.target) baseEntry.target = args.values.target;
134
+ if (args.values["global-name"]) baseEntry.globalName = args.values["global-name"];
135
+ if (args.values["no-clean"]) baseEntry.clean = false;
136
+ else if (args.values.clean !== void 0) baseEntry.clean = args.values.clean;
137
+ if (args.values.external) baseEntry.external = args.values.external.map((ext) => ext.startsWith("/") && ext.endsWith("/") ? new RegExp(ext.slice(1, -1)) : ext);
138
+ if (args.values["no-external"]) baseEntry.noExternal = args.values["no-external"].map((ext) => ext.startsWith("/") && ext.endsWith("/") ? new RegExp(ext.slice(1, -1)) : ext);
139
+ if (args.values["cjs-default"]) {
140
+ const mode = args.values["cjs-default"];
141
+ baseEntry.cjsDefault = mode === "true" ? true : mode === "false" ? false : mode;
142
+ }
143
+ if (args.values.shims) baseEntry.shims = true;
144
+ if (args.values["skip-node-modules"]) baseEntry.skipNodeModules = true;
145
+ if (args.values.unbundle) baseEntry.unbundle = true;
146
+ return baseEntry;
147
+ }
40
148
  }
41
149
  return entry;
42
150
  });
@@ -45,10 +153,32 @@ if (rawEntries.length === 0) {
45
153
  consola.error("No build entries specified.");
46
154
  process.exit(1);
47
155
  }
48
- await build({
156
+ const buildConfig = {
49
157
  cwd: args.values.dir,
50
158
  ...config,
51
- entries
52
- });
159
+ entries,
160
+ watch: args.values.watch ? {
161
+ enabled: true,
162
+ ...config.watch,
163
+ ...args.values["ignore-watch"] ? { exclude: [...config.watch?.exclude || [], ...args.values["ignore-watch"]] } : {}
164
+ } : config.watch
165
+ };
166
+ if (args.values["log-level"]) buildConfig.logLevel = args.values["log-level"];
167
+ if (args.values["on-success"]) buildConfig.onSuccess = args.values["on-success"];
168
+ if (args.values["fail-on-warn"]) buildConfig.failOnWarn = true;
169
+ if (args.values["ignore-watch"]) buildConfig.ignoreWatch = args.values["ignore-watch"];
170
+ if (args.values["from-vite"]) buildConfig.fromVite = true;
171
+ if (args.values.workspace) buildConfig.workspace = {
172
+ packages: ["packages/*", "apps/*"],
173
+ ...config.workspace
174
+ };
175
+ if (args.values.filter) buildConfig.filter = args.values.filter;
176
+ if (args.values["generate-exports"]) buildConfig.exports = {
177
+ enabled: true,
178
+ includeTypes: true,
179
+ autoUpdate: true,
180
+ ...config.exports
181
+ };
182
+ await build(buildConfig);
53
183
 
54
184
  //#endregion
package/dist/config.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { defineConfig } from "./_chunks/config-DxLkhDt6.mjs";
1
+ import { defineConfig } from "./_chunks/config-CeOzkcue.mjs";
2
2
  export { defineConfig };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BuildConfig, BuildEntry, BundleEntry, TransformEntry, defineConfig } from "./_chunks/config-DxLkhDt6.mjs";
1
+ import { BuildConfig, BuildEntry, BundleEntry, TransformEntry, defineConfig } from "./_chunks/config-CeOzkcue.mjs";
2
2
 
3
3
  //#region src/build.d.ts
4
4
 
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { build } from "./_chunks/build-eIjZ3Fk8.mjs";
1
+ import { build } from "./_chunks/build-5gEwHBbl.mjs";
2
2
  import { defineConfig } from "./_chunks/config-B_2eqpNJ.mjs";
3
3
 
4
4
  export { build, defineConfig };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "robuild",
3
3
  "type": "module",
4
- "version": "0.0.5",
4
+ "version": "0.0.7",
5
5
  "packageManager": "pnpm@10.11.1",
6
6
  "description": "Zero-config ESM/TS package builder. Powered by Rolldown and Oxc",
7
7
  "license": "MIT",
@@ -24,7 +24,8 @@
24
24
  "robuild": "esno src/cli.ts",
25
25
  "prepack": "pnpm build",
26
26
  "release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
27
- "test": "pnpm test:types",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
28
29
  "test:types": "tsc --noEmit --skipLibCheck",
29
30
  "docs:dev": "vitepress dev docs",
30
31
  "docs:build": "vitepress build docs",
@@ -32,10 +33,14 @@
32
33
  },
33
34
  "dependencies": {
34
35
  "c12": "^3.0.4",
36
+ "chokidar": "^4.0.3",
35
37
  "consola": "^3.4.2",
36
38
  "defu": "^6.1.4",
37
39
  "exsolve": "^1.0.5",
40
+ "glob": "^11.0.3",
41
+ "js-yaml": "^4.1.0",
38
42
  "magic-string": "^0.30.17",
43
+ "minimatch": "^10.0.3",
39
44
  "oxc-minify": "^0.89.0",
40
45
  "oxc-parser": "^0.89.0",
41
46
  "oxc-transform": "^0.89.0",
@@ -47,6 +52,7 @@
47
52
  },
48
53
  "devDependencies": {
49
54
  "@antfu/eslint-config": "^5.3.0",
55
+ "@types/js-yaml": "^4.0.9",
50
56
  "@types/node": "^24.4.0",
51
57
  "@vitest/coverage-v8": "^3.2.2",
52
58
  "automd": "^0.4.0",
@@ -1,388 +0,0 @@
1
- import { mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
2
- import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
4
- import { consola } from "consola";
5
- import { colors } from "consola/utils";
6
- import prettyBytes from "pretty-bytes";
7
- import { builtinModules } from "node:module";
8
- import { defu } from "defu";
9
- import { resolveModulePath } from "exsolve";
10
- import { parseSync } from "oxc-parser";
11
- import { rolldown } from "rolldown";
12
- import { dts } from "rolldown-plugin-dts";
13
- import { promises, readdirSync, statSync } from "node:fs";
14
- import { gzipSync } from "node:zlib";
15
- import { minify } from "oxc-minify";
16
- import MagicString from "magic-string";
17
- import { transform } from "oxc-transform";
18
- import { glob } from "tinyglobby";
19
-
20
- //#region src/utils.ts
21
- function fmtPath(path) {
22
- return resolve(path).replace(process.cwd(), ".");
23
- }
24
- function analyzeDir(dir) {
25
- if (Array.isArray(dir)) {
26
- let totalSize$1 = 0;
27
- let totalFiles = 0;
28
- for (const d of dir) {
29
- const { size, files: files$1 } = analyzeDir(d);
30
- totalSize$1 += size;
31
- totalFiles += files$1;
32
- }
33
- return {
34
- size: totalSize$1,
35
- files: totalFiles
36
- };
37
- }
38
- let totalSize = 0;
39
- const files = readdirSync(dir, {
40
- withFileTypes: true,
41
- recursive: true
42
- });
43
- for (const file of files) {
44
- const fullPath = join(file.parentPath, file.name);
45
- if (file.isFile()) {
46
- const { size } = statSync(fullPath);
47
- totalSize += size;
48
- }
49
- }
50
- return {
51
- size: totalSize,
52
- files: files.length
53
- };
54
- }
55
- async function distSize(dir, entry) {
56
- const build$1 = await rolldown({
57
- input: join(dir, entry),
58
- plugins: [],
59
- platform: "neutral",
60
- external: (id) => id[0] !== "." && !id.startsWith(dir)
61
- });
62
- const { output } = await build$1.generate({ inlineDynamicImports: true });
63
- const code = output[0].code;
64
- const { code: minified } = await minify(entry, code);
65
- return {
66
- size: Buffer.byteLength(code),
67
- minSize: Buffer.byteLength(minified),
68
- minGzipSize: gzipSync(minified).length
69
- };
70
- }
71
- async function sideEffectSize(dir, entry) {
72
- const virtualEntry = {
73
- name: "virtual-entry",
74
- async resolveId(id, importer, opts) {
75
- if (id === "#entry") return { id };
76
- const resolved = await this.resolve(id, importer, opts);
77
- if (!resolved) return null;
78
- resolved.moduleSideEffects = null;
79
- return resolved;
80
- },
81
- load(id) {
82
- if (id === "#entry") return `import * as _lib from "${join(dir, entry)}";`;
83
- }
84
- };
85
- const build$1 = await rolldown({
86
- input: "#entry",
87
- platform: "neutral",
88
- external: (id) => id[0] !== "." && !id.startsWith(dir),
89
- plugins: [virtualEntry]
90
- });
91
- const { output } = await build$1.generate({ inlineDynamicImports: true });
92
- if (process.env.INSPECT_BUILD) {
93
- console.log("---------[side effects]---------");
94
- console.log(entry);
95
- console.log(output[0].code);
96
- console.log("-------------------------------");
97
- }
98
- return Buffer.byteLength(output[0].code.trim());
99
- }
100
-
101
- //#endregion
102
- //#region src/builders/plugins/shebang.ts
103
- const SHEBANG_RE = /^#![^\n]*/;
104
- function shebangPlugin() {
105
- return {
106
- name: "robuild-shebang",
107
- async writeBundle(options, bundle) {
108
- for (const [fileName, output] of Object.entries(bundle)) {
109
- if (output.type !== "chunk") continue;
110
- if (hasShebang(output.code)) {
111
- const outFile = resolve(options.dir, fileName);
112
- await makeExecutable(outFile);
113
- }
114
- }
115
- }
116
- };
117
- }
118
- function hasShebang(code) {
119
- return SHEBANG_RE.test(code);
120
- }
121
- async function makeExecutable(filePath) {
122
- await promises.chmod(filePath, 493).catch(() => {});
123
- }
124
-
125
- //#endregion
126
- //#region src/builders/bundle.ts
127
- async function rolldownBuild(ctx, entry, hooks) {
128
- const inputs = normalizeBundleInputs(entry.input, ctx);
129
- if (entry.stub) {
130
- for (const [distName, srcPath] of Object.entries(inputs)) {
131
- const distPath = join(ctx.pkgDir, "dist", `${distName}.mjs`);
132
- await mkdir(dirname(distPath), { recursive: true });
133
- consola.log(`${colors.magenta("[stub bundle] ")} ${colors.underline(fmtPath(distPath))}`);
134
- const srcContents = await readFile(srcPath, "utf8");
135
- const parsed = parseSync(srcPath, srcContents);
136
- const exportNames = parsed.module.staticExports.flatMap((e) => e.entries.map((e$1) => e$1.exportName.kind === "Default" ? "default" : e$1.exportName.name));
137
- const hasDefaultExport = exportNames.includes("default");
138
- const firstLine = srcContents.split("\n")[0];
139
- const hasShebangLine = firstLine.startsWith("#!");
140
- await writeFile(distPath, `${hasShebangLine ? `${firstLine}\n` : ""}export * from "${srcPath}";\n${hasDefaultExport ? `export { default } from "${srcPath}";\n` : ""}`, "utf8");
141
- if (hasShebangLine) await makeExecutable(distPath);
142
- await writeFile(distPath.replace(/\.mjs$/, ".d.mts"), `export * from "${srcPath}";\n${hasDefaultExport ? `export { default } from "${srcPath}";\n` : ""}`, "utf8");
143
- }
144
- return;
145
- }
146
- const rolldownConfig = defu(entry.rolldown, {
147
- cwd: ctx.pkgDir,
148
- input: inputs,
149
- plugins: [shebangPlugin()],
150
- platform: "neutral",
151
- external: [
152
- ...builtinModules,
153
- ...builtinModules.map((m) => `node:${m}`),
154
- ...[...Object.keys(ctx.pkg.dependencies || {}), ...Object.keys(ctx.pkg.peerDependencies || {})].flatMap((p) => [p, /* @__PURE__ */ new RegExp(`^${p}/`)])
155
- ]
156
- });
157
- if (entry.dts !== false) rolldownConfig.plugins.push(...dts({ ...entry.dts }));
158
- await hooks.rolldownConfig?.(rolldownConfig, ctx);
159
- const res = await rolldown(rolldownConfig);
160
- const outDir = resolve(ctx.pkgDir, entry.outDir || "dist");
161
- const outConfig = {
162
- dir: outDir,
163
- entryFileNames: "[name].mjs",
164
- chunkFileNames: "_chunks/[name]-[hash].mjs",
165
- minify: entry.minify
166
- };
167
- await hooks.rolldownOutput?.(outConfig, res, ctx);
168
- const { output } = await res.write(outConfig);
169
- await res.close();
170
- const outputEntries = [];
171
- const depsCache = /* @__PURE__ */ new Map();
172
- const resolveDeps = (chunk) => {
173
- if (!depsCache.has(chunk)) depsCache.set(chunk, /* @__PURE__ */ new Set());
174
- const deps = depsCache.get(chunk);
175
- for (const id of chunk.imports) {
176
- if (builtinModules.includes(id) || id.startsWith("node:")) {
177
- deps.add(`[Node.js]`);
178
- continue;
179
- }
180
- const depChunk = output.find((o) => o.type === "chunk" && o.fileName === id);
181
- if (depChunk) {
182
- for (const dep of resolveDeps(depChunk)) deps.add(dep);
183
- continue;
184
- }
185
- deps.add(id);
186
- }
187
- return [...deps].sort();
188
- };
189
- for (const chunk of output) {
190
- if (chunk.type !== "chunk" || !chunk.isEntry) continue;
191
- if (chunk.fileName.endsWith("ts")) continue;
192
- outputEntries.push({
193
- name: chunk.fileName,
194
- exports: chunk.exports,
195
- deps: resolveDeps(chunk),
196
- ...await distSize(outDir, chunk.fileName),
197
- sideEffectSize: await sideEffectSize(outDir, chunk.fileName)
198
- });
199
- }
200
- consola.log(`\n${outputEntries.map((o) => [
201
- `${colors.magenta(`[bundle] `)}${colors.underline(fmtPath(join(outDir, o.name)))}`,
202
- colors.dim(`${colors.bold("Size:")} ${prettyBytes(o.size)}, ${colors.bold(prettyBytes(o.minSize))} minified, ${prettyBytes(o.minGzipSize)} min+gzipped (Side effects: ${prettyBytes(o.sideEffectSize)})`),
203
- o.exports.some((e) => e !== "default") ? colors.dim(`${colors.bold("Exports:")} ${o.exports.map((e) => e).join(", ")}`) : "",
204
- o.deps.length > 0 ? colors.dim(`${colors.bold("Dependencies:")} ${o.deps.join(", ")}`) : ""
205
- ].filter(Boolean).join("\n")).join("\n\n")}`);
206
- }
207
- function normalizeBundleInputs(input, ctx) {
208
- const inputs = {};
209
- for (let src of Array.isArray(input) ? input : [input]) {
210
- src = resolveModulePath(src, {
211
- from: ctx.pkgDir,
212
- extensions: [
213
- ".ts",
214
- ".js",
215
- ".mjs",
216
- ".cjs",
217
- ".json"
218
- ]
219
- });
220
- let relativeSrc = relative(join(ctx.pkgDir, "src"), src);
221
- if (relativeSrc.startsWith("..")) relativeSrc = relative(join(ctx.pkgDir), src);
222
- if (relativeSrc.startsWith("..")) throw new Error(`Source should be within the package directory (${ctx.pkgDir}): ${src}`);
223
- const distName = join(dirname(relativeSrc), basename(relativeSrc, extname(relativeSrc)));
224
- if (inputs[distName]) throw new Error(`Rename one of the entries to avoid a conflict in the dist name "${distName}":\n - ${src}\n - ${inputs[distName]}`);
225
- inputs[distName] = src;
226
- }
227
- return inputs;
228
- }
229
-
230
- //#endregion
231
- //#region src/builders/transform.ts
232
- /**
233
- * Transform all .ts modules in a directory using oxc-transform.
234
- */
235
- async function transformDir(ctx, entry) {
236
- if (entry.stub) {
237
- consola.log(`${colors.magenta("[stub transform] ")} ${colors.underline(`${fmtPath(entry.outDir)}/`)}`);
238
- await symlink(entry.input, entry.outDir, "junction");
239
- return;
240
- }
241
- const promises$1 = [];
242
- for await (const entryName of await glob("**/*.*", { cwd: entry.input })) promises$1.push((async () => {
243
- const entryPath = join(entry.input, entryName);
244
- const ext = extname(entryPath);
245
- switch (ext) {
246
- case ".ts": {
247
- const transformed = await transformModule(entryPath, entry);
248
- const entryDistPath = join(entry.outDir, entryName.replace(/\.ts$/, ".mjs"));
249
- await mkdir(dirname(entryDistPath), { recursive: true });
250
- await writeFile(entryDistPath, transformed.code, "utf8");
251
- if (SHEBANG_RE.test(transformed.code)) await makeExecutable(entryDistPath);
252
- if (transformed.declaration) await writeFile(entryDistPath.replace(/\.mjs$/, ".d.mts"), transformed.declaration, "utf8");
253
- return entryDistPath;
254
- }
255
- default: {
256
- const entryDistPath = join(entry.outDir, entryName);
257
- await mkdir(dirname(entryDistPath), { recursive: true });
258
- const code = await readFile(entryPath, "utf8");
259
- await writeFile(entryDistPath, code, "utf8");
260
- if (SHEBANG_RE.test(code)) await makeExecutable(entryDistPath);
261
- return entryDistPath;
262
- }
263
- }
264
- })());
265
- const writtenFiles = await Promise.all(promises$1);
266
- consola.log(`\n${colors.magenta("[transform] ")}${colors.underline(`${fmtPath(entry.outDir)}/`)}\n${writtenFiles.map((f) => colors.dim(fmtPath(f))).join("\n\n")}`);
267
- }
268
- /**
269
- * Transform a .ts module using oxc-transform.
270
- */
271
- async function transformModule(entryPath, entry) {
272
- let sourceText = await readFile(entryPath, "utf8");
273
- const sourceOptions = {
274
- lang: "ts",
275
- sourceType: "module"
276
- };
277
- const parsed = parseSync(entryPath, sourceText, { ...sourceOptions });
278
- if (parsed.errors.length > 0) throw new Error(`Errors while parsing ${entryPath}:`, { cause: parsed.errors });
279
- const resolveOptions = {
280
- ...entry.resolve,
281
- from: pathToFileURL(entryPath),
282
- extensions: entry.resolve?.extensions ?? [
283
- ".ts",
284
- ".js",
285
- ".mjs",
286
- ".cjs",
287
- ".json"
288
- ],
289
- suffixes: entry.resolve?.suffixes ?? ["", "/index"]
290
- };
291
- const magicString = new MagicString(sourceText);
292
- const updatedStarts = /* @__PURE__ */ new Set();
293
- const rewriteSpecifier = (req) => {
294
- const moduleId = req.value;
295
- if (!moduleId.startsWith(".")) return;
296
- if (updatedStarts.has(req.start)) return;
297
- updatedStarts.add(req.start);
298
- const resolvedAbsolute = resolveModulePath(moduleId, resolveOptions);
299
- const newId = relative(dirname(entryPath), resolvedAbsolute.replace(/\.ts$/, ".mjs"));
300
- magicString.remove(req.start, req.end);
301
- magicString.prependLeft(req.start, JSON.stringify(newId.startsWith(".") ? newId : `./${newId}`));
302
- };
303
- for (const staticImport of parsed.module.staticImports) rewriteSpecifier(staticImport.moduleRequest);
304
- for (const staticExport of parsed.module.staticExports) for (const staticExportEntry of staticExport.entries) if (staticExportEntry.moduleRequest) rewriteSpecifier(staticExportEntry.moduleRequest);
305
- sourceText = magicString.toString();
306
- const transformed = transform(entryPath, sourceText, {
307
- ...entry.oxc,
308
- ...sourceOptions,
309
- cwd: dirname(entryPath),
310
- typescript: {
311
- declaration: { stripInternal: true },
312
- ...entry.oxc?.typescript
313
- }
314
- });
315
- const transformErrors = transformed.errors.filter((err) => !err.message.includes("--isolatedDeclarations"));
316
- if (transformErrors.length > 0) {
317
- await writeFile("build-dump.ts", `/** Error dump for ${entryPath} */\n\n${sourceText}`, "utf8");
318
- throw new Error(`Errors while transforming ${entryPath}: (hint: check build-dump.ts)`, { cause: transformErrors });
319
- }
320
- if (entry.minify) {
321
- const res = minify(entryPath, transformed.code, entry.minify === true ? {} : entry.minify);
322
- transformed.code = res.code;
323
- transformed.map = res.map;
324
- }
325
- return transformed;
326
- }
327
-
328
- //#endregion
329
- //#region src/build.ts
330
- /**
331
- * Build dist/ from src/
332
- */
333
- async function build(config) {
334
- const start = Date.now();
335
- const pkgDir = normalizePath(config.cwd);
336
- const pkg = await readJSON(join(pkgDir, "package.json")).catch(() => ({}));
337
- const ctx = {
338
- pkg,
339
- pkgDir
340
- };
341
- consola.log(`šŸ“¦ Building \`${ctx.pkg.name || "<no name>"}\` (\`${ctx.pkgDir}\`)`);
342
- const hooks = config.hooks || {};
343
- await hooks.start?.(ctx);
344
- const entries = (config.entries || []).map((rawEntry) => {
345
- let entry;
346
- if (typeof rawEntry === "string") {
347
- const [input, outDir] = rawEntry.split(":");
348
- entry = input.endsWith("/") ? {
349
- type: "transform",
350
- input,
351
- outDir
352
- } : {
353
- type: "bundle",
354
- input: input.split(","),
355
- outDir
356
- };
357
- } else entry = rawEntry;
358
- if (!entry.input) throw new Error(`Build entry missing \`input\`: ${JSON.stringify(entry, null, 2)}`);
359
- entry = { ...entry };
360
- entry.outDir = normalizePath(entry.outDir || "dist", pkgDir);
361
- entry.input = Array.isArray(entry.input) ? entry.input.map((p) => normalizePath(p, pkgDir)) : normalizePath(entry.input, pkgDir);
362
- return entry;
363
- });
364
- await hooks.entries?.(entries, ctx);
365
- const outDirs = [];
366
- for (const outDir of entries.map((e) => e.outDir).sort()) if (!outDirs.some((dir) => outDir.startsWith(dir))) outDirs.push(outDir);
367
- for (const outDir of outDirs) {
368
- consola.log(`🧻 Cleaning up \`${fmtPath(outDir)}\``);
369
- await rm(outDir, {
370
- recursive: true,
371
- force: true
372
- });
373
- }
374
- for (const entry of entries) await (entry.type === "bundle" ? rolldownBuild(ctx, entry, hooks) : transformDir(ctx, entry));
375
- await hooks.end?.(ctx);
376
- const dirSize = analyzeDir(outDirs);
377
- consola.log(colors.dim(`\nΣ Total dist byte size: ${colors.underline(prettyBytes(dirSize.size))} (${colors.underline(dirSize.files)} files)`));
378
- consola.log(`\nāœ… robuild finished in ${Date.now() - start}ms`);
379
- }
380
- function normalizePath(path, resolveFrom) {
381
- return typeof path === "string" && isAbsolute(path) ? path : path instanceof URL ? fileURLToPath(path) : resolve(resolveFrom || ".", path || ".");
382
- }
383
- function readJSON(specifier) {
384
- return import(specifier, { with: { type: "json" } }).then((r) => r.default);
385
- }
386
-
387
- //#endregion
388
- export { build };