@akanjs/cli 3.0.0-beta.2 → 3.0.0-beta.20
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/CodeAgent-awv258wb.js +9 -0
- package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
- package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
- package/CodeTui-1nqh35ez.js +1457 -0
- package/README.md +3 -0
- package/TunnelShare-scf4e4pd.js +9 -0
- package/{agent.command-d2gfxfck.js → agent.command-1s9ag7sb.js} +8 -9
- package/akanCode.js +102 -0
- package/{application.command-pj2m7584.js → application.command-49hwy6va.js} +51 -78
- package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-ybyp97pv.js} +63 -64
- package/{applicationReleasePackager-4yasxwv9.js → applicationReleasePackager-esnrphw8.js} +40 -60
- package/buildBatch.proc.js +19 -24
- package/{capacitorApp-36rbr858.js → capacitorApp-1synz4en.js} +3 -4
- package/cloud.command-d7rqtzt9.js +94 -0
- package/cloud.script-bkbpcr96.js +19 -0
- package/code.command-nn48xzej.js +154 -0
- package/commandManifest.json +1 -1
- package/consoleToStderr-h5bryj94.js +7 -0
- package/context.command-s3mcmvpa.js +48 -0
- package/context.runner-k99nb5pk.js +21 -0
- package/{dependencyScanner-shs82ynp.js → dependencyScanner-ye2e6pdz.js} +2 -2
- package/{devTui-40ggmd99.js → devTui-q7k7bakd.js} +122 -40
- package/fileSys-5ngz93ga.js +9 -0
- package/guideline.command-sct4qnt5.js +42 -0
- package/guidelines/agentRule/agentRule.instruction.md +206 -25
- package/guidelines/conventions/conventions.instruction.md +79 -24
- package/guidelines/fieldRule/fieldRule.instruction.md +1 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
- package/guidelines/queryRule/queryRule.instruction.md +17 -7
- package/guidelines/runtimeRule/runtimeRule.instruction.md +74 -0
- package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
- package/guidelines/transportRule/transportRule.instruction.md +51 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
- package/incrementalBuilder.proc.js +31 -48
- package/{index-h7yw2z9n.js → index-0bq14vr1.js} +8 -14
- package/index-13ffe9wp.js +69 -0
- package/index-22d57v4c.js +266 -0
- package/{index-fz5q3gd7.js → index-31yr441d.js} +10 -17
- package/index-3hx1z96c.js +87 -0
- package/index-3sq321ak.js +53 -0
- package/{index-kcxmv48c.js → index-3t7g9e4r.js} +45 -79
- package/{index-q0y2jq9j.js → index-5b6tavv3.js} +6 -3
- package/{index-47pj3aee.js → index-5e0n4hqx.js} +11 -12
- package/{index-259dsnz3.js → index-5pc1qrbv.js} +5 -8
- package/index-7md2g9vw.js +6 -0
- package/index-8mna0947.js +187 -0
- package/{index-zry5nz81.js → index-8sf7wmdr.js} +51 -30
- package/{index-2tv3fdx4.js → index-9d9bgcx4.js} +342 -765
- package/index-9dp031by.js +12 -0
- package/{index-ne2qy0nk.js → index-ahemdr5n.js} +12 -12
- package/{index-ws5e0j51.js → index-as7xmyz8.js} +40 -24
- package/index-axzjaqve.js +1118 -0
- package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
- package/index-c6eggbee.js +123 -0
- package/index-d2242ksy.js +99 -0
- package/{index-a64esmtb.js → index-ddxvdd1p.js} +169 -305
- package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
- package/{index-pnqbkf5p.js → index-dzf3r49a.js} +6 -2
- package/{index-w8kmx1b6.js → index-fgq75haa.js} +198 -290
- package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
- package/{index-hwkygn9s.js → index-khpfpcsd.js} +302 -33
- package/{index-wt7qrtd4.js → index-mxav6j3c.js} +93 -232
- package/{index-gyd220p2.js → index-myhc3c1j.js} +554 -577
- package/{index-600zhnve.js → index-nv5976x3.js} +56 -197
- package/index-p6pbz9n5.js +25 -0
- package/{index-4edzf1gr.js → index-przybvy5.js} +77 -150
- package/index-smme4r47.js +49 -0
- package/{index-mak3cd28.js → index-w2zdcw3k.js} +137 -255
- package/index-wa5jbxj1.js +760 -0
- package/{index-v0qh106m.js → index-ww4z397j.js} +527 -723
- package/{index-j9yhg404.js → index-xqjwd384.js} +4 -7
- package/{index-7737gxcp.js → index-xqpzbab5.js} +107 -241
- package/index-xsjh6nzh.js +2729 -0
- package/{index-ktb5njgy.js → index-ygn77a5w.js} +47 -99
- package/index-ztp3e73t.js +700 -0
- package/index.js +23 -22
- package/{library.command-nbsky672.js → library.command-1gx04jgn.js} +4 -5
- package/{localRegistry.command-yeq57wjr.js → localRegistry.command-zndxj1q6.js} +22 -42
- package/{module.command-29vqzrh8.js → module.command-3waddk95.js} +8 -11
- package/{package.command-axv0abmn.js → package.command-zrc7br1y.js} +6 -7
- package/package.json +14 -5
- package/{page.command-vs9s3zrh.js → page.command-vpjgardh.js} +4 -5
- package/{primitive.command-cbxmqbtc.js → primitive.command-sz84tk4t.js} +9 -22
- package/prompter-ptaa3nk0.js +8 -0
- package/{quality.command-gmbs7nws.js → quality.command-g869hafs.js} +203 -376
- package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
- package/{repair.command-bqsjptsj.js → repair.command-chsnjvvv.js} +11 -35
- package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
- package/{scalar.command-6k1vhe9s.js → scalar.command-2v21newx.js} +7 -10
- package/skills/akan-code/SKILL.md +130 -0
- package/skills/akan-debug/SKILL.md +42 -0
- package/skills/akan-deps/SKILL.md +50 -0
- package/skills/akan-err/SKILL.md +39 -0
- package/skills/akan-module/SKILL.md +45 -0
- package/skills/akan-scaffold/SKILL.md +76 -0
- package/skills/akan-scalar/SKILL.md +52 -0
- package/skills/akan-service/SKILL.md +34 -0
- package/skills/akan-store/SKILL.md +67 -0
- package/skills/akan-ui/SKILL.md +63 -0
- package/skills/akan-validate/SKILL.md +44 -0
- package/{subspace.command-fwjfcts7.js → subspace.command-ckcbwfp1.js} +138 -67
- package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
- package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
- package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
- package/templates/appSample/lib/task/task.abstract.ts +12 -32
- package/templates/appSample/lib/task/task.signal.spec.ts +15 -18
- package/templates/appSample/lib/task/task.signal.test.ts +15 -1
- package/templates/appSample/lib/task/task.signal.ts +1 -1
- package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
- package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
- package/templates/client.ts +7 -30
- package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
- package/templates/crudPages/[__model__Id]/page.tsx +2 -1
- package/templates/crudPages/new/page.tsx +2 -1
- package/templates/crudPages/page.tsx +2 -1
- package/templates/crudSinglePage/page.tsx +2 -1
- package/templates/lib/__lib/lib.dictionary.ts +0 -2
- package/templates/lib/__lib/lib.document.ts +0 -2
- package/templates/lib/sig.ts +8 -30
- package/templates/localDev/docker-compose.yaml.template +3 -14
- package/templates/module/__model__.signal.ts +12 -4
- package/templates/pkgRoot/tsconfig.json.template +2 -7
- package/templates/server.ts +0 -2
- package/templates/service/__model__.abstract.md.template +8 -0
- package/tunnel.command-kd2yr4fx.js +129 -0
- package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
- package/typecheck.proc.js +1 -1
- package/workflow.command-44252cqv.js +79 -0
- package/{workspace.command-8s050m0h.js → workspace.command-fqcztt5p.js} +77 -109
- package/abstractCompactor-mjh5ppsq.js +0 -101
- package/cloud.command-jshwdq22.js +0 -93
- package/context.command-ez8a0zyz.js +0 -80
- package/devTuiView-c08ccbat.js +0 -9
- package/getDirname-dr3jz1xg.js +0 -7
- package/guideline.command-xmqwx8zm.js +0 -359
- package/guidelines/agentRule/agentRule.generate.json +0 -31
- package/guidelines/componentRule/componentRule.generate.json +0 -31
- package/guidelines/conventions/conventions.generate.json +0 -25
- package/guidelines/cssRule/cssRule.generate.json +0 -31
- package/guidelines/docPageRule/docPageRule.generate.json +0 -31
- package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
- package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
- package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
- package/guidelines/enumConstant/enumConstant.generate.json +0 -31
- package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
- package/guidelines/fieldRule/fieldRule.generate.json +0 -31
- package/guidelines/framework/framework.generate.json +0 -32
- package/guidelines/mcpRule/mcpRule.generate.json +0 -35
- package/guidelines/modelConstant/modelConstant.generate.json +0 -32
- package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
- package/guidelines/modelDocument/modelDocument.generate.json +0 -31
- package/guidelines/modelService/modelService.generate.json +0 -31
- package/guidelines/modelSignal/modelSignal.generate.json +0 -31
- package/guidelines/modelStore/modelStore.generate.json +0 -31
- package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
- package/guidelines/modelUnit/modelUnit.generate.json +0 -31
- package/guidelines/modelUtil/modelUtil.generate.json +0 -31
- package/guidelines/modelView/modelView.generate.json +0 -31
- package/guidelines/modelZone/modelZone.generate.json +0 -31
- package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
- package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
- package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
- package/guidelines/queryRule/queryRule.generate.json +0 -31
- package/guidelines/recipeRule/recipeRule.generate.json +0 -31
- package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
- package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
- package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
- package/guidelines/scalarModule/scalarModule.generate.json +0 -31
- package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
- package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
- package/guidelines/ssrRule/ssrRule.generate.json +0 -31
- package/guidelines/transportRule/transportRule.generate.json +0 -31
- package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
- package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
- package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -33
- package/index-2hq52jq3.js +0 -465
- package/index-6wwzs1bc.js +0 -7
- package/index-8pm30m73.js +0 -841
- package/index-kn1h7p1x.js +0 -560
- package/index-meh558jy.js +0 -65
- package/index-rwg2aa4f.js +0 -229
- package/templates/__scalar/__model__/__model__.abstract.md +0 -28
- package/templates/module/__model__.abstract.md +0 -28
- package/templates/service/__model__.abstract.md +0 -28
- package/workflow.command-nwpcdc8p.js +0 -107
|
@@ -2,26 +2,34 @@
|
|
|
2
2
|
import {
|
|
3
3
|
AsyncDefaultExportDetector,
|
|
4
4
|
resolveSsrPageEntriesForApp
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-9d9bgcx4.js";
|
|
6
6
|
import {
|
|
7
|
+
SOURCE_EXTS
|
|
8
|
+
} from "./index-khpfpcsd.js";
|
|
9
|
+
import {
|
|
10
|
+
loaderFor,
|
|
7
11
|
BarrelAnalyzer,
|
|
8
12
|
createBarrelImportsPlugin,
|
|
9
13
|
createTsconfigPackageResolver,
|
|
10
14
|
rewriteBarrelImports,
|
|
11
15
|
GraphClientEntryDiscovery,
|
|
12
16
|
transformUseClient,
|
|
17
|
+
bundleDefine,
|
|
13
18
|
ClientEntriesBundler,
|
|
14
19
|
VENDOR_SPECIFIERS,
|
|
15
20
|
RouteClientBuilder
|
|
16
|
-
} from "./index-
|
|
21
|
+
} from "./index-fgq75haa.js";
|
|
17
22
|
var __require = import.meta.require;
|
|
18
23
|
|
|
19
24
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
20
|
-
import
|
|
25
|
+
import path2 from "path";
|
|
21
26
|
|
|
22
27
|
// pkgs/@akanjs/devkit/artifact/routeSeedIndex.ts
|
|
23
28
|
import path from "path";
|
|
24
29
|
import { assertUniqueRoutePatterns, compareRouteSpecificity, parseRouteModuleKey } from "akanjs/common";
|
|
30
|
+
import {
|
|
31
|
+
ROUTE_SEED_INDEX_JSON
|
|
32
|
+
} from "akanjs/server/artifact/routeSeedIndexStore";
|
|
25
33
|
function computeRouteSeedIndex(pageEntries) {
|
|
26
34
|
const layoutsByPrefix = new Map;
|
|
27
35
|
const pagesBySegments = [];
|
|
@@ -29,9 +37,7 @@ function computeRouteSeedIndex(pageEntries) {
|
|
|
29
37
|
const parsed = parseRouteModuleKey(key);
|
|
30
38
|
const files = [path.resolve(moduleAbsPath), ...(seedAbsPaths ?? []).map((seed) => path.resolve(seed))];
|
|
31
39
|
if (parsed.kind === "layout" || parsed.kind === "overrides") {
|
|
32
|
-
|
|
33
|
-
const prev = layoutsByPrefix.get(prefix) ?? [];
|
|
34
|
-
layoutsByPrefix.set(prefix, [...prev, ...files]);
|
|
40
|
+
layoutsByPrefix.getOrInsert(parsed.routeSegments.join("/"), []).push(...files);
|
|
35
41
|
} else if (parsed.kind === "page") {
|
|
36
42
|
pagesBySegments.push({
|
|
37
43
|
key,
|
|
@@ -43,8 +49,7 @@ function computeRouteSeedIndex(pageEntries) {
|
|
|
43
49
|
}
|
|
44
50
|
}
|
|
45
51
|
assertUniqueRoutePatterns(pagesBySegments);
|
|
46
|
-
const
|
|
47
|
-
const globalLayoutFiles = rootLayouts;
|
|
52
|
+
const globalLayoutFiles = layoutsByPrefix.get("") ?? [];
|
|
48
53
|
const seedEntries = [];
|
|
49
54
|
for (const { pattern, segments, files, includeOwnLayout } of pagesBySegments) {
|
|
50
55
|
const layouts = [];
|
|
@@ -62,14 +67,10 @@ function computeRouteSeedIndex(pageEntries) {
|
|
|
62
67
|
seedEntries.sort((a, b) => compareRouteSpecificity(a.pattern, b.pattern));
|
|
63
68
|
return { entries: seedEntries, globalLayoutFiles };
|
|
64
69
|
}
|
|
65
|
-
var ROUTE_SEED_INDEX_JSON = "route-seed-index.json";
|
|
66
70
|
function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
67
71
|
const normalizedArtifactDir = path.resolve(artifactDir);
|
|
68
|
-
if (options.production)
|
|
69
|
-
return {
|
|
70
|
-
entries: index.entries.map((entry) => ({ routeId: entry.routeId }))
|
|
71
|
-
};
|
|
72
|
-
}
|
|
72
|
+
if (options.production)
|
|
73
|
+
return { entries: index.entries.map((entry) => ({ routeId: entry.routeId })) };
|
|
73
74
|
return {
|
|
74
75
|
entries: index.entries.map((entry) => ({
|
|
75
76
|
...entry,
|
|
@@ -91,7 +92,7 @@ function serializeArtifactPath(artifactPath, artifactDir) {
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
// pkgs/@akanjs/devkit/frontendBuild/routesManifestArtifactSerializer.ts
|
|
94
|
-
import
|
|
95
|
+
import { RoutesManifestStore } from "akanjs/server/artifact/routesManifestStore";
|
|
95
96
|
|
|
96
97
|
class RoutesManifestArtifactSerializer {
|
|
97
98
|
#manifest;
|
|
@@ -99,42 +100,17 @@ class RoutesManifestArtifactSerializer {
|
|
|
99
100
|
#production;
|
|
100
101
|
constructor(manifest, artifactDir, options = {}) {
|
|
101
102
|
this.#manifest = manifest;
|
|
102
|
-
this.#artifactDir =
|
|
103
|
+
this.#artifactDir = artifactDir;
|
|
103
104
|
this.#production = options.production ?? false;
|
|
104
105
|
}
|
|
105
106
|
static serialize(manifest, artifactDir, options = {}) {
|
|
106
107
|
return new RoutesManifestArtifactSerializer(manifest, artifactDir, options).serialize();
|
|
107
108
|
}
|
|
108
109
|
serialize() {
|
|
109
|
-
const serialized =
|
|
110
|
-
...this.#manifest,
|
|
111
|
-
knownEntries: this.#manifest.knownEntries.map((entry) => this.#serializeArtifactPath(entry))
|
|
112
|
-
};
|
|
110
|
+
const serialized = RoutesManifestStore.serialize(this.#manifest, this.#artifactDir);
|
|
113
111
|
if (this.#production)
|
|
114
112
|
delete serialized.knownEntries;
|
|
115
|
-
return
|
|
116
|
-
...serialized,
|
|
117
|
-
clientManifest: Object.fromEntries(Object.entries(this.#manifest.clientManifest).map(([key, row]) => [this.#serializeArtifactPath(key), row])),
|
|
118
|
-
ssrManifest: {
|
|
119
|
-
...this.#manifest.ssrManifest,
|
|
120
|
-
moduleMap: Object.fromEntries(Object.entries(this.#manifest.ssrManifest.moduleMap).map(([entryUrl, byName]) => [
|
|
121
|
-
entryUrl,
|
|
122
|
-
Object.fromEntries(Object.entries(byName).map(([name, entry]) => [
|
|
123
|
-
name,
|
|
124
|
-
{
|
|
125
|
-
...entry,
|
|
126
|
-
id: this.#serializeArtifactPath(entry.id),
|
|
127
|
-
chunks: entry.chunks.map((chunk) => this.#serializeArtifactPath(chunk))
|
|
128
|
-
}
|
|
129
|
-
]))
|
|
130
|
-
]))
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
#serializeArtifactPath(artifactPath) {
|
|
135
|
-
if (!path2.isAbsolute(artifactPath))
|
|
136
|
-
return artifactPath;
|
|
137
|
-
return path2.relative(this.#artifactDir, artifactPath).split(path2.sep).join("/");
|
|
113
|
+
return serialized;
|
|
138
114
|
}
|
|
139
115
|
}
|
|
140
116
|
|
|
@@ -164,27 +140,22 @@ class AllRoutesBuilder {
|
|
|
164
140
|
const seedIndex = computeRouteSeedIndex(pageEntries);
|
|
165
141
|
this.#app.verbose(`[build-all] discovered ${seedIndex.entries.length} routes`);
|
|
166
142
|
this.#discovery = await GraphClientEntryDiscovery.create(this.#app);
|
|
167
|
-
const allEntries =
|
|
168
|
-
const seen = new Set;
|
|
143
|
+
const allEntries = new Set;
|
|
169
144
|
for (const entry of seedIndex.entries) {
|
|
170
145
|
const seeds = Array.from(new Set([...seedIndex.globalLayoutFiles, ...entry.seeds]));
|
|
171
|
-
for (const discovered of await this.#discovery.discover(seeds))
|
|
172
|
-
|
|
173
|
-
continue;
|
|
174
|
-
seen.add(discovered);
|
|
175
|
-
allEntries.push(discovered);
|
|
176
|
-
}
|
|
146
|
+
for (const discovered of await this.#discovery.discover(seeds))
|
|
147
|
+
allEntries.add(discovered);
|
|
177
148
|
this.#routeIds.push(entry.routeId);
|
|
178
149
|
}
|
|
179
|
-
this.#app.verbose(`[build-all] ${allEntries.
|
|
180
|
-
const delta = await this.#buildEntries(allEntries);
|
|
150
|
+
this.#app.verbose(`[build-all] ${allEntries.size} client entries across ${this.#routeIds.length} routes`);
|
|
151
|
+
const delta = await this.#buildEntries([...allEntries]);
|
|
181
152
|
this.#mergeDelta(delta);
|
|
182
153
|
this.#merged.knownEntries = Array.from(this.#knownSet);
|
|
183
154
|
const manifest = {
|
|
184
155
|
routeIds: this.#routeIds,
|
|
185
156
|
...this.#merged
|
|
186
157
|
};
|
|
187
|
-
const manifestPath =
|
|
158
|
+
const manifestPath = path2.join(path2.resolve(this.#artifactDir), "routes-manifest.json");
|
|
188
159
|
await Bun.write(manifestPath, `${JSON.stringify(RoutesManifestArtifactSerializer.serialize(manifest, this.#artifactDir, {
|
|
189
160
|
production: this.#command === "build"
|
|
190
161
|
}), null, 2)}
|
|
@@ -216,18 +187,15 @@ class AllRoutesBuilder {
|
|
|
216
187
|
return delta;
|
|
217
188
|
}
|
|
218
189
|
#mergeDelta(delta) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
for (const [url, byName] of Object.entries(delta.ssrManifestDelta.moduleMap)) {
|
|
222
|
-
this.#merged.ssrManifest.moduleMap[url] = byName;
|
|
223
|
-
}
|
|
190
|
+
Object.assign(this.#merged.clientManifest, delta.manifestDelta);
|
|
191
|
+
Object.assign(this.#merged.ssrManifest.moduleMap, delta.ssrManifestDelta.moduleMap);
|
|
224
192
|
for (const abs of delta.newEntries)
|
|
225
193
|
this.#knownSet.add(abs);
|
|
226
194
|
}
|
|
227
195
|
}
|
|
228
196
|
|
|
229
197
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
230
|
-
import
|
|
198
|
+
import path4 from "path";
|
|
231
199
|
import { Logger } from "akanjs/common";
|
|
232
200
|
import { compile } from "tailwindcss";
|
|
233
201
|
|
|
@@ -298,7 +266,7 @@ class CssCandidateCache {
|
|
|
298
266
|
}
|
|
299
267
|
|
|
300
268
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
301
|
-
import
|
|
269
|
+
import path3 from "path";
|
|
302
270
|
var CSS_IMPORT_EXTS = ["", ".css", "/styles.css", "/index.css"];
|
|
303
271
|
|
|
304
272
|
class CssImportResolver {
|
|
@@ -317,8 +285,8 @@ class CssImportResolver {
|
|
|
317
285
|
async resolve(id, fromBase) {
|
|
318
286
|
for (const resolve of [
|
|
319
287
|
() => this.#resolveWithTsconfig(id),
|
|
320
|
-
() => this.#
|
|
321
|
-
() => this.#
|
|
288
|
+
() => this.#resolveCssWith(fromBase, (base) => Bun.resolveSync(id, base)),
|
|
289
|
+
() => this.#resolveCssWith(fromBase, (base) => __require.resolve(id, { paths: [base] })),
|
|
322
290
|
() => this.#resolvePackageStyle(id, fromBase)
|
|
323
291
|
]) {
|
|
324
292
|
const resolved = await resolve();
|
|
@@ -327,20 +295,10 @@ class CssImportResolver {
|
|
|
327
295
|
}
|
|
328
296
|
return null;
|
|
329
297
|
}
|
|
330
|
-
#
|
|
331
|
-
for (const base of this.#resolutionBases(fromBase)) {
|
|
332
|
-
try {
|
|
333
|
-
const resolved = Bun.resolveSync(id, base);
|
|
334
|
-
if (CssImportResolver.isCssFile(resolved))
|
|
335
|
-
return resolved;
|
|
336
|
-
} catch {}
|
|
337
|
-
}
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
340
|
-
#resolveWithRequire(id, fromBase) {
|
|
298
|
+
#resolveCssWith(fromBase, resolveFrom) {
|
|
341
299
|
for (const base of this.#resolutionBases(fromBase)) {
|
|
342
300
|
try {
|
|
343
|
-
const resolved =
|
|
301
|
+
const resolved = resolveFrom(base);
|
|
344
302
|
if (CssImportResolver.isCssFile(resolved))
|
|
345
303
|
return resolved;
|
|
346
304
|
} catch {}
|
|
@@ -351,7 +309,7 @@ class CssImportResolver {
|
|
|
351
309
|
const exact = this.#paths[id];
|
|
352
310
|
if (exact) {
|
|
353
311
|
for (const repl of exact) {
|
|
354
|
-
const resolved = await this.#firstExisting(
|
|
312
|
+
const resolved = await this.#firstExisting(path3.resolve(this.#workspaceRoot, repl));
|
|
355
313
|
if (resolved)
|
|
356
314
|
return resolved;
|
|
357
315
|
}
|
|
@@ -362,7 +320,7 @@ class CssImportResolver {
|
|
|
362
320
|
const suffix = id.slice(prefix.length);
|
|
363
321
|
for (const repl of replacements) {
|
|
364
322
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
365
|
-
const resolved = await this.#firstExisting(
|
|
323
|
+
const resolved = await this.#firstExisting(path3.resolve(this.#workspaceRoot, replPath + suffix));
|
|
366
324
|
if (resolved)
|
|
367
325
|
return resolved;
|
|
368
326
|
}
|
|
@@ -392,34 +350,34 @@ class CssImportResolver {
|
|
|
392
350
|
try {
|
|
393
351
|
if (!await Bun.file(pkgPath).exists())
|
|
394
352
|
return null;
|
|
395
|
-
const pkgDir =
|
|
353
|
+
const pkgDir = path3.dirname(pkgPath);
|
|
396
354
|
const pkg = await Bun.file(pkgPath).json();
|
|
397
355
|
const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
|
|
398
356
|
const exportValue = pkg.exports?.[subpath];
|
|
399
357
|
const exportedEntry = typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default;
|
|
400
358
|
if (exportedEntry)
|
|
401
|
-
return await this.#firstExisting(
|
|
359
|
+
return await this.#firstExisting(path3.resolve(pkgDir, exportedEntry));
|
|
402
360
|
if (subpath !== ".")
|
|
403
|
-
return await this.#firstExisting(
|
|
404
|
-
return await this.#firstExisting(
|
|
361
|
+
return await this.#firstExisting(path3.resolve(pkgDir, subpath));
|
|
362
|
+
return await this.#firstExisting(path3.resolve(pkgDir, pkg.exports?.["."]?.style || pkg.style || "index.css"));
|
|
405
363
|
} catch {
|
|
406
364
|
return null;
|
|
407
365
|
}
|
|
408
366
|
}
|
|
409
367
|
#resolutionBases(fromBase) {
|
|
410
|
-
return [fromBase, this.#workspaceRoot,
|
|
368
|
+
return [fromBase, this.#workspaceRoot, path3.dirname(Bun.main), path3.resolve(path3.dirname(Bun.main), "../..")];
|
|
411
369
|
}
|
|
412
370
|
#packageJsonCandidates(pkgName) {
|
|
413
371
|
return [
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
372
|
+
path3.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
|
|
373
|
+
path3.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
|
|
374
|
+
path3.join(path3.dirname(Bun.main), "node_modules", pkgName, "package.json"),
|
|
375
|
+
path3.join(path3.dirname(Bun.main), "../../", pkgName, "package.json")
|
|
418
376
|
];
|
|
419
377
|
}
|
|
420
378
|
async#firstExisting(basePath) {
|
|
421
379
|
for (const suffix of CSS_IMPORT_EXTS) {
|
|
422
|
-
const candidate = `${basePath}${suffix}
|
|
380
|
+
const candidate = path3.normalize(`${basePath}${suffix}`);
|
|
423
381
|
if (await Bun.file(candidate).exists())
|
|
424
382
|
return candidate;
|
|
425
383
|
}
|
|
@@ -432,12 +390,11 @@ class CssImportResolver {
|
|
|
432
390
|
return parts[0] ?? null;
|
|
433
391
|
}
|
|
434
392
|
static isCssFile(filePath) {
|
|
435
|
-
return
|
|
393
|
+
return path3.extname(filePath) === ".css";
|
|
436
394
|
}
|
|
437
395
|
}
|
|
438
396
|
|
|
439
397
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
440
|
-
var SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
441
398
|
var NON_SOURCE_EXT_RE = /\.(json|svg|png|jpe?g|webp|gif|avif|ico|woff2?|ttf|otf|mp3|mp4|wav)$/i;
|
|
442
399
|
var NODE_MODULES_RE = /[\\/]node_modules[\\/]/;
|
|
443
400
|
var AKANJS_NODE_MODULE_RE = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
@@ -451,7 +408,7 @@ class CssCompiler {
|
|
|
451
408
|
this.#app = app;
|
|
452
409
|
}
|
|
453
410
|
get #candidateCachePath() {
|
|
454
|
-
return
|
|
411
|
+
return path4.join(this.#app.cwdPath, ".akan/cache/cssCandidates.json");
|
|
455
412
|
}
|
|
456
413
|
#cssText = null;
|
|
457
414
|
#cssTextByBasePath = null;
|
|
@@ -481,7 +438,7 @@ class CssCompiler {
|
|
|
481
438
|
return filePath;
|
|
482
439
|
}
|
|
483
440
|
for (const ext of SOURCE_EXTS) {
|
|
484
|
-
const filePath =
|
|
441
|
+
const filePath = path4.join(absPathNoExt, `index${ext}`);
|
|
485
442
|
if (await this.#fileExists(filePath))
|
|
486
443
|
return filePath;
|
|
487
444
|
}
|
|
@@ -511,42 +468,33 @@ class CssCompiler {
|
|
|
511
468
|
const pageKeys = await this.#app.getPageKeys({ refresh });
|
|
512
469
|
const basePaths = [...akanConfig.basePaths];
|
|
513
470
|
const rootPageKeys = pageKeys.filter((pageKey) => getPageKeyBasePath(pageKey, basePaths) === null);
|
|
471
|
+
const compileBasePath = async (basePath, basePathPageKeys, label = basePath) => {
|
|
472
|
+
if (basePathPageKeys.length === 0)
|
|
473
|
+
return [basePath, ""];
|
|
474
|
+
const started = Date.now();
|
|
475
|
+
const { cssPaths, sourcePaths } = await this.discoverCssAndSources({ refresh, pageKeys: basePathPageKeys });
|
|
476
|
+
const { css, imported } = await this.#compileWithImports(cssPaths, sourcePaths);
|
|
477
|
+
this.importedStylesheetsByBasePath[basePath] = imported;
|
|
478
|
+
this.#logger.verbose(`css base=${label} paths=${cssPaths.length} sources=${sourcePaths.length} in ${Date.now() - started}ms`);
|
|
479
|
+
return [basePath, css];
|
|
480
|
+
};
|
|
514
481
|
const cssEntries = await Promise.all([
|
|
515
|
-
(
|
|
516
|
-
|
|
517
|
-
return ["", ""];
|
|
518
|
-
const started = Date.now();
|
|
519
|
-
const { cssPaths, sourcePaths } = await this.discoverCssAndSources({ refresh, pageKeys: rootPageKeys });
|
|
520
|
-
const { css, imported } = await this.#compileWithImports(cssPaths, sourcePaths);
|
|
521
|
-
this.importedStylesheetsByBasePath[""] = imported;
|
|
522
|
-
this.#logger.verbose(`css base=root paths=${cssPaths.length} sources=${sourcePaths.length} in ${Date.now() - started}ms`);
|
|
523
|
-
return ["", css];
|
|
524
|
-
})(),
|
|
525
|
-
...basePaths.map(async (basePath) => {
|
|
526
|
-
const basePathPageKeys = pageKeys.filter((pageKey) => getPageKeyBasePath(pageKey, basePaths) === basePath);
|
|
527
|
-
if (basePathPageKeys.length === 0)
|
|
528
|
-
return [basePath, ""];
|
|
529
|
-
const started = Date.now();
|
|
530
|
-
const { cssPaths, sourcePaths } = await this.discoverCssAndSources({ refresh, pageKeys: basePathPageKeys });
|
|
531
|
-
const { css, imported } = await this.#compileWithImports(cssPaths, sourcePaths);
|
|
532
|
-
this.importedStylesheetsByBasePath[basePath] = imported;
|
|
533
|
-
this.#logger.verbose(`css base=${basePath} paths=${cssPaths.length} sources=${sourcePaths.length} in ${Date.now() - started}ms`);
|
|
534
|
-
return [basePath, css];
|
|
535
|
-
})
|
|
482
|
+
compileBasePath("", rootPageKeys, "root"),
|
|
483
|
+
...basePaths.map((basePath) => compileBasePath(basePath, pageKeys.filter((pageKey) => getPageKeyBasePath(pageKey, basePaths) === basePath)))
|
|
536
484
|
]);
|
|
537
485
|
this.#cssTextByBasePath = Object.fromEntries(cssEntries);
|
|
538
486
|
await this.#warnUnreachableStylesheets();
|
|
539
487
|
return this.#cssTextByBasePath;
|
|
540
488
|
}
|
|
541
489
|
async#warnUnreachableStylesheets() {
|
|
542
|
-
const pageDir =
|
|
490
|
+
const pageDir = path4.join(this.#app.cwdPath, "page");
|
|
543
491
|
const glob = new Bun.Glob("**/*.css");
|
|
544
492
|
for await (const cssPath of glob.scan({ cwd: pageDir, absolute: true })) {
|
|
545
|
-
if (cssPath.includes(`${
|
|
493
|
+
if (cssPath.includes(`${path4.sep}(libs)${path4.sep}`))
|
|
546
494
|
continue;
|
|
547
495
|
if (this.#discoveredCssPaths.has(cssPath))
|
|
548
496
|
continue;
|
|
549
|
-
this.#logger.warn(`css ${
|
|
497
|
+
this.#logger.warn(`css ${path4.relative(this.#app.cwdPath, cssPath)} is imported by no route and never compiled`);
|
|
550
498
|
}
|
|
551
499
|
}
|
|
552
500
|
async discoverCss({ refresh } = {}) {
|
|
@@ -558,7 +506,7 @@ class CssCompiler {
|
|
|
558
506
|
pageKeys
|
|
559
507
|
} = {}) {
|
|
560
508
|
pageKeys ??= await this.#app.getPageKeys({ refresh });
|
|
561
|
-
const seeds = pageKeys.map((key) =>
|
|
509
|
+
const seeds = pageKeys.map((key) => path4.resolve(this.#app.cwdPath, "page", key));
|
|
562
510
|
const cssFiles = new Set;
|
|
563
511
|
const sourceFiles = new Set;
|
|
564
512
|
const queue = [...seeds];
|
|
@@ -590,7 +538,7 @@ class CssCompiler {
|
|
|
590
538
|
} catch {
|
|
591
539
|
continue;
|
|
592
540
|
}
|
|
593
|
-
const importerDir =
|
|
541
|
+
const importerDir = path4.dirname(filePath);
|
|
594
542
|
for (const imp of imports) {
|
|
595
543
|
const spec = imp.path;
|
|
596
544
|
if (!spec)
|
|
@@ -615,18 +563,18 @@ class CssCompiler {
|
|
|
615
563
|
return { cssPaths, sourcePaths: [...sourceFiles] };
|
|
616
564
|
}
|
|
617
565
|
async#libTokenStylesheets(sourceFiles) {
|
|
618
|
-
const libsRoot =
|
|
566
|
+
const libsRoot = path4.join(this.#app.workspace.workspaceRoot, "libs");
|
|
619
567
|
const libNames = new Set;
|
|
620
568
|
for (const filePath of sourceFiles) {
|
|
621
|
-
const relPath =
|
|
622
|
-
if (relPath.startsWith("..") ||
|
|
569
|
+
const relPath = path4.relative(libsRoot, filePath);
|
|
570
|
+
if (relPath.startsWith("..") || path4.isAbsolute(relPath))
|
|
623
571
|
continue;
|
|
624
|
-
const [libName] = relPath.split(
|
|
572
|
+
const [libName] = relPath.split(path4.sep);
|
|
625
573
|
if (libName)
|
|
626
574
|
libNames.add(libName);
|
|
627
575
|
}
|
|
628
576
|
const tokenPaths = await Promise.all([...libNames].sort().map(async (libName) => {
|
|
629
|
-
const tokensPath =
|
|
577
|
+
const tokensPath = path4.join(libsRoot, libName, "ui/tokens.css");
|
|
630
578
|
return await this.#fileExists(tokensPath) ? tokensPath : null;
|
|
631
579
|
}));
|
|
632
580
|
return tokenPaths.filter((tokensPath) => !!tokensPath);
|
|
@@ -641,7 +589,7 @@ class CssCompiler {
|
|
|
641
589
|
const compileStarted = Date.now();
|
|
642
590
|
const compilers = await Promise.all(cssPaths.map(async (cssPath) => {
|
|
643
591
|
const css = await Bun.file(cssPath).text();
|
|
644
|
-
const base =
|
|
592
|
+
const base = path4.dirname(cssPath);
|
|
645
593
|
const imported = new Map;
|
|
646
594
|
const compiler = await compile(css, {
|
|
647
595
|
base,
|
|
@@ -652,8 +600,6 @@ class CssCompiler {
|
|
|
652
600
|
}));
|
|
653
601
|
const sourceDirs = new Set;
|
|
654
602
|
for (const entry of compilers) {
|
|
655
|
-
if (!entry)
|
|
656
|
-
continue;
|
|
657
603
|
for (const s of entry.compiler.sources)
|
|
658
604
|
sourceDirs.add(s.base);
|
|
659
605
|
}
|
|
@@ -663,8 +609,6 @@ class CssCompiler {
|
|
|
663
609
|
const parts = [];
|
|
664
610
|
const imported = [];
|
|
665
611
|
for (const entry of compilers) {
|
|
666
|
-
if (!entry)
|
|
667
|
-
continue;
|
|
668
612
|
const part = entry.compiler.build(candidates);
|
|
669
613
|
parts.push(part);
|
|
670
614
|
for (const [cssPath, content] of entry.imported) {
|
|
@@ -685,31 +629,25 @@ class CssCompiler {
|
|
|
685
629
|
const content = await Bun.file(p).text();
|
|
686
630
|
imported?.set(p, content);
|
|
687
631
|
this.#logger.verbose(`css import "${id}" from ${fromBase} -> ${p} (${content.length} bytes)`);
|
|
688
|
-
return { path: p, base:
|
|
632
|
+
return { path: p, base: path4.dirname(p), content };
|
|
689
633
|
}
|
|
690
634
|
async#resolveCssImport(id, fromBase) {
|
|
691
635
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
692
|
-
const filePath =
|
|
636
|
+
const filePath = path4.resolve(fromBase, id);
|
|
693
637
|
if (await this.#fileExists(filePath))
|
|
694
638
|
return filePath;
|
|
695
639
|
throw new Error(`[css] failed to resolve stylesheet import "${id}" from ${fromBase} (no file at ${filePath})`);
|
|
696
640
|
}
|
|
697
|
-
|
|
698
|
-
const resolved = await
|
|
641
|
+
this.#cssImportResolver ??= await CssImportResolver.create(this.#app);
|
|
642
|
+
const resolved = await this.#cssImportResolver.resolve(id, fromBase);
|
|
699
643
|
if (resolved)
|
|
700
644
|
return resolved;
|
|
701
645
|
throw new Error(`[css] failed to resolve stylesheet import "${id}" from ${fromBase}`);
|
|
702
646
|
}
|
|
703
|
-
async#getCssImportResolver() {
|
|
704
|
-
if (this.#cssImportResolver)
|
|
705
|
-
return this.#cssImportResolver;
|
|
706
|
-
this.#cssImportResolver = await CssImportResolver.create(this.#app);
|
|
707
|
-
return this.#cssImportResolver;
|
|
708
|
-
}
|
|
709
647
|
async#loadModule(id, fromBase) {
|
|
710
648
|
const p = __require.resolve(id, { paths: [fromBase] });
|
|
711
649
|
const mod = await import(p);
|
|
712
|
-
return { path: p, base:
|
|
650
|
+
return { path: p, base: path4.dirname(p), module: mod.default ?? mod };
|
|
713
651
|
}
|
|
714
652
|
#resolveSourceImport(id, fromBase, resolvePackage) {
|
|
715
653
|
const cacheKey = `${fromBase}\x00${id}`;
|
|
@@ -722,7 +660,7 @@ class CssCompiler {
|
|
|
722
660
|
}
|
|
723
661
|
async#resolveSourceImportUncached(id, fromBase, resolvePackage) {
|
|
724
662
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
725
|
-
const abs = id.startsWith("/") ? id :
|
|
663
|
+
const abs = id.startsWith("/") ? id : path4.resolve(fromBase, id);
|
|
726
664
|
return this.#resolveSourceFileCandidate(abs);
|
|
727
665
|
}
|
|
728
666
|
const pkg = await resolvePackage(id);
|
|
@@ -773,7 +711,7 @@ function resolveSourceWithRequire(id, fromBase) {
|
|
|
773
711
|
}
|
|
774
712
|
}
|
|
775
713
|
function isSourceFile(filePath) {
|
|
776
|
-
return SOURCE_EXTS.
|
|
714
|
+
return SOURCE_EXTS.has(path4.extname(filePath));
|
|
777
715
|
}
|
|
778
716
|
function isIgnoredNodeModuleSource(filePath) {
|
|
779
717
|
return NODE_MODULES_RE.test(filePath) && !AKANJS_NODE_MODULE_RE.test(filePath);
|
|
@@ -783,17 +721,17 @@ function declaredCustomProperties(css) {
|
|
|
783
721
|
return [...new Set([...withoutThemeBlocks.matchAll(/(?:^|[\s;{])(--[\w-]+)\s*:/g)].map(([, name]) => name))].filter((name) => !!name);
|
|
784
722
|
}
|
|
785
723
|
function getPageKeyBasePath(pageKey, basePaths) {
|
|
786
|
-
const normalized = pageKey.split(
|
|
724
|
+
const normalized = pageKey.split(path4.sep).join("/").replace(/^\.\//, "");
|
|
787
725
|
const segments = normalized.split("/");
|
|
788
726
|
const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
|
|
789
727
|
return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
|
|
790
728
|
}
|
|
791
729
|
|
|
792
730
|
// pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
|
|
793
|
-
import
|
|
731
|
+
import path7 from "path";
|
|
794
732
|
|
|
795
733
|
// pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
|
|
796
|
-
import
|
|
734
|
+
import path5 from "path";
|
|
797
735
|
var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
|
|
798
736
|
var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
|
|
799
737
|
var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
|
|
@@ -835,20 +773,18 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
835
773
|
const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
|
|
836
774
|
if (!replPath)
|
|
837
775
|
continue;
|
|
838
|
-
const candidate =
|
|
776
|
+
const candidate = path5.resolve(workspaceRoot, replPath + suffix);
|
|
839
777
|
const hit = await firstExisting(candidate);
|
|
840
778
|
if (hit)
|
|
841
779
|
return hit;
|
|
842
780
|
}
|
|
843
781
|
}
|
|
844
782
|
for (const { pkg, entryFile } of rootEntries) {
|
|
845
|
-
if (
|
|
846
|
-
continue;
|
|
847
|
-
if (spec === pkg)
|
|
783
|
+
if (!spec.startsWith(`${pkg}/`))
|
|
848
784
|
continue;
|
|
849
785
|
const suffix = spec.slice(pkg.length + 1);
|
|
850
|
-
const pkgDir =
|
|
851
|
-
const candidate =
|
|
786
|
+
const pkgDir = path5.dirname(path5.resolve(workspaceRoot, entryFile));
|
|
787
|
+
const candidate = path5.join(pkgDir, suffix);
|
|
852
788
|
const hit = await firstExisting(candidate);
|
|
853
789
|
if (hit)
|
|
854
790
|
return hit;
|
|
@@ -876,15 +812,10 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
876
812
|
if (spec.startsWith(prefix))
|
|
877
813
|
return { path: spec, external: true };
|
|
878
814
|
}
|
|
879
|
-
|
|
880
|
-
if (!spec.startsWith(prefix))
|
|
881
|
-
continue;
|
|
882
|
-
const resolved = await resolveWorkspaceSubpath(spec);
|
|
883
|
-
if (resolved)
|
|
884
|
-
return { path: resolved };
|
|
815
|
+
if (!includePrefixes.some((prefix) => spec.startsWith(prefix)))
|
|
885
816
|
return;
|
|
886
|
-
|
|
887
|
-
return;
|
|
817
|
+
const resolved = await resolveWorkspaceSubpath(spec);
|
|
818
|
+
return resolved ? { path: resolved } : undefined;
|
|
888
819
|
});
|
|
889
820
|
}
|
|
890
821
|
};
|
|
@@ -898,7 +829,7 @@ async function firstExisting(basePath) {
|
|
|
898
829
|
return candidate;
|
|
899
830
|
}
|
|
900
831
|
for (const ext of CANDIDATE_EXTS) {
|
|
901
|
-
const candidate =
|
|
832
|
+
const candidate = path5.join(basePath, `index${ext}`);
|
|
902
833
|
if (await Bun.file(candidate).exists())
|
|
903
834
|
return candidate;
|
|
904
835
|
}
|
|
@@ -930,18 +861,9 @@ function createUseClientBundlePlugin(options = {}) {
|
|
|
930
861
|
}
|
|
931
862
|
};
|
|
932
863
|
}
|
|
933
|
-
function loaderFor(absPath) {
|
|
934
|
-
if (absPath.endsWith(".tsx"))
|
|
935
|
-
return "tsx";
|
|
936
|
-
if (absPath.endsWith(".jsx"))
|
|
937
|
-
return "jsx";
|
|
938
|
-
if (absPath.endsWith(".ts"))
|
|
939
|
-
return "ts";
|
|
940
|
-
return "js";
|
|
941
|
-
}
|
|
942
864
|
|
|
943
865
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
944
|
-
import
|
|
866
|
+
import path6 from "path";
|
|
945
867
|
class PagesEntrySourceGenerator {
|
|
946
868
|
#pageEntries;
|
|
947
869
|
constructor(pageEntries) {
|
|
@@ -982,7 +904,7 @@ ${entries.join(`
|
|
|
982
904
|
`;
|
|
983
905
|
}
|
|
984
906
|
static #toImportSpecifier(moduleAbsPath) {
|
|
985
|
-
return
|
|
907
|
+
return path6.resolve(moduleAbsPath).split(path6.sep).join("/");
|
|
986
908
|
}
|
|
987
909
|
}
|
|
988
910
|
|
|
@@ -1016,7 +938,7 @@ class PagesBundleBuilder {
|
|
|
1016
938
|
chunk: "chunks/[name]-[hash].[ext]",
|
|
1017
939
|
asset: "assets/[name]-[hash].[ext]"
|
|
1018
940
|
},
|
|
1019
|
-
define: this.#
|
|
941
|
+
define: bundleDefine(this.#app, this.#command, "ssr"),
|
|
1020
942
|
plugins: [
|
|
1021
943
|
PagesBundleBuilder.createPagesEntryPlugin(entrySource),
|
|
1022
944
|
PagesBundleBuilder.createCssStubPlugin(),
|
|
@@ -1035,11 +957,11 @@ class PagesBundleBuilder {
|
|
|
1035
957
|
const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
|
|
1036
958
|
if (!entryArtifact)
|
|
1037
959
|
throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
|
|
1038
|
-
const bundlePath =
|
|
960
|
+
const bundlePath = path7.resolve(entryArtifact.path);
|
|
1039
961
|
const buildId = Date.now();
|
|
1040
962
|
const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
|
|
1041
963
|
const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
|
|
1042
|
-
this.#app.verbose(`[PagesBundleBuilder] ${
|
|
964
|
+
this.#app.verbose(`[PagesBundleBuilder] ${path7.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`);
|
|
1043
965
|
return {
|
|
1044
966
|
bundlePath,
|
|
1045
967
|
buildId,
|
|
@@ -1056,14 +978,6 @@ class PagesBundleBuilder {
|
|
|
1056
978
|
get #splitting() {
|
|
1057
979
|
return process.env.AKAN_SERVER_PAGES_SPLITTING === "1";
|
|
1058
980
|
}
|
|
1059
|
-
#define() {
|
|
1060
|
-
const nodeEnv = this.#command === "build" ? "production" : "development";
|
|
1061
|
-
return {
|
|
1062
|
-
"process.env.NODE_ENV": JSON.stringify(nodeEnv),
|
|
1063
|
-
"process.env.AKAN_PUBLIC_RENDER_ENV": JSON.stringify("ssr"),
|
|
1064
|
-
...Object.fromEntries(Object.entries(this.#app.getPublicEnv()).map(([key, value]) => [`process.env.${key}`, JSON.stringify(value)]))
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
981
|
static createPagesEntryPlugin(source) {
|
|
1068
982
|
return {
|
|
1069
983
|
name: "akan-pages-entry",
|
|
@@ -1099,7 +1013,7 @@ class PagesBundleBuilder {
|
|
|
1099
1013
|
const transformed = PagesBundleBuilder.transformServerUseClientFetchSource(source);
|
|
1100
1014
|
if (transformed === source)
|
|
1101
1015
|
return;
|
|
1102
|
-
return { contents: transformed, loader:
|
|
1016
|
+
return { contents: transformed, loader: loaderFor(args.path) };
|
|
1103
1017
|
});
|
|
1104
1018
|
}
|
|
1105
1019
|
};
|
|
@@ -1110,19 +1024,10 @@ class PagesBundleBuilder {
|
|
|
1110
1024
|
return source.replace(/import\s+\{\s*getSerializedSignal\s*\}\s+from\s+["']\.\/sig["']\s+with\s+\{\s*type\s*:\s*["']macro["']\s*\};/, `import { fetch as serverFetch } from "./sig";`).replace(/const\s+fetchProto\s*=\s*FetchClient\.build<[^;]+;/, "const fetchProto = FetchClient.build<typeof signal>(cnst, serverFetch.serializedSignal, { Err: pageProto.Err, base: serverFetch });");
|
|
1111
1025
|
}
|
|
1112
1026
|
}
|
|
1113
|
-
function loaderFor2(absPath) {
|
|
1114
|
-
if (absPath.endsWith(".tsx"))
|
|
1115
|
-
return "tsx";
|
|
1116
|
-
if (absPath.endsWith(".jsx"))
|
|
1117
|
-
return "jsx";
|
|
1118
|
-
if (absPath.endsWith(".ts"))
|
|
1119
|
-
return "ts";
|
|
1120
|
-
return "js";
|
|
1121
|
-
}
|
|
1122
1027
|
|
|
1123
1028
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
1124
1029
|
import { mkdir, rm, unlink } from "fs/promises";
|
|
1125
|
-
import
|
|
1030
|
+
import path8 from "path";
|
|
1126
1031
|
class CsrArtifactBuilder {
|
|
1127
1032
|
#app;
|
|
1128
1033
|
#command;
|
|
@@ -1158,7 +1063,7 @@ class CsrArtifactBuilder {
|
|
|
1158
1063
|
splitting: false,
|
|
1159
1064
|
minify: true,
|
|
1160
1065
|
env: "AKAN_PUBLIC_*",
|
|
1161
|
-
define: this.#
|
|
1066
|
+
define: bundleDefine(this.#app, this.#command, "csr"),
|
|
1162
1067
|
optimizeImports: akanConfig.optimizeImports,
|
|
1163
1068
|
plugins: [PagesBundleBuilder.createCssStubPlugin()]
|
|
1164
1069
|
});
|
|
@@ -1185,28 +1090,20 @@ ${logs}` : ""}`);
|
|
|
1185
1090
|
return `${basePath || "index"}.csr.tsx`;
|
|
1186
1091
|
}
|
|
1187
1092
|
static basePathOfHtml(htmlPath) {
|
|
1188
|
-
const name =
|
|
1093
|
+
const name = path8.basename(htmlPath, ".html");
|
|
1189
1094
|
return name === "index" ? "" : name;
|
|
1190
1095
|
}
|
|
1191
1096
|
get #outputDir() {
|
|
1192
|
-
return
|
|
1097
|
+
return path8.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
|
|
1193
1098
|
}
|
|
1194
1099
|
get #generatedDir() {
|
|
1195
|
-
return
|
|
1100
|
+
return path8.join(this.#app.cwdPath, ".akan/generated/csr");
|
|
1196
1101
|
}
|
|
1197
1102
|
get #artifactDir() {
|
|
1198
|
-
return
|
|
1103
|
+
return path8.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
|
|
1199
1104
|
}
|
|
1200
1105
|
#generatedPath(filename) {
|
|
1201
|
-
return
|
|
1202
|
-
}
|
|
1203
|
-
#define() {
|
|
1204
|
-
const nodeEnv = this.#command === "build" ? "production" : "development";
|
|
1205
|
-
return {
|
|
1206
|
-
"process.env.NODE_ENV": JSON.stringify(nodeEnv),
|
|
1207
|
-
"process.env.AKAN_PUBLIC_RENDER_ENV": JSON.stringify("csr"),
|
|
1208
|
-
...Object.fromEntries(Object.entries(this.#app.getPublicEnv()).map(([key, value]) => [`process.env.${key}`, JSON.stringify(value)]))
|
|
1209
|
-
};
|
|
1106
|
+
return path8.join(this.#generatedDir, filename);
|
|
1210
1107
|
}
|
|
1211
1108
|
async#createEntryFile(basePath, pageEntries) {
|
|
1212
1109
|
return [
|
|
@@ -1237,7 +1134,7 @@ void bootCsr(pages);
|
|
|
1237
1134
|
];
|
|
1238
1135
|
}
|
|
1239
1136
|
async#loadCssAssets() {
|
|
1240
|
-
const artifactFile = Bun.file(
|
|
1137
|
+
const artifactFile = Bun.file(path8.join(this.#artifactDir, "base-artifact.json"));
|
|
1241
1138
|
if (!await artifactFile.exists())
|
|
1242
1139
|
return {};
|
|
1243
1140
|
const artifact = await artifactFile.json();
|
|
@@ -1245,14 +1142,14 @@ void bootCsr(pages);
|
|
|
1245
1142
|
}
|
|
1246
1143
|
async#inlineCsrArtifacts(cssAssets) {
|
|
1247
1144
|
const jsFiles = new Set;
|
|
1248
|
-
for (const htmlPath of await this.#
|
|
1145
|
+
for (const htmlPath of await this.#listOutputFiles((filePath) => filePath.endsWith(".html"))) {
|
|
1249
1146
|
const htmlFile = Bun.file(htmlPath);
|
|
1250
1147
|
if (!await htmlFile.exists())
|
|
1251
1148
|
continue;
|
|
1252
1149
|
const basePath = CsrArtifactBuilder.basePathOfHtml(htmlPath);
|
|
1253
1150
|
const cssAsset = cssAssets[basePath];
|
|
1254
1151
|
if (!cssAsset) {
|
|
1255
|
-
this.#app.logger.warn(`[csr-build] base-artifact.json has no compiled stylesheet for ${basePath || "root"}; ${
|
|
1152
|
+
this.#app.logger.warn(`[csr-build] base-artifact.json has no compiled stylesheet for ${basePath || "root"}; ${path8.basename(htmlPath)} ships without CSS`);
|
|
1256
1153
|
}
|
|
1257
1154
|
const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAsset);
|
|
1258
1155
|
for (const filePath of inlined.jsFiles)
|
|
@@ -1273,7 +1170,7 @@ ${remainingAssets.join(`
|
|
|
1273
1170
|
async#inlineHtmlAssets(html, htmlPath, cssAsset) {
|
|
1274
1171
|
let next = html;
|
|
1275
1172
|
if (cssAsset) {
|
|
1276
|
-
const css = await Bun.file(
|
|
1173
|
+
const css = await Bun.file(path8.join(this.#artifactDir, cssAsset.cssRelPath)).text();
|
|
1277
1174
|
next = CsrArtifactBuilder.injectBeforeHeadEnd(next, CsrArtifactBuilder.createInlineStyle(css));
|
|
1278
1175
|
}
|
|
1279
1176
|
const jsFiles = [];
|
|
@@ -1284,9 +1181,6 @@ ${remainingAssets.join(`
|
|
|
1284
1181
|
});
|
|
1285
1182
|
return { html: next, jsFiles };
|
|
1286
1183
|
}
|
|
1287
|
-
async#htmlOutputPaths() {
|
|
1288
|
-
return await this.#listOutputFiles((filePath) => filePath.endsWith(".html"));
|
|
1289
|
-
}
|
|
1290
1184
|
async#listOutputFiles(predicate) {
|
|
1291
1185
|
const glob = new Bun.Glob("**/*");
|
|
1292
1186
|
const files = [];
|
|
@@ -1346,13 +1240,13 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
|
1346
1240
|
throw new Error(`[csr-build] cannot inline external script: ${src}`);
|
|
1347
1241
|
}
|
|
1348
1242
|
const normalized = src.startsWith("/") ? src.slice(1) : src;
|
|
1349
|
-
return
|
|
1243
|
+
return path8.resolve(path8.dirname(htmlPath), normalized);
|
|
1350
1244
|
}
|
|
1351
1245
|
}
|
|
1352
1246
|
|
|
1353
1247
|
// pkgs/@akanjs/devkit/frontendBuild/fontOptimizer.ts
|
|
1354
1248
|
import { mkdir as mkdir2, stat as stat2 } from "fs/promises";
|
|
1355
|
-
import
|
|
1249
|
+
import path9 from "path";
|
|
1356
1250
|
import ts from "typescript";
|
|
1357
1251
|
var FONT_URL_PREFIX = "/_akan/fonts";
|
|
1358
1252
|
var DEFAULT_FONT_SUBSETS = ["latin"];
|
|
@@ -1369,7 +1263,7 @@ class FontOptimizer {
|
|
|
1369
1263
|
constructor(app, command = "start") {
|
|
1370
1264
|
this.#app = app;
|
|
1371
1265
|
this.#command = command;
|
|
1372
|
-
this.#artifactRoot =
|
|
1266
|
+
this.#artifactRoot = path9.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
|
|
1373
1267
|
}
|
|
1374
1268
|
async optimize() {
|
|
1375
1269
|
const fonts = await this.discoverFonts();
|
|
@@ -1394,7 +1288,7 @@ class FontOptimizer {
|
|
|
1394
1288
|
return result;
|
|
1395
1289
|
}
|
|
1396
1290
|
get #cachePath() {
|
|
1397
|
-
return
|
|
1291
|
+
return path9.join(this.#artifactRoot, "fontCache.json");
|
|
1398
1292
|
}
|
|
1399
1293
|
async#buildCacheKey(fonts) {
|
|
1400
1294
|
const sources = [];
|
|
@@ -1409,7 +1303,7 @@ class FontOptimizer {
|
|
|
1409
1303
|
sources.push({ optimizedSrc: face.optimizedSrc, ...stamp });
|
|
1410
1304
|
}
|
|
1411
1305
|
for (const filePath of font.subsetFiles ?? []) {
|
|
1412
|
-
const abs =
|
|
1306
|
+
const abs = path9.isAbsolute(filePath) ? filePath : path9.join(this.#app.cwdPath, filePath);
|
|
1413
1307
|
const stamp = await this.#fileStamp(abs);
|
|
1414
1308
|
if (!stamp)
|
|
1415
1309
|
return null;
|
|
@@ -1435,7 +1329,7 @@ class FontOptimizer {
|
|
|
1435
1329
|
const cache = await Bun.file(this.#cachePath).json().catch(() => null);
|
|
1436
1330
|
if (cache?.version !== FontOptimizer.#cacheVersion || cache.key !== key)
|
|
1437
1331
|
return null;
|
|
1438
|
-
const files = cache.files.map((relativePath) =>
|
|
1332
|
+
const files = cache.files.map((relativePath) => path9.join(this.#artifactRoot, relativePath));
|
|
1439
1333
|
for (const filePath of files) {
|
|
1440
1334
|
if (!await Bun.file(filePath).exists())
|
|
1441
1335
|
return null;
|
|
@@ -1447,7 +1341,7 @@ class FontOptimizer {
|
|
|
1447
1341
|
version: FontOptimizer.#cacheVersion,
|
|
1448
1342
|
key,
|
|
1449
1343
|
css: result.css,
|
|
1450
|
-
files: result.files.map((filePath) =>
|
|
1344
|
+
files: result.files.map((filePath) => path9.relative(this.#artifactRoot, filePath))
|
|
1451
1345
|
};
|
|
1452
1346
|
await Bun.write(this.#cachePath, JSON.stringify(cache));
|
|
1453
1347
|
}
|
|
@@ -1455,7 +1349,7 @@ class FontOptimizer {
|
|
|
1455
1349
|
const pageKeys = await this.#app.getPageKeys();
|
|
1456
1350
|
const fonts = [];
|
|
1457
1351
|
await Promise.all(pageKeys.map(async (key) => {
|
|
1458
|
-
const filePath =
|
|
1352
|
+
const filePath = path9.resolve(this.#app.cwdPath, "page", key);
|
|
1459
1353
|
const file = Bun.file(filePath);
|
|
1460
1354
|
if (!await file.exists())
|
|
1461
1355
|
return;
|
|
@@ -1464,7 +1358,7 @@ class FontOptimizer {
|
|
|
1464
1358
|
return;
|
|
1465
1359
|
fonts.push(...this.#extractFontsExport(source, filePath));
|
|
1466
1360
|
}));
|
|
1467
|
-
return
|
|
1361
|
+
return [...new Map(fonts.map((font) => [JSON.stringify(font), font])).values()];
|
|
1468
1362
|
}
|
|
1469
1363
|
async#optimizeFont(font) {
|
|
1470
1364
|
const faceCss = [];
|
|
@@ -1474,8 +1368,8 @@ class FontOptimizer {
|
|
|
1474
1368
|
this.#app.logger.warn(`[font] source not found: ${face.src}`);
|
|
1475
1369
|
continue;
|
|
1476
1370
|
}
|
|
1477
|
-
const outputPath =
|
|
1478
|
-
await mkdir2(
|
|
1371
|
+
const outputPath = path9.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
|
|
1372
|
+
await mkdir2(path9.dirname(outputPath), { recursive: true });
|
|
1479
1373
|
const sourceBuffer = Buffer.from(await Bun.file(sourcePath).arrayBuffer());
|
|
1480
1374
|
const outputBuffer = await this.#buildFontBuffer(font, sourceBuffer, sourcePath);
|
|
1481
1375
|
await Bun.write(outputPath, outputBuffer);
|
|
@@ -1497,8 +1391,8 @@ class FontOptimizer {
|
|
|
1497
1391
|
const entries = Array.isArray(value) ? value : [];
|
|
1498
1392
|
const fonts = entries.filter((entry) => this.#isReadableFont(entry));
|
|
1499
1393
|
if (fonts.length !== entries.length || !Array.isArray(value))
|
|
1500
|
-
this.#app.logger.warn(`[font] ${
|
|
1501
|
-
return fonts.map((font) =>
|
|
1394
|
+
this.#app.logger.warn(`[font] ${path9.relative(this.#app.cwdPath, filePath)} declares fonts the build cannot read without evaluating the module \u2014 write the list inline, or nothing is subset for it and every /_akan/fonts request 404s`);
|
|
1395
|
+
return fonts.map((font) => ({ ...font, subsets: font.subsets ?? [...DEFAULT_FONT_SUBSETS] }));
|
|
1502
1396
|
}
|
|
1503
1397
|
#isReadableFont(value) {
|
|
1504
1398
|
if (!value || typeof value !== "object")
|
|
@@ -1587,15 +1481,6 @@ class FontOptimizer {
|
|
|
1587
1481
|
return name.text;
|
|
1588
1482
|
return null;
|
|
1589
1483
|
}
|
|
1590
|
-
#dedupeFonts(fonts) {
|
|
1591
|
-
const map = new Map;
|
|
1592
|
-
for (const font of fonts)
|
|
1593
|
-
map.set(JSON.stringify(font), font);
|
|
1594
|
-
return [...map.values()];
|
|
1595
|
-
}
|
|
1596
|
-
#withFontDefaults(font) {
|
|
1597
|
-
return { ...font, subsets: font.subsets ?? [...DEFAULT_FONT_SUBSETS] };
|
|
1598
|
-
}
|
|
1599
1484
|
#getFontSubsets(font) {
|
|
1600
1485
|
return font.subsets ?? DEFAULT_FONT_SUBSETS;
|
|
1601
1486
|
}
|
|
@@ -1608,11 +1493,8 @@ class FontOptimizer {
|
|
|
1608
1493
|
#isFontOptimizationEnabled(font) {
|
|
1609
1494
|
return font.optimize !== false;
|
|
1610
1495
|
}
|
|
1611
|
-
#getFontStyles(font) {
|
|
1612
|
-
return font.styles?.length ? font.styles : ["normal"];
|
|
1613
|
-
}
|
|
1614
1496
|
#getFontFaces(font) {
|
|
1615
|
-
const enabledStyles = new Set(
|
|
1497
|
+
const enabledStyles = new Set(font.styles?.length ? font.styles : ["normal"]);
|
|
1616
1498
|
return font.paths.map((fontPath) => {
|
|
1617
1499
|
const style = fontPath.style ?? "normal";
|
|
1618
1500
|
return {
|
|
@@ -1667,8 +1549,8 @@ class FontOptimizer {
|
|
|
1667
1549
|
return null;
|
|
1668
1550
|
const rel = src.replace(/^\//, "");
|
|
1669
1551
|
const candidates = [
|
|
1670
|
-
this.#command === "build" ?
|
|
1671
|
-
|
|
1552
|
+
this.#command === "build" ? path9.join(this.#app.dist.cwdPath, "public", rel) : null,
|
|
1553
|
+
path9.join(this.#app.cwdPath, "public", rel),
|
|
1672
1554
|
this.#resolveWorkspacePublicPath(rel)
|
|
1673
1555
|
].filter(Boolean);
|
|
1674
1556
|
for (const candidate of candidates) {
|
|
@@ -1685,15 +1567,12 @@ class FontOptimizer {
|
|
|
1685
1567
|
}
|
|
1686
1568
|
async#convertToWoff2(buffer, sourcePath) {
|
|
1687
1569
|
const { createFont } = await import("fonteditor-core");
|
|
1688
|
-
await this.#initWoff2();
|
|
1689
|
-
const font = createFont(buffer, { type: this.#getFontType(sourcePath, buffer) });
|
|
1690
|
-
return font.write({ type: "woff2", toBuffer: true });
|
|
1691
|
-
}
|
|
1692
|
-
async#initWoff2() {
|
|
1693
1570
|
this.#woff2Ready ??= import("fonteditor-core").then(({ woff2 }) => woff2.init()).then(() => {
|
|
1694
1571
|
return;
|
|
1695
1572
|
});
|
|
1696
|
-
|
|
1573
|
+
await this.#woff2Ready;
|
|
1574
|
+
const font = createFont(buffer, { type: this.#getFontType(sourcePath, buffer) });
|
|
1575
|
+
return font.write({ type: "woff2", toBuffer: true });
|
|
1697
1576
|
}
|
|
1698
1577
|
#getFontType(sourcePath, buffer) {
|
|
1699
1578
|
const signature = buffer.toString("ascii", 0, 4);
|
|
@@ -1703,7 +1582,7 @@ class FontOptimizer {
|
|
|
1703
1582
|
return "woff2";
|
|
1704
1583
|
if (signature === "OTTO")
|
|
1705
1584
|
return "otf";
|
|
1706
|
-
const ext =
|
|
1585
|
+
const ext = path9.extname(sourcePath).slice(1).toLowerCase();
|
|
1707
1586
|
if (ext === "otf" || ext === "woff" || ext === "woff2")
|
|
1708
1587
|
return ext;
|
|
1709
1588
|
return "ttf";
|
|
@@ -1712,7 +1591,7 @@ class FontOptimizer {
|
|
|
1712
1591
|
const [root, dep, ...rest] = rel.split("/");
|
|
1713
1592
|
if (root !== "libs" || !dep || rest.length === 0)
|
|
1714
1593
|
return null;
|
|
1715
|
-
return
|
|
1594
|
+
return path9.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
|
|
1716
1595
|
}
|
|
1717
1596
|
async#getSubsetText(font) {
|
|
1718
1597
|
const parts = new Set;
|
|
@@ -1722,7 +1601,7 @@ class FontOptimizer {
|
|
|
1722
1601
|
if (font.subsetText)
|
|
1723
1602
|
parts.add(font.subsetText);
|
|
1724
1603
|
for (const filePath of font.subsetFiles ?? []) {
|
|
1725
|
-
const abs =
|
|
1604
|
+
const abs = path9.isAbsolute(filePath) ? filePath : path9.join(this.#app.cwdPath, filePath);
|
|
1726
1605
|
const file = Bun.file(abs);
|
|
1727
1606
|
if (await file.exists())
|
|
1728
1607
|
parts.add(await file.text());
|
|
@@ -1731,9 +1610,9 @@ class FontOptimizer {
|
|
|
1731
1610
|
}
|
|
1732
1611
|
async#getSubsetPresetText(subset) {
|
|
1733
1612
|
if (subset === "latin")
|
|
1734
|
-
return
|
|
1613
|
+
return FontOptimizer.#rangeText(32, 126);
|
|
1735
1614
|
if (subset === "latin-ext")
|
|
1736
|
-
return `${
|
|
1615
|
+
return `${FontOptimizer.#rangeText(32, 126)}${FontOptimizer.#rangeText(160, 591)}`;
|
|
1737
1616
|
if (subset === "ks-x-1001")
|
|
1738
1617
|
return FontOptimizer.#getKsX1001Text();
|
|
1739
1618
|
if (subset === "auto")
|
|
@@ -1742,7 +1621,7 @@ class FontOptimizer {
|
|
|
1742
1621
|
}
|
|
1743
1622
|
async#collectAutoSubsetText() {
|
|
1744
1623
|
const libPageRoots = (await this.#app.getPageRoots()).filter((root) => root.keyPrefix).map((root) => root.dir);
|
|
1745
|
-
const roots = [...["page", "ui", "lib"].map((dir) =>
|
|
1624
|
+
const roots = [...["page", "ui", "lib"].map((dir) => path9.join(this.#app.cwdPath, dir)), ...libPageRoots];
|
|
1746
1625
|
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,html,md}");
|
|
1747
1626
|
const parts = [];
|
|
1748
1627
|
for (const root of [...new Set(roots)].sort()) {
|
|
@@ -1757,12 +1636,6 @@ class FontOptimizer {
|
|
|
1757
1636
|
}
|
|
1758
1637
|
return parts.join("");
|
|
1759
1638
|
}
|
|
1760
|
-
#rangeText(start, end) {
|
|
1761
|
-
let text = "";
|
|
1762
|
-
for (let code = start;code <= end; code++)
|
|
1763
|
-
text += String.fromCodePoint(code);
|
|
1764
|
-
return text;
|
|
1765
|
-
}
|
|
1766
1639
|
static #getKsX1001Text() {
|
|
1767
1640
|
if (FontOptimizer.#ksX1001Text)
|
|
1768
1641
|
return FontOptimizer.#ksX1001Text;
|
|
@@ -1778,11 +1651,11 @@ class FontOptimizer {
|
|
|
1778
1651
|
}
|
|
1779
1652
|
FontOptimizer.#ksX1001Text = [...chars].join("");
|
|
1780
1653
|
} catch {
|
|
1781
|
-
FontOptimizer.#ksX1001Text = FontOptimizer.#
|
|
1654
|
+
FontOptimizer.#ksX1001Text = FontOptimizer.#rangeText(44032, 55203);
|
|
1782
1655
|
}
|
|
1783
1656
|
return FontOptimizer.#ksX1001Text;
|
|
1784
1657
|
}
|
|
1785
|
-
static #
|
|
1658
|
+
static #rangeText(start, end) {
|
|
1786
1659
|
let text = "";
|
|
1787
1660
|
for (let code = start;code <= end; code++)
|
|
1788
1661
|
text += String.fromCodePoint(code);
|
|
@@ -1862,7 +1735,7 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
|
|
|
1862
1735
|
|
|
1863
1736
|
// pkgs/@akanjs/devkit/frontendBuild/fontPruner.ts
|
|
1864
1737
|
import { rm as rm2, rmdir, stat as stat3 } from "fs/promises";
|
|
1865
|
-
import
|
|
1738
|
+
import path10 from "path";
|
|
1866
1739
|
import { isFontOptimizationEnabled } from "akanjs/client";
|
|
1867
1740
|
var FONT_GLOB = "**/*.{woff2,woff,ttf,otf,ttc,eot}";
|
|
1868
1741
|
var REFERRER_GLOB = "**/*.{css,js,mjs,cjs,json,html,htm,svg,xml,webmanifest}";
|
|
@@ -1875,8 +1748,8 @@ class FontPruner {
|
|
|
1875
1748
|
constructor(app, { keepFonts = [] } = {}) {
|
|
1876
1749
|
this.#app = app;
|
|
1877
1750
|
this.#keepGlobs = keepFonts;
|
|
1878
|
-
this.#publicRoot =
|
|
1879
|
-
this.#artifactRoot =
|
|
1751
|
+
this.#publicRoot = path10.join(app.dist.cwdPath, "public");
|
|
1752
|
+
this.#artifactRoot = path10.join(app.dist.cwdPath, ".akan/artifact");
|
|
1880
1753
|
}
|
|
1881
1754
|
async prune() {
|
|
1882
1755
|
const empty = { removed: [], kept: [], freedBytes: 0 };
|
|
@@ -1891,7 +1764,7 @@ class FontPruner {
|
|
|
1891
1764
|
for (const font of fonts) {
|
|
1892
1765
|
const target = isFontOptimizationEnabled(font) ? optimizedSrcs : unoptimizedSrcs;
|
|
1893
1766
|
for (const fontPath of font.paths)
|
|
1894
|
-
target.add(
|
|
1767
|
+
target.add(path10.posix.basename(fontPath.src));
|
|
1895
1768
|
}
|
|
1896
1769
|
const result = { removed: [], kept: [], freedBytes: 0 };
|
|
1897
1770
|
const undecided = [];
|
|
@@ -1929,10 +1802,10 @@ class FontPruner {
|
|
|
1929
1802
|
async#collectCandidates() {
|
|
1930
1803
|
const candidates = [];
|
|
1931
1804
|
for await (const rel of new Bun.Glob(FONT_GLOB).scan({ cwd: this.#publicRoot, dot: false })) {
|
|
1932
|
-
const entry = await stat3(
|
|
1805
|
+
const entry = await stat3(path10.join(this.#publicRoot, rel)).catch(() => null);
|
|
1933
1806
|
if (!entry?.isFile())
|
|
1934
1807
|
continue;
|
|
1935
|
-
candidates.push({ rel: rel.split(
|
|
1808
|
+
candidates.push({ rel: rel.split(path10.sep).join("/"), basename: path10.basename(rel), bytes: entry.size });
|
|
1936
1809
|
}
|
|
1937
1810
|
return candidates;
|
|
1938
1811
|
}
|
|
@@ -1942,11 +1815,11 @@ class FontPruner {
|
|
|
1942
1815
|
const bundled = candidates.filter((candidate) => !optimizedSrcs.has(candidate.basename));
|
|
1943
1816
|
const roots = [
|
|
1944
1817
|
{ dir: this.#publicRoot, label: "public", needles: authoritative },
|
|
1945
|
-
{ dir:
|
|
1946
|
-
{ dir:
|
|
1947
|
-
{ dir:
|
|
1948
|
-
{ dir:
|
|
1949
|
-
{ dir:
|
|
1818
|
+
{ dir: path10.join(this.#artifactRoot, "styles"), label: ".akan/artifact/styles", needles: authoritative },
|
|
1819
|
+
{ dir: path10.join(this.#artifactRoot, "client"), label: ".akan/artifact/client", needles: bundled },
|
|
1820
|
+
{ dir: path10.join(this.#artifactRoot, "client-ssr"), label: ".akan/artifact/client-ssr", needles: bundled },
|
|
1821
|
+
{ dir: path10.join(this.#artifactRoot, "server"), label: ".akan/artifact/server", needles: bundled },
|
|
1822
|
+
{ dir: path10.join(this.#app.dist.cwdPath, "csr"), label: "csr", needles: bundled }
|
|
1950
1823
|
];
|
|
1951
1824
|
for (const root of roots) {
|
|
1952
1825
|
const pending = root.needles.filter((candidate) => !referrers.has(candidate.rel));
|
|
@@ -1965,20 +1838,20 @@ class FontPruner {
|
|
|
1965
1838
|
const remaining = needles.filter((needle) => !referrers.has(needle.rel));
|
|
1966
1839
|
if (!remaining.length)
|
|
1967
1840
|
return;
|
|
1968
|
-
const text = await Bun.file(
|
|
1841
|
+
const text = await Bun.file(path10.join(root.dir, rel)).text().catch(() => "");
|
|
1969
1842
|
if (!text)
|
|
1970
1843
|
continue;
|
|
1971
1844
|
for (const needle of remaining) {
|
|
1972
1845
|
if (needle.forms.some((form) => text.includes(form)))
|
|
1973
|
-
referrers.set(needle.rel, `${root.label}/${rel.split(
|
|
1846
|
+
referrers.set(needle.rel, `${root.label}/${rel.split(path10.sep).join("/")}`);
|
|
1974
1847
|
}
|
|
1975
1848
|
}
|
|
1976
1849
|
}
|
|
1977
1850
|
async#remove(files) {
|
|
1978
|
-
await Promise.all(files.map((file) => rm2(
|
|
1979
|
-
const dirs = [...new Set(files.map((file) =>
|
|
1851
|
+
await Promise.all(files.map((file) => rm2(path10.join(this.#publicRoot, file), { force: true })));
|
|
1852
|
+
const dirs = [...new Set(files.map((file) => path10.posix.dirname(file)))].filter((dir) => dir !== "." && dir !== "/").sort((a, b) => b.length - a.length);
|
|
1980
1853
|
for (const dir of dirs)
|
|
1981
|
-
await rmdir(
|
|
1854
|
+
await rmdir(path10.join(this.#publicRoot, dir)).catch(() => {
|
|
1982
1855
|
return;
|
|
1983
1856
|
});
|
|
1984
1857
|
}
|
|
@@ -2026,17 +1899,18 @@ class FontPruner {
|
|
|
2026
1899
|
|
|
2027
1900
|
// pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
|
|
2028
1901
|
import fs from "fs";
|
|
2029
|
-
import
|
|
1902
|
+
import path11 from "path";
|
|
2030
1903
|
import zlib from "zlib";
|
|
2031
1904
|
var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
|
|
2032
1905
|
var MIN_COMPRESS_BYTES = 1024;
|
|
2033
1906
|
var BROTLI_QUALITY_BY_EXT = { ".css": 11 };
|
|
2034
1907
|
var DEFAULT_BROTLI_QUALITY = 9;
|
|
2035
1908
|
var GZIP_LEVEL = 9;
|
|
1909
|
+
var { formatBytes } = FontPruner;
|
|
2036
1910
|
async function precompressArtifacts(app) {
|
|
2037
1911
|
const roots = [
|
|
2038
|
-
|
|
2039
|
-
|
|
1912
|
+
path11.join(app.dist.cwdPath, ".akan/artifact/client"),
|
|
1913
|
+
path11.join(app.dist.cwdPath, ".akan/artifact/styles")
|
|
2040
1914
|
];
|
|
2041
1915
|
const result = { files: 0, inputBytes: 0, outputBytes: 0, brotliBytes: 0 };
|
|
2042
1916
|
await Promise.all(roots.map((root) => precompressRoot(root, result)));
|
|
@@ -2053,9 +1927,9 @@ async function precompressRoot(root, result) {
|
|
|
2053
1927
|
if (!await shouldPrecompress(filePath))
|
|
2054
1928
|
continue;
|
|
2055
1929
|
const bytes = await Bun.file(filePath).bytes();
|
|
2056
|
-
const buffer =
|
|
1930
|
+
const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
2057
1931
|
const gz = Bun.gzipSync(buffer, { level: GZIP_LEVEL });
|
|
2058
|
-
const br = brotliCompress(buffer,
|
|
1932
|
+
const br = brotliCompress(buffer, path11.extname(filePath).toLowerCase());
|
|
2059
1933
|
await Promise.all([Bun.write(`${filePath}.gz`, gz), Bun.write(`${filePath}.br`, br)]);
|
|
2060
1934
|
result.files += 1;
|
|
2061
1935
|
result.inputBytes += bytes.byteLength;
|
|
@@ -2075,26 +1949,16 @@ function brotliCompress(buffer, ext) {
|
|
|
2075
1949
|
async function shouldPrecompress(filePath) {
|
|
2076
1950
|
if (filePath.endsWith(".gz") || filePath.endsWith(".br"))
|
|
2077
1951
|
return false;
|
|
2078
|
-
if (!COMPRESSIBLE_EXTS.has(
|
|
1952
|
+
if (!COMPRESSIBLE_EXTS.has(path11.extname(filePath).toLowerCase()))
|
|
2079
1953
|
return false;
|
|
2080
1954
|
const file = Bun.file(filePath);
|
|
2081
1955
|
if (!await file.exists())
|
|
2082
1956
|
return false;
|
|
2083
1957
|
return file.size >= MIN_COMPRESS_BYTES;
|
|
2084
1958
|
}
|
|
2085
|
-
function toArrayBuffer(bytes) {
|
|
2086
|
-
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
2087
|
-
}
|
|
2088
|
-
function formatBytes(bytes) {
|
|
2089
|
-
if (bytes < 1024)
|
|
2090
|
-
return `${bytes}B`;
|
|
2091
|
-
if (bytes < 1024 * 1024)
|
|
2092
|
-
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
2093
|
-
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
2094
|
-
}
|
|
2095
1959
|
|
|
2096
1960
|
// pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
|
|
2097
|
-
import
|
|
1961
|
+
import path12 from "path";
|
|
2098
1962
|
import { optimize } from "@tailwindcss/node";
|
|
2099
1963
|
function prepareCssAsset(command, basePath, cssText) {
|
|
2100
1964
|
return optimize(cssText, { file: `${basePath || "root"}.css`, minify: command === "build" }).code;
|
|
@@ -2110,7 +1974,7 @@ class SsrBaseArtifactBuilder {
|
|
|
2110
1974
|
this.#app = app;
|
|
2111
1975
|
this.#command = command;
|
|
2112
1976
|
this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
|
|
2113
|
-
this.#absArtifactDir =
|
|
1977
|
+
this.#absArtifactDir = path12.resolve(this.#artifactDir);
|
|
2114
1978
|
}
|
|
2115
1979
|
async build() {
|
|
2116
1980
|
const akanConfig = await this.#app.getConfig();
|
|
@@ -2132,7 +1996,7 @@ class SsrBaseArtifactBuilder {
|
|
|
2132
1996
|
rscRuntimeSsrManifest,
|
|
2133
1997
|
vendorMap,
|
|
2134
1998
|
cssAssets,
|
|
2135
|
-
pagesBundlePath: this.#command === "build" ?
|
|
1999
|
+
pagesBundlePath: this.#command === "build" ? path12.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
|
|
2136
2000
|
pagesBundleBuildId: pagesBundle.buildId,
|
|
2137
2001
|
domains: [...akanConfig.domains],
|
|
2138
2002
|
subRoutes: Object.fromEntries(Array.from(akanConfig.subRoutes.entries()).map(([basePath, domains]) => [basePath, [...domains]])),
|
|
@@ -2149,18 +2013,18 @@ class SsrBaseArtifactBuilder {
|
|
|
2149
2013
|
androidSha256CertFingerprints: target.deepLinks?.android?.sha256CertFingerprints
|
|
2150
2014
|
}))
|
|
2151
2015
|
};
|
|
2152
|
-
await Bun.write(
|
|
2016
|
+
await Bun.write(path12.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
|
|
2153
2017
|
`);
|
|
2154
2018
|
this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
|
|
2155
2019
|
return { artifact, seedIndex, cssCompiler, optimizedFonts };
|
|
2156
2020
|
}
|
|
2157
2021
|
async#buildRuntimeClientEntries() {
|
|
2158
2022
|
const akanServerPath = await this.#resolveAkanServerPath();
|
|
2159
|
-
const rscClientEntry =
|
|
2160
|
-
const rscSegmentOutletEntry =
|
|
2023
|
+
const rscClientEntry = path12.resolve(akanServerPath, "rscClient.tsx");
|
|
2024
|
+
const rscSegmentOutletEntry = path12.resolve(akanServerPath, "rscSegmentOutlet.tsx");
|
|
2161
2025
|
const vendorEntries = VENDOR_SPECIFIERS.map((specifier) => ({
|
|
2162
2026
|
specifier,
|
|
2163
|
-
absPath:
|
|
2027
|
+
absPath: path12.resolve(akanServerPath, "vendor", `${specifier.replaceAll("/", "-").replaceAll(".", "-")}.ts`)
|
|
2164
2028
|
}));
|
|
2165
2029
|
const entries = [rscClientEntry, rscSegmentOutletEntry, ...vendorEntries.map((v) => v.absPath)];
|
|
2166
2030
|
const clientBundle = await new ClientEntriesBundler({ app: this.#app, entries, command: this.#command }).bundle();
|
|
@@ -2197,15 +2061,15 @@ class SsrBaseArtifactBuilder {
|
|
|
2197
2061
|
async#resolveAkanServerPath() {
|
|
2198
2062
|
const candidates = [];
|
|
2199
2063
|
try {
|
|
2200
|
-
candidates.push(
|
|
2064
|
+
candidates.push(path12.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
|
|
2201
2065
|
} catch {}
|
|
2202
|
-
candidates.push(
|
|
2066
|
+
candidates.push(path12.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path12.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
|
|
2203
2067
|
try {
|
|
2204
|
-
candidates.push(
|
|
2068
|
+
candidates.push(path12.dirname(Bun.resolveSync("akanjs/server", path12.dirname(Bun.main))));
|
|
2205
2069
|
} catch {}
|
|
2206
|
-
candidates.push(
|
|
2070
|
+
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"));
|
|
2207
2071
|
for (const candidate of candidates) {
|
|
2208
|
-
if (await Bun.file(
|
|
2072
|
+
if (await Bun.file(path12.join(candidate, "rscClient.tsx")).exists())
|
|
2209
2073
|
return candidate;
|
|
2210
2074
|
}
|
|
2211
2075
|
throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
|
|
@@ -2234,7 +2098,7 @@ ${preparedCssText}`).toString(36);
|
|
|
2234
2098
|
`styles/${cssAssetName}-${cssHash}.css`,
|
|
2235
2099
|
`/_akan/styles/${cssAssetName}-${cssHash}.css`
|
|
2236
2100
|
];
|
|
2237
|
-
await Bun.write(
|
|
2101
|
+
await Bun.write(path12.join(this.#absArtifactDir, cssRelPath), preparedCssText);
|
|
2238
2102
|
SsrBaseArtifactBuilder.#warnDroppedImports(this.#app, cssRelPath, preparedCssText, imported);
|
|
2239
2103
|
this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath} -> ${cssRelPath}`);
|
|
2240
2104
|
return [basePath, { cssUrl, cssRelPath }];
|