@akanjs/cli 3.0.0-alpha.50 → 3.0.0-alpha.52
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/.build-stamp +1 -1
- package/{agent.command-nqs3bw0g.js → agent.command-tsx1nsdj.js} +6 -5
- package/{application.command-k2v46pxf.js → application.command-n8ex8g9h.js} +5 -4
- package/{applicationBuildRunner-t5v6tcrm.js → applicationBuildRunner-x8h12rp0.js} +2 -1
- package/buildBatch.proc.js +3 -2
- package/{capacitorApp-927ahhz2.js → capacitorApp-8mv9e537.js} +3 -2
- package/{cloud.command-7jwmxtez.js → cloud.command-eqafzn1a.js} +8 -7
- package/{context.command-6kn3tady.js → context.command-s7a41qjs.js} +13 -12
- package/{guideline.command-pjdrndqk.js → guideline.command-qrw84ttb.js} +3 -2
- package/guidelines/agentRule/agentRule.instruction.md +47 -3
- package/guidelines/conventions/conventions.instruction.md +22 -1
- package/guidelines/mcpRule/mcpRule.instruction.md +18 -6
- package/incrementalBuilder.proc.js +2 -1
- package/{index-7w5vv8jk.js → index-4mtyaqj2.js} +2 -2
- package/{index-90zyjrby.js → index-681sx6nt.js} +6 -1
- package/{index-97cw8sg1.js → index-cc1mgv1f.js} +4 -4
- package/{index-zgkey4d0.js → index-ce9755av.js} +1 -1
- package/{index-8rr621r2.js → index-ckpwq052.js} +1 -1
- package/{index-k7sm38v6.js → index-dvg362vq.js} +3 -3
- package/{index-866yqz3y.js → index-ek4mkwxp.js} +10 -10
- package/{index-6bs24rb4.js → index-f0t3wjyr.js} +2 -2
- package/index-f39512t6.js +255 -0
- package/{index-5em412h5.js → index-g44fykfw.js} +1 -1
- package/{index-xe3ychw5.js → index-h0mnt0b0.js} +3 -3
- package/{index-4z05haak.js → index-kkya2ped.js} +1 -1
- package/{index-7etegaht.js → index-r8z20vnj.js} +5 -5
- package/{index-5fe016p2.js → index-ryns915y.js} +3 -3
- package/{index-y59x51f1.js → index-ssrz6xr1.js} +5 -5
- package/{index-xrdrttjb.js → index-tn46rr6w.js} +4 -4
- package/{index-24h5bqpj.js → index-wc19q8mb.js} +2 -2
- package/{index-bwt525ne.js → index-wmwcwn1f.js} +3 -3
- package/{index-7zd96bng.js → index-x1dbhd80.js} +2 -2
- package/{index-wr999y03.js → index-xj5b8c0w.js} +102 -352
- package/index.js +19 -18
- package/{library.command-7h3yezwc.js → library.command-p3jgf5h2.js} +4 -3
- package/{localRegistry.command-vnkc41gj.js → localRegistry.command-jewr722x.js} +7 -6
- package/{module.command-4g11k3xd.js → module.command-hb3xm07r.js} +6 -5
- package/{package.command-z7dd6vy2.js → package.command-fbpa6r4w.js} +4 -3
- package/package.json +2 -2
- package/{page.command-y996708m.js → page.command-92vrmw96.js} +4 -3
- package/{primitive.command-4fcn8k83.js → primitive.command-k6b9jfxr.js} +7 -6
- package/{quality.command-hx5af2yn.js → quality.command-89vwmjvf.js} +3 -2
- package/{repair.command-ysxd8pef.js → repair.command-nh9jn8rh.js} +6 -5
- package/{scalar.command-3chgxybs.js → scalar.command-zcsjgvax.js} +5 -4
- package/{workflow.command-endxfzv5.js → workflow.command-jj0cphfm.js} +10 -9
- package/{workspace.command-5f2nmmd5.js → workspace.command-zg8me6fg.js} +19 -18
|
@@ -10,275 +10,25 @@ import {
|
|
|
10
10
|
rewriteBarrelImports,
|
|
11
11
|
transformUseClient
|
|
12
12
|
} from "./index-qnv0aqmm.js";
|
|
13
|
+
import {
|
|
14
|
+
resolveSsrPageEntriesForApp
|
|
15
|
+
} from "./index-f39512t6.js";
|
|
13
16
|
import {
|
|
14
17
|
__require
|
|
15
18
|
} from "./index-yb2wsc7f.js";
|
|
16
19
|
|
|
17
20
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
// pkgs/@akanjs/devkit/artifact/implicitRootLayout.ts
|
|
21
|
-
import { mkdir } from "fs/promises";
|
|
22
|
-
import path from "path";
|
|
23
|
-
var LAYOUT_KEY_RE = /^\.\/(.+\/)?_layout\.(tsx|ts|jsx|js)$/;
|
|
24
|
-
async function appHasStModule(appCwdPath) {
|
|
25
|
-
return Bun.file(path.join(appCwdPath, "lib", "st.ts")).exists();
|
|
26
|
-
}
|
|
27
|
-
var IMPLICIT_LAYOUT_DIR = path.join(".akan", "generated", "root-layouts");
|
|
28
|
-
var IMPLICIT_DICT_DIR = path.join(".akan", "generated", "dict");
|
|
29
|
-
var IMPLICIT_OVERRIDES_DIR = path.join(".akan", "generated", "overrides");
|
|
30
|
-
var OVERRIDES_KEY_RE = /^\.\/(.+\/)?_overrides\.(tsx|ts|jsx|js)$/;
|
|
31
|
-
async function writeGeneratedOverridesLayoutFile(opts) {
|
|
32
|
-
const filename = `${opts.key.replace(/^\.\//, "").replace(/[^a-zA-Z0-9]+/g, "_")}.tsx`;
|
|
33
|
-
const absPath = path.join(path.resolve(opts.appCwdPath), IMPLICIT_OVERRIDES_DIR, filename);
|
|
34
|
-
const userRel = path.relative(path.dirname(absPath), opts.userAbsPath).split(path.sep).join("/");
|
|
35
|
-
const userSpecifier = userRel.startsWith(".") ? userRel : `./${userRel}`;
|
|
36
|
-
const source = `"use client";
|
|
37
|
-
import { UiOverrideProvider } from "akanjs/ui";
|
|
38
|
-
import { createElement, type ReactNode } from "react";
|
|
39
|
-
import value from ${JSON.stringify(userSpecifier)};
|
|
40
|
-
|
|
41
|
-
export default function AkanUiOverridesLayout({ children }: { children?: ReactNode }) {
|
|
42
|
-
return createElement(UiOverrideProvider, { value }, children);
|
|
43
|
-
}
|
|
44
|
-
`;
|
|
45
|
-
await Bun.write(absPath, source);
|
|
46
|
-
return absPath;
|
|
47
|
-
}
|
|
48
|
-
function getRootBoundarySegments(key) {
|
|
49
|
-
const match = LAYOUT_KEY_RE.exec(key);
|
|
50
|
-
if (!match)
|
|
51
|
-
return null;
|
|
52
|
-
const prefix = match[1]?.replace(/\/$/, "");
|
|
53
|
-
if (!prefix)
|
|
54
|
-
return [];
|
|
55
|
-
return prefix.split("/").filter(Boolean);
|
|
56
|
-
}
|
|
57
|
-
function implicitRootLayoutKey(segments) {
|
|
58
|
-
return `./${[...segments, "__root_layout"].join("/")}.tsx`;
|
|
59
|
-
}
|
|
60
|
-
function implicitRootLayoutAbsPath(appCwdPath, segments) {
|
|
61
|
-
const filename = segments.length ? `${segments.join("__")}__root_layout.tsx` : "__root_layout.tsx";
|
|
62
|
-
return path.join(path.resolve(appCwdPath), IMPLICIT_LAYOUT_DIR, filename);
|
|
63
|
-
}
|
|
64
|
-
function implicitDictionaryMacroAbsPath(appCwdPath) {
|
|
65
|
-
return path.join(path.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
|
|
66
|
-
}
|
|
67
|
-
function isRootBoundarySegments(segments, basePaths) {
|
|
68
|
-
const firstVisibleIndex = segments.findIndex((segment) => !/^\(.+\)$/.test(segment));
|
|
69
|
-
if (firstVisibleIndex === -1)
|
|
70
|
-
return segments.length <= 1;
|
|
71
|
-
if (segments.slice(firstVisibleIndex + 1).some((segment) => /^\(.+\)$/.test(segment)))
|
|
72
|
-
return false;
|
|
73
|
-
const visible = segments.slice(firstVisibleIndex);
|
|
74
|
-
const allowedBasePaths = new Set([...basePaths].map((basePath) => basePath.trim()).filter(Boolean));
|
|
75
|
-
return visible.length === 1 && (firstVisibleIndex > 0 || allowedBasePaths.has(visible[0] ?? ""));
|
|
76
|
-
}
|
|
77
|
-
function findRootBoundaries(pageKeys, appCwdPath, basePaths) {
|
|
78
|
-
const boundaries = new Map;
|
|
79
|
-
for (const key of pageKeys) {
|
|
80
|
-
const segments = getRootBoundarySegments(key);
|
|
81
|
-
if (!segments)
|
|
82
|
-
continue;
|
|
83
|
-
if (!isRootBoundarySegments(segments, basePaths))
|
|
84
|
-
continue;
|
|
85
|
-
const id = segments.join("/");
|
|
86
|
-
boundaries.set(id, {
|
|
87
|
-
sourceKey: key,
|
|
88
|
-
sourceAbsPath: path.resolve(appCwdPath, "page", key.replace(/^\.\//, "")),
|
|
89
|
-
segments
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
const hasExplicitRootBoundary = [...boundaries.values()].some((boundary) => boundary.segments.length === 0);
|
|
93
|
-
if (!hasExplicitRootBoundary && boundaries.size === 0) {
|
|
94
|
-
boundaries.set("", { sourceKey: null, sourceAbsPath: null, segments: [] });
|
|
95
|
-
}
|
|
96
|
-
return [...boundaries.values()].sort((a, b) => a.segments.join("/").localeCompare(b.segments.join("/")));
|
|
97
|
-
}
|
|
98
|
-
function hasAncestorRootBoundary(boundary, boundaries) {
|
|
99
|
-
return boundaries.some((candidate) => candidate !== boundary && candidate.segments.length < boundary.segments.length && candidate.segments.every((segment, index) => boundary.segments[index] === segment));
|
|
100
|
-
}
|
|
101
|
-
function findExplicitRootLayoutAbsPath(pageKeys, appCwdPath) {
|
|
102
|
-
const rootLayoutKey = pageKeys.find((key) => {
|
|
103
|
-
const segments = getRootBoundarySegments(key);
|
|
104
|
-
return segments !== null && segments.length === 0;
|
|
105
|
-
});
|
|
106
|
-
return rootLayoutKey ? path.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
|
|
107
|
-
}
|
|
108
|
-
function routePrefixForSegments(segments) {
|
|
109
|
-
const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
|
|
110
|
-
return visible[0] ?? null;
|
|
111
|
-
}
|
|
112
|
-
async function assertEnvClientConvention(appCwdPath, appName) {
|
|
113
|
-
const envPath = path.join(appCwdPath, "env", "env.client.ts");
|
|
114
|
-
if (!await Bun.file(envPath).exists()) {
|
|
115
|
-
throw new Error(`[route-convention] app "${appName}" must provide env/env.client.ts exporting "env" for generated System.Provider`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
async function writeGeneratedDictionaryMacroFile(appCwdPath, appName) {
|
|
119
|
-
const absPath = implicitDictionaryMacroAbsPath(appCwdPath);
|
|
120
|
-
await mkdir(path.dirname(absPath), { recursive: true });
|
|
121
|
-
await Bun.write(absPath, `import { getAllDictionary } from "@apps/${appName}/lib/dict" with { type: "macro" };
|
|
122
|
-
|
|
123
|
-
export const allDictionary = getAllDictionary();
|
|
124
|
-
`);
|
|
125
|
-
return absPath;
|
|
126
|
-
}
|
|
127
|
-
async function writeGeneratedRootLayoutFile(opts) {
|
|
128
|
-
await assertEnvClientConvention(opts.appCwdPath, opts.appName);
|
|
129
|
-
const dictMacroAbsPath = opts.includeSystemProvider ? await writeGeneratedDictionaryMacroFile(opts.appCwdPath, opts.appName) : null;
|
|
130
|
-
const absPath = implicitRootLayoutAbsPath(opts.appCwdPath, opts.boundary.segments);
|
|
131
|
-
await mkdir(path.dirname(absPath), { recursive: true });
|
|
132
|
-
const dictMacroRel = dictMacroAbsPath ? path.relative(path.dirname(absPath), dictMacroAbsPath).split(path.sep).join("/") : null;
|
|
133
|
-
const dictMacroSpecifier = dictMacroRel ? dictMacroRel.startsWith(".") ? dictMacroRel : `./${dictMacroRel}` : null;
|
|
134
|
-
const sourceRel = opts.boundary.sourceAbsPath ? path.relative(path.dirname(absPath), opts.boundary.sourceAbsPath).split(path.sep).join("/") : null;
|
|
135
|
-
const sourceSpecifier = sourceRel ? sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}` : null;
|
|
136
|
-
const inheritedSourceAbsPath = opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
|
|
137
|
-
const inheritedSourceRel = inheritedSourceAbsPath ? path.relative(path.dirname(absPath), inheritedSourceAbsPath).split(path.sep).join("/") : null;
|
|
138
|
-
const inheritedSourceSpecifier = inheritedSourceRel ? inheritedSourceRel.startsWith(".") ? inheritedSourceRel : `./${inheritedSourceRel}` : null;
|
|
139
|
-
const clientImport = opts.includeStInit ? `import { st } from "@apps/${opts.appName}/client";
|
|
140
|
-
void st;
|
|
141
|
-
` : `import "@apps/${opts.appName}/client";
|
|
142
|
-
`;
|
|
143
|
-
const inheritedImport = inheritedSourceSpecifier ? `import * as inheritedLayout from ${JSON.stringify(inheritedSourceSpecifier)};
|
|
144
|
-
` : `const inheritedLayout = {};
|
|
145
|
-
`;
|
|
146
|
-
const prefix = routePrefixForSegments(opts.boundary.segments);
|
|
147
|
-
const userImport = sourceSpecifier ? `import UserLayout, * as userLayout from ${JSON.stringify(sourceSpecifier)};
|
|
148
|
-
` : `const UserLayout = ({ children }) => children;
|
|
149
|
-
const userLayout = {};
|
|
150
|
-
`;
|
|
151
|
-
const source = opts.includeSystemProvider ? `import type { LayoutProps, PageProps } from "akanjs/client";
|
|
152
|
-
import { loadFonts } from "akanjs/client";
|
|
153
|
-
import { System } from "akanjs/ui";
|
|
154
|
-
import { env } from "@apps/${opts.appName}/env/env.client";
|
|
155
|
-
import { allDictionary } from ${JSON.stringify(dictMacroSpecifier)};
|
|
156
|
-
${clientImport}${inheritedImport}${userImport}
|
|
157
|
-
const userFonts = userLayout.fonts ?? inheritedLayout.fonts ?? [];
|
|
158
|
-
const defaultFonts = userFonts.filter((font) => font.default);
|
|
159
|
-
if (defaultFonts.length > 1) throw new Error("[route-convention] only one default font is allowed per root layout");
|
|
160
|
-
const defaultFont = defaultFonts[0];
|
|
161
|
-
const defaultFontClassName = defaultFont ? (defaultFont.className ?? \`font-\${defaultFont.name}\`) : undefined;
|
|
162
|
-
|
|
163
|
-
export async function generateHead(props: PageProps) {
|
|
164
|
-
if (userLayout.generateHead) return userLayout.generateHead(props);
|
|
165
|
-
if (userLayout.head !== undefined) return userLayout.head;
|
|
166
|
-
if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
|
|
167
|
-
return inheritedLayout.head;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export async function generateMetadata(props: PageProps) {
|
|
171
|
-
if (userLayout.generateMetadata) return userLayout.generateMetadata(props);
|
|
172
|
-
if (userLayout.metadata !== undefined) return userLayout.metadata;
|
|
173
|
-
if (inheritedLayout.generateMetadata) return inheritedLayout.generateMetadata(props);
|
|
174
|
-
return inheritedLayout.metadata;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export const NotFound = userLayout.NotFound ?? inheritedLayout.NotFound;
|
|
178
|
-
export const Error = userLayout.Error ?? inheritedLayout.Error;
|
|
179
|
-
export const pageConfig = userLayout.pageConfig ?? inheritedLayout.pageConfig;
|
|
180
|
-
|
|
181
|
-
export default function GeneratedLayout({ children, params, searchParams }: LayoutProps) {
|
|
182
|
-
return (
|
|
183
|
-
<System.Provider
|
|
184
|
-
of={GeneratedLayout as never}
|
|
185
|
-
appName=${JSON.stringify(opts.appName)}
|
|
186
|
-
${prefix ? `prefix=${JSON.stringify(prefix)}
|
|
187
|
-
` : ""}params={params}
|
|
188
|
-
manifest={userLayout.manifest ?? inheritedLayout.manifest}
|
|
189
|
-
env={env}
|
|
190
|
-
theme={userLayout.theme ?? inheritedLayout.theme}
|
|
191
|
-
fonts={loadFonts(userFonts)}
|
|
192
|
-
className={defaultFontClassName}
|
|
193
|
-
gaTrackingId={userLayout.gaTrackingId ?? inheritedLayout.gaTrackingId}
|
|
194
|
-
layoutStyle={userLayout.layoutStyle ?? inheritedLayout.layoutStyle}
|
|
195
|
-
reconnect={userLayout.reconnect ?? inheritedLayout.reconnect ?? false}
|
|
196
|
-
wsConnect={userLayout.wsConnect ?? inheritedLayout.wsConnect ?? true}
|
|
197
|
-
allDictionary={process.env.AKAN_PUBLIC_RENDER_ENV === "ssr" ? allDictionary : undefined}
|
|
198
|
-
>
|
|
199
|
-
<UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>
|
|
200
|
-
</System.Provider>
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
` : `import type { LayoutProps, PageProps } from "akanjs/client";
|
|
204
|
-
${inheritedImport}${userImport}
|
|
205
|
-
export async function generateHead(props: PageProps) {
|
|
206
|
-
if (userLayout.generateHead) return userLayout.generateHead(props);
|
|
207
|
-
if (userLayout.head !== undefined) return userLayout.head;
|
|
208
|
-
if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
|
|
209
|
-
return inheritedLayout.head;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export async function generateMetadata(props: PageProps) {
|
|
213
|
-
if (userLayout.generateMetadata) return userLayout.generateMetadata(props);
|
|
214
|
-
if (userLayout.metadata !== undefined) return userLayout.metadata;
|
|
215
|
-
if (inheritedLayout.generateMetadata) return inheritedLayout.generateMetadata(props);
|
|
216
|
-
return inheritedLayout.metadata;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export const NotFound = userLayout.NotFound ?? inheritedLayout.NotFound;
|
|
220
|
-
export const Error = userLayout.Error ?? inheritedLayout.Error;
|
|
221
|
-
export const pageConfig = userLayout.pageConfig ?? inheritedLayout.pageConfig;
|
|
222
|
-
|
|
223
|
-
export default function GeneratedLayout({ children, params, searchParams }: LayoutProps) {
|
|
224
|
-
return <UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>;
|
|
225
|
-
}
|
|
226
|
-
`;
|
|
227
|
-
await Bun.write(absPath, source);
|
|
228
|
-
return absPath;
|
|
229
|
-
}
|
|
230
|
-
async function resolveSsrPageEntries(opts) {
|
|
231
|
-
const absPageDir = path.resolve(opts.appCwdPath, "page");
|
|
232
|
-
const hasSt = await appHasStModule(opts.appCwdPath);
|
|
233
|
-
const basePaths = opts.basePaths ?? [];
|
|
234
|
-
const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
|
|
235
|
-
const rootBoundaries = findRootBoundaries(opts.pageKeys, opts.appCwdPath, basePaths);
|
|
236
|
-
const rootLayoutKeys = new Set(opts.pageKeys.filter((key) => {
|
|
237
|
-
const segments = getRootBoundarySegments(key);
|
|
238
|
-
return segments !== null && isRootBoundarySegments(segments, basePaths);
|
|
239
|
-
}));
|
|
240
|
-
const base = await Promise.all(opts.pageKeys.filter((key) => !rootLayoutKeys.has(key)).map(async (key) => {
|
|
241
|
-
const userAbsPath = path.resolve(absPageDir, key);
|
|
242
|
-
if (OVERRIDES_KEY_RE.test(key)) {
|
|
243
|
-
const moduleAbsPath = await writeGeneratedOverridesLayoutFile({
|
|
244
|
-
appCwdPath: opts.appCwdPath,
|
|
245
|
-
key,
|
|
246
|
-
userAbsPath
|
|
247
|
-
});
|
|
248
|
-
return { key, moduleAbsPath, seedAbsPaths: [userAbsPath] };
|
|
249
|
-
}
|
|
250
|
-
return { key, moduleAbsPath: userAbsPath };
|
|
251
|
-
}));
|
|
252
|
-
const generated = await Promise.all(rootBoundaries.map(async (boundary) => ({
|
|
253
|
-
key: implicitRootLayoutKey(boundary.segments),
|
|
254
|
-
moduleAbsPath: await writeGeneratedRootLayoutFile({
|
|
255
|
-
appCwdPath: opts.appCwdPath,
|
|
256
|
-
appName: opts.appName,
|
|
257
|
-
boundary,
|
|
258
|
-
rootSourceAbsPath,
|
|
259
|
-
includeStInit: hasSt && boundary.segments.length === 0,
|
|
260
|
-
includeSystemProvider: !hasAncestorRootBoundary(boundary, rootBoundaries)
|
|
261
|
-
}),
|
|
262
|
-
seedAbsPaths: [...new Set([boundary.sourceAbsPath, rootSourceAbsPath].filter((absPath) => absPath !== null))]
|
|
263
|
-
})));
|
|
264
|
-
const entries = [...base, ...generated];
|
|
265
|
-
entries.sort((a, b) => a.key.localeCompare(b.key));
|
|
266
|
-
return entries;
|
|
267
|
-
}
|
|
268
|
-
async function resolveSsrPageEntriesForApp(app, pageKeys) {
|
|
269
|
-
const config = await app.getConfig();
|
|
270
|
-
return resolveSsrPageEntries({ appCwdPath: app.cwdPath, appName: app.name, pageKeys, basePaths: config.basePaths });
|
|
271
|
-
}
|
|
21
|
+
import path3 from "path";
|
|
272
22
|
|
|
273
23
|
// pkgs/@akanjs/devkit/artifact/routeSeedIndex.ts
|
|
274
|
-
import
|
|
24
|
+
import path from "path";
|
|
275
25
|
import { assertUniqueRoutePatterns, compareRouteSpecificity, parseRouteModuleKey } from "akanjs/common";
|
|
276
26
|
function computeRouteSeedIndex(pageEntries) {
|
|
277
27
|
const layoutsByPrefix = new Map;
|
|
278
28
|
const pagesBySegments = [];
|
|
279
29
|
for (const { key, moduleAbsPath, seedAbsPaths } of pageEntries) {
|
|
280
30
|
const parsed = parseRouteModuleKey(key);
|
|
281
|
-
const files = [
|
|
31
|
+
const files = [path.resolve(moduleAbsPath), ...(seedAbsPaths ?? []).map((seed) => path.resolve(seed))];
|
|
282
32
|
if (parsed.kind === "layout" || parsed.kind === "overrides") {
|
|
283
33
|
const prefix = parsed.routeSegments.join("/");
|
|
284
34
|
const prev = layoutsByPrefix.get(prefix) ?? [];
|
|
@@ -315,7 +65,7 @@ function computeRouteSeedIndex(pageEntries) {
|
|
|
315
65
|
}
|
|
316
66
|
var ROUTE_SEED_INDEX_JSON = "route-seed-index.json";
|
|
317
67
|
function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
318
|
-
const normalizedArtifactDir =
|
|
68
|
+
const normalizedArtifactDir = path.resolve(artifactDir);
|
|
319
69
|
if (options.production) {
|
|
320
70
|
return {
|
|
321
71
|
entries: index.entries.map((entry) => ({ routeId: entry.routeId }))
|
|
@@ -330,19 +80,19 @@ function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
|
330
80
|
};
|
|
331
81
|
}
|
|
332
82
|
async function saveRouteSeedIndex(artifactDir, index, options = {}) {
|
|
333
|
-
const absPath =
|
|
83
|
+
const absPath = path.join(path.resolve(artifactDir), ROUTE_SEED_INDEX_JSON);
|
|
334
84
|
await Bun.write(absPath, `${JSON.stringify(serializeRouteSeedIndexForArtifact(index, artifactDir, options), null, 2)}
|
|
335
85
|
`);
|
|
336
86
|
return absPath;
|
|
337
87
|
}
|
|
338
88
|
function serializeArtifactPath(artifactPath, artifactDir) {
|
|
339
|
-
if (!
|
|
89
|
+
if (!path.isAbsolute(artifactPath))
|
|
340
90
|
return artifactPath;
|
|
341
|
-
return
|
|
91
|
+
return path.relative(artifactDir, artifactPath).split(path.sep).join("/");
|
|
342
92
|
}
|
|
343
93
|
|
|
344
94
|
// pkgs/@akanjs/devkit/frontendBuild/routesManifestArtifactSerializer.ts
|
|
345
|
-
import
|
|
95
|
+
import path2 from "path";
|
|
346
96
|
|
|
347
97
|
class RoutesManifestArtifactSerializer {
|
|
348
98
|
#manifest;
|
|
@@ -350,7 +100,7 @@ class RoutesManifestArtifactSerializer {
|
|
|
350
100
|
#production;
|
|
351
101
|
constructor(manifest, artifactDir, options = {}) {
|
|
352
102
|
this.#manifest = manifest;
|
|
353
|
-
this.#artifactDir =
|
|
103
|
+
this.#artifactDir = path2.resolve(artifactDir);
|
|
354
104
|
this.#production = options.production ?? false;
|
|
355
105
|
}
|
|
356
106
|
static serialize(manifest, artifactDir, options = {}) {
|
|
@@ -383,9 +133,9 @@ class RoutesManifestArtifactSerializer {
|
|
|
383
133
|
};
|
|
384
134
|
}
|
|
385
135
|
#serializeArtifactPath(artifactPath) {
|
|
386
|
-
if (!
|
|
136
|
+
if (!path2.isAbsolute(artifactPath))
|
|
387
137
|
return artifactPath;
|
|
388
|
-
return
|
|
138
|
+
return path2.relative(this.#artifactDir, artifactPath).split(path2.sep).join("/");
|
|
389
139
|
}
|
|
390
140
|
}
|
|
391
141
|
|
|
@@ -435,7 +185,7 @@ class AllRoutesBuilder {
|
|
|
435
185
|
routeIds: this.#routeIds,
|
|
436
186
|
...this.#merged
|
|
437
187
|
};
|
|
438
|
-
const manifestPath =
|
|
188
|
+
const manifestPath = path3.join(path3.resolve(this.#artifactDir), "routes-manifest.json");
|
|
439
189
|
await Bun.write(manifestPath, `${JSON.stringify(RoutesManifestArtifactSerializer.serialize(manifest, this.#artifactDir, {
|
|
440
190
|
production: this.#command === "build"
|
|
441
191
|
}), null, 2)}
|
|
@@ -478,12 +228,12 @@ class AllRoutesBuilder {
|
|
|
478
228
|
}
|
|
479
229
|
|
|
480
230
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
481
|
-
import { mkdir
|
|
482
|
-
import
|
|
231
|
+
import { mkdir, rm, unlink } from "fs/promises";
|
|
232
|
+
import path5 from "path";
|
|
483
233
|
|
|
484
234
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
485
235
|
import fs from "fs";
|
|
486
|
-
import
|
|
236
|
+
import path4 from "path";
|
|
487
237
|
import ts from "typescript";
|
|
488
238
|
|
|
489
239
|
class PagesEntrySourceGenerator {
|
|
@@ -526,11 +276,11 @@ ${entries.join(`
|
|
|
526
276
|
`;
|
|
527
277
|
}
|
|
528
278
|
static #toImportSpecifier(moduleAbsPath) {
|
|
529
|
-
return
|
|
279
|
+
return path4.resolve(moduleAbsPath).split(path4.sep).join("/");
|
|
530
280
|
}
|
|
531
281
|
static #hasAsyncDefaultExport(moduleAbsPath) {
|
|
532
282
|
try {
|
|
533
|
-
const source = fs.readFileSync(
|
|
283
|
+
const source = fs.readFileSync(path4.resolve(moduleAbsPath), "utf8");
|
|
534
284
|
const sourceFile = ts.createSourceFile(moduleAbsPath, source, ts.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
|
|
535
285
|
return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile);
|
|
536
286
|
} catch {
|
|
@@ -609,7 +359,7 @@ class CsrArtifactBuilder {
|
|
|
609
359
|
const csrBasePaths = [...akanConfig.basePaths];
|
|
610
360
|
const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
|
|
611
361
|
await rm(this.#outputDir, { recursive: true, force: true });
|
|
612
|
-
await
|
|
362
|
+
await mkdir(path5.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
|
|
613
363
|
const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath) => this.#createHtmlFile(basePath)));
|
|
614
364
|
const result = await Bun.build({
|
|
615
365
|
target: "browser",
|
|
@@ -641,7 +391,7 @@ ${logs}` : ""}`);
|
|
|
641
391
|
return { outputDir: this.#outputDir };
|
|
642
392
|
}
|
|
643
393
|
get #outputDir() {
|
|
644
|
-
return
|
|
394
|
+
return path5.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
|
|
645
395
|
}
|
|
646
396
|
#define() {
|
|
647
397
|
const nodeEnv = this.#command === "build" ? "production" : "development";
|
|
@@ -672,8 +422,8 @@ ${logs}` : ""}`);
|
|
|
672
422
|
];
|
|
673
423
|
}
|
|
674
424
|
async#loadCsrArtifact() {
|
|
675
|
-
const artifactDir =
|
|
676
|
-
const artifactFile = Bun.file(
|
|
425
|
+
const artifactDir = path5.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
|
|
426
|
+
const artifactFile = Bun.file(path5.join(artifactDir, "base-artifact.json"));
|
|
677
427
|
if (!await artifactFile.exists())
|
|
678
428
|
return { cssAssets: {} };
|
|
679
429
|
const artifact = await artifactFile.json();
|
|
@@ -686,7 +436,7 @@ ${logs}` : ""}`);
|
|
|
686
436
|
const htmlFile = Bun.file(htmlPath);
|
|
687
437
|
if (!await htmlFile.exists())
|
|
688
438
|
continue;
|
|
689
|
-
const basePath =
|
|
439
|
+
const basePath = path5.basename(htmlPath, ".html") === "index" ? "" : path5.basename(htmlPath, ".html");
|
|
690
440
|
const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAssets[basePath]);
|
|
691
441
|
for (const filePath of inlined.jsFiles)
|
|
692
442
|
jsFiles.add(filePath);
|
|
@@ -728,7 +478,7 @@ ${remainingAssets.join(`
|
|
|
728
478
|
next = CsrArtifactBuilder.injectBeforeHeadEnd(next, style);
|
|
729
479
|
}
|
|
730
480
|
if (cssAsset) {
|
|
731
|
-
const cssPath =
|
|
481
|
+
const cssPath = path5.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
|
|
732
482
|
const css = await Bun.file(cssPath).text();
|
|
733
483
|
const style = CsrArtifactBuilder.createInlineStyle(css);
|
|
734
484
|
if (!next.includes(style))
|
|
@@ -799,12 +549,12 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
|
799
549
|
throw new Error(`[csr-build] cannot inline external script: ${src}`);
|
|
800
550
|
}
|
|
801
551
|
const normalized = src.startsWith("/") ? src.slice(1) : src;
|
|
802
|
-
return
|
|
552
|
+
return path5.resolve(path5.dirname(htmlPath), normalized);
|
|
803
553
|
}
|
|
804
554
|
}
|
|
805
555
|
|
|
806
556
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
807
|
-
import
|
|
557
|
+
import path7 from "path";
|
|
808
558
|
import { Logger } from "akanjs/common";
|
|
809
559
|
import { compile } from "tailwindcss";
|
|
810
560
|
|
|
@@ -875,7 +625,7 @@ class CssCandidateCache {
|
|
|
875
625
|
}
|
|
876
626
|
|
|
877
627
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
878
|
-
import
|
|
628
|
+
import path6 from "path";
|
|
879
629
|
var CSS_IMPORT_EXTS = ["", ".css", "/styles.css", "/index.css"];
|
|
880
630
|
|
|
881
631
|
class CssImportResolver {
|
|
@@ -928,7 +678,7 @@ class CssImportResolver {
|
|
|
928
678
|
const exact = this.#paths[id];
|
|
929
679
|
if (exact) {
|
|
930
680
|
for (const repl of exact) {
|
|
931
|
-
const resolved = await this.#firstExisting(
|
|
681
|
+
const resolved = await this.#firstExisting(path6.resolve(this.#workspaceRoot, repl));
|
|
932
682
|
if (resolved)
|
|
933
683
|
return resolved;
|
|
934
684
|
}
|
|
@@ -939,7 +689,7 @@ class CssImportResolver {
|
|
|
939
689
|
const suffix = id.slice(prefix.length);
|
|
940
690
|
for (const repl of replacements) {
|
|
941
691
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
942
|
-
const resolved = await this.#firstExisting(
|
|
692
|
+
const resolved = await this.#firstExisting(path6.resolve(this.#workspaceRoot, replPath + suffix));
|
|
943
693
|
if (resolved)
|
|
944
694
|
return resolved;
|
|
945
695
|
}
|
|
@@ -969,29 +719,29 @@ class CssImportResolver {
|
|
|
969
719
|
try {
|
|
970
720
|
if (!await Bun.file(pkgPath).exists())
|
|
971
721
|
return null;
|
|
972
|
-
const pkgDir =
|
|
722
|
+
const pkgDir = path6.dirname(pkgPath);
|
|
973
723
|
const pkg = await Bun.file(pkgPath).json();
|
|
974
724
|
const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
|
|
975
725
|
const exportValue = pkg.exports?.[subpath];
|
|
976
726
|
const exportedEntry = typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default;
|
|
977
727
|
if (exportedEntry)
|
|
978
|
-
return await this.#firstExisting(
|
|
728
|
+
return await this.#firstExisting(path6.resolve(pkgDir, exportedEntry));
|
|
979
729
|
if (subpath !== ".")
|
|
980
|
-
return await this.#firstExisting(
|
|
981
|
-
return await this.#firstExisting(
|
|
730
|
+
return await this.#firstExisting(path6.resolve(pkgDir, subpath));
|
|
731
|
+
return await this.#firstExisting(path6.resolve(pkgDir, pkg.exports?.["."]?.style || pkg.style || "index.css"));
|
|
982
732
|
} catch {
|
|
983
733
|
return null;
|
|
984
734
|
}
|
|
985
735
|
}
|
|
986
736
|
#resolutionBases(fromBase) {
|
|
987
|
-
return [fromBase, this.#workspaceRoot,
|
|
737
|
+
return [fromBase, this.#workspaceRoot, path6.dirname(Bun.main), path6.resolve(path6.dirname(Bun.main), "../..")];
|
|
988
738
|
}
|
|
989
739
|
#packageJsonCandidates(pkgName) {
|
|
990
740
|
return [
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
741
|
+
path6.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
|
|
742
|
+
path6.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
|
|
743
|
+
path6.join(path6.dirname(Bun.main), "node_modules", pkgName, "package.json"),
|
|
744
|
+
path6.join(path6.dirname(Bun.main), "../../", pkgName, "package.json")
|
|
995
745
|
];
|
|
996
746
|
}
|
|
997
747
|
async#firstExisting(basePath) {
|
|
@@ -1009,7 +759,7 @@ class CssImportResolver {
|
|
|
1009
759
|
return parts[0] ?? null;
|
|
1010
760
|
}
|
|
1011
761
|
static isCssFile(filePath) {
|
|
1012
|
-
return
|
|
762
|
+
return path6.extname(filePath) === ".css";
|
|
1013
763
|
}
|
|
1014
764
|
}
|
|
1015
765
|
|
|
@@ -1028,7 +778,7 @@ class CssCompiler {
|
|
|
1028
778
|
this.#app = app;
|
|
1029
779
|
}
|
|
1030
780
|
get #candidateCachePath() {
|
|
1031
|
-
return
|
|
781
|
+
return path7.join(this.#app.cwdPath, ".akan/cache/cssCandidates.json");
|
|
1032
782
|
}
|
|
1033
783
|
#cssText = null;
|
|
1034
784
|
#cssTextByBasePath = null;
|
|
@@ -1058,7 +808,7 @@ class CssCompiler {
|
|
|
1058
808
|
return filePath;
|
|
1059
809
|
}
|
|
1060
810
|
for (const ext of SOURCE_EXTS) {
|
|
1061
|
-
const filePath =
|
|
811
|
+
const filePath = path7.join(absPathNoExt, `index${ext}`);
|
|
1062
812
|
if (await this.#fileExists(filePath))
|
|
1063
813
|
return filePath;
|
|
1064
814
|
}
|
|
@@ -1116,14 +866,14 @@ class CssCompiler {
|
|
|
1116
866
|
return this.#cssTextByBasePath;
|
|
1117
867
|
}
|
|
1118
868
|
async#warnUnreachableStylesheets() {
|
|
1119
|
-
const pageDir =
|
|
869
|
+
const pageDir = path7.join(this.#app.cwdPath, "page");
|
|
1120
870
|
const glob = new Bun.Glob("**/*.css");
|
|
1121
871
|
for await (const cssPath of glob.scan({ cwd: pageDir, absolute: true })) {
|
|
1122
|
-
if (cssPath.includes(`${
|
|
872
|
+
if (cssPath.includes(`${path7.sep}(libs)${path7.sep}`))
|
|
1123
873
|
continue;
|
|
1124
874
|
if (this.#discoveredCssPaths.has(cssPath))
|
|
1125
875
|
continue;
|
|
1126
|
-
this.#logger.warn(`css ${
|
|
876
|
+
this.#logger.warn(`css ${path7.relative(this.#app.cwdPath, cssPath)} is imported by no route and never compiled`);
|
|
1127
877
|
}
|
|
1128
878
|
}
|
|
1129
879
|
async discoverCss({ refresh } = {}) {
|
|
@@ -1135,7 +885,7 @@ class CssCompiler {
|
|
|
1135
885
|
pageKeys
|
|
1136
886
|
} = {}) {
|
|
1137
887
|
pageKeys ??= await this.#app.getPageKeys({ refresh });
|
|
1138
|
-
const seeds = pageKeys.map((key) =>
|
|
888
|
+
const seeds = pageKeys.map((key) => path7.resolve(this.#app.cwdPath, "page", key));
|
|
1139
889
|
const cssFiles = new Set;
|
|
1140
890
|
const sourceFiles = new Set;
|
|
1141
891
|
const queue = [...seeds];
|
|
@@ -1167,7 +917,7 @@ class CssCompiler {
|
|
|
1167
917
|
} catch {
|
|
1168
918
|
continue;
|
|
1169
919
|
}
|
|
1170
|
-
const importerDir =
|
|
920
|
+
const importerDir = path7.dirname(filePath);
|
|
1171
921
|
for (const imp of imports) {
|
|
1172
922
|
const spec = imp.path;
|
|
1173
923
|
if (!spec)
|
|
@@ -1192,18 +942,18 @@ class CssCompiler {
|
|
|
1192
942
|
return { cssPaths, sourcePaths: [...sourceFiles] };
|
|
1193
943
|
}
|
|
1194
944
|
async#libTokenStylesheets(sourceFiles) {
|
|
1195
|
-
const libsRoot =
|
|
945
|
+
const libsRoot = path7.join(this.#app.workspace.workspaceRoot, "libs");
|
|
1196
946
|
const libNames = new Set;
|
|
1197
947
|
for (const filePath of sourceFiles) {
|
|
1198
|
-
const relPath =
|
|
1199
|
-
if (relPath.startsWith("..") ||
|
|
948
|
+
const relPath = path7.relative(libsRoot, filePath);
|
|
949
|
+
if (relPath.startsWith("..") || path7.isAbsolute(relPath))
|
|
1200
950
|
continue;
|
|
1201
|
-
const [libName] = relPath.split(
|
|
951
|
+
const [libName] = relPath.split(path7.sep);
|
|
1202
952
|
if (libName)
|
|
1203
953
|
libNames.add(libName);
|
|
1204
954
|
}
|
|
1205
955
|
const tokenPaths = await Promise.all([...libNames].sort().map(async (libName) => {
|
|
1206
|
-
const tokensPath =
|
|
956
|
+
const tokensPath = path7.join(libsRoot, libName, "ui/tokens.css");
|
|
1207
957
|
return await this.#fileExists(tokensPath) ? tokensPath : null;
|
|
1208
958
|
}));
|
|
1209
959
|
return tokenPaths.filter((tokensPath) => !!tokensPath);
|
|
@@ -1218,7 +968,7 @@ class CssCompiler {
|
|
|
1218
968
|
const compileStarted = Date.now();
|
|
1219
969
|
const compilers = await Promise.all(cssPaths.map(async (cssPath) => {
|
|
1220
970
|
const css = await Bun.file(cssPath).text();
|
|
1221
|
-
const base =
|
|
971
|
+
const base = path7.dirname(cssPath);
|
|
1222
972
|
const imported2 = new Map;
|
|
1223
973
|
const compiler = await compile(css, {
|
|
1224
974
|
base,
|
|
@@ -1262,11 +1012,11 @@ class CssCompiler {
|
|
|
1262
1012
|
const content = await Bun.file(p).text();
|
|
1263
1013
|
imported?.set(p, content);
|
|
1264
1014
|
this.#logger.verbose(`css import "${id}" from ${fromBase} -> ${p} (${content.length} bytes)`);
|
|
1265
|
-
return { path: p, base:
|
|
1015
|
+
return { path: p, base: path7.dirname(p), content };
|
|
1266
1016
|
}
|
|
1267
1017
|
async#resolveCssImport(id, fromBase) {
|
|
1268
1018
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
1269
|
-
const filePath =
|
|
1019
|
+
const filePath = path7.resolve(fromBase, id);
|
|
1270
1020
|
if (await this.#fileExists(filePath))
|
|
1271
1021
|
return filePath;
|
|
1272
1022
|
throw new Error(`[css] failed to resolve stylesheet import "${id}" from ${fromBase} (no file at ${filePath})`);
|
|
@@ -1286,7 +1036,7 @@ class CssCompiler {
|
|
|
1286
1036
|
async#loadModule(id, fromBase) {
|
|
1287
1037
|
const p = __require.resolve(id, { paths: [fromBase] });
|
|
1288
1038
|
const mod = await import(p);
|
|
1289
|
-
return { path: p, base:
|
|
1039
|
+
return { path: p, base: path7.dirname(p), module: mod.default ?? mod };
|
|
1290
1040
|
}
|
|
1291
1041
|
#resolveSourceImport(id, fromBase, resolvePackage) {
|
|
1292
1042
|
const cacheKey = `${fromBase}\x00${id}`;
|
|
@@ -1299,7 +1049,7 @@ class CssCompiler {
|
|
|
1299
1049
|
}
|
|
1300
1050
|
async#resolveSourceImportUncached(id, fromBase, resolvePackage) {
|
|
1301
1051
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
1302
|
-
const abs = id.startsWith("/") ? id :
|
|
1052
|
+
const abs = id.startsWith("/") ? id : path7.resolve(fromBase, id);
|
|
1303
1053
|
return this.#resolveSourceFileCandidate(abs);
|
|
1304
1054
|
}
|
|
1305
1055
|
const pkg = await resolvePackage(id);
|
|
@@ -1350,7 +1100,7 @@ function resolveSourceWithRequire(id, fromBase) {
|
|
|
1350
1100
|
}
|
|
1351
1101
|
}
|
|
1352
1102
|
function isSourceFile(filePath) {
|
|
1353
|
-
return SOURCE_EXTS.includes(
|
|
1103
|
+
return SOURCE_EXTS.includes(path7.extname(filePath));
|
|
1354
1104
|
}
|
|
1355
1105
|
function isIgnoredNodeModuleSource(filePath) {
|
|
1356
1106
|
return NODE_MODULES_RE.test(filePath) && !AKANJS_NODE_MODULE_RE.test(filePath);
|
|
@@ -1360,15 +1110,15 @@ function declaredCustomProperties(css) {
|
|
|
1360
1110
|
return [...new Set([...withoutThemeBlocks.matchAll(/(?:^|[\s;{])(--[\w-]+)\s*:/g)].map(([, name]) => name))].filter((name) => !!name);
|
|
1361
1111
|
}
|
|
1362
1112
|
function getPageKeyBasePath(pageKey, basePaths) {
|
|
1363
|
-
const normalized = pageKey.split(
|
|
1113
|
+
const normalized = pageKey.split(path7.sep).join("/").replace(/^\.\//, "");
|
|
1364
1114
|
const segments = normalized.split("/");
|
|
1365
1115
|
const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
|
|
1366
1116
|
return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
|
|
1367
1117
|
}
|
|
1368
1118
|
|
|
1369
1119
|
// pkgs/@akanjs/devkit/frontendBuild/fontOptimizer.ts
|
|
1370
|
-
import { mkdir as
|
|
1371
|
-
import
|
|
1120
|
+
import { mkdir as mkdir2, stat as stat2 } from "fs/promises";
|
|
1121
|
+
import path8 from "path";
|
|
1372
1122
|
import ts2 from "typescript";
|
|
1373
1123
|
var FONT_URL_PREFIX = "/_akan/fonts";
|
|
1374
1124
|
var DEFAULT_FONT_SUBSETS = ["latin"];
|
|
@@ -1385,7 +1135,7 @@ class FontOptimizer {
|
|
|
1385
1135
|
constructor(app, command = "start") {
|
|
1386
1136
|
this.#app = app;
|
|
1387
1137
|
this.#command = command;
|
|
1388
|
-
this.#artifactRoot =
|
|
1138
|
+
this.#artifactRoot = path8.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
|
|
1389
1139
|
}
|
|
1390
1140
|
async optimize() {
|
|
1391
1141
|
const fonts = await this.discoverFonts();
|
|
@@ -1410,7 +1160,7 @@ class FontOptimizer {
|
|
|
1410
1160
|
return result;
|
|
1411
1161
|
}
|
|
1412
1162
|
get #cachePath() {
|
|
1413
|
-
return
|
|
1163
|
+
return path8.join(this.#artifactRoot, "fontCache.json");
|
|
1414
1164
|
}
|
|
1415
1165
|
async#buildCacheKey(fonts) {
|
|
1416
1166
|
const sources = [];
|
|
@@ -1425,7 +1175,7 @@ class FontOptimizer {
|
|
|
1425
1175
|
sources.push({ optimizedSrc: face.optimizedSrc, ...stamp });
|
|
1426
1176
|
}
|
|
1427
1177
|
for (const filePath of font.subsetFiles ?? []) {
|
|
1428
|
-
const abs =
|
|
1178
|
+
const abs = path8.isAbsolute(filePath) ? filePath : path8.join(this.#app.cwdPath, filePath);
|
|
1429
1179
|
const stamp = await this.#fileStamp(abs);
|
|
1430
1180
|
if (!stamp)
|
|
1431
1181
|
return null;
|
|
@@ -1448,7 +1198,7 @@ class FontOptimizer {
|
|
|
1448
1198
|
const cache = await Bun.file(this.#cachePath).json().catch(() => null);
|
|
1449
1199
|
if (cache?.version !== FontOptimizer.#cacheVersion || cache.key !== key)
|
|
1450
1200
|
return null;
|
|
1451
|
-
const files = cache.files.map((relativePath) =>
|
|
1201
|
+
const files = cache.files.map((relativePath) => path8.join(this.#artifactRoot, relativePath));
|
|
1452
1202
|
for (const filePath of files) {
|
|
1453
1203
|
if (!await Bun.file(filePath).exists())
|
|
1454
1204
|
return null;
|
|
@@ -1460,7 +1210,7 @@ class FontOptimizer {
|
|
|
1460
1210
|
version: FontOptimizer.#cacheVersion,
|
|
1461
1211
|
key,
|
|
1462
1212
|
css: result.css,
|
|
1463
|
-
files: result.files.map((filePath) =>
|
|
1213
|
+
files: result.files.map((filePath) => path8.relative(this.#artifactRoot, filePath))
|
|
1464
1214
|
};
|
|
1465
1215
|
await Bun.write(this.#cachePath, JSON.stringify(cache));
|
|
1466
1216
|
}
|
|
@@ -1468,7 +1218,7 @@ class FontOptimizer {
|
|
|
1468
1218
|
const pageKeys = await this.#app.getPageKeys();
|
|
1469
1219
|
const fonts = [];
|
|
1470
1220
|
await Promise.all(pageKeys.map(async (key) => {
|
|
1471
|
-
const filePath =
|
|
1221
|
+
const filePath = path8.resolve(this.#app.cwdPath, "page", key);
|
|
1472
1222
|
const file = Bun.file(filePath);
|
|
1473
1223
|
if (!await file.exists())
|
|
1474
1224
|
return;
|
|
@@ -1487,8 +1237,8 @@ class FontOptimizer {
|
|
|
1487
1237
|
this.#app.logger.warn(`[font] source not found: ${face.src}`);
|
|
1488
1238
|
continue;
|
|
1489
1239
|
}
|
|
1490
|
-
const outputPath =
|
|
1491
|
-
await
|
|
1240
|
+
const outputPath = path8.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
|
|
1241
|
+
await mkdir2(path8.dirname(outputPath), { recursive: true });
|
|
1492
1242
|
const sourceBuffer = Buffer.from(await Bun.file(sourcePath).arrayBuffer());
|
|
1493
1243
|
const outputBuffer = await this.#buildFontBuffer(font, sourceBuffer, sourcePath);
|
|
1494
1244
|
await Bun.write(outputPath, outputBuffer);
|
|
@@ -1635,8 +1385,8 @@ class FontOptimizer {
|
|
|
1635
1385
|
return null;
|
|
1636
1386
|
const rel = src.replace(/^\//, "");
|
|
1637
1387
|
const candidates = [
|
|
1638
|
-
this.#command === "build" ?
|
|
1639
|
-
|
|
1388
|
+
this.#command === "build" ? path8.join(this.#app.dist.cwdPath, "public", rel) : null,
|
|
1389
|
+
path8.join(this.#app.cwdPath, "public", rel),
|
|
1640
1390
|
this.#resolveWorkspacePublicPath(rel)
|
|
1641
1391
|
].filter(Boolean);
|
|
1642
1392
|
for (const candidate of candidates) {
|
|
@@ -1671,7 +1421,7 @@ class FontOptimizer {
|
|
|
1671
1421
|
return "woff2";
|
|
1672
1422
|
if (signature === "OTTO")
|
|
1673
1423
|
return "otf";
|
|
1674
|
-
const ext =
|
|
1424
|
+
const ext = path8.extname(sourcePath).slice(1).toLowerCase();
|
|
1675
1425
|
if (ext === "otf" || ext === "woff" || ext === "woff2")
|
|
1676
1426
|
return ext;
|
|
1677
1427
|
return "ttf";
|
|
@@ -1680,7 +1430,7 @@ class FontOptimizer {
|
|
|
1680
1430
|
const [root, dep, ...rest] = rel.split("/");
|
|
1681
1431
|
if (root !== "libs" || !dep || rest.length === 0)
|
|
1682
1432
|
return null;
|
|
1683
|
-
return
|
|
1433
|
+
return path8.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
|
|
1684
1434
|
}
|
|
1685
1435
|
async#getSubsetText(font) {
|
|
1686
1436
|
const parts = new Set;
|
|
@@ -1690,7 +1440,7 @@ class FontOptimizer {
|
|
|
1690
1440
|
if (font.subsetText)
|
|
1691
1441
|
parts.add(font.subsetText);
|
|
1692
1442
|
for (const filePath of font.subsetFiles ?? []) {
|
|
1693
|
-
const abs =
|
|
1443
|
+
const abs = path8.isAbsolute(filePath) ? filePath : path8.join(this.#app.cwdPath, filePath);
|
|
1694
1444
|
const file = Bun.file(abs);
|
|
1695
1445
|
if (await file.exists())
|
|
1696
1446
|
parts.add(await file.text());
|
|
@@ -1710,7 +1460,7 @@ class FontOptimizer {
|
|
|
1710
1460
|
}
|
|
1711
1461
|
async#collectAutoSubsetText() {
|
|
1712
1462
|
const libPageRoots = (await this.#app.getPageRoots()).filter((root) => root.keyPrefix).map((root) => root.dir);
|
|
1713
|
-
const roots = [...["page", "ui"].map((dir) =>
|
|
1463
|
+
const roots = [...["page", "ui"].map((dir) => path8.join(this.#app.cwdPath, dir)), ...libPageRoots];
|
|
1714
1464
|
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,html,md}");
|
|
1715
1465
|
const parts = [];
|
|
1716
1466
|
await Promise.all(roots.map(async (root) => {
|
|
@@ -1826,10 +1576,10 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
|
|
|
1826
1576
|
}
|
|
1827
1577
|
|
|
1828
1578
|
// pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
|
|
1829
|
-
import
|
|
1579
|
+
import path10 from "path";
|
|
1830
1580
|
|
|
1831
1581
|
// pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
|
|
1832
|
-
import
|
|
1582
|
+
import path9 from "path";
|
|
1833
1583
|
var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
|
|
1834
1584
|
var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
|
|
1835
1585
|
var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
|
|
@@ -1871,7 +1621,7 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
1871
1621
|
const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
|
|
1872
1622
|
if (!replPath)
|
|
1873
1623
|
continue;
|
|
1874
|
-
const candidate =
|
|
1624
|
+
const candidate = path9.resolve(workspaceRoot, replPath + suffix);
|
|
1875
1625
|
const hit = await firstExisting(candidate);
|
|
1876
1626
|
if (hit)
|
|
1877
1627
|
return hit;
|
|
@@ -1883,8 +1633,8 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
1883
1633
|
if (spec === pkg)
|
|
1884
1634
|
continue;
|
|
1885
1635
|
const suffix = spec.slice(pkg.length + 1);
|
|
1886
|
-
const pkgDir =
|
|
1887
|
-
const candidate =
|
|
1636
|
+
const pkgDir = path9.dirname(path9.resolve(workspaceRoot, entryFile));
|
|
1637
|
+
const candidate = path9.join(pkgDir, suffix);
|
|
1888
1638
|
const hit = await firstExisting(candidate);
|
|
1889
1639
|
if (hit)
|
|
1890
1640
|
return hit;
|
|
@@ -1934,7 +1684,7 @@ async function firstExisting(basePath) {
|
|
|
1934
1684
|
return candidate;
|
|
1935
1685
|
}
|
|
1936
1686
|
for (const ext of CANDIDATE_EXTS) {
|
|
1937
|
-
const candidate =
|
|
1687
|
+
const candidate = path9.join(basePath, `index${ext}`);
|
|
1938
1688
|
if (await Bun.file(candidate).exists())
|
|
1939
1689
|
return candidate;
|
|
1940
1690
|
}
|
|
@@ -2025,11 +1775,11 @@ class PagesBundleBuilder {
|
|
|
2025
1775
|
const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
|
|
2026
1776
|
if (!entryArtifact)
|
|
2027
1777
|
throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
|
|
2028
|
-
const bundlePath =
|
|
1778
|
+
const bundlePath = path10.resolve(entryArtifact.path);
|
|
2029
1779
|
const buildId = Date.now();
|
|
2030
1780
|
const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
|
|
2031
1781
|
const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
|
|
2032
|
-
this.#app.verbose(`[PagesBundleBuilder] ${
|
|
1782
|
+
this.#app.verbose(`[PagesBundleBuilder] ${path10.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
|
|
2033
1783
|
return {
|
|
2034
1784
|
bundlePath,
|
|
2035
1785
|
buildId,
|
|
@@ -2112,7 +1862,7 @@ function loaderFor2(absPath) {
|
|
|
2112
1862
|
|
|
2113
1863
|
// pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
|
|
2114
1864
|
import fs2 from "fs";
|
|
2115
|
-
import
|
|
1865
|
+
import path11 from "path";
|
|
2116
1866
|
import zlib from "zlib";
|
|
2117
1867
|
var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
|
|
2118
1868
|
var MIN_COMPRESS_BYTES = 1024;
|
|
@@ -2121,8 +1871,8 @@ var DEFAULT_BROTLI_QUALITY = 9;
|
|
|
2121
1871
|
var GZIP_LEVEL = 9;
|
|
2122
1872
|
async function precompressArtifacts(app) {
|
|
2123
1873
|
const roots = [
|
|
2124
|
-
|
|
2125
|
-
|
|
1874
|
+
path11.join(app.dist.cwdPath, ".akan/artifact/client"),
|
|
1875
|
+
path11.join(app.dist.cwdPath, ".akan/artifact/styles")
|
|
2126
1876
|
];
|
|
2127
1877
|
const result = { files: 0, inputBytes: 0, outputBytes: 0, brotliBytes: 0 };
|
|
2128
1878
|
await Promise.all(roots.map((root) => precompressRoot(root, result)));
|
|
@@ -2141,7 +1891,7 @@ async function precompressRoot(root, result) {
|
|
|
2141
1891
|
const bytes = await Bun.file(filePath).bytes();
|
|
2142
1892
|
const buffer = toArrayBuffer(bytes);
|
|
2143
1893
|
const gz = Bun.gzipSync(buffer, { level: GZIP_LEVEL });
|
|
2144
|
-
const br = brotliCompress(buffer,
|
|
1894
|
+
const br = brotliCompress(buffer, path11.extname(filePath).toLowerCase());
|
|
2145
1895
|
await Promise.all([Bun.write(`${filePath}.gz`, gz), Bun.write(`${filePath}.br`, br)]);
|
|
2146
1896
|
result.files += 1;
|
|
2147
1897
|
result.inputBytes += bytes.byteLength;
|
|
@@ -2161,7 +1911,7 @@ function brotliCompress(buffer, ext) {
|
|
|
2161
1911
|
async function shouldPrecompress(filePath) {
|
|
2162
1912
|
if (filePath.endsWith(".gz") || filePath.endsWith(".br"))
|
|
2163
1913
|
return false;
|
|
2164
|
-
if (!COMPRESSIBLE_EXTS.has(
|
|
1914
|
+
if (!COMPRESSIBLE_EXTS.has(path11.extname(filePath).toLowerCase()))
|
|
2165
1915
|
return false;
|
|
2166
1916
|
const file = Bun.file(filePath);
|
|
2167
1917
|
if (!await file.exists())
|
|
@@ -2180,7 +1930,7 @@ function formatBytes(bytes) {
|
|
|
2180
1930
|
}
|
|
2181
1931
|
|
|
2182
1932
|
// pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
|
|
2183
|
-
import
|
|
1933
|
+
import path12 from "path";
|
|
2184
1934
|
import { optimize } from "@tailwindcss/node";
|
|
2185
1935
|
function prepareCssAsset(command, basePath, cssText) {
|
|
2186
1936
|
return optimize(cssText, { file: `${basePath || "root"}.css`, minify: command === "build" }).code;
|
|
@@ -2196,7 +1946,7 @@ class SsrBaseArtifactBuilder {
|
|
|
2196
1946
|
this.#app = app;
|
|
2197
1947
|
this.#command = command;
|
|
2198
1948
|
this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
|
|
2199
|
-
this.#absArtifactDir =
|
|
1949
|
+
this.#absArtifactDir = path12.resolve(this.#artifactDir);
|
|
2200
1950
|
}
|
|
2201
1951
|
async build() {
|
|
2202
1952
|
const akanConfig = await this.#app.getConfig();
|
|
@@ -2218,7 +1968,7 @@ class SsrBaseArtifactBuilder {
|
|
|
2218
1968
|
rscRuntimeSsrManifest,
|
|
2219
1969
|
vendorMap,
|
|
2220
1970
|
cssAssets,
|
|
2221
|
-
pagesBundlePath: this.#command === "build" ?
|
|
1971
|
+
pagesBundlePath: this.#command === "build" ? path12.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
|
|
2222
1972
|
pagesBundleBuildId: pagesBundle.buildId,
|
|
2223
1973
|
domains: [...akanConfig.domains],
|
|
2224
1974
|
subRoutes: Object.fromEntries(Array.from(akanConfig.subRoutes.entries()).map(([basePath, domains]) => [basePath, [...domains]])),
|
|
@@ -2234,18 +1984,18 @@ class SsrBaseArtifactBuilder {
|
|
|
2234
1984
|
androidSha256CertFingerprints: target.deepLinks?.android?.sha256CertFingerprints
|
|
2235
1985
|
}))
|
|
2236
1986
|
};
|
|
2237
|
-
await Bun.write(
|
|
1987
|
+
await Bun.write(path12.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
|
|
2238
1988
|
`);
|
|
2239
1989
|
this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
|
|
2240
1990
|
return { artifact, seedIndex, cssCompiler, optimizedFonts };
|
|
2241
1991
|
}
|
|
2242
1992
|
async#buildRuntimeClientEntries() {
|
|
2243
1993
|
const akanServerPath = await this.#resolveAkanServerPath();
|
|
2244
|
-
const rscClientEntry =
|
|
2245
|
-
const rscSegmentOutletEntry =
|
|
1994
|
+
const rscClientEntry = path12.resolve(akanServerPath, "rscClient.tsx");
|
|
1995
|
+
const rscSegmentOutletEntry = path12.resolve(akanServerPath, "rscSegmentOutlet.tsx");
|
|
2246
1996
|
const vendorEntries = VENDOR_SPECIFIERS.map((specifier) => ({
|
|
2247
1997
|
specifier,
|
|
2248
|
-
absPath:
|
|
1998
|
+
absPath: path12.resolve(akanServerPath, "vendor", `${specifier.replaceAll("/", "-").replaceAll(".", "-")}.ts`)
|
|
2249
1999
|
}));
|
|
2250
2000
|
const entries = [rscClientEntry, rscSegmentOutletEntry, ...vendorEntries.map((v) => v.absPath)];
|
|
2251
2001
|
const clientBundle = await new ClientEntriesBundler({ app: this.#app, entries, command: this.#command }).bundle();
|
|
@@ -2282,15 +2032,15 @@ class SsrBaseArtifactBuilder {
|
|
|
2282
2032
|
async#resolveAkanServerPath() {
|
|
2283
2033
|
const candidates = [];
|
|
2284
2034
|
try {
|
|
2285
|
-
candidates.push(
|
|
2035
|
+
candidates.push(path12.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
|
|
2286
2036
|
} catch {}
|
|
2287
|
-
candidates.push(
|
|
2037
|
+
candidates.push(path12.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path12.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
|
|
2288
2038
|
try {
|
|
2289
|
-
candidates.push(
|
|
2039
|
+
candidates.push(path12.dirname(Bun.resolveSync("akanjs/server", path12.dirname(Bun.main))));
|
|
2290
2040
|
} catch {}
|
|
2291
|
-
candidates.push(
|
|
2041
|
+
candidates.push(path12.join(path12.dirname(Bun.main), "node_modules/akanjs/server"), path12.join(path12.dirname(Bun.main), "../../akanjs/server"), path12.resolve(import.meta.dir, "../../server"), path12.resolve(import.meta.dir, "../server"));
|
|
2292
2042
|
for (const candidate of candidates) {
|
|
2293
|
-
if (await Bun.file(
|
|
2043
|
+
if (await Bun.file(path12.join(candidate, "rscClient.tsx")).exists())
|
|
2294
2044
|
return candidate;
|
|
2295
2045
|
}
|
|
2296
2046
|
throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
|
|
@@ -2319,7 +2069,7 @@ ${preparedCssText}`).toString(36);
|
|
|
2319
2069
|
`styles/${cssAssetName}-${cssHash}.css`,
|
|
2320
2070
|
`/_akan/styles/${cssAssetName}-${cssHash}.css`
|
|
2321
2071
|
];
|
|
2322
|
-
await Bun.write(
|
|
2072
|
+
await Bun.write(path12.join(this.#absArtifactDir, cssRelPath), preparedCssText);
|
|
2323
2073
|
SsrBaseArtifactBuilder.#warnDroppedImports(this.#app, cssRelPath, preparedCssText, imported);
|
|
2324
2074
|
this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath} -> ${cssRelPath}`);
|
|
2325
2075
|
return [basePath, { cssUrl, cssRelPath }];
|