@akanjs/cli 3.1.0-rc.1 → 3.1.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.build-stamp +1 -1
- package/{CodeAgent-kyprmy06.js → CodeAgent-ctk4fh2b.js} +2 -2
- package/{CodeTui-21mtze3j.js → CodeTui-mrxtrdzw.js} +1 -1
- package/TunnelShare-rj74jd6x.js +13 -0
- package/{agent.command-f3gsc1gd.js → agent.command-ncre6kwz.js} +5 -5
- package/akanCode.js +2 -2
- package/{application.command-5s780vnz.js → application.command-54mawreg.js} +52 -41
- package/{applicationBuildRunner-1yaqsrdq.js → applicationBuildRunner-8573zr2w.js} +16 -30
- package/buildBatch.proc.js +22 -13
- package/{cloud.command-yj6xb2a7.js → cloud.command-nyemv0m3.js} +57 -65
- package/cloud.script-ht6yb203.js +23 -0
- package/{code.command-3wkn4ja5.js → code.command-spsrzg63.js} +6 -6
- package/{context.command-9jjn3gcw.js → context.command-768zv7z4.js} +16 -13
- package/context.runner-tf1b53qq.js +24 -0
- package/{guideline.command-dtczrqpf.js → guideline.command-4ycwc51q.js} +2 -2
- package/guidelines/conventions/conventions.instruction.md +28 -15
- package/guidelines/cssRule/cssRule.instruction.md +12 -6
- package/guidelines/mcpRule/mcpRule.instruction.md +27 -11
- package/guidelines/runtimeRule/runtimeRule.instruction.md +24 -15
- package/guidelines/transportRule/transportRule.instruction.md +28 -5
- package/incrementalBuilder.proc.js +9 -6
- package/{index-2etcv0sc.js → index-00seamy5.js} +1 -1
- package/{index-jx4bzvwg.js → index-1a7nhq56.js} +92 -52
- package/{index-e0cvze1s.js → index-1nyxvz8j.js} +4 -4
- package/index-2z3kykvd.js +248 -0
- package/{index-rtct7d43.js → index-3675mvjw.js} +1 -1
- package/{index-56d2g8ms.js → index-3ddt3qjg.js} +1 -1
- package/{index-6jjtnhkw.js → index-3x7yeecy.js} +51 -9
- package/{index-ww9bhp67.js → index-4pf8g7ff.js} +1 -1
- package/index-8935h3n1.js +33 -0
- package/{index-v29746vb.js → index-8eqkxwsx.js} +3 -3
- package/{index-c2yrsxdh.js → index-91rt5bye.js} +96 -320
- package/{index-55mynnqs.js → index-bv210r6t.js} +459 -210
- package/{index-c76k723e.js → index-c4h5b5nq.js} +2 -2
- package/{index-qt22xstj.js → index-c9zjb3tw.js} +5 -3
- package/{index-c1x0be5j.js → index-dmsvd2rv.js} +2 -2
- package/index-ec080x99.js +1124 -0
- package/{index-ctanya41.js → index-fjqvd5mx.js} +4 -4
- package/{index-aprt7pkz.js → index-fvn6f5wx.js} +229 -1327
- package/{index-rc5rwyps.js → index-jj7yapwq.js} +71 -60
- package/index-kmamh5bv.js +241 -0
- package/{index-fm46xrf1.js → index-q5abh0jq.js} +3 -3
- package/{index-1w2qaee2.js → index-qf8g88j9.js} +361 -291
- package/{index-gnyf1fqy.js → index-qvghfv6v.js} +2 -2
- package/{index-ae5pwhgs.js → index-r5d6rq19.js} +10 -8
- package/{index-2mx692qq.js → index-vhfjzda3.js} +2 -2
- package/{index-8r4d7cmt.js → index-w9b71b6y.js} +4 -4
- package/{index-8ggztp8k.js → index-wanhh011.js} +42 -177
- package/{index-05g3jayg.js → index-wdze51wz.js} +1 -1
- package/index-wjqbc7sf.js +668 -0
- package/{index-rwq3ekqc.js → index-xf40a295.js} +7 -7
- package/{index-krq7btbt.js → index-xm5tmpv0.js} +3 -3
- package/index.js +22 -22
- package/{library.command-gaga5bmq.js → library.command-88ahgych.js} +3 -3
- package/{localRegistry.command-vsreyy42.js → localRegistry.command-ykea1m7b.js} +12 -9
- package/{module.command-7vpf6db4.js → module.command-zky4b7m9.js} +5 -5
- package/{package.command-twmvvf69.js → package.command-vh8pcedh.js} +3 -3
- package/package.json +2 -2
- package/{page.command-5asq7fdf.js → page.command-fyqeqxc3.js} +3 -3
- package/{pipeline.command-d0v38572.js → pipeline.command-r5t30py6.js} +220 -219
- package/{primitive.command-dyrs2fm8.js → primitive.command-a0516zfk.js} +6 -6
- package/{projectTypecheck-cvtkrzp2.js → projectTypecheck-7djd4z50.js} +1 -1
- package/{quality.command-6emsqpbg.js → quality.command-k7jcnfn0.js} +2 -2
- package/{repair.command-8t6aegv5.js → repair.command-85zg2an3.js} +5 -5
- package/{scalar.command-bnggy1x7.js → scalar.command-g5vmqwca.js} +4 -4
- package/{subspace.command-md2teygq.js → subspace.command-mp4evgsj.js} +421 -362
- package/{tunnel.command-jx3tdm2d.js → tunnel.command-kbnr99sj.js} +7 -4
- package/{workflow.command-jx0wag5r.js → workflow.command-9y9p1n8y.js} +10 -10
- package/{workspace.command-yxd7rr7g.js → workspace.command-jmec2kjg.js} +33 -30
- package/TunnelShare-q4jq08qg.js +0 -9
- package/cloud.script-h6pvcpa2.js +0 -20
- package/context.runner-atcrzz5b.js +0 -21
- package/index-6w0rbr9d.js +0 -68
- package/index-pgj2rt78.js +0 -404
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
resolveSsrPageEntriesForApp
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-bv210r6t.js";
|
|
5
5
|
import {
|
|
6
6
|
computeRouteSeedIndex,
|
|
7
7
|
saveRouteSeedIndex,
|
|
8
|
-
BarrelAnalyzer,
|
|
9
|
-
createTsconfigPackageResolver,
|
|
10
|
-
rewriteBarrelImports,
|
|
11
8
|
GraphClientEntryDiscovery,
|
|
12
|
-
bundleDefine,
|
|
13
9
|
ClientEntriesBundler,
|
|
14
10
|
VENDOR_SPECIFIERS,
|
|
15
|
-
RouteClientBuilder
|
|
16
|
-
|
|
17
|
-
PagesEntrySourceGenerator,
|
|
18
|
-
PagesBundleBuilder
|
|
19
|
-
} from "./index-aprt7pkz.js";
|
|
11
|
+
RouteClientBuilder
|
|
12
|
+
} from "./index-fvn6f5wx.js";
|
|
20
13
|
import {
|
|
21
14
|
SOURCE_EXTS
|
|
22
15
|
} from "./index-k9rrten6.js";
|
|
16
|
+
import {
|
|
17
|
+
CsrEntryFiles,
|
|
18
|
+
BarrelAnalyzer,
|
|
19
|
+
createTsconfigPackageResolver,
|
|
20
|
+
rewriteBarrelImports,
|
|
21
|
+
PagesBundleBuilder
|
|
22
|
+
} from "./index-ec080x99.js";
|
|
23
23
|
var __require = import.meta.require;
|
|
24
24
|
|
|
25
25
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
@@ -128,232 +128,8 @@ class AllRoutesBuilder {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
132
|
-
import { mkdir, rm, unlink } from "fs/promises";
|
|
133
|
-
import path2 from "path";
|
|
134
|
-
class CsrArtifactBuilder {
|
|
135
|
-
#app;
|
|
136
|
-
#command;
|
|
137
|
-
#lang;
|
|
138
|
-
#cssAssets;
|
|
139
|
-
constructor(app, command = "start", lang = "en", { cssAssets = null } = {}) {
|
|
140
|
-
this.#app = app;
|
|
141
|
-
this.#command = command;
|
|
142
|
-
this.#lang = lang;
|
|
143
|
-
this.#cssAssets = cssAssets;
|
|
144
|
-
}
|
|
145
|
-
async build() {
|
|
146
|
-
const pageKeys = await this.#app.getPageKeys();
|
|
147
|
-
if (pageKeys.length === 0) {
|
|
148
|
-
this.#app.log(`[cli] no route files under ${this.#app.cwdPath}/page \u2014 skipping CSR build`);
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
const pageEntries = await resolveSsrPageEntriesForApp(this.#app, pageKeys);
|
|
152
|
-
const akanConfig = await this.#app.getConfig();
|
|
153
|
-
const cssAssets = await this.#loadCssAssets();
|
|
154
|
-
const basePaths = [...akanConfig.basePaths];
|
|
155
|
-
const htmlBasePaths = basePaths.length > 0 ? basePaths : [""];
|
|
156
|
-
await rm(this.#outputDir, { recursive: true, force: true });
|
|
157
|
-
await mkdir(this.#generatedDir, { recursive: true });
|
|
158
|
-
const generatedFiles = Object.fromEntries((await Promise.all(htmlBasePaths.map(async (basePath) => [
|
|
159
|
-
this.#createHtmlFile(basePath),
|
|
160
|
-
await this.#createEntryFile(basePath, CsrArtifactBuilder.pageEntriesForBasePath(pageEntries, basePath, basePaths))
|
|
161
|
-
]))).flat());
|
|
162
|
-
const result = await Bun.build({
|
|
163
|
-
...CsrArtifactBuilder.bundleOptions(this.#app, this.#command, akanConfig.optimizeImports),
|
|
164
|
-
entrypoints: htmlBasePaths.map((basePath) => this.#generatedPath(CsrArtifactBuilder.htmlFilename(basePath))),
|
|
165
|
-
files: generatedFiles,
|
|
166
|
-
root: this.#generatedDir,
|
|
167
|
-
outdir: this.#outputDir
|
|
168
|
-
});
|
|
169
|
-
if (!result.success) {
|
|
170
|
-
const logs = result.logs.map((log) => log.message).join(`
|
|
171
|
-
`);
|
|
172
|
-
throw new Error(`[csr-build] failed${logs ? `
|
|
173
|
-
${logs}` : ""}`);
|
|
174
|
-
}
|
|
175
|
-
await this.#inlineCsrArtifacts(cssAssets);
|
|
176
|
-
this.#app.verbose(`[csr-build] output -> ${this.#outputDir}`);
|
|
177
|
-
return { outputDir: this.#outputDir };
|
|
178
|
-
}
|
|
179
|
-
static bundleOptions(app, command, optimizeImports = []) {
|
|
180
|
-
return {
|
|
181
|
-
target: "browser",
|
|
182
|
-
splitting: false,
|
|
183
|
-
minify: true,
|
|
184
|
-
define: bundleDefine(app, command, "csr"),
|
|
185
|
-
optimizeImports,
|
|
186
|
-
plugins: [PagesBundleBuilder.createCssStubPlugin()]
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
static pageEntriesForBasePath(pageEntries, basePath, basePaths) {
|
|
190
|
-
return CsrEntryFiles.pageEntriesForBasePath(pageEntries, basePath, basePaths);
|
|
191
|
-
}
|
|
192
|
-
static htmlFilename(basePath) {
|
|
193
|
-
return `${basePath || "index"}.html`;
|
|
194
|
-
}
|
|
195
|
-
static entryFilename(basePath) {
|
|
196
|
-
return CsrEntryFiles.entryFilename(basePath);
|
|
197
|
-
}
|
|
198
|
-
static basePathOfHtml(htmlPath) {
|
|
199
|
-
const name = path2.basename(htmlPath, ".html");
|
|
200
|
-
return name === "index" ? "" : name;
|
|
201
|
-
}
|
|
202
|
-
get #outputDir() {
|
|
203
|
-
return path2.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
|
|
204
|
-
}
|
|
205
|
-
get #generatedDir() {
|
|
206
|
-
return path2.join(this.#app.cwdPath, ".akan/generated/csr");
|
|
207
|
-
}
|
|
208
|
-
get #artifactDir() {
|
|
209
|
-
return path2.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
|
|
210
|
-
}
|
|
211
|
-
#generatedPath(filename) {
|
|
212
|
-
return path2.join(this.#generatedDir, filename);
|
|
213
|
-
}
|
|
214
|
-
async#createEntryFile(basePath, pageEntries) {
|
|
215
|
-
return [
|
|
216
|
-
this.#generatedPath(CsrArtifactBuilder.entryFilename(basePath)),
|
|
217
|
-
`import { bootCsr } from "akanjs/webkit";
|
|
218
|
-
${await PagesEntrySourceGenerator.generateStatic(pageEntries)}
|
|
219
|
-
void bootCsr(pages);
|
|
220
|
-
`
|
|
221
|
-
];
|
|
222
|
-
}
|
|
223
|
-
#createHtmlFile(basePath) {
|
|
224
|
-
return [
|
|
225
|
-
this.#generatedPath(CsrArtifactBuilder.htmlFilename(basePath)),
|
|
226
|
-
`<!doctype html>
|
|
227
|
-
<html lang="${this.#lang}">
|
|
228
|
-
<head>
|
|
229
|
-
<meta charset="utf-8" />
|
|
230
|
-
<title>${this.#app.name}</title>
|
|
231
|
-
<base href="/" />
|
|
232
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
233
|
-
</head>
|
|
234
|
-
<body>
|
|
235
|
-
<div id="root"></div>
|
|
236
|
-
<script type="module" src="./${CsrArtifactBuilder.entryFilename(basePath)}"></script>
|
|
237
|
-
</body>
|
|
238
|
-
</html>
|
|
239
|
-
`
|
|
240
|
-
];
|
|
241
|
-
}
|
|
242
|
-
async#loadCssAssets() {
|
|
243
|
-
if (this.#cssAssets)
|
|
244
|
-
return this.#cssAssets;
|
|
245
|
-
const artifactFile = Bun.file(path2.join(this.#artifactDir, "base-artifact.json"));
|
|
246
|
-
if (!await artifactFile.exists())
|
|
247
|
-
return {};
|
|
248
|
-
const artifact = await artifactFile.json();
|
|
249
|
-
return artifact.cssAssets ?? {};
|
|
250
|
-
}
|
|
251
|
-
async#inlineCsrArtifacts(cssAssets) {
|
|
252
|
-
const jsFiles = new Set;
|
|
253
|
-
for (const htmlPath of await this.#listOutputFiles((filePath) => filePath.endsWith(".html"))) {
|
|
254
|
-
const htmlFile = Bun.file(htmlPath);
|
|
255
|
-
if (!await htmlFile.exists())
|
|
256
|
-
continue;
|
|
257
|
-
const basePath = CsrArtifactBuilder.basePathOfHtml(htmlPath);
|
|
258
|
-
const cssAsset = cssAssets[basePath];
|
|
259
|
-
if (!cssAsset) {
|
|
260
|
-
this.#app.logger.warn(`[csr-build] base-artifact.json has no compiled stylesheet for ${basePath || "root"}; ${path2.basename(htmlPath)} ships without CSS`);
|
|
261
|
-
}
|
|
262
|
-
const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAsset);
|
|
263
|
-
for (const filePath of inlined.jsFiles)
|
|
264
|
-
jsFiles.add(filePath);
|
|
265
|
-
await Bun.write(htmlPath, inlined.html);
|
|
266
|
-
}
|
|
267
|
-
for (const filePath of jsFiles)
|
|
268
|
-
await unlink(filePath).catch(() => {
|
|
269
|
-
return;
|
|
270
|
-
});
|
|
271
|
-
const remainingAssets = await this.#listOutputFiles((filePath) => filePath.endsWith(".js") || filePath.endsWith(".css"));
|
|
272
|
-
if (remainingAssets.length > 0) {
|
|
273
|
-
throw new Error(`[csr-build] expected single-file HTML, but CSR assets remain:
|
|
274
|
-
${remainingAssets.join(`
|
|
275
|
-
`)}`);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
async#inlineHtmlAssets(html, htmlPath, cssAsset) {
|
|
279
|
-
let next = html;
|
|
280
|
-
if (cssAsset) {
|
|
281
|
-
const css = await Bun.file(path2.join(this.#artifactDir, cssAsset.cssRelPath)).text();
|
|
282
|
-
next = CsrArtifactBuilder.injectBeforeHeadEnd(next, CsrArtifactBuilder.createInlineStyle(css));
|
|
283
|
-
}
|
|
284
|
-
const jsFiles = [];
|
|
285
|
-
next = await CsrArtifactBuilder.replaceModuleScriptSrc(next, async (src) => {
|
|
286
|
-
const jsPath = CsrArtifactBuilder.resolveHtmlAssetPath(htmlPath, src);
|
|
287
|
-
jsFiles.push(jsPath);
|
|
288
|
-
return await Bun.file(jsPath).text();
|
|
289
|
-
});
|
|
290
|
-
return { html: next, jsFiles };
|
|
291
|
-
}
|
|
292
|
-
async#listOutputFiles(predicate) {
|
|
293
|
-
const glob = new Bun.Glob("**/*");
|
|
294
|
-
const files = [];
|
|
295
|
-
for await (const filePath of glob.scan({ cwd: this.#outputDir, absolute: true })) {
|
|
296
|
-
if (predicate(filePath))
|
|
297
|
-
files.push(filePath);
|
|
298
|
-
}
|
|
299
|
-
return files.sort();
|
|
300
|
-
}
|
|
301
|
-
static injectBeforeHeadEnd(html, snippet) {
|
|
302
|
-
const scannable = CsrArtifactBuilder.blankEmbeddedContent(html);
|
|
303
|
-
const headEnd = scannable.search(/<\/head\s*>/i);
|
|
304
|
-
if (headEnd !== -1)
|
|
305
|
-
return `${html.slice(0, headEnd)}${snippet}
|
|
306
|
-
${html.slice(headEnd)}`;
|
|
307
|
-
const bodyStart = scannable.search(/<body(?:\s|>)/i);
|
|
308
|
-
if (bodyStart !== -1)
|
|
309
|
-
return `${html.slice(0, bodyStart)}${snippet}
|
|
310
|
-
${html.slice(bodyStart)}`;
|
|
311
|
-
return `${html}
|
|
312
|
-
${snippet}`;
|
|
313
|
-
}
|
|
314
|
-
static blankEmbeddedContent(html) {
|
|
315
|
-
return html.replace(/<script\b[^>]*>[\s\S]*?<\/script\s*>|<style\b[^>]*>[\s\S]*?<\/style\s*>|<!--[\s\S]*?-->/gi, (match) => " ".repeat(match.length));
|
|
316
|
-
}
|
|
317
|
-
static createInlineStyle(css) {
|
|
318
|
-
return `<style data-akan-css="active">
|
|
319
|
-
${css.replace(/<\/style/gi, "<\\/style")}
|
|
320
|
-
</style>`;
|
|
321
|
-
}
|
|
322
|
-
static async replaceModuleScriptSrc(html, loadScript) {
|
|
323
|
-
const scriptRe = /<script\b(?=[^>]*\btype=["']module["'])(?=[^>]*\bsrc=["']([^"']+)["'])[^>]*>\s*<\/script>/gi;
|
|
324
|
-
let result = "";
|
|
325
|
-
let lastIndex = 0;
|
|
326
|
-
let matched = false;
|
|
327
|
-
for (const match of html.matchAll(scriptRe)) {
|
|
328
|
-
const full = match[0];
|
|
329
|
-
const src = match[1];
|
|
330
|
-
if (match.index === undefined || !src)
|
|
331
|
-
continue;
|
|
332
|
-
matched = true;
|
|
333
|
-
result += html.slice(lastIndex, match.index);
|
|
334
|
-
result += `<script type="module">
|
|
335
|
-
${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
336
|
-
</script>`;
|
|
337
|
-
lastIndex = match.index + full.length;
|
|
338
|
-
}
|
|
339
|
-
if (!matched)
|
|
340
|
-
return html;
|
|
341
|
-
return result + html.slice(lastIndex);
|
|
342
|
-
}
|
|
343
|
-
static escapeInlineScript(source) {
|
|
344
|
-
return source.replace(/<\/script/gi, "<\\/script");
|
|
345
|
-
}
|
|
346
|
-
static resolveHtmlAssetPath(htmlPath, src) {
|
|
347
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(src) || src.startsWith("//")) {
|
|
348
|
-
throw new Error(`[csr-build] cannot inline external script: ${src}`);
|
|
349
|
-
}
|
|
350
|
-
const normalized = src.startsWith("/") ? src.slice(1) : src;
|
|
351
|
-
return path2.resolve(path2.dirname(htmlPath), normalized);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
131
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
356
|
-
import
|
|
132
|
+
import path3 from "path";
|
|
357
133
|
import { Logger } from "akanjs/common";
|
|
358
134
|
import { compile } from "tailwindcss";
|
|
359
135
|
|
|
@@ -424,7 +200,7 @@ class CssCandidateCache {
|
|
|
424
200
|
}
|
|
425
201
|
|
|
426
202
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
427
|
-
import
|
|
203
|
+
import path2 from "path";
|
|
428
204
|
var CSS_IMPORT_EXTS = ["", ".css", "/styles.css", "/index.css"];
|
|
429
205
|
|
|
430
206
|
class CssImportResolver {
|
|
@@ -467,7 +243,7 @@ class CssImportResolver {
|
|
|
467
243
|
const exact = this.#paths[id];
|
|
468
244
|
if (exact) {
|
|
469
245
|
for (const repl of exact) {
|
|
470
|
-
const resolved = await this.#firstExisting(
|
|
246
|
+
const resolved = await this.#firstExisting(path2.resolve(this.#workspaceRoot, repl));
|
|
471
247
|
if (resolved)
|
|
472
248
|
return resolved;
|
|
473
249
|
}
|
|
@@ -478,7 +254,7 @@ class CssImportResolver {
|
|
|
478
254
|
const suffix = id.slice(prefix.length);
|
|
479
255
|
for (const repl of replacements) {
|
|
480
256
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
481
|
-
const resolved = await this.#firstExisting(
|
|
257
|
+
const resolved = await this.#firstExisting(path2.resolve(this.#workspaceRoot, replPath + suffix));
|
|
482
258
|
if (resolved)
|
|
483
259
|
return resolved;
|
|
484
260
|
}
|
|
@@ -508,34 +284,34 @@ class CssImportResolver {
|
|
|
508
284
|
try {
|
|
509
285
|
if (!await Bun.file(pkgPath).exists())
|
|
510
286
|
return null;
|
|
511
|
-
const pkgDir =
|
|
287
|
+
const pkgDir = path2.dirname(pkgPath);
|
|
512
288
|
const pkg = await Bun.file(pkgPath).json();
|
|
513
289
|
const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
|
|
514
290
|
const exportValue = pkg.exports?.[subpath];
|
|
515
291
|
const exportedEntry = typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default;
|
|
516
292
|
if (exportedEntry)
|
|
517
|
-
return await this.#firstExisting(
|
|
293
|
+
return await this.#firstExisting(path2.resolve(pkgDir, exportedEntry));
|
|
518
294
|
if (subpath !== ".")
|
|
519
|
-
return await this.#firstExisting(
|
|
520
|
-
return await this.#firstExisting(
|
|
295
|
+
return await this.#firstExisting(path2.resolve(pkgDir, subpath));
|
|
296
|
+
return await this.#firstExisting(path2.resolve(pkgDir, pkg.exports?.["."]?.style || pkg.style || "index.css"));
|
|
521
297
|
} catch {
|
|
522
298
|
return null;
|
|
523
299
|
}
|
|
524
300
|
}
|
|
525
301
|
#resolutionBases(fromBase) {
|
|
526
|
-
return [fromBase, this.#workspaceRoot,
|
|
302
|
+
return [fromBase, this.#workspaceRoot, path2.dirname(Bun.main), path2.resolve(path2.dirname(Bun.main), "../..")];
|
|
527
303
|
}
|
|
528
304
|
#packageJsonCandidates(pkgName) {
|
|
529
305
|
return [
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
306
|
+
path2.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
|
|
307
|
+
path2.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
|
|
308
|
+
path2.join(path2.dirname(Bun.main), "node_modules", pkgName, "package.json"),
|
|
309
|
+
path2.join(path2.dirname(Bun.main), "../../", pkgName, "package.json")
|
|
534
310
|
];
|
|
535
311
|
}
|
|
536
312
|
async#firstExisting(basePath) {
|
|
537
313
|
for (const suffix of CSS_IMPORT_EXTS) {
|
|
538
|
-
const candidate =
|
|
314
|
+
const candidate = path2.normalize(`${basePath}${suffix}`);
|
|
539
315
|
if (await Bun.file(candidate).exists())
|
|
540
316
|
return candidate;
|
|
541
317
|
}
|
|
@@ -548,7 +324,7 @@ class CssImportResolver {
|
|
|
548
324
|
return parts[0] ?? null;
|
|
549
325
|
}
|
|
550
326
|
static isCssFile(filePath) {
|
|
551
|
-
return
|
|
327
|
+
return path2.extname(filePath) === ".css";
|
|
552
328
|
}
|
|
553
329
|
}
|
|
554
330
|
|
|
@@ -566,7 +342,7 @@ class CssCompiler {
|
|
|
566
342
|
this.#app = app;
|
|
567
343
|
}
|
|
568
344
|
get #candidateCachePath() {
|
|
569
|
-
return
|
|
345
|
+
return path3.join(this.#app.cwdPath, ".akan/cache/cssCandidates.json");
|
|
570
346
|
}
|
|
571
347
|
#cssText = null;
|
|
572
348
|
#cssTextByBasePath = null;
|
|
@@ -596,7 +372,7 @@ class CssCompiler {
|
|
|
596
372
|
return filePath;
|
|
597
373
|
}
|
|
598
374
|
for (const ext of SOURCE_EXTS) {
|
|
599
|
-
const filePath =
|
|
375
|
+
const filePath = path3.join(absPathNoExt, `index${ext}`);
|
|
600
376
|
if (await this.#fileExists(filePath))
|
|
601
377
|
return filePath;
|
|
602
378
|
}
|
|
@@ -645,14 +421,14 @@ class CssCompiler {
|
|
|
645
421
|
return this.#cssTextByBasePath;
|
|
646
422
|
}
|
|
647
423
|
async#warnUnreachableStylesheets() {
|
|
648
|
-
const pageDir =
|
|
424
|
+
const pageDir = path3.join(this.#app.cwdPath, "page");
|
|
649
425
|
const glob = new Bun.Glob("**/*.css");
|
|
650
426
|
for await (const cssPath of glob.scan({ cwd: pageDir, absolute: true })) {
|
|
651
|
-
if (cssPath.includes(`${
|
|
427
|
+
if (cssPath.includes(`${path3.sep}(libs)${path3.sep}`))
|
|
652
428
|
continue;
|
|
653
429
|
if (this.#discoveredCssPaths.has(cssPath))
|
|
654
430
|
continue;
|
|
655
|
-
this.#logger.warn(`css ${
|
|
431
|
+
this.#logger.warn(`css ${path3.relative(this.#app.cwdPath, cssPath)} is imported by no route and never compiled`);
|
|
656
432
|
}
|
|
657
433
|
}
|
|
658
434
|
async discoverCss({ refresh } = {}) {
|
|
@@ -664,7 +440,7 @@ class CssCompiler {
|
|
|
664
440
|
pageKeys
|
|
665
441
|
} = {}) {
|
|
666
442
|
pageKeys ??= await this.#app.getPageKeys({ refresh });
|
|
667
|
-
const seeds = pageKeys.map((key) =>
|
|
443
|
+
const seeds = pageKeys.map((key) => path3.resolve(this.#app.cwdPath, "page", key));
|
|
668
444
|
const cssFiles = new Set;
|
|
669
445
|
const sourceFiles = new Set;
|
|
670
446
|
const queue = [...seeds];
|
|
@@ -696,7 +472,7 @@ class CssCompiler {
|
|
|
696
472
|
} catch {
|
|
697
473
|
continue;
|
|
698
474
|
}
|
|
699
|
-
const importerDir =
|
|
475
|
+
const importerDir = path3.dirname(filePath);
|
|
700
476
|
for (const imp of imports) {
|
|
701
477
|
const spec = imp.path;
|
|
702
478
|
if (!spec)
|
|
@@ -721,18 +497,18 @@ class CssCompiler {
|
|
|
721
497
|
return { cssPaths, sourcePaths: [...sourceFiles] };
|
|
722
498
|
}
|
|
723
499
|
async#libTokenStylesheets(sourceFiles) {
|
|
724
|
-
const libsRoot =
|
|
500
|
+
const libsRoot = path3.join(this.#app.workspace.workspaceRoot, "libs");
|
|
725
501
|
const libNames = new Set;
|
|
726
502
|
for (const filePath of sourceFiles) {
|
|
727
|
-
const relPath =
|
|
728
|
-
if (relPath.startsWith("..") ||
|
|
503
|
+
const relPath = path3.relative(libsRoot, filePath);
|
|
504
|
+
if (relPath.startsWith("..") || path3.isAbsolute(relPath))
|
|
729
505
|
continue;
|
|
730
|
-
const [libName] = relPath.split(
|
|
506
|
+
const [libName] = relPath.split(path3.sep);
|
|
731
507
|
if (libName)
|
|
732
508
|
libNames.add(libName);
|
|
733
509
|
}
|
|
734
510
|
const tokenPaths = await Promise.all([...libNames].sort().map(async (libName) => {
|
|
735
|
-
const tokensPath =
|
|
511
|
+
const tokensPath = path3.join(libsRoot, libName, "ui/tokens.css");
|
|
736
512
|
return await this.#fileExists(tokensPath) ? tokensPath : null;
|
|
737
513
|
}));
|
|
738
514
|
return tokenPaths.filter((tokensPath) => !!tokensPath);
|
|
@@ -747,7 +523,7 @@ class CssCompiler {
|
|
|
747
523
|
const compileStarted = Date.now();
|
|
748
524
|
const compilers = await Promise.all(cssPaths.map(async (cssPath) => {
|
|
749
525
|
const css = await Bun.file(cssPath).text();
|
|
750
|
-
const base =
|
|
526
|
+
const base = path3.dirname(cssPath);
|
|
751
527
|
const imported = new Map;
|
|
752
528
|
const compiler = await compile(css, {
|
|
753
529
|
base,
|
|
@@ -787,11 +563,11 @@ class CssCompiler {
|
|
|
787
563
|
const content = await Bun.file(p).text();
|
|
788
564
|
imported?.set(p, content);
|
|
789
565
|
this.#logger.verbose(`css import "${id}" from ${fromBase} -> ${p} (${content.length} bytes)`);
|
|
790
|
-
return { path: p, base:
|
|
566
|
+
return { path: p, base: path3.dirname(p), content };
|
|
791
567
|
}
|
|
792
568
|
async#resolveCssImport(id, fromBase) {
|
|
793
569
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
794
|
-
const filePath =
|
|
570
|
+
const filePath = path3.resolve(fromBase, id);
|
|
795
571
|
if (await this.#fileExists(filePath))
|
|
796
572
|
return filePath;
|
|
797
573
|
throw new Error(`[css] failed to resolve stylesheet import "${id}" from ${fromBase} (no file at ${filePath})`);
|
|
@@ -805,7 +581,7 @@ class CssCompiler {
|
|
|
805
581
|
async#loadModule(id, fromBase) {
|
|
806
582
|
const p = __require.resolve(id, { paths: [fromBase] });
|
|
807
583
|
const mod = await import(p);
|
|
808
|
-
return { path: p, base:
|
|
584
|
+
return { path: p, base: path3.dirname(p), module: mod.default ?? mod };
|
|
809
585
|
}
|
|
810
586
|
#resolveSourceImport(id, fromBase, resolvePackage) {
|
|
811
587
|
const cacheKey = `${fromBase}\x00${id}`;
|
|
@@ -818,7 +594,7 @@ class CssCompiler {
|
|
|
818
594
|
}
|
|
819
595
|
async#resolveSourceImportUncached(id, fromBase, resolvePackage) {
|
|
820
596
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
821
|
-
const abs = id.startsWith("/") ? id :
|
|
597
|
+
const abs = id.startsWith("/") ? id : path3.resolve(fromBase, id);
|
|
822
598
|
return this.#resolveSourceFileCandidate(abs);
|
|
823
599
|
}
|
|
824
600
|
const pkg = await resolvePackage(id);
|
|
@@ -869,7 +645,7 @@ function resolveSourceWithRequire(id, fromBase) {
|
|
|
869
645
|
}
|
|
870
646
|
}
|
|
871
647
|
function isSourceFile(filePath) {
|
|
872
|
-
return SOURCE_EXTS.has(
|
|
648
|
+
return SOURCE_EXTS.has(path3.extname(filePath));
|
|
873
649
|
}
|
|
874
650
|
function isIgnoredNodeModuleSource(filePath) {
|
|
875
651
|
return NODE_MODULES_RE.test(filePath) && !AKANJS_NODE_MODULE_RE.test(filePath);
|
|
@@ -883,8 +659,8 @@ function getPageKeyBasePath(pageKey, basePaths) {
|
|
|
883
659
|
}
|
|
884
660
|
|
|
885
661
|
// pkgs/@akanjs/devkit/frontendBuild/fontOptimizer.ts
|
|
886
|
-
import { mkdir
|
|
887
|
-
import
|
|
662
|
+
import { mkdir, stat as stat2 } from "fs/promises";
|
|
663
|
+
import path4 from "path";
|
|
888
664
|
import ts from "typescript";
|
|
889
665
|
var FONT_URL_PREFIX = "/_akan/fonts";
|
|
890
666
|
var DEFAULT_FONT_SUBSETS = ["latin"];
|
|
@@ -901,7 +677,7 @@ class FontOptimizer {
|
|
|
901
677
|
constructor(app, command = "start") {
|
|
902
678
|
this.#app = app;
|
|
903
679
|
this.#command = command;
|
|
904
|
-
this.#artifactRoot =
|
|
680
|
+
this.#artifactRoot = path4.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
|
|
905
681
|
}
|
|
906
682
|
async optimize() {
|
|
907
683
|
const fonts = await this.discoverFonts();
|
|
@@ -926,7 +702,7 @@ class FontOptimizer {
|
|
|
926
702
|
return result;
|
|
927
703
|
}
|
|
928
704
|
get #cachePath() {
|
|
929
|
-
return
|
|
705
|
+
return path4.join(this.#artifactRoot, "fontCache.json");
|
|
930
706
|
}
|
|
931
707
|
async#buildCacheKey(fonts) {
|
|
932
708
|
const sources = [];
|
|
@@ -941,7 +717,7 @@ class FontOptimizer {
|
|
|
941
717
|
sources.push({ optimizedSrc: face.optimizedSrc, ...stamp });
|
|
942
718
|
}
|
|
943
719
|
for (const filePath of font.subsetFiles ?? []) {
|
|
944
|
-
const abs =
|
|
720
|
+
const abs = path4.isAbsolute(filePath) ? filePath : path4.join(this.#app.cwdPath, filePath);
|
|
945
721
|
const stamp = await this.#fileStamp(abs);
|
|
946
722
|
if (!stamp)
|
|
947
723
|
return null;
|
|
@@ -967,7 +743,7 @@ class FontOptimizer {
|
|
|
967
743
|
const cache = await Bun.file(this.#cachePath).json().catch(() => null);
|
|
968
744
|
if (cache?.version !== FontOptimizer.#cacheVersion || cache.key !== key)
|
|
969
745
|
return null;
|
|
970
|
-
const files = cache.files.map((relativePath) =>
|
|
746
|
+
const files = cache.files.map((relativePath) => path4.join(this.#artifactRoot, relativePath));
|
|
971
747
|
for (const filePath of files) {
|
|
972
748
|
if (!await Bun.file(filePath).exists())
|
|
973
749
|
return null;
|
|
@@ -979,7 +755,7 @@ class FontOptimizer {
|
|
|
979
755
|
version: FontOptimizer.#cacheVersion,
|
|
980
756
|
key,
|
|
981
757
|
css: result.css,
|
|
982
|
-
files: result.files.map((filePath) =>
|
|
758
|
+
files: result.files.map((filePath) => path4.relative(this.#artifactRoot, filePath))
|
|
983
759
|
};
|
|
984
760
|
await Bun.write(this.#cachePath, JSON.stringify(cache));
|
|
985
761
|
}
|
|
@@ -987,7 +763,7 @@ class FontOptimizer {
|
|
|
987
763
|
const pageKeys = await this.#app.getPageKeys();
|
|
988
764
|
const fonts = [];
|
|
989
765
|
await Promise.all(pageKeys.map(async (key) => {
|
|
990
|
-
const filePath =
|
|
766
|
+
const filePath = path4.resolve(this.#app.cwdPath, "page", key);
|
|
991
767
|
const file = Bun.file(filePath);
|
|
992
768
|
if (!await file.exists())
|
|
993
769
|
return;
|
|
@@ -1006,8 +782,8 @@ class FontOptimizer {
|
|
|
1006
782
|
this.#app.logger.warn(`[font] source not found: ${face.src}`);
|
|
1007
783
|
continue;
|
|
1008
784
|
}
|
|
1009
|
-
const outputPath =
|
|
1010
|
-
await
|
|
785
|
+
const outputPath = path4.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
|
|
786
|
+
await mkdir(path4.dirname(outputPath), { recursive: true });
|
|
1011
787
|
const sourceBuffer = Buffer.from(await Bun.file(sourcePath).arrayBuffer());
|
|
1012
788
|
const outputBuffer = await this.#buildFontBuffer(font, sourceBuffer, sourcePath);
|
|
1013
789
|
await Bun.write(outputPath, outputBuffer);
|
|
@@ -1029,7 +805,7 @@ class FontOptimizer {
|
|
|
1029
805
|
const entries = Array.isArray(value) ? value : [];
|
|
1030
806
|
const fonts = entries.filter((entry) => this.#isReadableFont(entry));
|
|
1031
807
|
if (fonts.length !== entries.length || !Array.isArray(value))
|
|
1032
|
-
this.#app.logger.warn(`[font] ${
|
|
808
|
+
this.#app.logger.warn(`[font] ${path4.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`);
|
|
1033
809
|
return fonts.map((font) => ({ ...font, subsets: font.subsets ?? [...DEFAULT_FONT_SUBSETS] }));
|
|
1034
810
|
}
|
|
1035
811
|
#isReadableFont(value) {
|
|
@@ -1187,8 +963,8 @@ class FontOptimizer {
|
|
|
1187
963
|
return null;
|
|
1188
964
|
const rel = src.replace(/^\//, "");
|
|
1189
965
|
const candidates = [
|
|
1190
|
-
this.#command === "build" ?
|
|
1191
|
-
|
|
966
|
+
this.#command === "build" ? path4.join(this.#app.dist.cwdPath, "public", rel) : null,
|
|
967
|
+
path4.join(this.#app.cwdPath, "public", rel),
|
|
1192
968
|
this.#resolveWorkspacePublicPath(rel)
|
|
1193
969
|
].filter(Boolean);
|
|
1194
970
|
for (const candidate of candidates) {
|
|
@@ -1220,7 +996,7 @@ class FontOptimizer {
|
|
|
1220
996
|
return "woff2";
|
|
1221
997
|
if (signature === "OTTO")
|
|
1222
998
|
return "otf";
|
|
1223
|
-
const ext =
|
|
999
|
+
const ext = path4.extname(sourcePath).slice(1).toLowerCase();
|
|
1224
1000
|
if (ext === "otf" || ext === "woff" || ext === "woff2")
|
|
1225
1001
|
return ext;
|
|
1226
1002
|
return "ttf";
|
|
@@ -1229,7 +1005,7 @@ class FontOptimizer {
|
|
|
1229
1005
|
const [root, dep, ...rest] = rel.split("/");
|
|
1230
1006
|
if (root !== "libs" || !dep || rest.length === 0)
|
|
1231
1007
|
return null;
|
|
1232
|
-
return
|
|
1008
|
+
return path4.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
|
|
1233
1009
|
}
|
|
1234
1010
|
async#getSubsetText(font) {
|
|
1235
1011
|
const parts = new Set;
|
|
@@ -1239,7 +1015,7 @@ class FontOptimizer {
|
|
|
1239
1015
|
if (font.subsetText)
|
|
1240
1016
|
parts.add(font.subsetText);
|
|
1241
1017
|
for (const filePath of font.subsetFiles ?? []) {
|
|
1242
|
-
const abs =
|
|
1018
|
+
const abs = path4.isAbsolute(filePath) ? filePath : path4.join(this.#app.cwdPath, filePath);
|
|
1243
1019
|
const file = Bun.file(abs);
|
|
1244
1020
|
if (await file.exists())
|
|
1245
1021
|
parts.add(await file.text());
|
|
@@ -1259,7 +1035,7 @@ class FontOptimizer {
|
|
|
1259
1035
|
}
|
|
1260
1036
|
async#collectAutoSubsetText() {
|
|
1261
1037
|
const libPageRoots = (await this.#app.getPageRoots()).filter((root) => root.keyPrefix).map((root) => root.dir);
|
|
1262
|
-
const roots = [...["page", "ui", "lib"].map((dir) =>
|
|
1038
|
+
const roots = [...["page", "ui", "lib"].map((dir) => path4.join(this.#app.cwdPath, dir)), ...libPageRoots];
|
|
1263
1039
|
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,html,md}");
|
|
1264
1040
|
const parts = [];
|
|
1265
1041
|
for (const root of [...new Set(roots)].sort()) {
|
|
@@ -1372,8 +1148,8 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
|
|
|
1372
1148
|
}
|
|
1373
1149
|
|
|
1374
1150
|
// pkgs/@akanjs/devkit/frontendBuild/fontPruner.ts
|
|
1375
|
-
import { rm
|
|
1376
|
-
import
|
|
1151
|
+
import { rm, rmdir, stat as stat3 } from "fs/promises";
|
|
1152
|
+
import path5 from "path";
|
|
1377
1153
|
import { isFontOptimizationEnabled } from "akanjs/client";
|
|
1378
1154
|
var FONT_GLOB = "**/*.{woff2,woff,ttf,otf,ttc,eot}";
|
|
1379
1155
|
var REFERRER_GLOB = "**/*.{css,js,mjs,cjs,json,html,htm,svg,xml,webmanifest}";
|
|
@@ -1386,8 +1162,8 @@ class FontPruner {
|
|
|
1386
1162
|
constructor(app, { keepFonts = [] } = {}) {
|
|
1387
1163
|
this.#app = app;
|
|
1388
1164
|
this.#keepGlobs = keepFonts;
|
|
1389
|
-
this.#publicRoot =
|
|
1390
|
-
this.#artifactRoot =
|
|
1165
|
+
this.#publicRoot = path5.join(app.dist.cwdPath, "public");
|
|
1166
|
+
this.#artifactRoot = path5.join(app.dist.cwdPath, ".akan/artifact");
|
|
1391
1167
|
}
|
|
1392
1168
|
async prune() {
|
|
1393
1169
|
const empty = { removed: [], kept: [], freedBytes: 0 };
|
|
@@ -1402,7 +1178,7 @@ class FontPruner {
|
|
|
1402
1178
|
for (const font of fonts) {
|
|
1403
1179
|
const target = isFontOptimizationEnabled(font) ? optimizedSrcs : unoptimizedSrcs;
|
|
1404
1180
|
for (const fontPath of font.paths)
|
|
1405
|
-
target.add(
|
|
1181
|
+
target.add(path5.posix.basename(fontPath.src));
|
|
1406
1182
|
}
|
|
1407
1183
|
const result = { removed: [], kept: [], freedBytes: 0 };
|
|
1408
1184
|
const undecided = [];
|
|
@@ -1440,10 +1216,10 @@ class FontPruner {
|
|
|
1440
1216
|
async#collectCandidates() {
|
|
1441
1217
|
const candidates = [];
|
|
1442
1218
|
for await (const rel of new Bun.Glob(FONT_GLOB).scan({ cwd: this.#publicRoot, dot: false })) {
|
|
1443
|
-
const entry = await stat3(
|
|
1219
|
+
const entry = await stat3(path5.join(this.#publicRoot, rel)).catch(() => null);
|
|
1444
1220
|
if (!entry?.isFile())
|
|
1445
1221
|
continue;
|
|
1446
|
-
candidates.push({ rel: rel.split(
|
|
1222
|
+
candidates.push({ rel: rel.split(path5.sep).join("/"), basename: path5.basename(rel), bytes: entry.size });
|
|
1447
1223
|
}
|
|
1448
1224
|
return candidates;
|
|
1449
1225
|
}
|
|
@@ -1453,11 +1229,11 @@ class FontPruner {
|
|
|
1453
1229
|
const bundled = candidates.filter((candidate) => !optimizedSrcs.has(candidate.basename));
|
|
1454
1230
|
const roots = [
|
|
1455
1231
|
{ dir: this.#publicRoot, label: "public", needles: authoritative },
|
|
1456
|
-
{ dir:
|
|
1457
|
-
{ dir:
|
|
1458
|
-
{ dir:
|
|
1459
|
-
{ dir:
|
|
1460
|
-
{ dir:
|
|
1232
|
+
{ dir: path5.join(this.#artifactRoot, "styles"), label: ".akan/artifact/styles", needles: authoritative },
|
|
1233
|
+
{ dir: path5.join(this.#artifactRoot, "client"), label: ".akan/artifact/client", needles: bundled },
|
|
1234
|
+
{ dir: path5.join(this.#artifactRoot, "client-ssr"), label: ".akan/artifact/client-ssr", needles: bundled },
|
|
1235
|
+
{ dir: path5.join(this.#artifactRoot, "server"), label: ".akan/artifact/server", needles: bundled },
|
|
1236
|
+
{ dir: path5.join(this.#app.dist.cwdPath, "csr"), label: "csr", needles: bundled }
|
|
1461
1237
|
];
|
|
1462
1238
|
for (const root of roots) {
|
|
1463
1239
|
const pending = root.needles.filter((candidate) => !referrers.has(candidate.rel));
|
|
@@ -1476,20 +1252,20 @@ class FontPruner {
|
|
|
1476
1252
|
const remaining = needles.filter((needle) => !referrers.has(needle.rel));
|
|
1477
1253
|
if (!remaining.length)
|
|
1478
1254
|
return;
|
|
1479
|
-
const text = await Bun.file(
|
|
1255
|
+
const text = await Bun.file(path5.join(root.dir, rel)).text().catch(() => "");
|
|
1480
1256
|
if (!text)
|
|
1481
1257
|
continue;
|
|
1482
1258
|
for (const needle of remaining) {
|
|
1483
1259
|
if (needle.forms.some((form) => text.includes(form)))
|
|
1484
|
-
referrers.set(needle.rel, `${root.label}/${rel.split(
|
|
1260
|
+
referrers.set(needle.rel, `${root.label}/${rel.split(path5.sep).join("/")}`);
|
|
1485
1261
|
}
|
|
1486
1262
|
}
|
|
1487
1263
|
}
|
|
1488
1264
|
async#remove(files) {
|
|
1489
|
-
await Promise.all(files.map((file) =>
|
|
1490
|
-
const dirs = [...new Set(files.map((file) =>
|
|
1265
|
+
await Promise.all(files.map((file) => rm(path5.join(this.#publicRoot, file), { force: true })));
|
|
1266
|
+
const dirs = [...new Set(files.map((file) => path5.posix.dirname(file)))].filter((dir) => dir !== "." && dir !== "/").sort((a, b) => b.length - a.length);
|
|
1491
1267
|
for (const dir of dirs)
|
|
1492
|
-
await rmdir(
|
|
1268
|
+
await rmdir(path5.join(this.#publicRoot, dir)).catch(() => {
|
|
1493
1269
|
return;
|
|
1494
1270
|
});
|
|
1495
1271
|
}
|
|
@@ -1537,7 +1313,7 @@ class FontPruner {
|
|
|
1537
1313
|
|
|
1538
1314
|
// pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
|
|
1539
1315
|
import fs from "fs";
|
|
1540
|
-
import
|
|
1316
|
+
import path6 from "path";
|
|
1541
1317
|
import zlib from "zlib";
|
|
1542
1318
|
var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
|
|
1543
1319
|
var MIN_COMPRESS_BYTES = 1024;
|
|
@@ -1547,8 +1323,8 @@ var GZIP_LEVEL = 9;
|
|
|
1547
1323
|
var { formatBytes } = FontPruner;
|
|
1548
1324
|
async function precompressArtifacts(app) {
|
|
1549
1325
|
const roots = [
|
|
1550
|
-
|
|
1551
|
-
|
|
1326
|
+
path6.join(app.dist.cwdPath, ".akan/artifact/client"),
|
|
1327
|
+
path6.join(app.dist.cwdPath, ".akan/artifact/styles")
|
|
1552
1328
|
];
|
|
1553
1329
|
const result = { files: 0, inputBytes: 0, outputBytes: 0, brotliBytes: 0 };
|
|
1554
1330
|
await Promise.all(roots.map((root) => precompressRoot(root, result)));
|
|
@@ -1567,7 +1343,7 @@ async function precompressRoot(root, result) {
|
|
|
1567
1343
|
const bytes = await Bun.file(filePath).bytes();
|
|
1568
1344
|
const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
1569
1345
|
const gz = Bun.gzipSync(buffer, { level: GZIP_LEVEL });
|
|
1570
|
-
const br = brotliCompress(buffer,
|
|
1346
|
+
const br = brotliCompress(buffer, path6.extname(filePath).toLowerCase());
|
|
1571
1347
|
await Promise.all([Bun.write(`${filePath}.gz`, gz), Bun.write(`${filePath}.br`, br)]);
|
|
1572
1348
|
result.files += 1;
|
|
1573
1349
|
result.inputBytes += bytes.byteLength;
|
|
@@ -1587,7 +1363,7 @@ function brotliCompress(buffer, ext) {
|
|
|
1587
1363
|
async function shouldPrecompress(filePath) {
|
|
1588
1364
|
if (filePath.endsWith(".gz") || filePath.endsWith(".br"))
|
|
1589
1365
|
return false;
|
|
1590
|
-
if (!COMPRESSIBLE_EXTS.has(
|
|
1366
|
+
if (!COMPRESSIBLE_EXTS.has(path6.extname(filePath).toLowerCase()))
|
|
1591
1367
|
return false;
|
|
1592
1368
|
const file = Bun.file(filePath);
|
|
1593
1369
|
if (!await file.exists())
|
|
@@ -1596,7 +1372,7 @@ async function shouldPrecompress(filePath) {
|
|
|
1596
1372
|
}
|
|
1597
1373
|
|
|
1598
1374
|
// pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
|
|
1599
|
-
import
|
|
1375
|
+
import path7 from "path";
|
|
1600
1376
|
import { optimize } from "@tailwindcss/node";
|
|
1601
1377
|
function prepareCssAsset(command, basePath, cssText) {
|
|
1602
1378
|
return optimize(cssText, { file: `${basePath || "root"}.css`, minify: command === "build" }).code;
|
|
@@ -1614,7 +1390,7 @@ class SsrBaseArtifactBuilder {
|
|
|
1614
1390
|
this.#command = command;
|
|
1615
1391
|
this.#serverEnv = serverEnv;
|
|
1616
1392
|
this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
|
|
1617
|
-
this.#absArtifactDir =
|
|
1393
|
+
this.#absArtifactDir = path7.resolve(this.#artifactDir);
|
|
1618
1394
|
}
|
|
1619
1395
|
static servedWeb(command, web) {
|
|
1620
1396
|
return command === "start" ? { ssr: true, csr: true } : web;
|
|
@@ -1639,7 +1415,7 @@ class SsrBaseArtifactBuilder {
|
|
|
1639
1415
|
rscRuntimeSsrManifest,
|
|
1640
1416
|
vendorMap,
|
|
1641
1417
|
cssAssets,
|
|
1642
|
-
pagesBundlePath: this.#command === "build" ?
|
|
1418
|
+
pagesBundlePath: this.#command === "build" ? path7.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
|
|
1643
1419
|
pagesBundleBuildId: pagesBundle.buildId,
|
|
1644
1420
|
domains: [...akanConfig.domains],
|
|
1645
1421
|
subRoutes: Object.fromEntries(Array.from(akanConfig.subRoutes.entries()).map(([basePath, domains]) => [basePath, [...domains]])),
|
|
@@ -1657,18 +1433,18 @@ class SsrBaseArtifactBuilder {
|
|
|
1657
1433
|
androidSha256CertFingerprints: target.android?.sha256CertFingerprints
|
|
1658
1434
|
}))
|
|
1659
1435
|
};
|
|
1660
|
-
await Bun.write(
|
|
1436
|
+
await Bun.write(path7.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
|
|
1661
1437
|
`);
|
|
1662
1438
|
this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
|
|
1663
1439
|
return { artifact, seedIndex, cssCompiler, optimizedFonts };
|
|
1664
1440
|
}
|
|
1665
1441
|
async#buildRuntimeClientEntries() {
|
|
1666
1442
|
const akanServerPath = await this.#resolveAkanServerPath();
|
|
1667
|
-
const rscClientEntry =
|
|
1668
|
-
const rscSegmentOutletEntry =
|
|
1443
|
+
const rscClientEntry = path7.resolve(akanServerPath, "rscClient.tsx");
|
|
1444
|
+
const rscSegmentOutletEntry = path7.resolve(akanServerPath, "rscSegmentOutlet.tsx");
|
|
1669
1445
|
const vendorEntries = VENDOR_SPECIFIERS.map((specifier) => ({
|
|
1670
1446
|
specifier,
|
|
1671
|
-
absPath:
|
|
1447
|
+
absPath: path7.resolve(akanServerPath, "vendor", `${specifier.replaceAll("/", "-").replaceAll(".", "-")}.ts`)
|
|
1672
1448
|
}));
|
|
1673
1449
|
const entries = [rscClientEntry, rscSegmentOutletEntry, ...vendorEntries.map((v) => v.absPath)];
|
|
1674
1450
|
const clientBundle = await new ClientEntriesBundler({ app: this.#app, entries, command: this.#command }).bundle();
|
|
@@ -1705,15 +1481,15 @@ class SsrBaseArtifactBuilder {
|
|
|
1705
1481
|
async#resolveAkanServerPath() {
|
|
1706
1482
|
const candidates = [];
|
|
1707
1483
|
try {
|
|
1708
|
-
candidates.push(
|
|
1484
|
+
candidates.push(path7.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
|
|
1709
1485
|
} catch {}
|
|
1710
|
-
candidates.push(
|
|
1486
|
+
candidates.push(path7.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path7.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
|
|
1711
1487
|
try {
|
|
1712
|
-
candidates.push(
|
|
1488
|
+
candidates.push(path7.dirname(Bun.resolveSync("akanjs/server", path7.dirname(Bun.main))));
|
|
1713
1489
|
} catch {}
|
|
1714
|
-
candidates.push(
|
|
1490
|
+
candidates.push(path7.join(path7.dirname(Bun.main), "node_modules/akanjs/server"), path7.join(path7.dirname(Bun.main), "../../akanjs/server"), path7.resolve(import.meta.dir, "../../server"), path7.resolve(import.meta.dir, "../server"));
|
|
1715
1491
|
for (const candidate of candidates) {
|
|
1716
|
-
if (await Bun.file(
|
|
1492
|
+
if (await Bun.file(path7.join(candidate, "rscClient.tsx")).exists())
|
|
1717
1493
|
return candidate;
|
|
1718
1494
|
}
|
|
1719
1495
|
throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
|
|
@@ -1742,7 +1518,7 @@ ${preparedCssText}`).toString(36);
|
|
|
1742
1518
|
`styles/${cssAssetName}-${cssHash}.css`,
|
|
1743
1519
|
`/_akan/styles/${cssAssetName}-${cssHash}.css`
|
|
1744
1520
|
];
|
|
1745
|
-
await Bun.write(
|
|
1521
|
+
await Bun.write(path7.join(this.#absArtifactDir, cssRelPath), preparedCssText);
|
|
1746
1522
|
SsrBaseArtifactBuilder.#warnDroppedImports(this.#app, cssRelPath, preparedCssText, imported);
|
|
1747
1523
|
this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath} -> ${cssRelPath}`);
|
|
1748
1524
|
return [basePath, { cssUrl, cssRelPath }];
|
|
@@ -1758,4 +1534,4 @@ ${preparedCssText}`).toString(36);
|
|
|
1758
1534
|
}
|
|
1759
1535
|
}
|
|
1760
1536
|
}
|
|
1761
|
-
export { AllRoutesBuilder,
|
|
1537
|
+
export { AllRoutesBuilder, CssCompiler, FontOptimizer, FontPruner, precompressArtifacts, SsrBaseArtifactBuilder };
|