veryfront 0.1.84 → 0.1.85

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/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.84",
3
+ "version": "0.1.85",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -11,10 +11,21 @@ interface RouteCandidateOptions {
11
11
  files: SourceFileLike[];
12
12
  developmentMode: boolean;
13
13
  }
14
+ interface ProjectCandidateOptions {
15
+ projectScope: string;
16
+ projectVersion: string;
17
+ projectDir: string;
18
+ files: SourceFileLike[];
19
+ developmentMode: boolean;
20
+ }
14
21
  /**
15
22
  * Resolve route-scoped Tailwind candidates from a precomputed per-project manifest.
16
23
  */
17
24
  export declare function getRouteCandidates(options: RouteCandidateOptions): Set<string>;
25
+ /**
26
+ * Resolve full-project Tailwind candidates from a precomputed per-project manifest.
27
+ */
28
+ export declare function getProjectCandidates(options: ProjectCandidateOptions): Set<string>;
18
29
  /**
19
30
  * Invalidate cached candidate manifests for one project scope (or all scopes).
20
31
  */
@@ -1 +1 @@
1
- {"version":3,"file":"css-candidate-manifest.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/css-candidate-manifest.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,UAAU,qBAAqB;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAmFD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,qBAAqB,GAAG,GAAG,CAAC,MAAM,CAAC,CA+C9E;AAED;;GAEG;AACH,wBAAgB,mCAAmC,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAc/E"}
1
+ {"version":3,"file":"css-candidate-manifest.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/css-candidate-manifest.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,UAAU,qBAAqB;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,uBAAuB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CAC1B;AA0GD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,qBAAqB,GAAG,GAAG,CAAC,MAAM,CAAC,CAkC9E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,uBAAuB,GAAG,GAAG,CAAC,MAAM,CAAC,CAGlF;AAED;;GAEG;AACH,wBAAgB,mCAAmC,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAc/E"}
@@ -58,6 +58,21 @@ function buildCandidateManifest(files, projectDir) {
58
58
  }
59
59
  return { fileCandidates, allCandidates, builtAt: Date.now() };
60
60
  }
