@reliverse/build 2.2.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/impl/assets.d.ts +28 -0
- package/dist/impl/assets.js +188 -0
- package/dist/impl/cache.d.ts +25 -0
- package/dist/impl/cache.js +209 -0
- package/dist/impl/constants.d.ts +44 -0
- package/dist/impl/constants.js +45 -0
- package/dist/impl/debug.d.ts +30 -0
- package/dist/impl/debug.js +150 -0
- package/dist/impl/dependency-tracker.d.ts +23 -0
- package/dist/impl/dependency-tracker.js +113 -0
- package/dist/impl/dev-server.d.ts +24 -0
- package/dist/impl/dev-server.js +360 -0
- package/dist/impl/dts-generator.d.ts +26 -0
- package/dist/impl/dts-generator.js +514 -0
- package/dist/impl/go-build.d.ts +10 -0
- package/dist/impl/go-build.js +350 -0
- package/dist/impl/html-processor.d.ts +21 -0
- package/dist/impl/html-processor.js +167 -0
- package/dist/impl/impl.d.ts +0 -0
- package/dist/impl/impl.js +0 -0
- package/dist/impl/plugins/asset-optimization.d.ts +2 -0
- package/dist/impl/plugins/asset-optimization.js +114 -0
- package/dist/impl/plugins/bundle-analyzer.d.ts +2 -0
- package/dist/impl/plugins/bundle-analyzer.js +156 -0
- package/dist/impl/plugins/css-modules.d.ts +2 -0
- package/dist/impl/plugins/css-modules.js +19 -0
- package/dist/impl/plugins/index.d.ts +21 -0
- package/dist/impl/plugins/index.js +65 -0
- package/dist/impl/plugins/performance.d.ts +2 -0
- package/dist/impl/plugins/performance.js +62 -0
- package/dist/impl/plugins/react-refresh.d.ts +2 -0
- package/dist/impl/plugins/react-refresh.js +33 -0
- package/dist/impl/plugins/svg-as-react.d.ts +2 -0
- package/dist/impl/plugins/svg-as-react.js +18 -0
- package/dist/impl/plugins/typescript-declarations.d.ts +2 -0
- package/dist/impl/plugins/typescript-declarations.js +48 -0
- package/dist/impl/plugins/worker.d.ts +2 -0
- package/dist/impl/plugins/worker.js +20 -0
- package/dist/impl/presets.d.ts +10 -0
- package/dist/impl/presets.js +196 -0
- package/dist/impl/providers/mkdist/loader.d.ts +4 -0
- package/dist/impl/providers/mkdist/loader.js +26 -0
- package/dist/impl/providers/mkdist/loaders/js.d.ts +2 -0
- package/dist/impl/providers/mkdist/loaders/js.js +50 -0
- package/dist/impl/providers/mkdist/loaders/loaders-mod.d.ts +9 -0
- package/dist/impl/providers/mkdist/loaders/loaders-mod.js +22 -0
- package/dist/impl/providers/mkdist/make.d.ts +11 -0
- package/dist/impl/providers/mkdist/make.js +230 -0
- package/dist/impl/providers/mkdist/utils/dts.d.ts +11 -0
- package/dist/impl/providers/mkdist/utils/dts.js +117 -0
- package/dist/impl/providers/mkdist/utils/fs.d.ts +1 -0
- package/dist/impl/providers/mkdist/utils/fs.js +15 -0
- package/dist/impl/providers/mkdist-dts.d.ts +24 -0
- package/dist/impl/providers/mkdist-dts.js +8 -0
- package/dist/impl/tsconfig-validator.d.ts +35 -0
- package/dist/impl/tsconfig-validator.js +184 -0
- package/dist/impl/type-guards.d.ts +20 -0
- package/dist/impl/type-guards.js +147 -0
- package/dist/impl/types.d.ts +322 -0
- package/dist/impl/types.js +0 -0
- package/dist/impl/utils/go-build-handler.d.ts +12 -0
- package/dist/impl/utils/go-build-handler.js +83 -0
- package/dist/impl/utils/log-extraction.d.ts +25 -0
- package/dist/impl/utils/log-extraction.js +24 -0
- package/dist/impl/utils/package-filtering.d.ts +5 -0
- package/dist/impl/utils/package-filtering.js +22 -0
- package/dist/impl/utils/rebuild-queue.d.ts +38 -0
- package/dist/impl/utils/rebuild-queue.js +110 -0
- package/dist/impl/validation.d.ts +9 -0
- package/dist/impl/validation.js +332 -0
- package/dist/impl/watch.d.ts +21 -0
- package/dist/impl/watch.js +144 -0
- package/dist/mod.d.ts +17 -0
- package/dist/mod.js +1390 -0
- package/package.json +42 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { relinka } from "@reliverse/relinka";
|
|
2
|
+
import { buildGo } from "../go-build.js";
|
|
3
|
+
export async function handleGoBuild(pkg, options, verbose) {
|
|
4
|
+
if (options.tsOnly) {
|
|
5
|
+
if (verbose) {
|
|
6
|
+
await relinka.info(
|
|
7
|
+
`\u23ED\uFE0F ${pkg.name}: Skipping Go build (--ts-only flag set)`
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (!pkg.hasGoFiles) {
|
|
13
|
+
if (verbose) {
|
|
14
|
+
await relinka.debug(`\u23ED\uFE0F ${pkg.name}: No Go files detected`);
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const goConfig = options.go ?? pkg.buildConfig?.go;
|
|
19
|
+
if (goConfig?.enable === false) {
|
|
20
|
+
if (verbose) {
|
|
21
|
+
await relinka.info(`\u23ED\uFE0F ${pkg.name}: Go build disabled in config`);
|
|
22
|
+
}
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
await relinka.info(`\u{1F528} ${pkg.name}: Building Go binaries...`);
|
|
27
|
+
const goResult = await buildGo(
|
|
28
|
+
pkg.path,
|
|
29
|
+
pkg.name,
|
|
30
|
+
goConfig ?? { enable: true }
|
|
31
|
+
);
|
|
32
|
+
if (!goResult.success) {
|
|
33
|
+
await relinka.warn(
|
|
34
|
+
`\u26A0\uFE0F ${pkg.name}: Go build failed: ${goResult.errors.join(", ")}`
|
|
35
|
+
);
|
|
36
|
+
} else {
|
|
37
|
+
await relinka.success(`\u2705 ${pkg.name}: Go binaries built successfully`);
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
await relinka.warn(
|
|
41
|
+
`\u26A0\uFE0F ${pkg.name}: Go build error: ${error instanceof Error ? error.message : String(error)}`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function handleGoOnlyBuild(pkg, options) {
|
|
46
|
+
if (!pkg.hasGoFiles) {
|
|
47
|
+
return {
|
|
48
|
+
success: true,
|
|
49
|
+
errors: []
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const goConfig = options.go ?? pkg.buildConfig?.go;
|
|
53
|
+
if (goConfig?.enable === false) {
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
errors: []
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
await relinka.info(`\u{1F528} ${pkg.name}: Building Go binaries...`);
|
|
61
|
+
const goResult = await buildGo(
|
|
62
|
+
pkg.path,
|
|
63
|
+
pkg.name,
|
|
64
|
+
goConfig ?? { enable: true }
|
|
65
|
+
);
|
|
66
|
+
if (!goResult.success) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
errors: goResult.errors
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
await relinka.success(`\u2705 ${pkg.name}: Go binaries built successfully`);
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
errors: []
|
|
76
|
+
};
|
|
77
|
+
} catch (error) {
|
|
78
|
+
return {
|
|
79
|
+
success: false,
|
|
80
|
+
errors: [error instanceof Error ? error.message : String(error)]
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun build log entry - matches the structure from Bun.build().logs
|
|
3
|
+
*/
|
|
4
|
+
interface BunLogEntry {
|
|
5
|
+
level: "error" | "warning" | "info" | "debug" | "verbose";
|
|
6
|
+
message: string;
|
|
7
|
+
position?: {
|
|
8
|
+
file: string;
|
|
9
|
+
line: number;
|
|
10
|
+
column: number;
|
|
11
|
+
} | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extract error messages from Bun build logs
|
|
15
|
+
*/
|
|
16
|
+
export declare function extractErrors(logs: BunLogEntry[]): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Extract warning messages from Bun build logs
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractWarnings(logs: BunLogEntry[]): string[];
|
|
21
|
+
/**
|
|
22
|
+
* Format all log messages into a single string
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatLogMessages(logs: BunLogEntry[]): string;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function extractErrors(logs) {
|
|
2
|
+
return logs.filter((log) => log.level === "error").map((log) => {
|
|
3
|
+
if (log.position) {
|
|
4
|
+
return `${log.message} (${log.position.file}:${log.position.line}:${log.position.column})`;
|
|
5
|
+
}
|
|
6
|
+
return log.message;
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
export function extractWarnings(logs) {
|
|
10
|
+
return logs.filter((log) => log.level === "warning").map((log) => {
|
|
11
|
+
if (log.position) {
|
|
12
|
+
return `${log.message} (${log.position.file}:${log.position.line}:${log.position.column})`;
|
|
13
|
+
}
|
|
14
|
+
return log.message;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export function formatLogMessages(logs) {
|
|
18
|
+
return logs.map((log) => {
|
|
19
|
+
if (log.position) {
|
|
20
|
+
return `${log.message} (${log.position.file}:${log.position.line}:${log.position.column})`;
|
|
21
|
+
}
|
|
22
|
+
return log.message;
|
|
23
|
+
}).join("\n");
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function isPackageAllowed(pkgName, allowedPatterns) {
|
|
2
|
+
for (const pattern of allowedPatterns) {
|
|
3
|
+
if (pattern.includes("*")) {
|
|
4
|
+
const regexPattern = pattern.replace(/\*/g, ".*");
|
|
5
|
+
if (new RegExp(`^${regexPattern}$`).test(pkgName)) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
} else if (pkgName === pattern) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
export function filterPrivatePackages(packages, allowPrivateBuild) {
|
|
15
|
+
if (!allowPrivateBuild) {
|
|
16
|
+
return packages.filter((pkg) => pkg.private !== true);
|
|
17
|
+
}
|
|
18
|
+
const allowedPatterns = Array.isArray(allowPrivateBuild) ? allowPrivateBuild : [allowPrivateBuild];
|
|
19
|
+
return packages.filter(
|
|
20
|
+
(pkg) => pkg.private !== true || isPackageAllowed(pkg.name, allowedPatterns)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BuildOptions, BuildResult, PackageInfo } from "../types.js";
|
|
2
|
+
interface RebuildQueueOptions {
|
|
3
|
+
debounceMs?: number;
|
|
4
|
+
incremental?: boolean;
|
|
5
|
+
buildOptions?: BuildOptions;
|
|
6
|
+
onRebuildComplete?: (result: BuildResult) => void | Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Shared rebuild queue processor for watch mode and dev server
|
|
10
|
+
*/
|
|
11
|
+
export declare class RebuildQueueProcessor {
|
|
12
|
+
private rebuildQueue;
|
|
13
|
+
private rebuildTimeout;
|
|
14
|
+
private readonly options;
|
|
15
|
+
private readonly packages;
|
|
16
|
+
constructor(packages: PackageInfo[], options?: RebuildQueueOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Add a package to the rebuild queue
|
|
19
|
+
*/
|
|
20
|
+
add(packageName: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Clear the rebuild queue
|
|
23
|
+
*/
|
|
24
|
+
clear(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Schedule a rebuild with debouncing
|
|
27
|
+
*/
|
|
28
|
+
private scheduleRebuild;
|
|
29
|
+
/**
|
|
30
|
+
* Process the rebuild queue
|
|
31
|
+
*/
|
|
32
|
+
private processQueue;
|
|
33
|
+
/**
|
|
34
|
+
* Process rebuild queue with custom build options
|
|
35
|
+
*/
|
|
36
|
+
processWithOptions(options: BuildOptions): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { relinka } from "@reliverse/relinka";
|
|
2
|
+
import { DEFAULT_DEBOUNCE_MS } from "../constants.js";
|
|
3
|
+
export class RebuildQueueProcessor {
|
|
4
|
+
rebuildQueue = /* @__PURE__ */ new Set();
|
|
5
|
+
rebuildTimeout = null;
|
|
6
|
+
options;
|
|
7
|
+
packages;
|
|
8
|
+
constructor(packages, options = {}) {
|
|
9
|
+
this.packages = packages;
|
|
10
|
+
this.options = {
|
|
11
|
+
debounceMs: options.debounceMs ?? DEFAULT_DEBOUNCE_MS,
|
|
12
|
+
incremental: options.incremental ?? false,
|
|
13
|
+
buildOptions: options.buildOptions,
|
|
14
|
+
onRebuildComplete: options.onRebuildComplete
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Add a package to the rebuild queue
|
|
19
|
+
*/
|
|
20
|
+
add(packageName) {
|
|
21
|
+
this.rebuildQueue.add(packageName);
|
|
22
|
+
this.scheduleRebuild();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Clear the rebuild queue
|
|
26
|
+
*/
|
|
27
|
+
clear() {
|
|
28
|
+
this.rebuildQueue.clear();
|
|
29
|
+
if (this.rebuildTimeout) {
|
|
30
|
+
clearTimeout(this.rebuildTimeout);
|
|
31
|
+
this.rebuildTimeout = null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Schedule a rebuild with debouncing
|
|
36
|
+
*/
|
|
37
|
+
scheduleRebuild() {
|
|
38
|
+
if (this.rebuildTimeout) {
|
|
39
|
+
clearTimeout(this.rebuildTimeout);
|
|
40
|
+
}
|
|
41
|
+
this.rebuildTimeout = setTimeout(() => {
|
|
42
|
+
void this.processQueue();
|
|
43
|
+
}, this.options.debounceMs);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Process the rebuild queue
|
|
47
|
+
*/
|
|
48
|
+
async processQueue() {
|
|
49
|
+
if (this.rebuildQueue.size === 0) return;
|
|
50
|
+
const packagesToRebuild = Array.from(this.rebuildQueue).map((name) => this.packages.find((pkg) => pkg.name === name)).filter((pkg) => pkg !== void 0);
|
|
51
|
+
this.rebuildQueue.clear();
|
|
52
|
+
const rebuildMessage = this.options.incremental ? `\u{1F504} Incrementally rebuilding ${packagesToRebuild.length} packages...` : `\u{1F504} Rebuilding ${packagesToRebuild.length} packages...`;
|
|
53
|
+
await relinka.info(rebuildMessage);
|
|
54
|
+
const { buildPackage } = await import("../../mod.js");
|
|
55
|
+
const buildOptions = this.options.buildOptions ?? {};
|
|
56
|
+
const buildPromises = packagesToRebuild.map(async (pkg) => {
|
|
57
|
+
try {
|
|
58
|
+
const result = await buildPackage(pkg, buildOptions);
|
|
59
|
+
if (result.success) {
|
|
60
|
+
await relinka.success(`\u2705 ${pkg.name}: Rebuilt successfully`);
|
|
61
|
+
} else {
|
|
62
|
+
await relinka.error(`\u274C ${pkg.name}: Rebuild failed`);
|
|
63
|
+
for (const error of result.errors) {
|
|
64
|
+
await relinka.error(` ${error}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (this.options.onRebuildComplete) {
|
|
68
|
+
await this.options.onRebuildComplete(result);
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
await relinka.error(
|
|
73
|
+
`\u274C ${pkg.name}: Rebuild error - ${error instanceof Error ? error.message : String(error)}`
|
|
74
|
+
);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
await Promise.all(buildPromises);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Process rebuild queue with custom build options
|
|
82
|
+
*/
|
|
83
|
+
async processWithOptions(options) {
|
|
84
|
+
if (this.rebuildQueue.size === 0) return;
|
|
85
|
+
const packagesToRebuild = Array.from(this.rebuildQueue).map((name) => this.packages.find((pkg) => pkg.name === name)).filter((pkg) => pkg !== void 0);
|
|
86
|
+
this.rebuildQueue.clear();
|
|
87
|
+
await relinka.info(`\u{1F504} Rebuilding ${packagesToRebuild.length} packages...`);
|
|
88
|
+
const { buildPackage } = await import("../../mod.js");
|
|
89
|
+
for (const pkg of packagesToRebuild) {
|
|
90
|
+
try {
|
|
91
|
+
const result = await buildPackage(pkg, options);
|
|
92
|
+
if (result.success) {
|
|
93
|
+
await relinka.success(`\u2705 ${pkg.name}: Rebuilt successfully`);
|
|
94
|
+
} else {
|
|
95
|
+
await relinka.error(`\u274C ${pkg.name}: Rebuild failed`);
|
|
96
|
+
for (const error of result.errors) {
|
|
97
|
+
await relinka.error(` ${error}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (this.options.onRebuildComplete) {
|
|
101
|
+
await this.options.onRebuildComplete(result);
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
await relinka.error(
|
|
105
|
+
`\u274C ${pkg.name}: Rebuild error - ${error instanceof Error ? error.message : String(error)}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BuildOptions } from "./types.js";
|
|
2
|
+
export interface ValidationError {
|
|
3
|
+
field: string;
|
|
4
|
+
message: string;
|
|
5
|
+
suggestion?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function validateBuildOptions(options: BuildOptions): ValidationError[];
|
|
8
|
+
export declare function logValidationErrors(errors: ValidationError[]): void;
|
|
9
|
+
export declare function validateAndExit(options: BuildOptions): void;
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { logger } from "@reliverse/relinka";
|
|
2
|
+
export function validateBuildOptions(options) {
|
|
3
|
+
const errors = [];
|
|
4
|
+
if (options.bundler && !["bun", "mkdist"].includes(options.bundler)) {
|
|
5
|
+
errors.push({
|
|
6
|
+
field: "bundler",
|
|
7
|
+
message: 'Bundler must be "bun" or "mkdist"',
|
|
8
|
+
suggestion: 'Set --bundler to "bun" or "mkdist"'
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
if (options.bytecode) {
|
|
12
|
+
if (options.format !== "cjs") {
|
|
13
|
+
errors.push({
|
|
14
|
+
field: "bytecode",
|
|
15
|
+
message: 'Bytecode compilation requires format: "cjs"',
|
|
16
|
+
suggestion: "Set --format cjs or remove --bytecode"
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (options.target !== "bun") {
|
|
20
|
+
errors.push({
|
|
21
|
+
field: "bytecode",
|
|
22
|
+
message: 'Bytecode compilation requires target: "bun"',
|
|
23
|
+
suggestion: "Set --target bun or remove --bytecode"
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (options.jsx) {
|
|
28
|
+
if (options.jsx.runtime && !["automatic", "classic"].includes(options.jsx.runtime)) {
|
|
29
|
+
errors.push({
|
|
30
|
+
field: "jsx.runtime",
|
|
31
|
+
message: 'JSX runtime must be "automatic" or "classic"',
|
|
32
|
+
suggestion: 'Set --jsxRuntime to "automatic" or "classic"'
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
if (options.jsx.importSource && typeof options.jsx.importSource !== "string") {
|
|
36
|
+
errors.push({
|
|
37
|
+
field: "jsx.importSource",
|
|
38
|
+
message: "JSX import source must be a string",
|
|
39
|
+
suggestion: 'Set --jsxImportSource to a valid package name like "react"'
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (options.format === "iife") {
|
|
44
|
+
if (options.target !== "browser") {
|
|
45
|
+
errors.push({
|
|
46
|
+
field: "format",
|
|
47
|
+
message: 'IIFE format requires target: "browser"',
|
|
48
|
+
suggestion: "Set --target browser or use --format esm/cjs"
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (options.splitting) {
|
|
52
|
+
errors.push({
|
|
53
|
+
field: "splitting",
|
|
54
|
+
message: "Code splitting is not supported with IIFE format",
|
|
55
|
+
suggestion: "Set --splitting false or use --format esm/cjs"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (options.format === "cjs") {
|
|
60
|
+
if (options.target === "browser") {
|
|
61
|
+
errors.push({
|
|
62
|
+
field: "format",
|
|
63
|
+
message: "CommonJS format is not recommended for browser targets",
|
|
64
|
+
suggestion: "Use --format esm for browser or --target node for CommonJS"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
errors.push({
|
|
68
|
+
field: "format",
|
|
69
|
+
message: "CommonJS format is experimental in Bun",
|
|
70
|
+
suggestion: "Consider using --format esm for better compatibility"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (options.format === "iife") {
|
|
74
|
+
errors.push({
|
|
75
|
+
field: "format",
|
|
76
|
+
message: "IIFE format is experimental in Bun",
|
|
77
|
+
suggestion: "Consider using --format esm for better compatibility"
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (options.production && options.dev) {
|
|
81
|
+
errors.push({
|
|
82
|
+
field: "production",
|
|
83
|
+
message: "Cannot use both --production and --dev flags",
|
|
84
|
+
suggestion: "Choose either --production or --dev"
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (options.watch && options.compile) {
|
|
88
|
+
errors.push({
|
|
89
|
+
field: "watch",
|
|
90
|
+
message: "Watch mode is not supported with --compile",
|
|
91
|
+
suggestion: "Remove --watch or --compile flag"
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (options.compile) {
|
|
95
|
+
if (options.target === "browser") {
|
|
96
|
+
errors.push({
|
|
97
|
+
field: "compile",
|
|
98
|
+
message: "Standalone executables cannot be built for browser target",
|
|
99
|
+
suggestion: "Use --target bun or --target node for executables"
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (options.html) {
|
|
103
|
+
errors.push({
|
|
104
|
+
field: "compile",
|
|
105
|
+
message: "HTML processing is not compatible with standalone executables",
|
|
106
|
+
suggestion: "Remove --html or --compile flag"
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (!options.bytecode && options.format === "cjs" && options.target === "bun") {
|
|
110
|
+
logger.info(
|
|
111
|
+
"\u{1F4A1} Consider using --bytecode with --compile for faster cold starts"
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (options.entryNaming && !isValidNamingPattern(options.entryNaming)) {
|
|
116
|
+
errors.push({
|
|
117
|
+
field: "entryNaming",
|
|
118
|
+
message: "Invalid entry naming pattern",
|
|
119
|
+
suggestion: "Use valid placeholders: [dir], [name], [ext], [hash]"
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (options.chunkNaming && !isValidNamingPattern(options.chunkNaming)) {
|
|
123
|
+
errors.push({
|
|
124
|
+
field: "chunkNaming",
|
|
125
|
+
message: "Invalid chunk naming pattern",
|
|
126
|
+
suggestion: "Use valid placeholders: [dir], [name], [ext], [hash]"
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (options.assetNaming && !isValidNamingPattern(options.assetNaming)) {
|
|
130
|
+
errors.push({
|
|
131
|
+
field: "assetNaming",
|
|
132
|
+
message: "Invalid asset naming pattern",
|
|
133
|
+
suggestion: "Use valid placeholders: [dir], [name], [ext], [hash]"
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (options.external && Array.isArray(options.external)) {
|
|
137
|
+
for (const ext of options.external) {
|
|
138
|
+
if (typeof ext !== "string" || ext.trim() === "") {
|
|
139
|
+
errors.push({
|
|
140
|
+
field: "external",
|
|
141
|
+
message: "External packages must be non-empty strings",
|
|
142
|
+
suggestion: "Remove empty strings from external array"
|
|
143
|
+
});
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (options.drop && Array.isArray(options.drop)) {
|
|
149
|
+
for (const drop of options.drop) {
|
|
150
|
+
if (typeof drop !== "string" || drop.trim() === "") {
|
|
151
|
+
errors.push({
|
|
152
|
+
field: "drop",
|
|
153
|
+
message: "Drop patterns must be non-empty strings",
|
|
154
|
+
suggestion: "Remove empty strings from drop array"
|
|
155
|
+
});
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (options.concurrency !== void 0) {
|
|
161
|
+
if (!Number.isInteger(options.concurrency) || options.concurrency < 1) {
|
|
162
|
+
errors.push({
|
|
163
|
+
field: "concurrency",
|
|
164
|
+
message: "Concurrency must be a positive integer",
|
|
165
|
+
suggestion: "Set --concurrency to a number >= 1"
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (options.devServer) {
|
|
170
|
+
if (options.target !== "browser") {
|
|
171
|
+
errors.push({
|
|
172
|
+
field: "devServer",
|
|
173
|
+
message: 'Dev server requires target: "browser"',
|
|
174
|
+
suggestion: "Set --target browser or remove --devServer"
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (options.compile) {
|
|
178
|
+
errors.push({
|
|
179
|
+
field: "devServer",
|
|
180
|
+
message: "Dev server is not supported with --compile",
|
|
181
|
+
suggestion: "Remove --compile or --devServer flag"
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (options.port !== void 0) {
|
|
186
|
+
if (!Number.isInteger(options.port) || options.port < 1 || options.port > 65535) {
|
|
187
|
+
errors.push({
|
|
188
|
+
field: "port",
|
|
189
|
+
message: "Port must be between 1 and 65535",
|
|
190
|
+
suggestion: "Set --port to a valid port number"
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (options.html && options.target === "node") {
|
|
195
|
+
errors.push({
|
|
196
|
+
field: "html",
|
|
197
|
+
message: 'HTML processing is not supported with target: "node"',
|
|
198
|
+
suggestion: "Use --target browser for HTML processing"
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (options.cssChunking && options.format === "iife") {
|
|
202
|
+
errors.push({
|
|
203
|
+
field: "cssChunking",
|
|
204
|
+
message: "CSS chunking is not supported with IIFE format",
|
|
205
|
+
suggestion: "Use --format esm or remove --cssChunking"
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (options.minify && typeof options.minify === "object") {
|
|
209
|
+
const minify = options.minify;
|
|
210
|
+
if (minify.whitespace !== void 0 && typeof minify.whitespace !== "boolean") {
|
|
211
|
+
errors.push({
|
|
212
|
+
field: "minify.whitespace",
|
|
213
|
+
message: "Minify whitespace option must be boolean",
|
|
214
|
+
suggestion: "Set --minifyWhitespace to true or false"
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
if (minify.syntax !== void 0 && typeof minify.syntax !== "boolean") {
|
|
218
|
+
errors.push({
|
|
219
|
+
field: "minify.syntax",
|
|
220
|
+
message: "Minify syntax option must be boolean",
|
|
221
|
+
suggestion: "Set --minifySyntax to true or false"
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
if (minify.identifiers !== void 0 && typeof minify.identifiers !== "boolean") {
|
|
225
|
+
errors.push({
|
|
226
|
+
field: "minify.identifiers",
|
|
227
|
+
message: "Minify identifiers option must be boolean",
|
|
228
|
+
suggestion: "Set --minifyIdentifiers to true or false"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (options.loader && typeof options.loader === "object") {
|
|
233
|
+
const validLoaders = [
|
|
234
|
+
"js",
|
|
235
|
+
"jsx",
|
|
236
|
+
"ts",
|
|
237
|
+
"tsx",
|
|
238
|
+
"json",
|
|
239
|
+
"toml",
|
|
240
|
+
"file",
|
|
241
|
+
"napi",
|
|
242
|
+
"wasm",
|
|
243
|
+
"text"
|
|
244
|
+
];
|
|
245
|
+
for (const [ext, loader] of Object.entries(options.loader)) {
|
|
246
|
+
if (typeof loader !== "string" || !validLoaders.includes(loader)) {
|
|
247
|
+
errors.push({
|
|
248
|
+
field: "loader",
|
|
249
|
+
message: `Invalid loader for extension .${ext}: ${loader}`,
|
|
250
|
+
suggestion: `Use one of: ${validLoaders.join(", ")}`
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (options.env && typeof options.env === "string") {
|
|
256
|
+
if (options.env !== "inline" && options.env !== "disable" && !options.env.endsWith("*")) {
|
|
257
|
+
errors.push({
|
|
258
|
+
field: "env",
|
|
259
|
+
message: 'env must be "inline", "disable", or a string ending with "*"',
|
|
260
|
+
suggestion: 'Use --env inline, --env disable, or --env "PUBLIC_*"'
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (options.conditions && Array.isArray(options.conditions)) {
|
|
265
|
+
for (const condition of options.conditions) {
|
|
266
|
+
if (typeof condition !== "string" || condition.trim() === "") {
|
|
267
|
+
errors.push({
|
|
268
|
+
field: "conditions",
|
|
269
|
+
message: "Conditions must be non-empty strings",
|
|
270
|
+
suggestion: "Remove empty strings from conditions array"
|
|
271
|
+
});
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (options.naming) {
|
|
277
|
+
if (options.naming.chunk && !isValidNamingPattern(options.naming.chunk)) {
|
|
278
|
+
errors.push({
|
|
279
|
+
field: "naming.chunk",
|
|
280
|
+
message: "Invalid chunk naming pattern",
|
|
281
|
+
suggestion: "Use valid placeholders: [dir], [name], [ext], [hash]"
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (options.naming.entry && !isValidNamingPattern(options.naming.entry)) {
|
|
285
|
+
errors.push({
|
|
286
|
+
field: "naming.entry",
|
|
287
|
+
message: "Invalid entry naming pattern",
|
|
288
|
+
suggestion: "Use valid placeholders: [dir], [name], [ext], [hash]"
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
if (options.naming.asset && !isValidNamingPattern(options.naming.asset)) {
|
|
292
|
+
errors.push({
|
|
293
|
+
field: "naming.asset",
|
|
294
|
+
message: "Invalid asset naming pattern",
|
|
295
|
+
suggestion: "Use valid placeholders: [dir], [name], [ext], [hash]"
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return errors;
|
|
300
|
+
}
|
|
301
|
+
function isValidNamingPattern(pattern) {
|
|
302
|
+
const validPlaceholders = /\[(dir|name|ext|hash)\]/g;
|
|
303
|
+
const matches = pattern.match(validPlaceholders);
|
|
304
|
+
if (!matches) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
const invalidChars = /[<>:"|?*]/;
|
|
308
|
+
if (invalidChars.test(pattern)) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
export function logValidationErrors(errors) {
|
|
314
|
+
if (errors.length === 0) return;
|
|
315
|
+
logger.error("\u274C Build configuration validation failed:");
|
|
316
|
+
logger.error("");
|
|
317
|
+
for (const error of errors) {
|
|
318
|
+
logger.error(` \u2022 ${error.field}: ${error.message}`);
|
|
319
|
+
if (error.suggestion) {
|
|
320
|
+
logger.error(` \u{1F4A1} ${error.suggestion}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
logger.error("");
|
|
324
|
+
logger.error("Run with --help to see all available options.");
|
|
325
|
+
}
|
|
326
|
+
export function validateAndExit(options) {
|
|
327
|
+
const errors = validateBuildOptions(options);
|
|
328
|
+
if (errors.length > 0) {
|
|
329
|
+
logValidationErrors(errors);
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BuildOptions, PackageInfo } from "./types.js";
|
|
2
|
+
export interface WatchOptions extends BuildOptions {
|
|
3
|
+
debounceMs?: number;
|
|
4
|
+
ignorePatterns?: string[];
|
|
5
|
+
incremental?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class FileWatcher {
|
|
8
|
+
private watchers;
|
|
9
|
+
private rebuildQueue;
|
|
10
|
+
private options;
|
|
11
|
+
private packages;
|
|
12
|
+
constructor(packages: PackageInfo[], options: WatchOptions);
|
|
13
|
+
start(): Promise<void>;
|
|
14
|
+
stop(): Promise<void>;
|
|
15
|
+
private watchPackage;
|
|
16
|
+
private watchFile;
|
|
17
|
+
private watchDirectory;
|
|
18
|
+
private handleFileChange;
|
|
19
|
+
private shouldIgnoreFile;
|
|
20
|
+
}
|
|
21
|
+
export declare function startWatchMode(packages: PackageInfo[], options: WatchOptions): Promise<void>;
|