@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.
Files changed (75) hide show
  1. package/dist/impl/assets.d.ts +28 -0
  2. package/dist/impl/assets.js +188 -0
  3. package/dist/impl/cache.d.ts +25 -0
  4. package/dist/impl/cache.js +209 -0
  5. package/dist/impl/constants.d.ts +44 -0
  6. package/dist/impl/constants.js +45 -0
  7. package/dist/impl/debug.d.ts +30 -0
  8. package/dist/impl/debug.js +150 -0
  9. package/dist/impl/dependency-tracker.d.ts +23 -0
  10. package/dist/impl/dependency-tracker.js +113 -0
  11. package/dist/impl/dev-server.d.ts +24 -0
  12. package/dist/impl/dev-server.js +360 -0
  13. package/dist/impl/dts-generator.d.ts +26 -0
  14. package/dist/impl/dts-generator.js +514 -0
  15. package/dist/impl/go-build.d.ts +10 -0
  16. package/dist/impl/go-build.js +350 -0
  17. package/dist/impl/html-processor.d.ts +21 -0
  18. package/dist/impl/html-processor.js +167 -0
  19. package/dist/impl/impl.d.ts +0 -0
  20. package/dist/impl/impl.js +0 -0
  21. package/dist/impl/plugins/asset-optimization.d.ts +2 -0
  22. package/dist/impl/plugins/asset-optimization.js +114 -0
  23. package/dist/impl/plugins/bundle-analyzer.d.ts +2 -0
  24. package/dist/impl/plugins/bundle-analyzer.js +156 -0
  25. package/dist/impl/plugins/css-modules.d.ts +2 -0
  26. package/dist/impl/plugins/css-modules.js +19 -0
  27. package/dist/impl/plugins/index.d.ts +21 -0
  28. package/dist/impl/plugins/index.js +65 -0
  29. package/dist/impl/plugins/performance.d.ts +2 -0
  30. package/dist/impl/plugins/performance.js +62 -0
  31. package/dist/impl/plugins/react-refresh.d.ts +2 -0
  32. package/dist/impl/plugins/react-refresh.js +33 -0
  33. package/dist/impl/plugins/svg-as-react.d.ts +2 -0
  34. package/dist/impl/plugins/svg-as-react.js +18 -0
  35. package/dist/impl/plugins/typescript-declarations.d.ts +2 -0
  36. package/dist/impl/plugins/typescript-declarations.js +48 -0
  37. package/dist/impl/plugins/worker.d.ts +2 -0
  38. package/dist/impl/plugins/worker.js +20 -0
  39. package/dist/impl/presets.d.ts +10 -0
  40. package/dist/impl/presets.js +196 -0
  41. package/dist/impl/providers/mkdist/loader.d.ts +4 -0
  42. package/dist/impl/providers/mkdist/loader.js +26 -0
  43. package/dist/impl/providers/mkdist/loaders/js.d.ts +2 -0
  44. package/dist/impl/providers/mkdist/loaders/js.js +50 -0
  45. package/dist/impl/providers/mkdist/loaders/loaders-mod.d.ts +9 -0
  46. package/dist/impl/providers/mkdist/loaders/loaders-mod.js +22 -0
  47. package/dist/impl/providers/mkdist/make.d.ts +11 -0
  48. package/dist/impl/providers/mkdist/make.js +230 -0
  49. package/dist/impl/providers/mkdist/utils/dts.d.ts +11 -0
  50. package/dist/impl/providers/mkdist/utils/dts.js +117 -0
  51. package/dist/impl/providers/mkdist/utils/fs.d.ts +1 -0
  52. package/dist/impl/providers/mkdist/utils/fs.js +15 -0
  53. package/dist/impl/providers/mkdist-dts.d.ts +24 -0
  54. package/dist/impl/providers/mkdist-dts.js +8 -0
  55. package/dist/impl/tsconfig-validator.d.ts +35 -0
  56. package/dist/impl/tsconfig-validator.js +184 -0
  57. package/dist/impl/type-guards.d.ts +20 -0
  58. package/dist/impl/type-guards.js +147 -0
  59. package/dist/impl/types.d.ts +322 -0
  60. package/dist/impl/types.js +0 -0
  61. package/dist/impl/utils/go-build-handler.d.ts +12 -0
  62. package/dist/impl/utils/go-build-handler.js +83 -0
  63. package/dist/impl/utils/log-extraction.d.ts +25 -0
  64. package/dist/impl/utils/log-extraction.js +24 -0
  65. package/dist/impl/utils/package-filtering.d.ts +5 -0
  66. package/dist/impl/utils/package-filtering.js +22 -0
  67. package/dist/impl/utils/rebuild-queue.d.ts +38 -0
  68. package/dist/impl/utils/rebuild-queue.js +110 -0
  69. package/dist/impl/validation.d.ts +9 -0
  70. package/dist/impl/validation.js +332 -0
  71. package/dist/impl/watch.d.ts +21 -0
  72. package/dist/impl/watch.js +144 -0
  73. package/dist/mod.d.ts +17 -0
  74. package/dist/mod.js +1390 -0
  75. package/package.json +42 -0