61
+ function getOrBuildManifest(options) {
62
+ const manifestKey = buildManifestCacheKey(options.projectScope, options.projectVersion);
63
+ const existingManifest = manifestCache.get(manifestKey);
64
+ const manifest = shouldRebuildManifest(existingManifest, options.developmentMode)
65
+ ? buildCandidateManifest(options.files, options.projectDir)
66
+ : existingManifest;
67
+ if (manifest !== existingManifest) {
68
+ manifestCache.set(manifestKey, manifest);
69
+ for (const key of routeCandidateCache.keys()) {
70
+ if (key.startsWith(`${manifestKey}:`))
71
+ routeCandidateCache.delete(key);
72
+ }
73
+ }
74
+ return manifest;
75
+ }
61
76
  function addCandidatesForPath(target, manifest, path, projectDir) {
62
77
  const absolutePath = normalizePath(path);
63
78
  const relativePath = toRelativeProjectPath(path, projectDir);
@@ -73,18 +88,7 @@ function addCandidatesForPath(target, manifest, path, projectDir) {
73
88
  */
74
89
  export function getRouteCandidates(options) {
75
90
  const manifestKey = buildManifestCacheKey(options.projectScope, options.projectVersion);
76
- const existingManifest = manifestCache.get(manifestKey);
77
- const manifest = shouldRebuildManifest(existingManifest, options.developmentMode)
78
- ? buildCandidateManifest(options.files, options.projectDir)
79
- : existingManifest;
80
- if (manifest !== existingManifest) {
81
- manifestCache.set(manifestKey, manifest);
82
- // Clear route subsets when project-level file manifest is rebuilt.
83
- for (const key of routeCandidateCache.keys()) {
84
- if (key.startsWith(`${manifestKey}:`))
85
- routeCandidateCache.delete(key);
86
- }
87
- }
91
+ const manifest = getOrBuildManifest(options);
88
92
  const routeCacheKey = `${manifestKey}:${options.routeKey}`;
89
93
  const cachedRoute = routeCandidateCache.get(routeCacheKey);
90
94
  if (cachedRoute)
@@ -112,6 +116,13 @@ export function getRouteCandidates(options) {
112
116
  });
113
117
  return new Set(routeCandidates);
114
118
  }
119
+ /**
120
+ * Resolve full-project Tailwind candidates from a precomputed per-project manifest.
121
+ */
122
+ export function getProjectCandidates(options) {
123
+ const manifest = getOrBuildManifest(options);
124
+ return new Set(manifest.allCandidates);
125
+ }
115
126
  /**
116
127
  * Invalidate cached candidate manifests for one project scope (or all scopes).
117
128
  */
@@ -1 +1 @@
1
- {"version":3,"file":"styles-candidate-scanner.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/dev/styles-candidate-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAWlD;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAqCxF"}
1
+ {"version":3,"file":"styles-candidate-scanner.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/dev/styles-candidate-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA8BlD;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CA0CxF"}
@@ -11,12 +11,26 @@ import { extractCandidates } from "../../../html/styles-builder/tailwind-compile
11
11
  import { serverLogger } from "../../../utils/index.js";
12
12
  import { createFileSystem } from "../../../platform/compat/fs.js";
13
13
  import { join } from "../../../platform/compat/path/index.js";
14
+ import { getProjectCandidates } from "../../../rendering/orchestrator/css-candidate-manifest.js";
14
15
  import { FRAMEWORK_CANDIDATES } from "./framework-candidates.generated.js";
15
16
  const logger = serverLogger.component("styles-candidate-scanner");
16
17
  const SOURCE_EXTENSIONS = [".tsx", ".jsx", ".mdx", ".ts", ".js"];
17
18
  const SKIP_DIRS = new Set(["node_modules", ".cache", ".git", "dist", "build", ".vscode"]);
18
19
  /** De-duplicated set of framework candidates, computed once at import time. */
19
20
  const frameworkCandidates = new Set(FRAMEWORK_CANDIDATES);
21
+ function resolveProjectVersion(ctx, contentContext) {
22
+ if (contentContext?.releaseId)
23
+ return `release:${contentContext.releaseId}`;
24
+ if (contentContext?.branch)
25
+ return `branch:${contentContext.branch}`;
26
+ if (contentContext?.environmentName)
27
+ return `environment:${contentContext.environmentName}`;
28
+ if (ctx.releaseId)
29
+ return `release:${ctx.releaseId}`;
30
+ if (ctx.parsedDomain?.branch)
31
+ return `branch:${ctx.parsedDomain.branch}`;
32
+ return "live";
33
+ }
20
34
  /**
21
35
  * Extract Tailwind CSS candidate class names from all project source files.
22
36
  *
@@ -38,14 +52,17 @@ export async function extractProjectCandidates(ctx) {
38
52
  }
39
53
  const candidates = new Set(frameworkCandidates);
40
54
  const files = await fsAdapter.getAllSourceFiles();
41
- for (const file of files) {
42
- if (!file.content)
43
- continue;
44
- if (!SOURCE_EXTENSIONS.some((ext) => file.path.endsWith(ext)))
45
- continue;
46
- for (const cls of extractCandidates(file.content)) {
47
- candidates.add(cls);
48
- }
55
+ const contentContext = typeof fsAdapter.getContentContext === "function"
56
+ ? fsAdapter.getContentContext()
57
+ : null;
58
+ for (const cls of getProjectCandidates({
59
+ projectScope: ctx.projectSlug ?? contentContext?.projectSlug ?? ctx.projectDir,
60
+ projectVersion: resolveProjectVersion(ctx, contentContext),
61
+ projectDir: ctx.projectDir,
62
+ files,
63
+ developmentMode: contentContext?.sourceType === "branch",
64
+ })) {
65
+ candidates.add(cls);
49
66
  }
50
67
  return candidates;
51
68
  }
@@ -11,5 +11,6 @@ export declare class StylesCSSHandler extends BaseHandler {
11
11
  metadata: HandlerMetadata;
12
12
  handle(req: dntShim.Request, ctx: HandlerContext): Promise<HandlerResult>;
13
13
  private loadStylesheet;
14
+ private generateStylesheet;
14
15
  }
15
16
  //# sourceMappingURL=styles-css.handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles-css.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/dev/styles-css.handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAanG,qBAAa,gBAAiB,SAAQ,WAAW;IAC/C,QAAQ,EAAE,eAAe,CAKvB;IAEI,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;YAkGjE,cAAc;CAiB7B"}
1
+ {"version":3,"file":"styles-css.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/dev/styles-css.handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAkBnG,qBAAa,gBAAiB,SAAQ,WAAW;IAC/C,QAAQ,EAAE,eAAe,CAKvB;IAEI,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;YAkGjE,cAAc;IAkB5B,OAAO,CAAC,kBAAkB;CAe3B"}
@@ -1,7 +1,7 @@
1
1
  import { BaseHandler } from "../response/base.js";
2
2
  import { HTTP_OK, PRIORITY_HIGH_DEV } from "../../../utils/constants/index.js";
3
3
  import { joinPath } from "../../../utils/path-utils.js";
4
- import { formatCSSError, generateTailwindCSS, } from "../../../html/styles-builder/tailwind-compiler.js";
4
+ import { formatCSSError, generateTailwindCSS, getProjectCSS, } from "../../../html/styles-builder/tailwind-compiler.js";
5
5
  import { DEFAULT_STYLESHEET } from "../../../html/styles-builder/css-hash-cache.js";
6
6
  import { serverLogger } from "../../../utils/index.js";
7
7
  import { extractProjectCandidates } from "./styles-candidate-scanner.js";
@@ -39,10 +39,8 @@ export class StylesCSSHandler extends BaseHandler {
39
39
  });
40
40
  candidates = new Set();
41
41
  }
42
- const result = await generateTailwindCSS(rawCss, candidates, {
43
- projectSlug: ctx.projectSlug,
44
- });
45
- if (result.error) {
42
+ const result = await this.generateStylesheet(ctx, rawCss, candidates);
43
+ if ("error" in result && result.error) {
46
44
  const formatted = formatCSSError(result.error);
47
45
  logger.error("Tailwind error", {
48
46
  error: formatted.message,
@@ -82,6 +80,8 @@ body::before {
82
80
  logger.debug("CSS generated", {
83
81
  candidates: candidates.size,
84
82
  cssLength: result.css.length,
83
+ fromCache: "fromCache" in result ? result.fromCache : false,
84
+ cssHash: "hash" in result ? result.hash : undefined,
85
85
  });
86
86
  return this.respond(responseBuilder.withContentType("text/css; charset=utf-8", result.css, HTTP_OK));
87
87
  });
@@ -114,4 +114,14 @@ body::before {
114
114
  return DEFAULT_STYLESHEET;
115
115
  }
116
116
  }
117
+ generateStylesheet(ctx, rawCss, candidates) {
118
+ if (!ctx.projectSlug) {
119
+ return generateTailwindCSS(rawCss, candidates);
120
+ }
121
+ return getProjectCSS(ctx.projectSlug, rawCss, candidates, {
122
+ minify: true,
123
+ environment: "preview",
124
+ buildMode: "production",
125
+ });
126
+ }
117
127
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.84",
3
+ "version": "0.1.85",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.84",
3
+ "version": "0.1.85",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -23,6 +23,14 @@ interface RouteCandidateOptions {
23
23
  developmentMode: boolean;
24
24
  }
25
25
 
26
+ interface ProjectCandidateOptions {
27
+ projectScope: string;
28
+ projectVersion: string;
29
+ projectDir: string;
30
+ files: SourceFileLike[];
31
+ developmentMode: boolean;
32
+ }
33
+
26
34
  const logger = rendererLogger.component("css-candidate-manifest");
27
35
  const SOURCE_EXTENSIONS = [".tsx", ".jsx", ".mdx", ".ts", ".js"];
28
36
  const DEV_MANIFEST_TTL_MS = 2_000;
@@ -90,6 +98,29 @@ function buildCandidateManifest(files: SourceFileLike[], projectDir: string): Ca
90
98
  return { fileCandidates, allCandidates, builtAt: Date.now() };
91
99
  }
92
100
 
101
+ function getOrBuildManifest(
102
+ options: Pick<
103
+ ProjectCandidateOptions,
104
+ "projectScope" | "projectVersion" | "projectDir" | "files" | "developmentMode"
105
+ >,
106
+ ): CandidateManifest {
107
+ const manifestKey = buildManifestCacheKey(options.projectScope, options.projectVersion);
108
+ const existingManifest = manifestCache.get(manifestKey);
109
+ const manifest = shouldRebuildManifest(existingManifest, options.developmentMode)
110
+ ? buildCandidateManifest(options.files, options.projectDir)
111
+ : existingManifest!;
112
+
113
+ if (manifest !== existingManifest) {
114
+ manifestCache.set(manifestKey, manifest);
115
+
116
+ for (const key of routeCandidateCache.keys()) {
117
+ if (key.startsWith(`${manifestKey}:`)) routeCandidateCache.delete(key);
118
+ }
119
+ }
120
+
121
+ return manifest;
122
+ }
123
+
93
124
  function addCandidatesForPath(
94
125
  target: Set<string>,
95
126
  manifest: CandidateManifest,
@@ -109,20 +140,7 @@ function addCandidatesForPath(
109
140
  */
110
141
  export function getRouteCandidates(options: RouteCandidateOptions): Set<string> {
111
142
  const manifestKey = buildManifestCacheKey(options.projectScope, options.projectVersion);
112
- const existingManifest = manifestCache.get(manifestKey);
113
- const manifest = shouldRebuildManifest(existingManifest, options.developmentMode)
114
- ? buildCandidateManifest(options.files, options.projectDir)
115
- : existingManifest!;
116
-
117
- if (manifest !== existingManifest) {
118
- manifestCache.set(manifestKey, manifest);
119
-
120
- // Clear route subsets when project-level file manifest is rebuilt.
121
- for (const key of routeCandidateCache.keys()) {
122
- if (key.startsWith(`${manifestKey}:`)) routeCandidateCache.delete(key);
123
- }
124
- }
125
-
143
+ const manifest = getOrBuildManifest(options);
126
144
  const routeCacheKey = `${manifestKey}:${options.routeKey}`;
127
145
  const cachedRoute = routeCandidateCache.get(routeCacheKey);
128
146
  if (cachedRoute) return new Set(cachedRoute);
@@ -156,6 +174,14 @@ export function getRouteCandidates(options: RouteCandidateOptions): Set<string>
156
174
  return new Set(routeCandidates);
157
175
  }
158
176
 
177
+ /**
178
+ * Resolve full-project Tailwind candidates from a precomputed per-project manifest.
179
+ */
180
+ export function getProjectCandidates(options: ProjectCandidateOptions): Set<string> {
181
+ const manifest = getOrBuildManifest(options);
182
+ return new Set(manifest.allCandidates);
183
+ }
184
+
159
185
  /**
160
186
  * Invalidate cached candidate manifests for one project scope (or all scopes).
161
187
  */
@@ -12,6 +12,8 @@ import { extractCandidates } from "../../../html/styles-builder/tailwind-compile
12
12
  import { serverLogger } from "../../../utils/index.js";
13
13
  import { createFileSystem } from "../../../platform/compat/fs.js";
14
14
  import { join } from "../../../platform/compat/path/index.js";
15
+ import { getProjectCandidates } from "../../../rendering/orchestrator/css-candidate-manifest.js";
16
+ import type { ResolvedContentContext } from "../../../platform/adapters/fs/veryfront/types.js";
15
17
  import type { HandlerContext } from "../types.js";
16
18
  import { FRAMEWORK_CANDIDATES } from "./framework-candidates.generated.js";
17
19
 
@@ -23,6 +25,25 @@ const SKIP_DIRS = new Set(["node_modules", ".cache", ".git", "dist", "build", ".
23
25
  /** De-duplicated set of framework candidates, computed once at import time. */
24
26
  const frameworkCandidates = new Set<string>(FRAMEWORK_CANDIDATES);
25
27
 
28
+ interface SourceFileProvider {
29
+ getAllSourceFiles?: () =>
30
+ | Array<{ path: string; content?: string }>
31
+ | Promise<Array<{ path: string; content?: string }>>;
32
+ getContentContext?: () => ResolvedContentContext | null;
33
+ }
34
+
35
+ function resolveProjectVersion(
36
+ ctx: HandlerContext,
37
+ contentContext: ResolvedContentContext | null,
38
+ ): string {
39
+ if (contentContext?.releaseId) return `release:${contentContext.releaseId}`;
40
+ if (contentContext?.branch) return `branch:${contentContext.branch}`;
41
+ if (contentContext?.environmentName) return `environment:${contentContext.environmentName}`;
42
+ if (ctx.releaseId) return `release:${ctx.releaseId}`;
43
+ if (ctx.parsedDomain?.branch) return `branch:${ctx.parsedDomain.branch}`;
44
+ return "live";
45
+ }
46
+
26
47
  /**
27
48
  * Extract Tailwind CSS candidate class names from all project source files.
28
49
  *
@@ -42,9 +63,8 @@ export async function extractProjectCandidates(ctx: HandlerContext): Promise<Set
42
63
 
43
64
  // Call method directly on wrappedFs to preserve 'this' context
44
65
  const fsAdapter = wrappedFs.getUnderlyingAdapter() as {
45
- getAllSourceFiles?: () =>
46
- | Array<{ path: string; content?: string }>
47
- | Promise<Array<{ path: string; content?: string }>>;
66
+ getAllSourceFiles?: SourceFileProvider["getAllSourceFiles"];
67
+ getContentContext?: SourceFileProvider["getContentContext"];
48
68
  };
49
69
 
50
70
  if (typeof fsAdapter.getAllSourceFiles !== "function") {
@@ -56,14 +76,20 @@ export async function extractProjectCandidates(ctx: HandlerContext): Promise<Set
56
76
 
57
77
  const candidates = new Set<string>(frameworkCandidates);
58
78
  const files = await fsAdapter.getAllSourceFiles();
59
-
60
- for (const file of files) {
61
- if (!file.content) continue;
62
- if (!SOURCE_EXTENSIONS.some((ext) => file.path.endsWith(ext))) continue;
63
-
64
- for (const cls of extractCandidates(file.content)) {
65
- candidates.add(cls);
66
- }
79
+ const contentContext = typeof fsAdapter.getContentContext === "function"
80
+ ? fsAdapter.getContentContext()
81
+ : null;
82
+
83
+ for (
84
+ const cls of getProjectCandidates({
85
+ projectScope: ctx.projectSlug ?? contentContext?.projectSlug ?? ctx.projectDir,
86
+ projectVersion: resolveProjectVersion(ctx, contentContext),
87
+ projectDir: ctx.projectDir,
88
+ files,
89
+ developmentMode: contentContext?.sourceType === "branch",
90
+ })
91
+ ) {
92
+ candidates.add(cls);
67
93
  }
68
94
 
69
95
  return candidates;
@@ -14,6 +14,7 @@ import { joinPath } from "../../../utils/path-utils.js";
14
14
  import {
15
15
  formatCSSError,
16
16
  generateTailwindCSS,
17
+ getProjectCSS,
17
18
  } from "../../../html/styles-builder/tailwind-compiler.js";
18
19
  import { DEFAULT_STYLESHEET } from "../../../html/styles-builder/css-hash-cache.js";
19
20
  import { serverLogger } from "../../../utils/index.js";
@@ -21,6 +22,10 @@ import { extractProjectCandidates } from "./styles-candidate-scanner.js";
21
22
 
22
23
  const logger = serverLogger.component("styles-css-handler");
23
24
 
25
+ type GeneratedStylesResult =
26
+ | Awaited<ReturnType<typeof generateTailwindCSS>>
27
+ | Awaited<ReturnType<typeof getProjectCSS>>;
28
+
24
29
  export class StylesCSSHandler extends BaseHandler {
25
30
  metadata: HandlerMetadata = {
26
31
  name: "StylesCSSHandler",
@@ -54,11 +59,9 @@ export class StylesCSSHandler extends BaseHandler {
54
59
  });
55
60
  candidates = new Set<string>();
56
61
  }
57
- const result = await generateTailwindCSS(rawCss, candidates, {
58
- projectSlug: ctx.projectSlug,
59
- });
62
+ const result = await this.generateStylesheet(ctx, rawCss, candidates);
60
63
 
61
- if (result.error) {
64
+ if ("error" in result && result.error) {
62
65
  const formatted = formatCSSError(result.error);
63
66
  logger.error("Tailwind error", {
64
67
  error: formatted.message,
@@ -104,6 +107,8 @@ body::before {
104
107
  logger.debug("CSS generated", {
105
108
  candidates: candidates.size,
106
109
  cssLength: result.css.length,
110
+ fromCache: "fromCache" in result ? result.fromCache : false,
111
+ cssHash: "hash" in result ? result.hash : undefined,
107
112
  });
108
113
 
109
114
  return this.respond(
@@ -144,4 +149,20 @@ body::before {
144
149
  return DEFAULT_STYLESHEET;
145
150
  }
146
151
  }
152
+
153
+ private generateStylesheet(
154
+ ctx: HandlerContext,
155
+ rawCss: string,
156
+ candidates: Set<string>,
157
+ ): Promise<GeneratedStylesResult> {
158
+ if (!ctx.projectSlug) {
159
+ return generateTailwindCSS(rawCss, candidates);
160
+ }
161
+
162
+ return getProjectCSS(ctx.projectSlug, rawCss, candidates, {
163
+ minify: true,
164
+ environment: "preview",
165
+ buildMode: "production",
166
+ });
167
+ }
147
168
  }