@harpy-js/core 0.5.1 → 0.5.3

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.js CHANGED
@@ -8,11 +8,13 @@ const scripts = {
8
8
  "build-hydration": path.join(__dirname, "../scripts/build-hydration.ts"),
9
9
  "auto-wrap": path.join(__dirname, "../scripts/auto-wrap-exports.ts"),
10
10
  "build-styles": path.join(__dirname, "../scripts/build-page-styles.ts"),
11
+ build: path.join(__dirname, "../scripts/build.ts"),
12
+ start: path.join(__dirname, "../scripts/start.ts"),
11
13
  dev: path.join(__dirname, "../scripts/dev.ts"),
12
14
  };
13
15
  if (!command || !scripts[command]) {
14
16
  console.error("Usage: harpy <command>");
15
- console.error("Commands: build-hydration, auto-wrap, build-styles, dev");
17
+ console.error("Commands: build, start, dev, build-hydration, auto-wrap, build-styles");
16
18
  process.exit(1);
17
19
  }
18
20
  const scriptPath = scripts[command];
package/dist/index.d.ts CHANGED
@@ -7,6 +7,8 @@ export { StaticAssetsController } from "./core/static-assets.controller";
7
7
  export { JsxRender } from "./decorators/jsx.decorator";
8
8
  export { WithLayout } from "./decorators/layout.decorator";
9
9
  export type { MetaOptions, RenderOptions } from "./decorators/jsx.decorator";
10
+ export { SeoModule, BaseSeoService, DefaultSeoService } from "./seo";
11
+ export type { SitemapUrl, RobotsConfig, SeoModuleOptions } from "./seo";
10
12
  export type { JsxLayout, JsxLayoutProps, PageProps } from "./types/jsx.types";
11
13
  export { RouterModule } from "./core/router.module";
12
14
  export { NavigationService } from "./core/navigation.service";
@@ -17,3 +19,4 @@ export { configureHarpyApp, HarpyAppOptions } from "./core/app-setup";
17
19
  export { setupHarpyApp } from "./core/app-setup";
18
20
  export { default as Link } from "./client/Link";
19
21
  export { buildHrefIndex, getActiveItemIdFromIndex, getActiveItemIdFromManifest, } from "./client/getActiveItemId";
22
+ export { useI18n } from "./client/use-i18n";
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getActiveItemIdFromManifest = exports.getActiveItemIdFromIndex = exports.buildHrefIndex = exports.Link = exports.setupHarpyApp = exports.configureHarpyApp = exports.AutoRegisterModule = exports.NavigationService = exports.RouterModule = exports.WithLayout = exports.JsxRender = exports.StaticAssetsController = exports.LiveReloadController = exports.withJsxEngine = exports.getHydrationManifest = exports.getChunkPath = exports.initializeHydrationContext = exports.hydrationContext = exports.autoWrapClientComponent = void 0;
6
+ exports.useI18n = exports.getActiveItemIdFromManifest = exports.getActiveItemIdFromIndex = exports.buildHrefIndex = exports.Link = exports.setupHarpyApp = exports.configureHarpyApp = exports.AutoRegisterModule = exports.NavigationService = exports.RouterModule = exports.DefaultSeoService = exports.BaseSeoService = exports.SeoModule = exports.WithLayout = exports.JsxRender = exports.StaticAssetsController = exports.LiveReloadController = exports.withJsxEngine = exports.getHydrationManifest = exports.getChunkPath = exports.initializeHydrationContext = exports.hydrationContext = exports.autoWrapClientComponent = void 0;
7
7
  var client_component_wrapper_1 = require("./core/client-component-wrapper");
8
8
  Object.defineProperty(exports, "autoWrapClientComponent", { enumerable: true, get: function () { return client_component_wrapper_1.autoWrapClientComponent; } });
9
9
  var hydration_1 = require("./core/hydration");
@@ -22,6 +22,10 @@ var jsx_decorator_1 = require("./decorators/jsx.decorator");
22
22
  Object.defineProperty(exports, "JsxRender", { enumerable: true, get: function () { return jsx_decorator_1.JsxRender; } });
