@aerobuilt/core 0.3.0 → 0.3.1
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/dist/runtime/instance.mjs +8 -4
- package/dist/vite/index.mjs +89 -30
- package/package.json +3 -3
|
@@ -31,10 +31,14 @@ const notify = () => {
|
|
|
31
31
|
};
|
|
32
32
|
if (!globalThis.__AERO_INSTANCE__) globalThis.__AERO_INSTANCE__ = instance;
|
|
33
33
|
if (!globalThis.__AERO_LISTENERS__) globalThis.__AERO_LISTENERS__ = listeners;
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Eager globs so pages, layouts, and components are available synchronously for SSR/build.
|
|
36
|
+
* Patterns use default client dir (./client/...) so Vite's import-glob accepts them; apps with
|
|
37
|
+
* custom dirs rely on path aliases mapping @components/@layouts/@pages to the same structure.
|
|
38
|
+
*/
|
|
39
|
+
const components = /* @__PURE__ */ Object.assign({});
|
|
40
|
+
const layouts = /* @__PURE__ */ Object.assign({});
|
|
41
|
+
const pages = /* @__PURE__ */ Object.assign({});
|
|
38
42
|
aero.registerPages(components);
|
|
39
43
|
aero.registerPages(layouts);
|
|
40
44
|
aero.registerPages(pages);
|
package/dist/vite/index.mjs
CHANGED
|
@@ -648,31 +648,20 @@ var Lowerer = class {
|
|
|
648
648
|
}
|
|
649
649
|
/** Gets the condition value from if/else-if attribute */
|
|
650
650
|
getCondition(node, attr) {
|
|
651
|
+
const tagName = node?.tagName?.toLowerCase?.() || "element";
|
|
651
652
|
const plainValue = node.getAttribute(attr);
|
|
652
|
-
if (plainValue !== null) return
|
|
653
|
+
if (plainValue !== null) return stripBraces(validateSingleBracedExpression(plainValue, {
|
|
654
|
+
directive: attr,
|
|
655
|
+
tagName
|
|
656
|
+
}));
|
|
653
657
|
const dataAttr = ATTR_PREFIX + attr;
|
|
654
658
|
const dataValue = node.getAttribute(dataAttr);
|
|
655
|
-
if (dataValue !== null) return
|
|
659
|
+
if (dataValue !== null) return stripBraces(validateSingleBracedExpression(dataValue, {
|
|
660
|
+
directive: dataAttr,
|
|
661
|
+
tagName
|
|
662
|
+
}));
|
|
656
663
|
return null;
|
|
657
664
|
}
|
|
658
|
-
/**
|
|
659
|
-
* Require directive value to be a braced expression; optionally strip outer braces.
|
|
660
|
-
*
|
|
661
|
-
* @param value - Raw attribute value.
|
|
662
|
-
* @param directive - Attribute name for error message (e.g. `each`, `pass:data`).
|
|
663
|
-
* @param node - DOM node for error message (tag name).
|
|
664
|
-
* @param options - `strip: true` (default) returns inner expression; `strip: false` returns trimmed value including braces (e.g. for pass:data).
|
|
665
|
-
* @returns Trimmed value, with or without outer braces per options.
|
|
666
|
-
*/
|
|
667
|
-
requireBracedExpression(value, directive, node, options) {
|
|
668
|
-
const strip = options?.strip !== false;
|
|
669
|
-
const trimmed = value.trim();
|
|
670
|
-
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
671
|
-
const tagName = node?.tagName?.toLowerCase?.() || "element";
|
|
672
|
-
throw new Error(`Directive \`${directive}\` on <${tagName}> must use a braced expression, e.g. ${directive}="{ expression }".`);
|
|
673
|
-
}
|
|
674
|
-
return strip ? stripBraces(trimmed) : trimmed;
|
|
675
|
-
}
|
|
676
665
|
isSingleWrappedExpression(value) {
|
|
677
666
|
const trimmed = value.trim();
|
|
678
667
|
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return false;
|
|
@@ -702,7 +691,13 @@ var Lowerer = class {
|
|
|
702
691
|
if (isAttr(attr.name, ATTR_PROPS, ATTR_PREFIX)) {
|
|
703
692
|
const value = attr.value?.trim() || "";
|
|
704
693
|
if (!value) dataPropsExpression = "...props";
|
|
705
|
-
else
|
|
694
|
+
else {
|
|
695
|
+
const tagName = node?.tagName?.toLowerCase?.() || "element";
|
|
696
|
+
dataPropsExpression = stripBraces(validateSingleBracedExpression(value, {
|
|
697
|
+
directive: attr.name,
|
|
698
|
+
tagName
|
|
699
|
+
}));
|
|
700
|
+
}
|
|
706
701
|
continue;
|
|
707
702
|
}
|
|
708
703
|
const rawValue = attr.value ?? "";
|
|
@@ -725,7 +720,11 @@ var Lowerer = class {
|
|
|
725
720
|
if (node.attributes) for (let i = 0; i < node.attributes.length; i++) {
|
|
726
721
|
const attr = node.attributes[i];
|
|
727
722
|
if (isAttr(attr.name, ATTR_EACH, ATTR_PREFIX)) {
|
|
728
|
-
const
|
|
723
|
+
const tagName = node?.tagName?.toLowerCase?.() || "element";
|
|
724
|
+
const match = stripBraces(validateSingleBracedExpression(attr.value || "", {
|
|
725
|
+
directive: attr.name,
|
|
726
|
+
tagName
|
|
727
|
+
})).match(EACH_REGEX);
|
|
729
728
|
if (!match) {
|
|
730
729
|
const tagName = node?.tagName?.toLowerCase?.() || "element";
|
|
731
730
|
throw new Error(`Directive \`${attr.name}\` on <${tagName}> must match "{ item in items }".`);
|
|
@@ -1493,12 +1492,15 @@ function createBuildConfig(options = {}, root = process.cwd()) {
|
|
|
1493
1492
|
const require = createRequire(import.meta.url);
|
|
1494
1493
|
const AERO_DIR = ".aero";
|
|
1495
1494
|
const NITRO_CONFIG_FILENAME = "nitro.config.mjs";
|
|
1495
|
+
/** Filename for the generated runtime instance (uses app dirs for globs); written under .aero so Vite treats it as a real module. */
|
|
1496
|
+
const RUNTIME_INSTANCE_FILENAME = "runtime-instance.mjs";
|
|
1496
1497
|
/**
|
|
1497
1498
|
* Generate Nitro config from Aero options and write to <projectRoot>/.aero/nitro.config.mjs.
|
|
1498
1499
|
* root is the app/site directory (Vite config.root), e.g. examples/kitchen-sink or a create-aerobuilt project folder.
|
|
1500
|
+
* distDir is the configured output dir (e.g. 'build') so the catch-all route serves from the same path at preview time.
|
|
1499
1501
|
* Returns the absolute path to .aero (Nitro cwd so it loads this file).
|
|
1500
1502
|
*/
|
|
1501
|
-
function writeGeneratedNitroConfig(root, serverDir, redirects) {
|
|
1503
|
+
function writeGeneratedNitroConfig(root, serverDir, redirects, distDir) {
|
|
1502
1504
|
const aeroDir = path.join(root, AERO_DIR);
|
|
1503
1505
|
mkdirSync(aeroDir, { recursive: true });
|
|
1504
1506
|
const routeRules = redirectsToRouteRules(redirects ?? []);
|
|
@@ -1507,7 +1509,8 @@ function writeGeneratedNitroConfig(root, serverDir, redirects) {
|
|
|
1507
1509
|
output: { dir: path.join(root, ".output") },
|
|
1508
1510
|
scanDirs: [path.join(root, serverDir)],
|
|
1509
1511
|
routeRules,
|
|
1510
|
-
noPublicDir: true
|
|
1512
|
+
noPublicDir: true,
|
|
1513
|
+
replace: { "process.env.AERO_DIST": JSON.stringify(distDir) }
|
|
1511
1514
|
};
|
|
1512
1515
|
const content = `// Generated by Aero — do not edit
|
|
1513
1516
|
export default ${JSON.stringify(nitroConfig, null, 2)}
|
|
@@ -1540,9 +1543,7 @@ function createAeroConfigPlugin(state) {
|
|
|
1540
1543
|
enforce: "pre",
|
|
1541
1544
|
config(userConfig, env) {
|
|
1542
1545
|
const root = userConfig.root || process.cwd();
|
|
1543
|
-
|
|
1544
|
-
state.aliasResult = mergeWithDefaultAliases(rawAliases, root, state.dirs);
|
|
1545
|
-
if (state.dirs.client !== DEFAULT_DIRS.client && rawAliases.projectRoot != null) console.warn("[aero] Custom dirs.client is set; ensure tsconfig paths for @pages, @layouts, @components match (e.g. @pages → \"" + state.dirs.client + "/pages\").");
|
|
1546
|
+
state.aliasResult = mergeWithDefaultAliases(loadTsconfigAliases(root), root, state.dirs);
|
|
1546
1547
|
const site = state.options.site ?? "";
|
|
1547
1548
|
return {
|
|
1548
1549
|
base: "./",
|
|
@@ -1559,6 +1560,13 @@ function createAeroConfigPlugin(state) {
|
|
|
1559
1560
|
},
|
|
1560
1561
|
configResolved(resolvedConfig) {
|
|
1561
1562
|
state.config = resolvedConfig;
|
|
1563
|
+
const dir = path.join(resolvedConfig.root, AERO_DIR);
|
|
1564
|
+
mkdirSync(dir, { recursive: true });
|
|
1565
|
+
const filePath = path.join(dir, RUNTIME_INSTANCE_FILENAME);
|
|
1566
|
+
const runtimeIndexPath = path.join(path.dirname(state.runtimeInstancePath), "index.mjs");
|
|
1567
|
+
const runtimeImportPath = path.relative(dir, runtimeIndexPath).replace(/\\/g, "/");
|
|
1568
|
+
writeFileSync(filePath, getRuntimeInstanceVirtualSource(state.dirs.client, runtimeImportPath.startsWith(".") ? runtimeImportPath : "./" + runtimeImportPath), "utf-8");
|
|
1569
|
+
state.generatedRuntimeInstancePath = filePath;
|
|
1562
1570
|
}
|
|
1563
1571
|
};
|
|
1564
1572
|
}
|
|
@@ -1570,6 +1578,56 @@ function isAeroTemplateHtml(filePath, root, dirs) {
|
|
|
1570
1578
|
const sep = path.sep;
|
|
1571
1579
|
return rel.startsWith("pages" + sep) || rel.startsWith("components" + sep) || rel.startsWith("layouts" + sep);
|
|
1572
1580
|
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Prefix for import.meta.glob patterns. In virtual modules Vite requires globs to start with '/'
|
|
1583
|
+
* (absolute from project root). Uses app-configured client dir so custom dirs (e.g. frontend/) resolve correctly.
|
|
1584
|
+
*/
|
|
1585
|
+
function clientGlobPrefix(clientDir) {
|
|
1586
|
+
const normalized = clientDir.replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
1587
|
+
return normalized ? `/${normalized}` : "/client";
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Virtual module source for the runtime instance with glob patterns using the app's client dir.
|
|
1591
|
+
* Ensures template resolution works for custom dirs (e.g. dirs.client === 'frontend').
|
|
1592
|
+
* runtimeImportPath: path that resolves to @aerobuilt/core/runtime from the generated file (e.g. relative to .aero/ for SSR).
|
|
1593
|
+
*/
|
|
1594
|
+
function getRuntimeInstanceVirtualSource(clientDir, runtimeImportPath = "@aerobuilt/core/runtime") {
|
|
1595
|
+
const prefix = clientGlobPrefix(clientDir);
|
|
1596
|
+
const componentsPattern = `${prefix}/components/**/*.html`;
|
|
1597
|
+
const layoutsPattern = `${prefix}/layouts/*.html`;
|
|
1598
|
+
const pagesPattern = `${prefix}/pages/**/*.html`;
|
|
1599
|
+
return `import { Aero } from ${JSON.stringify(runtimeImportPath)}
|
|
1600
|
+
|
|
1601
|
+
const instance = globalThis.__AERO_INSTANCE__ || new Aero()
|
|
1602
|
+
const listeners = globalThis.__AERO_LISTENERS__ || new Set()
|
|
1603
|
+
const aero = instance
|
|
1604
|
+
|
|
1605
|
+
const onUpdate = (cb) => {
|
|
1606
|
+
listeners.add(cb)
|
|
1607
|
+
return () => listeners.delete(cb)
|
|
1608
|
+
}
|
|
1609
|
+
const notify = () => {
|
|
1610
|
+
listeners.forEach((cb) => cb())
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
if (!globalThis.__AERO_INSTANCE__) globalThis.__AERO_INSTANCE__ = instance
|
|
1614
|
+
if (!globalThis.__AERO_LISTENERS__) globalThis.__AERO_LISTENERS__ = listeners
|
|
1615
|
+
|
|
1616
|
+
const components = import.meta.glob(${JSON.stringify(componentsPattern)}, { eager: true })
|
|
1617
|
+
const layouts = import.meta.glob(${JSON.stringify(layoutsPattern)}, { eager: true })
|
|
1618
|
+
const pages = import.meta.glob(${JSON.stringify(pagesPattern)}, { eager: true })
|
|
1619
|
+
|
|
1620
|
+
aero.registerPages(components)
|
|
1621
|
+
aero.registerPages(layouts)
|
|
1622
|
+
aero.registerPages(pages)
|
|
1623
|
+
|
|
1624
|
+
notify()
|
|
1625
|
+
|
|
1626
|
+
if (import.meta.hot) import.meta.hot.accept()
|
|
1627
|
+
|
|
1628
|
+
export { aero, onUpdate }
|
|
1629
|
+
`;
|
|
1630
|
+
}
|
|
1573
1631
|
function createAeroVirtualsPlugin(state) {
|
|
1574
1632
|
return {
|
|
1575
1633
|
name: "vite-plugin-aero-virtuals",
|
|
@@ -1579,7 +1637,7 @@ function createAeroVirtualsPlugin(state) {
|
|
|
1579
1637
|
discoverClientScriptContentMap(state.config.root, state.dirs.client).forEach((entry, url) => state.clientScripts.set(url, entry));
|
|
1580
1638
|
},
|
|
1581
1639
|
async resolveId(id, importer) {
|
|
1582
|
-
if (id === RUNTIME_INSTANCE_MODULE_ID) return RESOLVED_RUNTIME_INSTANCE_MODULE_ID;
|
|
1640
|
+
if (id === RUNTIME_INSTANCE_MODULE_ID) return state.generatedRuntimeInstancePath ?? RESOLVED_RUNTIME_INSTANCE_MODULE_ID;
|
|
1583
1641
|
if (id.startsWith(CLIENT_SCRIPT_PREFIX)) return "\0" + id;
|
|
1584
1642
|
if (id.startsWith("\0" + CLIENT_SCRIPT_PREFIX)) return id;
|
|
1585
1643
|
if (id.startsWith(AERO_HTML_VIRTUAL_PREFIX)) return id;
|
|
@@ -1600,7 +1658,7 @@ function createAeroVirtualsPlugin(state) {
|
|
|
1600
1658
|
return null;
|
|
1601
1659
|
},
|
|
1602
1660
|
load(id) {
|
|
1603
|
-
if (id === RESOLVED_RUNTIME_INSTANCE_MODULE_ID) return
|
|
1661
|
+
if (id === RESOLVED_RUNTIME_INSTANCE_MODULE_ID) return getRuntimeInstanceVirtualSource(state.dirs.client);
|
|
1604
1662
|
if (id.startsWith(AERO_EMPTY_INLINE_CSS_PREFIX)) return "/* aero: no inline styles */";
|
|
1605
1663
|
if (id.startsWith(AERO_HTML_VIRTUAL_PREFIX)) {
|
|
1606
1664
|
const filePath = id.slice(AERO_HTML_VIRTUAL_PREFIX.length).replace(/\.aero$/i, ".html");
|
|
@@ -1796,6 +1854,7 @@ function aero(options = {}) {
|
|
|
1796
1854
|
aliasResult: null,
|
|
1797
1855
|
clientScripts: /* @__PURE__ */ new Map(),
|
|
1798
1856
|
runtimeInstancePath,
|
|
1857
|
+
generatedRuntimeInstancePath: null,
|
|
1799
1858
|
dirs,
|
|
1800
1859
|
apiPrefix,
|
|
1801
1860
|
options
|
|
@@ -1833,7 +1892,7 @@ function aero(options = {}) {
|
|
|
1833
1892
|
site: options.site,
|
|
1834
1893
|
redirects: options.redirects
|
|
1835
1894
|
}, outDir);
|
|
1836
|
-
if (enableNitro) await runNitroBuild(root, writeGeneratedNitroConfig(root, dirs.server, options.redirects));
|
|
1895
|
+
if (enableNitro) await runNitroBuild(root, writeGeneratedNitroConfig(root, dirs.server, options.redirects, dirs.dist));
|
|
1837
1896
|
}
|
|
1838
1897
|
},
|
|
1839
1898
|
ViteImageOptimizer({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aerobuilt/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jamie Wilson",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"sharp": "^0.34.5",
|
|
61
61
|
"svgo": "^4.0.0",
|
|
62
62
|
"vite-plugin-image-optimizer": "^2.0.3",
|
|
63
|
-
"@aerobuilt/interpolation": "0.3.
|
|
63
|
+
"@aerobuilt/interpolation": "0.3.1"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"vite": "^8.0.0-0"
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"vitest": "^4.0.18"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
|
-
"build": "tsdown
|
|
80
|
+
"build": "tsdown",
|
|
81
81
|
"typecheck": "tsc --noEmit",
|
|
82
82
|
"test": "vitest run"
|
|
83
83
|
}
|