@@ -0,0 +1,150 @@
1
+ import { logger } from "@reliverse/relinka";
2
+ export class DebugLogger {
3
+ enabled;
4
+ startTime = 0;
5
+ constructor(enabled = false) {
6
+ this.enabled = enabled;
7
+ }
8
+ start() {
9
+ this.startTime = Date.now();
10
+ if (this.enabled) {
11
+ logger.info("\u{1F41B} Debug mode enabled");
12
+ }
13
+ }
14
+ logConfigResolution(pkg, configSource, configPath) {
15
+ if (!this.enabled) return;
16
+ logger.info(`\u{1F4CB} Config resolution for ${pkg.name}:`);
17
+ logger.info(` Source: ${configSource}`);
18
+ if (configPath) {
19
+ logger.info(` Path: ${configPath}`);
20
+ }
21
+ }
22
+ logBuildOptions(options, pkg) {
23
+ if (!this.enabled) return;
24
+ logger.info(`\u2699\uFE0F Build options for ${pkg.name}:`);
25
+ logger.info(` Target: ${options.target || "bun"}`);
26
+ logger.info(` Format: ${options.format || "esm"}`);
27
+ logger.info(` Minify: ${options.minify ? "enabled" : "disabled"}`);
28
+ logger.info(` Sourcemap: ${options.sourcemap || "none"}`);
29
+ logger.info(` Splitting: ${options.splitting ? "enabled" : "disabled"}`);
30
+ if (options.jsx) {
31
+ logger.info(` JSX Runtime: ${options.jsx.runtime || "automatic"}`);
32
+ if (options.jsx.importSource) {
33
+ logger.info(` JSX Import Source: ${options.jsx.importSource}`);
34
+ }
35
+ }
36
+ if (options.external) {
37
+ const externals = Array.isArray(options.external) ? options.external : [options.external];
38
+ logger.info(` External: ${externals.join(", ")}`);
39
+ }
40
+ if (options.define) {
41
+ logger.info(` Define: ${JSON.stringify(options.define)}`);
42
+ }
43
+ }
44
+ logEntryPoints(pkg) {
45
+ if (!this.enabled) return;
46
+ logger.info(`\u{1F4C1} Entry points for ${pkg.name}:`);
47
+ for (const entryPoint of pkg.entryPoints) {
48
+ logger.info(` \u2022 ${entryPoint}`);
49
+ }
50
+ }
51
+ logBuildStats(summary) {
52
+ if (!this.enabled) return;
53
+ const totalTime = Date.now() - this.startTime;
54
+ logger.info("\u{1F4CA} Build Statistics:");
55
+ logger.info(` Total packages: ${summary.totalPackages}`);
56
+ logger.info(` Successful: ${summary.successfulPackages}`);
57
+ logger.info(` Failed: ${summary.failedPackages}`);
58
+ logger.info(` Skipped: ${summary.skippedPackages}`);
59
+ logger.info(` Cache hits: ${summary.cacheHits}`);
60
+ logger.info(` Total build time: ${summary.totalBuildTime}ms`);
61
+ logger.info(
62
+ ` Total bundle size: ${formatBytes(summary.totalBundleSize)}`
63
+ );
64
+ logger.info(` Process time: ${totalTime}ms`);
65
+ logger.info(
66
+ ` Average per package: ${Math.round(summary.totalBuildTime / summary.totalPackages)}ms`
67
+ );
68
+ if (summary.cacheHits > 0) {
69
+ const cacheHitRate = Math.round(
70
+ summary.cacheHits / summary.totalPackages * 100
71
+ );
72
+ logger.info(` Cache hit rate: ${cacheHitRate}%`);
73
+ }
74
+ }
75
+ logPackageResult(result) {
76
+ if (!this.enabled) return;
77
+ logger.info(`\u{1F4E6} Build result for ${result.package.name}:`);
78
+ logger.info(` Success: ${result.success ? "\u2705" : "\u274C"}`);
79
+ logger.info(` Skipped: ${result.skipped ? "\u23ED\uFE0F" : "\u274C"}`);
80
+ logger.info(` Build time: ${result.buildTime}ms`);
81
+ if (result.bundleSize) {
82
+ logger.info(` Bundle size: ${formatBytes(result.bundleSize)}`);
83
+ }
84
+ if (result.cacheHit) {
85
+ logger.info(` Cache hit: \u26A1`);
86
+ }
87
+ if (result.errors.length > 0) {
88
+ logger.info(` Errors: ${result.errors.length}`);
89
+ for (const error of result.errors) {
90
+ logger.info(` \u2022 ${error}`);
91
+ }
92
+ }
93
+ if (result.warnings.length > 0) {
94
+ logger.info(` Warnings: ${result.warnings.length}`);
95
+ for (const warning of result.warnings) {
96
+ logger.info(` \u2022 ${warning}`);
97
+ }
98
+ }
99
+ }
100
+ logDependencyGraph(pkg, dependencies) {
101
+ if (!this.enabled) return;
102
+ logger.info(`\u{1F517} Dependencies for ${pkg.name}:`);
103
+ for (const dep of dependencies) {
104
+ logger.info(` \u2022 ${dep}`);
105
+ }
106
+ }
107
+ logCacheInfo(pkg, cacheHit, cacheKey) {
108
+ if (!this.enabled) return;
109
+ if (cacheHit) {
110
+ logger.info(`\u26A1 Cache hit for ${pkg.name}`);
111
+ if (cacheKey) {
112
+ logger.info(` Key: ${cacheKey}`);
113
+ }
114
+ } else {
115
+ logger.info(`\u{1F504} Cache miss for ${pkg.name}`);
116
+ }
117
+ }
118
+ logFileWatching(pkg, watchedFiles) {
119
+ if (!this.enabled) return;
120
+ logger.info(`\u{1F440} Watching files for ${pkg.name}:`);
121
+ for (const file of watchedFiles) {
122
+ logger.info(` \u2022 ${file}`);
123
+ }
124
+ }
125
+ logAssetProcessing(pkg, assets) {
126
+ if (!this.enabled) return;
127
+ logger.info(`\u{1F3A8} Asset processing for ${pkg.name}:`);
128
+ for (const asset of assets) {
129
+ logger.info(` \u2022 ${asset}`);
130
+ }
131
+ }
132
+ logError(error, context) {
133
+ if (!this.enabled) return;
134
+ logger.error(`\u{1F41B} Debug error${context ? ` in ${context}` : ""}:`);
135
+ logger.error(` Message: ${error.message}`);
136
+ if (error.stack) {
137
+ logger.error(` Stack: ${error.stack}`);
138
+ }
139
+ }
140
+ }
141
+ function formatBytes(bytes) {
142
+ if (bytes === 0) return "0 B";
143
+ const k = 1024;
144
+ const sizes = ["B", "KB", "MB", "GB"];
145
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
146
+ return `${parseFloat((bytes / k ** i).toFixed(1))} ${sizes[i]}`;
147
+ }
148
+ export function createDebugLogger(options) {
149
+ return new DebugLogger(options.debug || false);
150
+ }
@@ -0,0 +1,23 @@
1
+ export interface DependencyInfo {
2
+ filePath: string;
3
+ hash: string;
4
+ dependencies: string[];
5
+ lastModified: number;
6
+ }
7
+ export interface DependencyGraph {
8
+ [filePath: string]: DependencyInfo;
9
+ }
10
+ export declare class DependencyTracker {
11
+ private graph;
12
+ private visitedFiles;
13
+ trackDependencies(entryPoints: string[]): Promise<DependencyGraph>;
14
+ private trackFile;
15
+ private extractDependencies;
16
+ private resolveImportPath;
17
+ getFileHash(filePath: string): string | null;
18
+ getDependencies(filePath: string): string[];
19
+ getAllDependencies(filePath: string): string[];
20
+ hasFileChanged(filePath: string): boolean;
21
+ hasAnyDependencyChanged(filePath: string): boolean;
22
+ getGraph(): DependencyGraph;
23
+ }
@@ -0,0 +1,113 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { logger } from "@reliverse/relinka";
5
+ export class DependencyTracker {
6
+ graph = {};
7
+ visitedFiles = /* @__PURE__ */ new Set();
8
+ async trackDependencies(entryPoints) {
9
+ this.graph = {};
10
+ this.visitedFiles.clear();
11
+ for (const entryPoint of entryPoints) {
12
+ await this.trackFile(entryPoint);
13
+ }
14
+ return this.graph;
15
+ }
16
+ async trackFile(filePath) {
17
+ if (this.visitedFiles.has(filePath) || !existsSync(filePath)) {
18
+ return;
19
+ }
20
+ this.visitedFiles.add(filePath);
21
+ try {
22
+ const content = readFileSync(filePath, "utf-8");
23
+ const hash = createHash("sha256").update(content).digest("hex");
24
+ const stats = require("node:fs").statSync(filePath);
25
+ const dependencies = await this.extractDependencies(filePath, content);
26
+ this.graph[filePath] = {
27
+ filePath,
28
+ hash,
29
+ dependencies,
30
+ lastModified: stats.mtime.getTime()
31
+ };
32
+ for (const dep of dependencies) {
33
+ await this.trackFile(dep);
34
+ }
35
+ } catch (error) {
36
+ logger.warn(`Failed to track file ${filePath}: ${error}`);
37
+ }
38
+ }
39
+ async extractDependencies(filePath, content) {
40
+ const dependencies = [];
41
+ const dir = resolve(filePath, "..");
42
+ const importRegex = /(?:import\s+.*?\s+from\s+['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\)|import\s*\(\s*['"]([^'"]+)['"]\s*\))/g;
43
+ let match;
44
+ match = importRegex.exec(content);
45
+ while (match !== null) {
46
+ const importPath = match[1] || match[2] || match[3];
47
+ if (importPath && typeof importPath === "string") {
48
+ const resolvedPath = this.resolveImportPath(importPath, dir);
49
+ if (resolvedPath && existsSync(resolvedPath)) {
50
+ dependencies.push(resolvedPath);
51
+ }
52
+ }
53
+ match = importRegex.exec(content);
54
+ }
55
+ return [...new Set(dependencies)];
56
+ }
57
+ resolveImportPath(importPath, fromDir) {
58
+ if (importPath.startsWith("./") || importPath.startsWith("../")) {
59
+ return resolve(fromDir, importPath);
60
+ }
61
+ if (importPath.startsWith("/")) {
62
+ return importPath;
63
+ }
64
+ if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
65
+ return null;
66
+ }
67
+ return null;
68
+ }
69
+ getFileHash(filePath) {
70
+ return this.graph[filePath]?.hash || null;
71
+ }
72
+ getDependencies(filePath) {
73
+ return this.graph[filePath]?.dependencies || [];
74
+ }
75
+ getAllDependencies(filePath) {
76
+ const visited = /* @__PURE__ */ new Set();
77
+ const deps = [];
78
+ const collectDeps = (currentPath) => {
79
+ if (visited.has(currentPath)) return;
80
+ visited.add(currentPath);
81
+ const fileDeps = this.getDependencies(currentPath);
82
+ for (const dep of fileDeps) {
83
+ deps.push(dep);
84
+ collectDeps(dep);
85
+ }
86
+ };
87
+ collectDeps(filePath);
88
+ return deps;
89
+ }
90
+ hasFileChanged(filePath) {
91
+ if (!existsSync(filePath)) return true;
92
+ try {
93
+ const content = readFileSync(filePath, "utf-8");
94
+ const currentHash = createHash("sha256").update(content).digest("hex");
95
+ const cachedHash = this.getFileHash(filePath);
96
+ return currentHash !== cachedHash;
97
+ } catch {
98
+ return true;
99
+ }
100
+ }
101
+ hasAnyDependencyChanged(filePath) {
102
+ const deps = this.getAllDependencies(filePath);
103
+ for (const dep of deps) {
104
+ if (this.hasFileChanged(dep)) {
105
+ return true;
106
+ }
107
+ }
108
+ return false;
109
+ }
110
+ getGraph() {
111
+ return { ...this.graph };
112
+ }
113
+ }
@@ -0,0 +1,24 @@
1
+ import type { BuildOptions, DevServerOptions, PackageInfo } from "./types.js";
2
+ export declare class DevServer {
3
+ private server;
4
+ private config;
5
+ private packages;
6
+ private watchers;
7
+ private rebuildQueue;
8
+ constructor(packages: PackageInfo[], options: BuildOptions, devServerOptions?: DevServerOptions);
9
+ start(): Promise<void>;
10
+ stop(): Promise<void>;
11
+ private serveIndexHtml;
12
+ private serveStaticAsset;
13
+ private serveBuiltFile;
14
+ private serveFile;
15
+ private getContentType;
16
+ private generateFallbackHtml;
17
+ private startFileWatching;
18
+ private watchFile;
19
+ private watchDirectory;
20
+ private handleFileChange;
21
+ private handleHMRMessage;
22
+ private notifyClients;
23
+ }
24
+ export declare function startDevServer(packages: PackageInfo[], options: BuildOptions, devServerOptions?: DevServerOptions): Promise<DevServer>;
@@ -0,0 +1,360 @@
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import { extname, join } from "node:path";
3
+ import { relinka } from "@reliverse/relinka";
4
+ import {
5
+ DEFAULT_DEBOUNCE_MS,
6
+ DEFAULT_DEV_SERVER_HOST,
7
+ DEFAULT_DEV_SERVER_PORT
8
+ } from "./constants.js";
9
+ import { RebuildQueueProcessor } from "./utils/rebuild-queue.js";
10
+ export class DevServer {
11
+ server = null;
12
+ config;
13
+ packages;
14
+ watchers = /* @__PURE__ */ new Map();
15
+ rebuildQueue;
16
+ constructor(packages, options, devServerOptions) {
17
+ this.packages = packages;
18
+ this.config = {
19
+ port: devServerOptions?.port ?? DEFAULT_DEV_SERVER_PORT,
20
+ host: devServerOptions?.host ?? DEFAULT_DEV_SERVER_HOST,
21
+ hmr: devServerOptions?.hmr ?? true,
22
+ publicDir: options.publicAssets ?? "public"
23
+ };
24
+ this.rebuildQueue = new RebuildQueueProcessor(packages, {
25
+ debounceMs: DEFAULT_DEBOUNCE_MS,
26
+ buildOptions: { ...options },
27
+ onRebuildComplete: (result) => {
28
+ if (result.success) {
29
+ this.notifyClients("reload");
30
+ } else {
31
+ this.notifyClients("error", {
32
+ message: `Build failed: ${result.errors.join(", ")}`
33
+ });
34
+ }
35
+ }
36
+ });
37
+ }
38
+ async start() {
39
+ if (this.server) {
40
+ await relinka.warn("Dev server is already running");
41
+ return;
42
+ }
43
+ try {
44
+ this.server = Bun.serve({
45
+ port: this.config.port,
46
+ hostname: this.config.host,
47
+ fetch: async (request) => {
48
+ const url2 = new URL(request.url);
49
+ const pathname = url2.pathname;
50
+ const corsHeaders = {
51
+ "Access-Control-Allow-Origin": "*",
52
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
53
+ "Access-Control-Allow-Headers": "Content-Type, Authorization"
54
+ };
55
+ if (request.method === "OPTIONS") {
56
+ return new Response(null, {
57
+ status: 200,
58
+ headers: corsHeaders
59
+ });
60
+ }
61
+ if (pathname === "/" || pathname === "/index.html") {
62
+ const response = await this.serveIndexHtml();
63
+ if (response) {
64
+ Object.entries(corsHeaders).forEach(([key, value]) => {
65
+ response.headers.set(key, value);
66
+ });
67
+ }
68
+ return response;
69
+ }
70
+ const assetResponse = await this.serveStaticAsset(pathname);
71
+ if (assetResponse) {
72
+ Object.entries(corsHeaders).forEach(([key, value]) => {
73
+ assetResponse.headers.set(key, value);
74
+ });
75
+ return assetResponse;
76
+ }
77
+ const builtResponse = await this.serveBuiltFile(pathname);
78
+ if (builtResponse) {
79
+ Object.entries(corsHeaders).forEach(([key, value]) => {
80
+ builtResponse.headers.set(key, value);
81
+ });
82
+ return builtResponse;
83
+ }
84
+ return new Response("Not Found", {
85
+ status: 404,
86
+ headers: corsHeaders
87
+ });
88
+ },
89
+ websocket: {
90
+ open: (ws) => {
91
+ if (this.config.hmr) {
92
+ ws.subscribe("hmr");
93
+ }
94
+ },
95
+ message: (ws, message) => {
96
+ if (this.config.hmr) {
97
+ this.handleHMRMessage(ws, message);
98
+ }
99
+ }
100
+ }
101
+ });
102
+ const url = `http://${this.config.host}:${this.config.port}`;
103
+ await relinka.success(`\u{1F680} Dev server running at ${url}`);
104
+ if (this.config.hmr) {
105
+ await this.startFileWatching();
106
+ }
107
+ } catch (error) {
108
+ await relinka.error(`Failed to start dev server: ${error}`);
109
+ throw error;
110
+ }
111
+ }
112
+ async stop() {
113
+ if (this.server) {
114
+ this.server.stop();
115
+ this.server = null;
116
+ }
117
+ for (const watcher of this.watchers.values()) {
118
+ watcher.close();
119
+ }
120
+ this.watchers.clear();
121
+ await relinka.info("Dev server stopped");
122
+ }
123
+ async serveIndexHtml() {
124
+ for (const pkg of this.packages) {
125
+ if (pkg.hasHtmlEntry) {
126
+ const htmlFiles = pkg.entryPoints.filter((ep) => ep.endsWith(".html"));
127
+ if (htmlFiles.length > 0) {
128
+ const htmlPath = htmlFiles[0];
129
+ if (htmlPath && existsSync(htmlPath)) {
130
+ const content = readFileSync(htmlPath, "utf-8");
131
+ return new Response(content, {
132
+ headers: { "Content-Type": "text/html" }
133
+ });
134
+ }
135
+ }
136
+ }
137
+ }
138
+ const html = this.generateFallbackHtml();
139
+ return new Response(html, {
140
+ headers: { "Content-Type": "text/html" }
141
+ });
142
+ }
143
+ async serveStaticAsset(pathname) {
144
+ const assetPath = pathname.slice(1);
145
+ for (const pkg of this.packages) {
146
+ if (pkg.hasPublicDir) {
147
+ const publicPath = join(pkg.path, "public", assetPath);
148
+ if (existsSync(publicPath)) {
149
+ return this.serveFile(publicPath);
150
+ }
151
+ }
152
+ }
153
+ return null;
154
+ }
155
+ async serveBuiltFile(pathname) {
156
+ const filePath = pathname.slice(1);
157
+ for (const pkg of this.packages) {
158
+ const builtPath = join(pkg.outputDir, filePath);
159
+ if (existsSync(builtPath)) {
160
+ return this.serveFile(builtPath);
161
+ }
162
+ }
163
+ return null;
164
+ }
165
+ async serveFile(filePath) {
166
+ try {
167
+ if (!existsSync(filePath)) {
168
+ return null;
169
+ }
170
+ const content = readFileSync(filePath);
171
+ const ext = extname(filePath);
172
+ const contentType = this.getContentType(ext);
173
+ return new Response(content, {
174
+ headers: { "Content-Type": contentType }
175
+ });
176
+ } catch (error) {
177
+ await relinka.error(`Error serving file ${filePath}: ${error}`);
178
+ return null;
179
+ }
180
+ }
181
+ getContentType(ext) {
182
+ const types = {
183
+ ".html": "text/html",
184
+ ".js": "application/javascript",
185
+ ".mjs": "application/javascript",
186
+ ".css": "text/css",
187
+ ".json": "application/json",
188
+ ".png": "image/png",
189
+ ".jpg": "image/jpeg",
190
+ ".jpeg": "image/jpeg",
191
+ ".gif": "image/gif",
192
+ ".svg": "image/svg+xml",
193
+ ".webp": "image/webp",
194
+ ".ico": "image/x-icon",
195
+ ".woff": "font/woff",
196
+ ".woff2": "font/woff2",
197
+ ".ttf": "font/ttf",
198
+ ".eot": "application/vnd.ms-fontobject"
199
+ };
200
+ return types[ext] || "application/octet-stream";
201
+ }
202
+ generateFallbackHtml() {
203
+ const title = this.packages.length === 1 ? this.packages[0]?.name || "Frontend App" : "Frontend App";
204
+ return `<!DOCTYPE html>
205
+ <html lang="en">
206
+ <head>
207
+ <meta charset="UTF-8">
208
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
209
+ <title>${title}</title>
210
+ <style>
211
+ body {
212
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
213
+ margin: 0;
214
+ padding: 2rem;
215
+ background: #f5f5f5;
216
+ }
217
+ .container {
218
+ max-width: 800px;
219
+ margin: 0 auto;
220
+ background: white;
221
+ padding: 2rem;
222
+ border-radius: 8px;
223
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
224
+ }
225
+ h1 { color: #333; }
226
+ p { color: #666; line-height: 1.6; }
227
+ .status {
228
+ background: #e8f5e8;
229
+ color: #2d5a2d;
230
+ padding: 1rem;
231
+ border-radius: 4px;
232
+ margin: 1rem 0;
233
+ }
234
+ </style>
235
+ </head>
236
+ <body>
237
+ <div class="container">
238
+ <h1>${title}</h1>
239
+ <div class="status">
240
+ \u2705 Dev server is running successfully!
241
+ </div>
242
+ <p>This is a fallback page. To customize this page:</p>
243
+ <ul>
244
+ <li>Add an <code>index.html</code> file to your project root</li>
245
+ <li>Or add HTML files to your <code>public/</code> directory</li>
246
+ <li>Or configure entry points in your <code>package.json</code></li>
247
+ </ul>
248
+ <p>Hot Module Replacement (HMR) is enabled for development.</p>
249
+ </div>
250
+ <script>
251
+ // Basic HMR client
252
+ if (typeof WebSocket !== 'undefined') {
253
+ const ws = new WebSocket('ws://${this.config.host}:${this.config.port}');
254
+ ws.onmessage = (event) => {
255
+ if (event.data === 'reload') {
256
+ window.location.reload();
257
+ }
258
+ };
259
+ }
260
+ <\/script>
261
+ </body>
262
+ </html>`;
263
+ }
264
+ async startFileWatching() {
265
+ for (const pkg of this.packages) {
266
+ if (pkg.entryPoints.length === 0) continue;
267
+ const sourceFiles = pkg.entryPoints.filter((ep) => !ep.endsWith(".html"));
268
+ for (const file of sourceFiles) {
269
+ if (existsSync(file)) {
270
+ await this.watchFile(file, pkg);
271
+ }
272
+ }
273
+ const htmlFiles = pkg.entryPoints.filter((ep) => ep.endsWith(".html"));
274
+ for (const file of htmlFiles) {
275
+ if (existsSync(file)) {
276
+ await this.watchFile(file, pkg);
277
+ }
278
+ }
279
+ const srcDir = join(pkg.path, "src");
280
+ if (existsSync(srcDir) && statSync(srcDir).isDirectory()) {
281
+ await this.watchDirectory(srcDir, pkg);
282
+ }
283
+ }
284
+ await relinka.info("\u{1F440} File watching started for HMR");
285
+ }
286
+ async watchFile(filePath, pkg) {
287
+ if (this.watchers.has(filePath)) return;
288
+ try {
289
+ const { watch } = await import("node:fs");
290
+ const watcher = watch(filePath, (eventType) => {
291
+ if (eventType === "change") {
292
+ this.handleFileChange(filePath, pkg);
293
+ }
294
+ });
295
+ watcher.on("error", (error) => {
296
+ void relinka.warn(
297
+ `File watcher error for ${filePath}: ${error.message}`
298
+ );
299
+ this.watchers.delete(filePath);
300
+ });
301
+ this.watchers.set(filePath, watcher);
302
+ } catch (error) {
303
+ void relinka.warn(`Failed to watch file ${filePath}: ${error}`);
304
+ }
305
+ }
306
+ async watchDirectory(dirPath, pkg) {
307
+ if (this.watchers.has(dirPath)) return;
308
+ try {
309
+ const { watch } = await import("node:fs");
310
+ const watcher = watch(
311
+ dirPath,
312
+ { recursive: true },
313
+ (eventType, filename) => {
314
+ if (eventType === "change" && filename) {
315
+ const fullPath = join(dirPath, filename);
316
+ this.handleFileChange(fullPath, pkg);
317
+ }
318
+ }
319
+ );
320
+ watcher.on("error", (error) => {
321
+ void relinka.warn(
322
+ `Directory watcher error for ${dirPath}: ${error.message}`
323
+ );
324
+ this.watchers.delete(dirPath);
325
+ });
326
+ this.watchers.set(dirPath, watcher);
327
+ } catch (error) {
328
+ void relinka.warn(`Failed to watch directory ${dirPath}: ${error}`);
329
+ }
330
+ }
331
+ handleFileChange(filePath, pkg) {
332
+ void relinka.info(`\u{1F4DD} File changed: ${filePath}`);
333
+ this.rebuildQueue.add(pkg.name);
334
+ }
335
+ handleHMRMessage(ws, message) {
336
+ try {
337
+ const data = JSON.parse(message.toString());
338
+ switch (data.type) {
339
+ case "ping":
340
+ ws.send(JSON.stringify({ type: "pong" }));
341
+ break;
342
+ case "reload":
343
+ this.notifyClients("reload");
344
+ break;
345
+ }
346
+ } catch (_error) {
347
+ }
348
+ }
349
+ notifyClients(type, data) {
350
+ if (this.server?.publish) {
351
+ const message = JSON.stringify({ type, data, timestamp: Date.now() });
352
+ this.server.publish("hmr", message);
353
+ }
354
+ }
355
+ }
356
+ export async function startDevServer(packages, options, devServerOptions) {
357
+ const server = new DevServer(packages, options, devServerOptions);
358
+ await server.start();
359
+ return server;
360
+ }
@@ -0,0 +1,26 @@
1
+ import type { DtsOptions } from "@reliverse/config/impl/build";
2
+ import type { PackageInfo } from "./types.js";
3
+ export interface DtsGeneratorOptions {
4
+ /** Package information */
5
+ package: PackageInfo;
6
+ /** DTS configuration options */
7
+ dtsOptions: DtsOptions;
8
+ /** Build format (esm, cjs, iife) */
9
+ format?: "esm" | "cjs" | "iife";
10
+ /** Output directory for built files */
11
+ outputDir: string;
12
+ }
13
+ export interface DtsGeneratorResult {
14
+ success: boolean;
15
+ outputDir?: string;
16
+ error?: string;
17
+ files?: string[];
18
+ }
19
+ /**
20
+ * Generate TypeScript declaration files using Rslib's recommended approach
21
+ */
22
+ export declare function generateDeclarations(options: DtsGeneratorOptions): Promise<DtsGeneratorResult>;
23
+ /**
24
+ * Generate declarations with experimental tsgo
25
+ */
26
+ export declare function generateWithTsgo(pkg: PackageInfo, dtsOptions: DtsOptions, outputDir: string): Promise<DtsGeneratorResult>;