23
23
  var layout_decorator_1 = require("./decorators/layout.decorator");
24
24
  Object.defineProperty(exports, "WithLayout", { enumerable: true, get: function () { return layout_decorator_1.WithLayout; } });
25
+ var seo_1 = require("./seo");
26
+ Object.defineProperty(exports, "SeoModule", { enumerable: true, get: function () { return seo_1.SeoModule; } });
27
+ Object.defineProperty(exports, "BaseSeoService", { enumerable: true, get: function () { return seo_1.BaseSeoService; } });
28
+ Object.defineProperty(exports, "DefaultSeoService", { enumerable: true, get: function () { return seo_1.DefaultSeoService; } });
25
29
  var router_module_1 = require("./core/router.module");
26
30
  Object.defineProperty(exports, "RouterModule", { enumerable: true, get: function () { return router_module_1.RouterModule; } });
27
31
  var navigation_service_1 = require("./core/navigation.service");
@@ -38,3 +42,5 @@ var getActiveItemId_1 = require("./client/getActiveItemId");
38
42
  Object.defineProperty(exports, "buildHrefIndex", { enumerable: true, get: function () { return getActiveItemId_1.buildHrefIndex; } });
39
43
  Object.defineProperty(exports, "getActiveItemIdFromIndex", { enumerable: true, get: function () { return getActiveItemId_1.getActiveItemIdFromIndex; } });
40
44
  Object.defineProperty(exports, "getActiveItemIdFromManifest", { enumerable: true, get: function () { return getActiveItemId_1.getActiveItemIdFromManifest; } });
