gofront 1.3.9 → 1.3.10
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/README.md +16 -0
- package/package.json +1 -1
- package/src/asset-manager.js +4 -25
- package/src/cli-core.js +18 -22
- package/src/minifier.js +46 -2
- package/src/project-config.js +23 -0
- package/src/vendor.js +2 -9
package/README.md
CHANGED
|
@@ -401,7 +401,23 @@ gofront init [dir] scaffold a new project
|
|
|
401
401
|
gofront --version / -v print version
|
|
402
402
|
gofront --help / -h print this help
|
|
403
403
|
```
|
|
404
|
+
### Project configuration
|
|
404
405
|
|
|
406
|
+
`gofront dev`, `build`, `prep`, `check` and `test` read optional settings from a `gofront.json`
|
|
407
|
+
file or a `"gofront": { … }` object in `package.json`:
|
|
408
|
+
|
|
409
|
+
| Key | Default | Description |
|
|
410
|
+
|---|---|---|
|
|
411
|
+
| `src` | `app/src`, `src` or `main.go` | Package directory (or single file) to compile |
|
|
412
|
+
| `serveDir` | `app`, `.` or `public` (first with `index.html`) | Directory served by `dev` and mirrored into the build |
|
|
413
|
+
| `outDir` | `public` | Release output directory for `build` |
|
|
414
|
+
| `output` | `app/app.js` | Dev-mode compiled bundle path |
|
|
415
|
+
| `port` | `3000` | Dev server port |
|
|
416
|
+
| `assetExtensions` | `[]` | Extra file extensions (e.g. `[".bmesh", ".mat"]`) copied from `serveDir` into `outDir` on `build`, in addition to the built-in web asset list (html, css, js, json, images, fonts, audio, video, wasm) |
|
|
417
|
+
| `vendor` | `app/vendor.js` | Vendor bundle written by `prep`/`build` from `package.json` `dependencies`. Either a destination path string or `{ "dest": string \| string[], "packages": string[], "minify": boolean, "globals": { "<pkg>": string \| string[] } }` |
|
|
418
|
+
| `assetCopy` | `[]` | Static files copied by `prep`/`build`: `[{ "source": "node_modules/x/font.woff2", "dest": "app/fonts/font.woff2" }]` |
|
|
419
|
+
|
|
420
|
+
All settings live in this one place — top-level `"vendor"` / `"assetCopy"` keys in `package.json` are not read.
|
|
405
421
|
---
|
|
406
422
|
|
|
407
423
|
## Multi-file packages
|
package/package.json
CHANGED
package/src/asset-manager.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
// Native static asset manager for GoFront projects.
|
|
2
2
|
// Zero-dependency file and directory copier using node:fs.
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
copyFileSync,
|
|
6
|
-
cpSync,
|
|
7
|
-
existsSync,
|
|
8
|
-
mkdirSync,
|
|
9
|
-
readFileSync,
|
|
10
|
-
statSync,
|
|
11
|
-
} from "node:fs";
|
|
4
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync, statSync } from "node:fs";
|
|
12
5
|
import {
|
|
13
6
|
basename,
|
|
14
7
|
dirname,
|
|
@@ -18,25 +11,11 @@ import {
|
|
|
18
11
|
resolve,
|
|
19
12
|
sep,
|
|
20
13
|
} from "node:path";
|
|
14
|
+
import { loadProjectConfig } from "./project-config.js";
|
|
21
15
|
|
|
22
16
|
export function loadAssetConfig(projectDir) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const parsed = JSON.parse(readFileSync(gofrontJsonPath, "utf8"));
|
|
27
|
-
if (Array.isArray(parsed.assetCopy)) return parsed.assetCopy;
|
|
28
|
-
} catch {}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const pkgJsonPath = join(projectDir, "package.json");
|
|
32
|
-
if (existsSync(pkgJsonPath)) {
|
|
33
|
-
try {
|
|
34
|
-
const parsed = JSON.parse(readFileSync(pkgJsonPath, "utf8"));
|
|
35
|
-
if (Array.isArray(parsed.assetCopy)) return parsed.assetCopy;
|
|
36
|
-
} catch {}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return [];
|
|
17
|
+
const entries = loadProjectConfig(projectDir).assetCopy;
|
|
18
|
+
return Array.isArray(entries) ? entries : [];
|
|
40
19
|
}
|
|
41
20
|
|
|
42
21
|
function copyFileAsset(srcPath, destPath, dest) {
|
package/src/cli-core.js
CHANGED
|
@@ -26,6 +26,7 @@ import { copyAssets } from "./asset-manager.js";
|
|
|
26
26
|
import { compileDir, compileSingleFile } from "./compiler.js";
|
|
27
27
|
import { createDevServer } from "./dev-server.js";
|
|
28
28
|
import { minify } from "./minifier.js";
|
|
29
|
+
import { loadProjectConfig } from "./project-config.js";
|
|
29
30
|
import { generatePwa } from "./pwa.js";
|
|
30
31
|
import { runTests } from "./test-runner.js";
|
|
31
32
|
import { bundleVendor } from "./vendor.js";
|
|
@@ -314,25 +315,6 @@ export function findPackageDirs(root) {
|
|
|
314
315
|
|
|
315
316
|
// ── Project detection ─────────────────────────────────────────
|
|
316
317
|
|
|
317
|
-
function loadProjectConfig(projectRoot) {
|
|
318
|
-
const gofrontJson = join(projectRoot, "gofront.json");
|
|
319
|
-
if (existsSync(gofrontJson)) {
|
|
320
|
-
try {
|
|
321
|
-
return JSON.parse(readFileSync(gofrontJson, "utf8"));
|
|
322
|
-
} catch {}
|
|
323
|
-
}
|
|
324
|
-
const pkgJson = join(projectRoot, "package.json");
|
|
325
|
-
if (existsSync(pkgJson)) {
|
|
326
|
-
try {
|
|
327
|
-
const pkg = JSON.parse(readFileSync(pkgJson, "utf8"));
|
|
328
|
-
if (pkg.gofront && typeof pkg.gofront === "object") {
|
|
329
|
-
return pkg.gofront;
|
|
330
|
-
}
|
|
331
|
-
} catch {}
|
|
332
|
-
}
|
|
333
|
-
return {};
|
|
334
|
-
}
|
|
335
|
-
|
|
336
318
|
function resolveSrcDir(projectRoot, config) {
|
|
337
319
|
const src = config.src || config.input;
|
|
338
320
|
if (src) return isAbsolute(src) ? src : resolve(projectRoot, src);
|
|
@@ -562,10 +544,23 @@ const STATIC_ASSET_EXTS = new Set([
|
|
|
562
544
|
|
|
563
545
|
const ROOT_CONFIG_EXTS = new Set([".js", ".mjs", ".json"]);
|
|
564
546
|
|
|
547
|
+
// Builds the asset extension whitelist: defaults plus any `assetExtensions` from project config.
|
|
548
|
+
export function resolveAssetExtensions(config = {}) {
|
|
549
|
+
const exts = new Set(STATIC_ASSET_EXTS);
|
|
550
|
+
const extra = config.assetExtensions;
|
|
551
|
+
if (!Array.isArray(extra)) return exts;
|
|
552
|
+
for (const raw of extra) {
|
|
553
|
+
if (typeof raw !== "string" || raw.trim() === "") continue;
|
|
554
|
+
const ext = raw.trim().toLowerCase();
|
|
555
|
+
exts.add(ext.startsWith(".") ? ext : `.${ext}`);
|
|
556
|
+
}
|
|
557
|
+
return exts;
|
|
558
|
+
}
|
|
559
|
+
|
|
565
560
|
// Whether a file in the served directory is a web asset worth copying to the build output.
|
|
566
|
-
function isStaticAsset(name, atProjectRoot) {
|
|
561
|
+
function isStaticAsset(name, atProjectRoot, exts = STATIC_ASSET_EXTS) {
|
|
567
562
|
const ext = extname(name).toLowerCase();
|
|
568
|
-
if (!
|
|
563
|
+
if (!exts.has(ext)) return false;
|
|
569
564
|
// At the project root, .js/.json files are tooling config, not web assets.
|
|
570
565
|
if (atProjectRoot && ROOT_CONFIG_EXTS.has(ext))
|
|
571
566
|
return name === "manifest.json";
|
|
@@ -578,6 +573,7 @@ function copyServeDirAssets(project, outDir, srcDir) {
|
|
|
578
573
|
const out = resolve(outDir);
|
|
579
574
|
if (!existsSync(serveDir) || serveDir === out) return 0;
|
|
580
575
|
const isRoot = serveDir === resolve(project.projectRoot);
|
|
576
|
+
const exts = resolveAssetExtensions(project.config);
|
|
581
577
|
const skipDirs = [out, resolve(srcDir)];
|
|
582
578
|
const devOutput = resolve(project.devOutputFile);
|
|
583
579
|
const skipFiles = new Set([devOutput, `${devOutput}.map`]);
|
|
@@ -600,7 +596,7 @@ function copyServeDirAssets(project, outDir, srcDir) {
|
|
|
600
596
|
} else if (
|
|
601
597
|
entry.isFile() &&
|
|
602
598
|
!skipFiles.has(full) &&
|
|
603
|
-
isStaticAsset(entry.name, isRoot)
|
|
599
|
+
isStaticAsset(entry.name, isRoot, exts)
|
|
604
600
|
) {
|
|
605
601
|
copyFile(full);
|
|
606
602
|
}
|
package/src/minifier.js
CHANGED
|
@@ -462,12 +462,29 @@ function _collectVarLocalDecls(tokens, i, declaredLocals) {
|
|
|
462
462
|
collectDestructured(tokens, next.idx, declaredLocals);
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
+
function _matchingParen(tokens, openIdx) {
|
|
466
|
+
let depth = 1;
|
|
467
|
+
for (let i = openIdx + 1; i < tokens.length; i++) {
|
|
468
|
+
const v = tokens[i].value;
|
|
469
|
+
if (v === "(") depth++;
|
|
470
|
+
else if (v === ")" && --depth === 0) return i;
|
|
471
|
+
}
|
|
472
|
+
return -1;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// A `(` opens a parameter list only when its `)` is followed by a body `{` or `=>`;
|
|
476
|
+
// otherwise `name(...)` is a call and its arguments may be free globals.
|
|
465
477
|
function _collectParamDecls(tokens, i, declaredLocals) {
|
|
466
478
|
const prev = findPrevNonWsToken(tokens, i);
|
|
467
479
|
if (
|
|
468
|
-
prev
|
|
469
|
-
(prev.value
|
|
480
|
+
!prev ||
|
|
481
|
+
(prev.value !== "function" && prev.type !== "ident" && prev.value !== ")")
|
|
470
482
|
)
|
|
483
|
+
return;
|
|
484
|
+
const close = _matchingParen(tokens, i);
|
|
485
|
+
if (close < 0) return;
|
|
486
|
+
const after = nextNonWs(tokens, close);
|
|
487
|
+
if (after && (after.tok.value === "{" || after.tok.value === "=>"))
|
|
471
488
|
collectParams(tokens, i, declaredLocals);
|
|
472
489
|
}
|
|
473
490
|
|
|
@@ -519,6 +536,33 @@ const MANGLE_GLOBALS = new Set([
|
|
|
519
536
|
"Infinity",
|
|
520
537
|
"TextEncoder",
|
|
521
538
|
"TextDecoder",
|
|
539
|
+
"globalThis",
|
|
540
|
+
"Reflect",
|
|
541
|
+
"Proxy",
|
|
542
|
+
"WeakMap",
|
|
543
|
+
"WeakSet",
|
|
544
|
+
"ArrayBuffer",
|
|
545
|
+
"DataView",
|
|
546
|
+
"Int8Array",
|
|
547
|
+
"Uint8Array",
|
|
548
|
+
"Uint8ClampedArray",
|
|
549
|
+
"Int16Array",
|
|
550
|
+
"Uint16Array",
|
|
551
|
+
"Int32Array",
|
|
552
|
+
"Uint32Array",
|
|
553
|
+
"Float32Array",
|
|
554
|
+
"Float64Array",
|
|
555
|
+
"BigInt64Array",
|
|
556
|
+
"BigUint64Array",
|
|
557
|
+
"Image",
|
|
558
|
+
"URL",
|
|
559
|
+
"Event",
|
|
560
|
+
"fetch",
|
|
561
|
+
"navigator",
|
|
562
|
+
"performance",
|
|
563
|
+
"localStorage",
|
|
564
|
+
"requestAnimationFrame",
|
|
565
|
+
"cancelAnimationFrame",
|
|
522
566
|
"setTimeout",
|
|
523
567
|
"setInterval",
|
|
524
568
|
"clearTimeout",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Project configuration loader shared by the CLI, asset manager and vendor bundler.
|
|
2
|
+
// Settings live in `gofront.json` at the project root, or under `"gofront"` in `package.json`.
|
|
3
|
+
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
export function loadProjectConfig(projectRoot) {
|
|
8
|
+
const gofrontJson = join(projectRoot, "gofront.json");
|
|
9
|
+
if (existsSync(gofrontJson)) {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(readFileSync(gofrontJson, "utf8"));
|
|
12
|
+
if (parsed && typeof parsed === "object") return parsed;
|
|
13
|
+
} catch {}
|
|
14
|
+
}
|
|
15
|
+
const pkgJson = join(projectRoot, "package.json");
|
|
16
|
+
if (existsSync(pkgJson)) {
|
|
17
|
+
try {
|
|
18
|
+
const pkg = JSON.parse(readFileSync(pkgJson, "utf8"));
|
|
19
|
+
if (pkg.gofront && typeof pkg.gofront === "object") return pkg.gofront;
|
|
20
|
+
} catch {}
|
|
21
|
+
}
|
|
22
|
+
return {};
|
|
23
|
+
}
|
package/src/vendor.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { createRequire } from "node:module";
|
|
13
13
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
14
14
|
import { pathToFileURL } from "node:url";
|
|
15
|
+
import { loadProjectConfig } from "./project-config.js";
|
|
15
16
|
|
|
16
17
|
export function getExportNames(pkgName, globals = {}) {
|
|
17
18
|
const base = pkgName.replace(/^@[^/]+\//, "");
|
|
@@ -111,15 +112,7 @@ export function loadVendorConfig(projectDir) {
|
|
|
111
112
|
} catch {}
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
const
|
|
115
|
-
let gfj = {};
|
|
116
|
-
if (existsSync(gfjPath)) {
|
|
117
|
-
try {
|
|
118
|
-
gfj = JSON.parse(readFileSync(gfjPath, "utf8"));
|
|
119
|
-
} catch {}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const vendorConfig = gfj.vendor ?? pkg.vendor ?? null;
|
|
115
|
+
const vendorConfig = loadProjectConfig(projectDir).vendor ?? null;
|
|
123
116
|
const dependencies = Object.keys(pkg.dependencies ?? {});
|
|
124
117
|
|
|
125
118
|
let dest = null;
|