@nexus_js/compiler 0.6.0
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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/codegen.d.ts +4 -0
- package/dist/codegen.d.ts.map +1 -0
- package/dist/codegen.js +308 -0
- package/dist/codegen.js.map +1 -0
- package/dist/css-scope.d.ts +76 -0
- package/dist/css-scope.d.ts.map +1 -0
- package/dist/css-scope.js +327 -0
- package/dist/css-scope.js.map +1 -0
- package/dist/guard.d.ts +59 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +212 -0
- package/dist/guard.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/island-ssr-stubs.d.ts +25 -0
- package/dist/island-ssr-stubs.d.ts.map +1 -0
- package/dist/island-ssr-stubs.js +107 -0
- package/dist/island-ssr-stubs.js.map +1 -0
- package/dist/island-wrap.d.ts +19 -0
- package/dist/island-wrap.d.ts.map +1 -0
- package/dist/island-wrap.js +108 -0
- package/dist/island-wrap.js.map +1 -0
- package/dist/parser.d.ts +28 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +128 -0
- package/dist/parser.js.map +1 -0
- package/dist/preload-scanner.d.ts +60 -0
- package/dist/preload-scanner.d.ts.map +1 -0
- package/dist/preload-scanner.js +156 -0
- package/dist/preload-scanner.js.map +1 -0
- package/dist/server-actions-extract.d.ts +9 -0
- package/dist/server-actions-extract.d.ts.map +1 -0
- package/dist/server-actions-extract.js +89 -0
- package/dist/server-actions-extract.js.map +1 -0
- package/dist/types.d.ts +98 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nexus Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @nexus_js/compiler
|
|
2
|
+
|
|
3
|
+
Nexus compiler — transforms .nx files into optimized server/client bundles.
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
All guides, API reference, and examples live on **[nexusjs.dev](https://nexusjs.dev)**.
|
|
8
|
+
|
|
9
|
+
## Links
|
|
10
|
+
|
|
11
|
+
- **Website:** [https://nexusjs.dev](https://nexusjs.dev)
|
|
12
|
+
- **Repository:** [github.com/bierfor/nexus](https://github.com/bierfor/nexus) (see `packages/compiler/`)
|
|
13
|
+
- **Issues:** [github.com/bierfor/nexus/issues](https://github.com/bierfor/nexus/issues)
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
MIT © Nexus contributors
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ParsedComponent, CompileOptions, CompileResult } from './types.js';
|
|
2
|
+
/** Compiles a parsed .nx component into server + client output */
|
|
3
|
+
export declare function generate(parsed: ParsedComponent, opts: CompileOptions): CompileResult;
|
|
4
|
+
//# sourceMappingURL=codegen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,aAAa,EAKd,MAAM,YAAY,CAAC;AAuBpB,kEAAkE;AAClE,wBAAgB,QAAQ,CACtB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,GACnB,aAAa,CAgEf"}
|
package/dist/codegen.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { join, normalize } from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { scopeCSS, scopeTemplate, unwrapOuterTemplateElement } from './css-scope.js';
|
|
4
|
+
import { wrapSelfClientIslandMarkers } from './island-wrap.js';
|
|
5
|
+
import { islandSsrStubLines } from './island-ssr-stubs.js';
|
|
6
|
+
/** Generates a unique stable island ID from filepath + component name */
|
|
7
|
+
function islandId(filepath, componentName) {
|
|
8
|
+
const base = filepath.replace(/[^a-zA-Z0-9]/g, '_');
|
|
9
|
+
return `island_${base}_${componentName}`.toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
/** Resolve `$lib/…` in server frontmatter to absolute file URLs for Node ESM. */
|
|
12
|
+
function rewriteDollarLibImports(code, appRoot) {
|
|
13
|
+
if (!appRoot)
|
|
14
|
+
return code;
|
|
15
|
+
const root = normalize(appRoot);
|
|
16
|
+
return code.replace(/from\s*['"]\$lib\/([^'"]+)['"]/gu, (_, rel) => {
|
|
17
|
+
const abs = join(root, 'src/lib', rel);
|
|
18
|
+
return `from ${JSON.stringify(pathToFileURL(abs).href)}`;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** Compiles a parsed .nx component into server + client output */
|
|
22
|
+
export function generate(parsed, opts) {
|
|
23
|
+
const warnings = [];
|
|
24
|
+
// ── CSS (AOT hash scoping — zero runtime) ─────────────────────────────────
|
|
25
|
+
// Computed first so it can be passed into generateServerModule
|
|
26
|
+
let css = null;
|
|
27
|
+
let processedTemplate = parsed.template?.content ?? '';
|
|
28
|
+
if (parsed.style) {
|
|
29
|
+
const scoped = scopeCSS(parsed.style.content, parsed.filepath);
|
|
30
|
+
css = scoped.css;
|
|
31
|
+
// Inject data-nx hash onto template root elements
|
|
32
|
+
processedTemplate = scopeTemplate(processedTemplate, scoped.hash);
|
|
33
|
+
}
|
|
34
|
+
// <template> roots are inert in the browser — unwrap for visible SSR HTML
|
|
35
|
+
processedTemplate = unwrapOuterTemplateElement(processedTemplate);
|
|
36
|
+
const islandWrap = wrapSelfClientIslandMarkers(processedTemplate, parsed.filepath, opts.appRoot);
|
|
37
|
+
processedTemplate = islandWrap.template;
|
|
38
|
+
// ── Server module ──────────────────────────────────────────────────────────
|
|
39
|
+
const serverCode = generateServerModule(parsed, opts, processedTemplate, islandWrap);
|
|
40
|
+
// ── Client island code (only if there are reactive islands) ───────────────
|
|
41
|
+
const needsClientIsland = islandWrap.didWrap ||
|
|
42
|
+
parsed.islandDirectives.length > 0 ||
|
|
43
|
+
(parsed.script?.content ?? '').includes('$state');
|
|
44
|
+
const clientCode = needsClientIsland ? generateClientIsland(parsed, opts, islandWrap) : null;
|
|
45
|
+
// ── Island manifest ────────────────────────────────────────────────────────
|
|
46
|
+
const islandManifest = opts.emitIslandManifest && parsed.islandDirectives.length > 0
|
|
47
|
+
? {
|
|
48
|
+
islands: parsed.islandDirectives.map((d) => {
|
|
49
|
+
const entry = {
|
|
50
|
+
id: islandId(parsed.filepath, d.componentName),
|
|
51
|
+
componentPath: parsed.filepath,
|
|
52
|
+
directive: d.directive,
|
|
53
|
+
props: [],
|
|
54
|
+
};
|
|
55
|
+
if (d.mediaQuery !== undefined) {
|
|
56
|
+
entry.mediaQuery = d.mediaQuery;
|
|
57
|
+
}
|
|
58
|
+
return entry;
|
|
59
|
+
}),
|
|
60
|
+
}
|
|
61
|
+
: null;
|
|
62
|
+
// ── Server Actions module ──────────────────────────────────────────────────
|
|
63
|
+
const actionsModule = parsed.serverActions.length > 0
|
|
64
|
+
? generateActionsModule(parsed.serverActions, parsed.filepath)
|
|
65
|
+
: null;
|
|
66
|
+
return {
|
|
67
|
+
serverCode,
|
|
68
|
+
clientCode,
|
|
69
|
+
css,
|
|
70
|
+
islandManifest,
|
|
71
|
+
actionsModule,
|
|
72
|
+
map: null,
|
|
73
|
+
warnings,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
77
|
+
// Server module: runs on every request
|
|
78
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
79
|
+
function generateServerModule(parsed, opts, processedTemplate, islandWrap) {
|
|
80
|
+
const lines = [];
|
|
81
|
+
lines.push(`// [Nexus] Server module — generated from ${parsed.filepath}`);
|
|
82
|
+
lines.push(`// DO NOT EDIT — this file is auto-generated`);
|
|
83
|
+
lines.push('');
|
|
84
|
+
// Frontmatter imports + data fetching
|
|
85
|
+
if (parsed.frontmatter) {
|
|
86
|
+
lines.push('// ── Server-only data fetching (runs per request) ──');
|
|
87
|
+
lines.push(rewriteDollarLibImports(parsed.frontmatter.content.trim(), opts.appRoot));
|
|
88
|
+
lines.push('');
|
|
89
|
+
}
|
|
90
|
+
// Runes from the client script — SSR must define matching locals whenever the template interpolates them.
|
|
91
|
+
const runes = extractRuneDeclarations(parsed.script?.content ?? '');
|
|
92
|
+
// Build render function
|
|
93
|
+
lines.push('export async function render(ctx) {');
|
|
94
|
+
lines.push(' const __html = await renderTemplate(ctx);');
|
|
95
|
+
lines.push(' return {');
|
|
96
|
+
lines.push(' html: __html,');
|
|
97
|
+
lines.push(` css: ${parsed.style ? 'true' : 'false'},`);
|
|
98
|
+
lines.push(` hasIslands: ${islandWrap.didWrap || parsed.islandDirectives.length > 0},`);
|
|
99
|
+
lines.push(' };');
|
|
100
|
+
lines.push('}');
|
|
101
|
+
lines.push('');
|
|
102
|
+
// Template renderer (simple expression interpolation → SSR)
|
|
103
|
+
lines.push('async function renderTemplate(ctx) {');
|
|
104
|
+
lines.push(' // Server-side template rendering (CSS-scoped at compile time)');
|
|
105
|
+
// Island-wrapped pages may reference only plain functions (e.g. onsubmit={preventSubmit}) with no $state.
|
|
106
|
+
if (parsed.script?.content && (runes.length > 0 || islandWrap.didWrap)) {
|
|
107
|
+
for (const stub of islandSsrStubLines(parsed.script.content)) {
|
|
108
|
+
lines.push(stub);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
lines.push(" const __ssrAttr = (v) => String(v ?? '').replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<');");
|
|
112
|
+
lines.push(` return \`${templateToSSR(processedTemplate)}\`;`);
|
|
113
|
+
lines.push('}');
|
|
114
|
+
return lines.join('\n');
|
|
115
|
+
}
|
|
116
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
117
|
+
// Client island: sent to browser only for interactive components
|
|
118
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
119
|
+
function generateClientIsland(parsed, _opts, islandWrap) {
|
|
120
|
+
const lines = [];
|
|
121
|
+
lines.push(`// [Nexus] Client Island — ${parsed.filepath}`);
|
|
122
|
+
lines.push(`// Hydration strategy: ${parsed.islandDirectives.map((d) => d.directive).join(', ') || 'client:load'}`);
|
|
123
|
+
lines.push('');
|
|
124
|
+
lines.push("import { createIsland, $state, $derived, $effect } from '/_nexus/rt/island.js';");
|
|
125
|
+
lines.push('');
|
|
126
|
+
const fragments = islandWrap.clientFragments.length > 0
|
|
127
|
+
? islandWrap.clientFragments
|
|
128
|
+
: [islandWrap.clientTemplate ?? parsed.template?.content ?? ''];
|
|
129
|
+
lines.push(`const __nxTemplates = [${fragments.map((f) => JSON.stringify(f)).join(', ')}];`);
|
|
130
|
+
lines.push('');
|
|
131
|
+
// Script content with Runes (already Svelte-5-style, pass through)
|
|
132
|
+
if (parsed.script) {
|
|
133
|
+
lines.push('// ── Reactive State (Runes) ──');
|
|
134
|
+
lines.push(transformRunesToRuntime(parsed.script.content));
|
|
135
|
+
lines.push('');
|
|
136
|
+
}
|
|
137
|
+
// Mount function — each <nexus-island> passes data-nexus-island-index to pick the right template slice
|
|
138
|
+
lines.push('export function mount(el, props = {}) {');
|
|
139
|
+
lines.push(` const idx = Number(el.getAttribute('data-nexus-island-index') ?? '0');`);
|
|
140
|
+
lines.push(' const tpl = __nxTemplates[idx] ?? __nxTemplates[0];');
|
|
141
|
+
lines.push(' return createIsland(el, {');
|
|
142
|
+
lines.push(' template: tpl,');
|
|
143
|
+
lines.push(' ...props,');
|
|
144
|
+
lines.push(' });');
|
|
145
|
+
lines.push('}');
|
|
146
|
+
return lines.join('\n');
|
|
147
|
+
}
|
|
148
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
149
|
+
// Server Actions module: type-safe RPC stubs
|
|
150
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
151
|
+
function generateActionsModule(actions, filepath) {
|
|
152
|
+
const lines = [];
|
|
153
|
+
lines.push(`// [Nexus] Server Actions — generated from ${filepath}`);
|
|
154
|
+
lines.push(`"use server";`);
|
|
155
|
+
lines.push('');
|
|
156
|
+
const needsCreateAction = actions.some((a) => a.createActionSource);
|
|
157
|
+
lines.push(needsCreateAction
|
|
158
|
+
? "import { createAction, registerAction } from '@nexus_js/server/actions';"
|
|
159
|
+
: "import { registerAction } from '@nexus_js/server/actions';");
|
|
160
|
+
lines.push('');
|
|
161
|
+
for (const action of actions) {
|
|
162
|
+
lines.push(`/** @nexus-action "${action.name}" */`);
|
|
163
|
+
if (action.createActionSource) {
|
|
164
|
+
lines.push(`registerAction(${JSON.stringify(action.name)}, ${action.createActionSource}, { csrf: false });`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
lines.push(`registerAction(${JSON.stringify(action.name)}, async (${action.params.join(', ')}) => {`);
|
|
168
|
+
for (const line of action.body.split('\n')) {
|
|
169
|
+
const t = line.trim();
|
|
170
|
+
if (!t)
|
|
171
|
+
continue;
|
|
172
|
+
lines.push(` ${t}`);
|
|
173
|
+
}
|
|
174
|
+
lines.push(`}, { csrf: false });`);
|
|
175
|
+
}
|
|
176
|
+
lines.push('');
|
|
177
|
+
}
|
|
178
|
+
return lines.join('\n');
|
|
179
|
+
}
|
|
180
|
+
function extractRuneDeclarations(code) {
|
|
181
|
+
const runes = [];
|
|
182
|
+
const re = /(?:let|const)\s+(\w+)\s*=\s*(\$state|\$derived|\$effect|\$props)\(([^)]*)\)/g;
|
|
183
|
+
let m;
|
|
184
|
+
while ((m = re.exec(code)) !== null) {
|
|
185
|
+
runes.push({
|
|
186
|
+
name: m[1] ?? '',
|
|
187
|
+
kind: (m[2] ?? '$state'),
|
|
188
|
+
initializer: m[3] ?? '',
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return runes;
|
|
192
|
+
}
|
|
193
|
+
function transformRunesToRuntime(code) {
|
|
194
|
+
// The rune primitives ($state, $derived, $effect, $props) are imported at the top of
|
|
195
|
+
// the generated client module from '/_nexus/rt/island.js'. They work as plain function
|
|
196
|
+
// calls — no namespace prefix needed. Strip any legacy "use server" directives that
|
|
197
|
+
// must not appear in the browser bundle.
|
|
198
|
+
return code.replace(/^\s*"use server"\s*;?\s*$/gm, '// [server-only removed]');
|
|
199
|
+
}
|
|
200
|
+
const EACH_OPEN = '{#each ';
|
|
201
|
+
/**
|
|
202
|
+
* Expands `{#each list as item}...{/each}` into `${list.map((item) => `...`).join('')}`.
|
|
203
|
+
* Inner blocks are expanded first so nesting works.
|
|
204
|
+
*/
|
|
205
|
+
function expandEachBlocks(template) {
|
|
206
|
+
let t = template;
|
|
207
|
+
while (t.includes(EACH_OPEN)) {
|
|
208
|
+
const start = t.indexOf(EACH_OPEN);
|
|
209
|
+
const closeHeader = t.indexOf('}', start);
|
|
210
|
+
if (closeHeader === -1)
|
|
211
|
+
return t;
|
|
212
|
+
const header = t.slice(start + EACH_OPEN.length, closeHeader);
|
|
213
|
+
const hm = /^(.+?)\s+as\s+(\w+)\s*$/.exec(header.trim());
|
|
214
|
+
if (!hm || !hm[1] || !hm[2])
|
|
215
|
+
return t;
|
|
216
|
+
const listExpr = hm[1].trim();
|
|
217
|
+
const alias = hm[2];
|
|
218
|
+
let depth = 1;
|
|
219
|
+
let pos = closeHeader + 1;
|
|
220
|
+
let closeIdx = -1;
|
|
221
|
+
while (pos < t.length && depth > 0) {
|
|
222
|
+
const subEach = t.indexOf(EACH_OPEN, pos);
|
|
223
|
+
const subEnd = t.indexOf('{/each}', pos);
|
|
224
|
+
if (subEnd === -1)
|
|
225
|
+
return t;
|
|
226
|
+
if (subEach !== -1 && subEach < subEnd) {
|
|
227
|
+
depth++;
|
|
228
|
+
pos = subEach + EACH_OPEN.length;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
depth--;
|
|
232
|
+
if (depth === 0)
|
|
233
|
+
closeIdx = subEnd;
|
|
234
|
+
else
|
|
235
|
+
pos = subEnd + 7;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (closeIdx === -1)
|
|
239
|
+
return t;
|
|
240
|
+
const body = t.slice(closeHeader + 1, closeIdx).trim();
|
|
241
|
+
const bodyExpanded = expandEachBlocks(body);
|
|
242
|
+
const inner = interpolateExpressionsForSSR(bodyExpanded);
|
|
243
|
+
const replacement = '${' + listExpr + '.map((' + alias + ') => `' + inner + '`).join(\'\')}';
|
|
244
|
+
t = t.slice(0, start) + replacement + t.slice(closeIdx + 7);
|
|
245
|
+
}
|
|
246
|
+
return t;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* `{foo}` → `${foo}` for the server `return \`...\`` template literal.
|
|
250
|
+
* Skips `<style>` / `<script>` regions so CSS `{ ... }` and JS blocks are not treated as expressions.
|
|
251
|
+
*/
|
|
252
|
+
function interpolateExpressionsForSSR(s) {
|
|
253
|
+
const interp = (fragment) => fragment.replace(/(?<!\$)\{([^}]+)\}/g, '${$1}');
|
|
254
|
+
let out = '';
|
|
255
|
+
let i = 0;
|
|
256
|
+
while (i < s.length) {
|
|
257
|
+
const rest = s.slice(i);
|
|
258
|
+
const low = rest.toLowerCase();
|
|
259
|
+
const styleRel = low.indexOf('<style');
|
|
260
|
+
const scriptRel = low.indexOf('<script');
|
|
261
|
+
let skipFrom = -1;
|
|
262
|
+
let isStyle = true;
|
|
263
|
+
if (styleRel === -1 && scriptRel === -1) {
|
|
264
|
+
out += interp(rest);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
if (styleRel === -1 || (scriptRel !== -1 && scriptRel < styleRel)) {
|
|
268
|
+
skipFrom = i + scriptRel;
|
|
269
|
+
isStyle = false;
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
skipFrom = i + styleRel;
|
|
273
|
+
isStyle = true;
|
|
274
|
+
}
|
|
275
|
+
out += interp(s.slice(i, skipFrom));
|
|
276
|
+
const gt = s.indexOf('>', skipFrom);
|
|
277
|
+
if (gt === -1) {
|
|
278
|
+
out += s.slice(skipFrom);
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
const closeTag = isStyle ? '</style>' : '</script>';
|
|
282
|
+
const closeIdx = s.toLowerCase().indexOf(closeTag, gt + 1);
|
|
283
|
+
if (closeIdx === -1) {
|
|
284
|
+
out += s.slice(skipFrom);
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
const blockEnd = closeIdx + closeTag.length;
|
|
288
|
+
out += s.slice(skipFrom, blockEnd);
|
|
289
|
+
i = blockEnd;
|
|
290
|
+
}
|
|
291
|
+
return out;
|
|
292
|
+
}
|
|
293
|
+
function templateToSSR(template) {
|
|
294
|
+
const attrSafe = transformDynamicAttributesForSSR(template);
|
|
295
|
+
const expanded = expandEachBlocks(attrSafe);
|
|
296
|
+
return interpolateExpressionsForSSR(expanded);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* SSR HTML must not emit unquoted `value=${nick}` (breaks tokenization) or
|
|
300
|
+
* `onsubmit=${fn}` (function `toString()` injects `{}` into the document).
|
|
301
|
+
* Event handlers are omitted here; the client island attaches them on hydrate.
|
|
302
|
+
*/
|
|
303
|
+
function transformDynamicAttributesForSSR(html) {
|
|
304
|
+
let s = html.replace(/\s+on[a-zA-Z][a-zA-Z0-9-]*\s*=\s*\{[^}]+\}/g, '');
|
|
305
|
+
s = s.replace(/([a-zA-Z_:][-a-zA-Z0-9_:.]*)\s*=\s*\{\s*([a-zA-Z_$][\w$.]*)\s*\}/g, (_, name, expr) => `${name}="\${__ssrAttr(${expr})}"`);
|
|
306
|
+
return s;
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=codegen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus CSS Scoping — Compile-time class hash injection with @layer.
|
|
3
|
+
*
|
|
4
|
+
* Strategy: Pure AOT, zero runtime overhead.
|
|
5
|
+
*
|
|
6
|
+
* Specificity fix (the insight from the user):
|
|
7
|
+
* Plain [data-nx="hash"] .card has higher specificity than .card,
|
|
8
|
+
* which breaks overrides from parent components or third-party libraries.
|
|
9
|
+
*
|
|
10
|
+
* Solution: Wrap ALL generated scoped styles inside @layer nexus.scoped.
|
|
11
|
+
* CSS Cascade Layers (Level 5 spec, baseline 2022) have LOWER specificity
|
|
12
|
+
* than unlayered styles by design, regardless of selector weight.
|
|
13
|
+
*
|
|
14
|
+
* Layer precedence (highest wins, last wins within same layer):
|
|
15
|
+
* unlayered styles > @layer nexus.global > @layer nexus.scoped
|
|
16
|
+
*
|
|
17
|
+
* This means:
|
|
18
|
+
* - Component styles (.card) are isolated by hash ✓
|
|
19
|
+
* - Parent overrides work without !important ✓
|
|
20
|
+
* - Third-party libraries can override without !important ✓
|
|
21
|
+
* - :global(selector) still works as an escape hatch ✓
|
|
22
|
+
*
|
|
23
|
+
* How it works:
|
|
24
|
+
* 1. Compute a stable 6-char hash from the component filepath (FNV-1a).
|
|
25
|
+
* 2. Rewrite every CSS selector to be scoped with [data-nx="<hash>"].
|
|
26
|
+
* 3. Wrap the entire output in @layer nexus.scoped { ... }.
|
|
27
|
+
* 4. Inject data-nx="<hash>" onto every root element in the template.
|
|
28
|
+
*
|
|
29
|
+
* Example — input:
|
|
30
|
+
* .card { color: red }
|
|
31
|
+
* .card:hover h2 { font-size: 2rem }
|
|
32
|
+
* @media (max-width: 768px) { .card { display: none } }
|
|
33
|
+
*
|
|
34
|
+
* Output:
|
|
35
|
+
* @layer nexus.scoped {
|
|
36
|
+
* [data-nx="a3f9c1"] .card { color: red }
|
|
37
|
+
* [data-nx="a3f9c1"] .card:hover h2 { font-size: 2rem }
|
|
38
|
+
* @media (max-width: 768px) { [data-nx="a3f9c1"] .card { display: none } }
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* Template rewrite:
|
|
42
|
+
* <div class="card"> → <div class="card" data-nx="a3f9c1">
|
|
43
|
+
*
|
|
44
|
+
* Layer declaration (injected once in root layout):
|
|
45
|
+
* @layer nexus.scoped, nexus.global;
|
|
46
|
+
*/
|
|
47
|
+
/** Murmurhash-inspired: fast, stable 32-bit hash → 6 hex chars */
|
|
48
|
+
export declare function componentHash(filepath: string): string;
|
|
49
|
+
export interface ScopedCSS {
|
|
50
|
+
css: string;
|
|
51
|
+
hash: string;
|
|
52
|
+
/** Class names defined in this scope */
|
|
53
|
+
classes: Set<string>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Transforms raw CSS into scoped CSS using the component hash.
|
|
57
|
+
* Handles: selectors, @media, @keyframes (not scoped), @layer, :global() escape hatch.
|
|
58
|
+
*/
|
|
59
|
+
/** Layer declaration to emit once in the root <head> */
|
|
60
|
+
export declare const NEXUS_LAYER_DECLARATION = "@layer nexus.scoped, nexus.global;";
|
|
61
|
+
export declare function scopeCSS(rawCSS: string, filepath: string): ScopedCSS;
|
|
62
|
+
/**
|
|
63
|
+
* Adds scope attribute to every HTML root element in a template string.
|
|
64
|
+
* Skips elements that are: slot, nexus-island, html, head, body.
|
|
65
|
+
* Handles :global(selector) — removes scoping for that selector.
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
* `.nx` pages often use `<template>...</template>` as the root. In the live DOM,
|
|
69
|
+
* `<template>` contents are inert (not rendered). SSR must unwrap the outer
|
|
70
|
+
* wrapper so the shell is visible; nested `<template>` inside the tree is rare
|
|
71
|
+
* and still wrapped until unwrapped by the same pass on inner routes only when
|
|
72
|
+
* they are the file root.
|
|
73
|
+
*/
|
|
74
|
+
export declare function unwrapOuterTemplateElement(html: string): string;
|
|
75
|
+
export declare function scopeTemplate(html: string, hash: string): string;
|
|
76
|
+
//# sourceMappingURL=css-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-scope.d.ts","sourceRoot":"","sources":["../src/css-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACtB;AAED;;;GAGG;AACH,wDAAwD;AACxD,eAAO,MAAM,uBAAuB,uCAAuC,CAAC;AAE5E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAoBpE;AAED;;;;GAIG;AACH;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqC/D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAyFhE"}
|