45
+ var use_i18n_1 = require("./client/use-i18n");
46
+ Object.defineProperty(exports, "useI18n", { enumerable: true, get: function () { return use_i18n_1.useI18n; } });
@@ -0,0 +1,5 @@
1
+ export { SeoModule } from './seo.module';
2
+ export { BaseSeoService, DefaultSeoService } from './seo.service';
3
+ export { RobotsController } from './robots.controller';
4
+ export { SitemapController } from './sitemap.controller';
5
+ export type { SitemapUrl, RobotsConfig, SeoModuleOptions } from './seo.types';
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SitemapController = exports.RobotsController = exports.DefaultSeoService = exports.BaseSeoService = exports.SeoModule = void 0;
4
+ var seo_module_1 = require("./seo.module");
5
+ Object.defineProperty(exports, "SeoModule", { enumerable: true, get: function () { return seo_module_1.SeoModule; } });
6
+ var seo_service_1 = require("./seo.service");
7
+ Object.defineProperty(exports, "BaseSeoService", { enumerable: true, get: function () { return seo_service_1.BaseSeoService; } });
8
+ Object.defineProperty(exports, "DefaultSeoService", { enumerable: true, get: function () { return seo_service_1.DefaultSeoService; } });
9
+ var robots_controller_1 = require("./robots.controller");
10
+ Object.defineProperty(exports, "RobotsController", { enumerable: true, get: function () { return robots_controller_1.RobotsController; } });
11
+ var sitemap_controller_1 = require("./sitemap.controller");
12
+ Object.defineProperty(exports, "SitemapController", { enumerable: true, get: function () { return sitemap_controller_1.SitemapController; } });
@@ -0,0 +1,6 @@
1
+ import { BaseSeoService } from './seo.service';
2
+ export declare class RobotsController {
3
+ private readonly seoService;
4
+ constructor(seoService: BaseSeoService);
5
+ getRobots(): string;
6
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RobotsController = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const seo_service_1 = require("./seo.service");
15
+ let RobotsController = class RobotsController {
16
+ seoService;
17
+ constructor(seoService) {
18
+ this.seoService = seoService;
19
+ }
20
+ getRobots() {
21
+ const config = this.seoService.getRobotsConfig();
22
+ return this.seoService.formatRobotsTxt(config);
23
+ }
24
+ };
25
+ exports.RobotsController = RobotsController;
26
+ __decorate([
27
+ (0, common_1.Get)(),
28
+ (0, common_1.Header)('Content-Type', 'text/plain'),
29
+ (0, common_1.Header)('Cache-Control', 'public, max-age=86400'),
30
+ __metadata("design:type", Function),
31
+ __metadata("design:paramtypes", []),
32
+ __metadata("design:returntype", String)
33
+ ], RobotsController.prototype, "getRobots", null);
34
+ exports.RobotsController = RobotsController = __decorate([
35
+ (0, common_1.Controller)('robots.txt'),
36
+ __metadata("design:paramtypes", [seo_service_1.BaseSeoService])
37
+ ], RobotsController);
@@ -0,0 +1,7 @@
1
+ import { DynamicModule, Type } from '@nestjs/common';
2
+ import { BaseSeoService } from './seo.service';
3
+ import type { SeoModuleOptions } from './seo.types';
4
+ export declare class SeoModule {
5
+ static forRoot(options?: SeoModuleOptions): DynamicModule;
6
+ static forRootWithService(customService: Type<BaseSeoService>, options?: SeoModuleOptions): DynamicModule;
7
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var SeoModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.SeoModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const robots_controller_1 = require("./robots.controller");
13
+ const sitemap_controller_1 = require("./sitemap.controller");
14
+ const seo_service_1 = require("./seo.service");
15
+ let SeoModule = SeoModule_1 = class SeoModule {
16
+ static forRoot(options) {
17
+ return {
18
+ module: SeoModule_1,
19
+ controllers: [robots_controller_1.RobotsController, sitemap_controller_1.SitemapController],
20
+ providers: [
21
+ {
22
+ provide: seo_service_1.SEO_MODULE_OPTIONS,
23
+ useValue: options || {},
24
+ },
25
+ {
26
+ provide: seo_service_1.BaseSeoService,
27
+ useClass: seo_service_1.DefaultSeoService,
28
+ },
29
+ ],
30
+ exports: [seo_service_1.BaseSeoService],
31
+ };
32
+ }
33
+ static forRootWithService(customService, options) {
34
+ return {
35
+ module: SeoModule_1,
36
+ controllers: [robots_controller_1.RobotsController, sitemap_controller_1.SitemapController],
37
+ providers: [
38
+ {
39
+ provide: seo_service_1.SEO_MODULE_OPTIONS,
40
+ useValue: options || {},
41
+ },
42
+ {
43
+ provide: seo_service_1.BaseSeoService,
44
+ useClass: customService,
45
+ },
46
+ ],
47
+ exports: [seo_service_1.BaseSeoService],
48
+ };
49
+ }
50
+ };
51
+ exports.SeoModule = SeoModule;
52
+ exports.SeoModule = SeoModule = SeoModule_1 = __decorate([
53
+ (0, common_1.Module)({})
54
+ ], SeoModule);
@@ -0,0 +1,16 @@
1
+ import type { SitemapUrl, RobotsConfig, SeoModuleOptions } from './seo.types';
2
+ export declare const SEO_MODULE_OPTIONS = "SEO_MODULE_OPTIONS";
3
+ export declare abstract class BaseSeoService {
4
+ protected readonly options?: SeoModuleOptions | undefined;
5
+ protected readonly baseUrl: string;
6
+ constructor(options?: SeoModuleOptions | undefined);
7
+ abstract getSitemapUrls(): Promise<SitemapUrl[]>;
8
+ abstract getRobotsConfig(): RobotsConfig;
9
+ formatSitemapXml(urls: SitemapUrl[]): string;
10
+ formatRobotsTxt(config: RobotsConfig): string;
11
+ protected escapeXml(str: string): string;
12
+ }
13
+ export declare class DefaultSeoService extends BaseSeoService {
14
+ getSitemapUrls(): Promise<SitemapUrl[]>;
15
+ getRobotsConfig(): RobotsConfig;
16
+ }
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.DefaultSeoService = exports.BaseSeoService = exports.SEO_MODULE_OPTIONS = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ exports.SEO_MODULE_OPTIONS = 'SEO_MODULE_OPTIONS';
18
+ let BaseSeoService = class BaseSeoService {
19
+ options;
20
+ baseUrl;
21
+ constructor(options) {
22
+ this.options = options;
23
+ this.baseUrl = options?.baseUrl || 'http://localhost:3000';
24
+ }
25
+ formatSitemapXml(urls) {
26
+ const urlEntries = urls
27
+ .map((entry) => {
28
+ const lastmod = entry.lastModified
29
+ ? new Date(entry.lastModified).toISOString()
30
+ : new Date().toISOString();
31
+ return ` <url>
32
+ <loc>${this.escapeXml(entry.url)}</loc>
33
+ <lastmod>${lastmod}</lastmod>
34
+ ${entry.changeFrequency ? `<changefreq>${entry.changeFrequency}</changefreq>` : ''}
35
+ ${entry.priority !== undefined ? `<priority>${entry.priority}</priority>` : ''}
36
+ </url>`;
37
+ })
38
+ .join('\n');
39
+ return `<?xml version="1.0" encoding="UTF-8"?>
40
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
41
+ ${urlEntries}
42
+ </urlset>`;
43
+ }
44
+ formatRobotsTxt(config) {
45
+ const rules = Array.isArray(config.rules) ? config.rules : [config.rules];
46
+ const rulesText = rules
47
+ .map((rule) => {
48
+ const userAgents = Array.isArray(rule.userAgent)
49
+ ? rule.userAgent
50
+ : [rule.userAgent];
51
+ const allows = rule.allow
52
+ ? Array.isArray(rule.allow)
53
+ ? rule.allow
54
+ : [rule.allow]
55
+ : [];
56
+ const disallows = rule.disallow
57
+ ? Array.isArray(rule.disallow)
58
+ ? rule.disallow
59
+ : [rule.disallow]
60
+ : [];
61
+ let text = userAgents.map((ua) => `User-agent: ${ua}`).join('\n');
62
+ if (allows.length > 0) {
63
+ text += '\n' + allows.map((path) => `Allow: ${path}`).join('\n');
64
+ }
65
+ if (disallows.length > 0) {
66
+ text +=
67
+ '\n' + disallows.map((path) => `Disallow: ${path}`).join('\n');
68
+ }
69
+ if (rule.crawlDelay) {
70
+ text += `\nCrawl-delay: ${rule.crawlDelay}`;
71
+ }
72
+ return text;
73
+ })
74
+ .join('\n\n');
75
+ let result = rulesText;
76
+ if (config.sitemap) {
77
+ const sitemaps = Array.isArray(config.sitemap)
78
+ ? config.sitemap
79
+ : [config.sitemap];
80
+ result += '\n\n' + sitemaps.map((s) => `Sitemap: ${s}`).join('\n');
81
+ }
82
+ if (config.host) {
83
+ result += `\n\nHost: ${config.host}`;
84
+ }
85
+ return result;
86
+ }
87
+ escapeXml(str) {
88
+ return str
89
+ .replace(/&/g, '&amp;')
90
+ .replace(/</g, '&lt;')
91
+ .replace(/>/g, '&gt;')
92
+ .replace(/"/g, '&quot;')
93
+ .replace(/'/g, '&apos;');
94
+ }
95
+ };
96
+ exports.BaseSeoService = BaseSeoService;
97
+ exports.BaseSeoService = BaseSeoService = __decorate([
98
+ (0, common_1.Injectable)(),
99
+ __param(0, (0, common_1.Optional)()),
100
+ __param(0, (0, common_1.Inject)(exports.SEO_MODULE_OPTIONS)),
101
+ __metadata("design:paramtypes", [Object])
102
+ ], BaseSeoService);
103
+ let DefaultSeoService = class DefaultSeoService extends BaseSeoService {
104
+ async getSitemapUrls() {
105
+ const now = new Date();
106
+ return [
107
+ {
108
+ url: this.baseUrl,
109
+ lastModified: now,
110
+ changeFrequency: 'daily',
111
+ priority: 1.0,
112
+ },
113
+ ];
114
+ }
115
+ getRobotsConfig() {
116
+ const defaultConfig = {
117
+ rules: {
118
+ userAgent: '*',
119
+ allow: '/',
120
+ },
121
+ sitemap: `${this.baseUrl}/sitemap.xml`,
122
+ host: this.baseUrl,
123
+ };
124
+ if (this.options?.robotsConfig) {
125
+ return {
126
+ ...defaultConfig,
127
+ ...this.options.robotsConfig,
128
+ };
129
+ }
130
+ return defaultConfig;
131
+ }
132
+ };
133
+ exports.DefaultSeoService = DefaultSeoService;
134
+ exports.DefaultSeoService = DefaultSeoService = __decorate([
135
+ (0, common_1.Injectable)()
136
+ ], DefaultSeoService);
@@ -0,0 +1,29 @@
1
+ export interface SitemapUrl {
2
+ url: string;
3
+ lastModified?: Date | string;
4
+ changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
5
+ priority?: number;
6
+ alternates?: {
7
+ languages?: Record<string, string>;
8
+ };
9
+ }
10
+ export interface RobotsConfig {
11
+ rules: {
12
+ userAgent: string | string[];
13
+ allow?: string | string[];
14
+ disallow?: string | string[];
15
+ crawlDelay?: number;
16
+ } | Array<{
17
+ userAgent: string | string[];
18
+ allow?: string | string[];
19
+ disallow?: string | string[];
20
+ crawlDelay?: number;
21
+ }>;
22
+ sitemap?: string | string[];
23
+ host?: string;
24
+ }
25
+ export interface SeoModuleOptions {
26
+ baseUrl: string;
27
+ robotsConfig?: Partial<RobotsConfig>;
28
+ sitemapGenerator?: () => Promise<SitemapUrl[]>;
29
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import { BaseSeoService } from './seo.service';
2
+ export declare class SitemapController {
3
+ private readonly seoService;
4
+ constructor(seoService: BaseSeoService);
5
+ getSitemap(): Promise<string>;
6
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SitemapController = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const seo_service_1 = require("./seo.service");
15
+ let SitemapController = class SitemapController {
16
+ seoService;
17
+ constructor(seoService) {
18
+ this.seoService = seoService;
19
+ }
20
+ async getSitemap() {
21
+ const urls = await this.seoService.getSitemapUrls();
22
+ return this.seoService.formatSitemapXml(urls);
23
+ }
24
+ };
25
+ exports.SitemapController = SitemapController;
26
+ __decorate([
27
+ (0, common_1.Get)(),
28
+ (0, common_1.Header)('Content-Type', 'application/xml'),
29
+ (0, common_1.Header)('Cache-Control', 'public, max-age=3600, s-maxage=3600'),
30
+ __metadata("design:type", Function),
31
+ __metadata("design:paramtypes", []),
32
+ __metadata("design:returntype", Promise)
33
+ ], SitemapController.prototype, "getSitemap", null);
34
+ exports.SitemapController = SitemapController = __decorate([
35
+ (0, common_1.Controller)('sitemap.xml'),
36
+ __metadata("design:paramtypes", [seo_service_1.BaseSeoService])
37
+ ], SitemapController);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harpy-js/core",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Harpy - A powerful NestJS + React/JSX SSR framework with automatic hydration and i18n support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,6 +11,9 @@
11
11
 
12
12
  import * as fs from "fs";
13
13
  import * as path from "path";
14
+ import { Logger } from "./logger";
15
+
16
+ const logger = new Logger("AutoWrapper");
14
17
 
15
18
  const PROJECT_ROOT = process.cwd();
16
19
  const SRC_DIR = path.join(PROJECT_ROOT, "src");
@@ -213,16 +216,16 @@ function transformCompiledFile(
213
216
  * Main function
214
217
  */
215
218
  function main(): void {
216
- console.log("šŸ”„ Auto-wrapping client component exports...\n");
219
+ logger.log("Auto-wrapping client component exports...");
217
220
 
218
221
  const clientComponents = findClientComponentsInSource();
219
222
 
220
223
  if (clientComponents.size === 0) {
221
- console.log("āš ļø No client components found\n");
224
+ logger.warn("No client components found");
222
225
  return;
223
226
  }
224
227
 
225
- console.log(`Found ${clientComponents.size} client component(s):\n`);
228
+ logger.log(`Found ${clientComponents.size} client component(s)`);
226
229
 
227
230
  let wrapped = 0;
228
231
  for (const [compiledPath, componentName] of clientComponents) {
@@ -231,9 +234,7 @@ function main(): void {
231
234
  }
232
235
  }
233
236
 
234
- console.log(
235
- `\n✨ Auto-wrap complete: ${wrapped}/${clientComponents.size} components wrapped\n`,
236
- );
237
+ logger.log(`Auto-wrap complete: ${wrapped}/${clientComponents.size} components wrapped`);
237
238
  }
238
239
 
239
240
  main();
@@ -13,6 +13,9 @@ import { execSync } from "child_process";
13
13
  import * as crypto from "crypto";
14
14
  import * as fs from "fs";
15
15
  import * as path from "path";
16
+ import { Logger } from "./logger";
17
+
18
+ const logger = new Logger("HydrationBuilder");
16
19
 
17
20
  const PROJECT_ROOT = process.cwd();
18
21
  const SRC_DIR = path.join(PROJECT_ROOT, "src");
@@ -181,11 +184,11 @@ function main(): void {
181
184
  fs.mkdirSync(HYDRATION_ENTRIES_DIR, { recursive: true });
182
185
  }
183
186
 
184
- console.log("šŸ” Detecting client components...");
187
+ logger.log("Detecting client components...");
185
188
  const clientComponents = findClientComponents();
186
189
 
187
190
  if (clientComponents.length === 0) {
188
- console.log("āš ļø No client components found");
191
+ logger.warn("No client components found");
189
192
  // Still ensure chunks directory exists and clear manifest
190
193
  if (!fs.existsSync(CHUNKS_DIR)) {
191
194
  fs.mkdirSync(CHUNKS_DIR, { recursive: true });
@@ -207,7 +210,7 @@ function main(): void {
207
210
  fs.mkdirSync(CHUNKS_DIR, { recursive: true });
208
211
  }
209
212
 
210
- console.log("\nšŸ“ Generating hydration entries...");
213
+ logger.log("Generating hydration entries...");
211
214
 
212
215
  // Generate hydration entry files
213
216
  const entryFiles: { path: string; componentName: string }[] = [];
@@ -223,11 +226,10 @@ function main(): void {
223
226
  path: entryPath,
224
227
  componentName: component.componentName,
225
228
  });
226
- console.log(` āœ“ ${component.componentName}.tsx`);
227
229
  }
228
230
 
229
231
  // Build shared vendor bundle first
230
- console.log("\nšŸ“¦ Building shared vendor bundle...");
232
+ logger.log("Building shared vendor bundle...");
231
233
  const vendorEntryPath = path.join(HYDRATION_ENTRIES_DIR, "_vendor.js");
232
234
  const vendorContent = `
233
235
  import React from 'react';
@@ -242,16 +244,15 @@ window.ReactDOM = ReactDOM;
242
244
 
243
245
  const vendorOutputPath = path.join(CHUNKS_DIR, VENDOR_BUNDLE);
244
246
  try {
245
- const vendorCommand = `npx esbuild "${vendorEntryPath}" --bundle --minify --target=es2020 --format=iife --outfile="${vendorOutputPath}" --platform=browser --tree-shaking=true --define:process.env.NODE_ENV=\\"production\\"`;
247
+ const vendorCommand = `npx esbuild "${vendorEntryPath}" --bundle --minify --target=es2020 --format=iife --outfile="${vendorOutputPath}" --platform=browser --tree-shaking=true --define:process.env.NODE_ENV='"production"'`;
246
248
  execSync(vendorCommand, { stdio: "inherit" });
247
- console.log(` āœ“ vendor.js (React + ReactDOM)`);
248
249
  } catch (error) {
249
- console.error(` āœ— Failed to bundle vendor:`, error);
250
+ logger.error(`Failed to bundle vendor: ${error}`);
250
251
  process.exit(1);
251
252
  }
252
253
 
253
254
  // Bundle each entry file separately with cache-busted names
254
- console.log("\nšŸ“¦ Bundling hydration scripts...");
255
+ logger.log("Bundling hydration scripts...");
255
256
 
256
257
  // Create React shim files for aliasing
257
258
  const SHIMS_DIR = path.join(DIST_DIR, ".shims");
@@ -301,27 +302,25 @@ module.exports = {
301
302
 
302
303
  try {
303
304
  // Use aliases to redirect React imports to window.React from vendor bundle
304
- const command = `npx esbuild "${entry.path}" --bundle --minify --target=es2020 --format=iife --keep-names --outfile="${outputPath}" --platform=browser --tree-shaking=true --define:process.env.NODE_ENV=\\"production\\" --alias:react=${reactShimPath} --alias:react-dom=${reactDomShimPath} --alias:react-dom/client=${reactDomClientShimPath} --alias:react/jsx-runtime=${jsxRuntimeShimPath}`;
305
+ const command = `npx esbuild "${entry.path}" --bundle --minify --target=es2020 --format=iife --keep-names --outfile="${outputPath}" --platform=browser --tree-shaking=true --define:process.env.NODE_ENV='"production"' --alias:react=${reactShimPath} --alias:react-dom=${reactDomShimPath} --alias:react-dom/client=${reactDomClientShimPath} --alias:react/jsx-runtime=${jsxRuntimeShimPath}`;
305
306
  execSync(command, { stdio: "inherit" });
306
307
  manifest[entry.componentName] = chunkFilename;
307
- console.log(` āœ“ ${entry.componentName} -> ${chunkFilename}`);
308
308
  } catch (error) {
309
- console.error(` āœ— Failed to bundle ${entry.componentName}:`, error);
309
+ logger.error(`Failed to bundle ${entry.componentName}: ${error}`);
310
310
  process.exit(1);
311
311
  }
312
312
  }
313
313
 
314
314
  // Write manifest file for server-side lookup
315
- console.log("\nšŸ“‹ Writing hydration manifest...");
315
+ logger.log("Writing hydration manifest...");
316
316
  fs.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2), "utf-8");
317
- console.log(` āœ“ Manifest written to ${MANIFEST_FILE}`);
318
317
 
319
318
  // Clean up temporary entries directory
320
319
  if (fs.existsSync(HYDRATION_ENTRIES_DIR)) {
321
320
  fs.rmSync(HYDRATION_ENTRIES_DIR, { recursive: true });
322
321
  }
323
322
 
324
- console.log("\n✨ Hydration build complete!");
323
+ logger.log("Hydration build complete!");
325
324
  }
326
325
 
327
326
  main();
@@ -7,7 +7,9 @@
7
7
  import { execSync } from "child_process";
8
8
  import * as fs from "fs";
9
9
  import * as path from "path";
10
+ import { Logger } from "./logger";
10
11
 
12
+ const logger = new Logger("StylesBuilder");
11
13
  const projectRoot = process.cwd();
12
14
  const distDir = path.join(projectRoot, "dist");
13
15
  const stylesDir = path.join(distDir, "styles");
@@ -15,7 +17,7 @@ const srcAssetsDir = path.join(projectRoot, "src/assets");
15
17
  const outputCssPath = path.join(stylesDir, "styles.css");
16
18
 
17
19
  async function main(): Promise<void> {
18
- console.log("šŸŽØ Building styles...");
20
+ logger.log("Building styles...");
19
21
 
20
22
  try {
21
23
  // Ensure styles directory exists
@@ -24,7 +26,7 @@ async function main(): Promise<void> {
24
26
  }
25
27
 
26
28
  // Compile Tailwind CSS
27
- console.log(" Compiling Tailwind CSS...");
29
+ logger.log("Compiling Tailwind CSS...");
28
30
  execSync(
29
31
  `NODE_ENV=production postcss ${path.join(srcAssetsDir, "styles.css")} -o ${outputCssPath}`,
30
32
  {
@@ -32,10 +34,9 @@ async function main(): Promise<void> {
32
34
  },
33
35
  );
34
36
 
35
- console.log(` āœ“ Generated styles.css`);
36
- console.log("✨ Styles build complete!");
37
+ logger.log("Styles build complete!");
37
38
  } catch (error: any) {
38
- console.error("āŒ CSS generation failed:", error.message);
39
+ logger.error(`CSS generation failed: ${error.message}`);
39
40
  process.exit(1);
40
41
  }
41
42
  }