@invisibleloop/pulse 0.2.13 → 0.2.14
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/docs/public/.pulse-ui-version +1 -1
- package/docs/server.js +8 -0
- package/docs/src/lib/layout.js +8 -2
- package/package.json +1 -1
- package/public/.pulse-ui-version +1 -1
- package/scripts/build.js +39 -0
- package/src/server/index.js +7 -0
- package/src/ui/charts.js +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.
|
|
1
|
+
0.2.12
|
package/docs/server.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
1
2
|
import { createServer } from '../src/server/index.js'
|
|
3
|
+
import { initLayoutManifest } from './src/lib/layout.js'
|
|
2
4
|
import { metrics } from './src/lib/stats.js'
|
|
3
5
|
import { metricsStore } from './src/lib/metrics-store.js'
|
|
4
6
|
metricsStore.current = metrics
|
|
7
|
+
|
|
8
|
+
// Populate hashed asset paths in layout.js before any page renders
|
|
9
|
+
try {
|
|
10
|
+
const raw = fs.readFileSync(new URL('./public/dist/manifest.json', import.meta.url), 'utf8')
|
|
11
|
+
initLayoutManifest(JSON.parse(raw))
|
|
12
|
+
} catch { /* dev: no manifest yet, layout falls back to unhashed paths */ }
|
|
5
13
|
import home from './src/pages/home.js'
|
|
6
14
|
import howItWorks from './src/pages/how-it-works.js'
|
|
7
15
|
import faq from './src/pages/faq.js'
|
package/docs/src/lib/layout.js
CHANGED
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
import { NAV } from './nav.js'
|
|
9
9
|
import pkg from '../../../package.json' with { type: 'json' }
|
|
10
10
|
|
|
11
|
+
// Resolve static asset paths through the build manifest (hashed in prod, raw in dev).
|
|
12
|
+
// Populated by initLayoutManifest() in server.js before the server starts.
|
|
13
|
+
let _manifest = {}
|
|
14
|
+
export function initLayoutManifest(m) { _manifest = m }
|
|
15
|
+
const asset = href => _manifest[href] || href
|
|
16
|
+
|
|
11
17
|
const { version } = pkg
|
|
12
18
|
|
|
13
19
|
function esc(s) {
|
|
@@ -90,8 +96,8 @@ export function renderLayout({ currentHref, content, prev = null, next = null })
|
|
|
90
96
|
${prevNextBar(prev, next)}
|
|
91
97
|
</main>
|
|
92
98
|
</div>
|
|
93
|
-
<script src="/menu.js"></script>
|
|
94
|
-
<script src="/pulse-ui.js"></script>`
|
|
99
|
+
<script src="${asset('/menu.js')}" defer></script>
|
|
100
|
+
<script src="${asset('/pulse-ui.js')}" defer></script>`
|
|
95
101
|
}
|
|
96
102
|
|
|
97
103
|
/**
|
package/package.json
CHANGED
package/public/.pulse-ui-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.
|
|
1
|
+
0.2.14
|
package/scripts/build.js
CHANGED
|
@@ -404,6 +404,12 @@ fs.rmSync(TMP_DIR, { recursive: true })
|
|
|
404
404
|
|
|
405
405
|
await purgeCssStep(pages, manifest, ROOT, OUT_DIR)
|
|
406
406
|
|
|
407
|
+
// ---------------------------------------------------------------------------
|
|
408
|
+
// JS static assets — minify + hash any .js files directly in public/
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
|
|
411
|
+
await jsAssetsStep(ROOT, OUT_DIR, manifest)
|
|
412
|
+
|
|
407
413
|
// ---------------------------------------------------------------------------
|
|
408
414
|
// Report
|
|
409
415
|
// ---------------------------------------------------------------------------
|
|
@@ -420,6 +426,39 @@ for (const [src, bundle] of Object.entries(manifest)) {
|
|
|
420
426
|
}
|
|
421
427
|
console.log('\n✓ manifest written to public/dist/manifest.json\n')
|
|
422
428
|
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
// JS static assets implementation
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
|
|
433
|
+
async function jsAssetsStep(root, outDir, manifest) {
|
|
434
|
+
const publicDir = path.join(root, 'public')
|
|
435
|
+
if (!fs.existsSync(publicDir)) return
|
|
436
|
+
|
|
437
|
+
const jsFiles = fs.readdirSync(publicDir).filter(f => f.endsWith('.js'))
|
|
438
|
+
if (jsFiles.length === 0) return
|
|
439
|
+
|
|
440
|
+
console.log('⚡ Hashing static JS assets...\n')
|
|
441
|
+
|
|
442
|
+
for (const file of jsFiles) {
|
|
443
|
+
const srcPath = path.join(publicDir, file)
|
|
444
|
+
const source = fs.readFileSync(srcPath, 'utf8')
|
|
445
|
+
const { code } = await esbuild.transform(source, { minify: true, target: 'es2018' })
|
|
446
|
+
const hash = createHash('sha256').update(code).digest('hex').slice(0, 8)
|
|
447
|
+
const name = path.basename(file, '.js')
|
|
448
|
+
const outName = `${name}-${hash}.js`
|
|
449
|
+
|
|
450
|
+
fs.writeFileSync(path.join(outDir, outName), code)
|
|
451
|
+
manifest[`/${file}`] = `/dist/${outName}`
|
|
452
|
+
|
|
453
|
+
const origKb = (Buffer.byteLength(source) / 1024).toFixed(1)
|
|
454
|
+
const minKb = (Buffer.byteLength(code) / 1024).toFixed(1)
|
|
455
|
+
console.log(` /${file.padEnd(24)} → /dist/${outName} (${minKb} kB from ${origKb} kB)`)
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
fs.writeFileSync(path.join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2))
|
|
459
|
+
console.log('\n✓ JS asset entries added to manifest\n')
|
|
460
|
+
}
|
|
461
|
+
|
|
423
462
|
// ---------------------------------------------------------------------------
|
|
424
463
|
// CSS Purge implementation
|
|
425
464
|
// ---------------------------------------------------------------------------
|
package/src/server/index.js
CHANGED
|
@@ -1315,6 +1315,13 @@ function resolveSpec(spec, hydrateMap) {
|
|
|
1315
1315
|
}
|
|
1316
1316
|
}
|
|
1317
1317
|
|
|
1318
|
+
if (Array.isArray(spec.meta?.scripts)) {
|
|
1319
|
+
const resolvedScripts = spec.meta.scripts.map(href => hydrateMap[href] || href)
|
|
1320
|
+
if (resolvedScripts.some((s, i) => s !== spec.meta.scripts[i])) {
|
|
1321
|
+
resolved = { ...resolved, meta: { ...resolved.meta, scripts: resolvedScripts } }
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1318
1325
|
return resolved
|
|
1319
1326
|
}
|
|
1320
1327
|
|
package/src/ui/charts.js
CHANGED
|
@@ -117,7 +117,7 @@ export function barChart({
|
|
|
117
117
|
const ariaLabel = `Bar chart: ${data.map(d => `${d.label ?? ''} ${d.value}`).join(', ')}`
|
|
118
118
|
const clsAttr = cls ? ` class="${e(cls)}"` : ''
|
|
119
119
|
|
|
120
|
-
return `<
|
|
120
|
+
return `<div${clsAttr} style="width:100%;aspect-ratio:${IW}/${height}"><svg viewBox="0 0 ${IW} ${height}" width="100%" height="100%" style="display:block" role="img" aria-label="${e(ariaLabel)}">${grid}${baseline}${bars}</svg></div>`
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// ─── Line chart ───────────────────────────────────────────────────────────────
|
|
@@ -193,7 +193,7 @@ export function lineChart({
|
|
|
193
193
|
const ariaLabel = `Line chart: ${data.map(d => `${d.label ?? ''} ${d.value}`).join(', ')}`
|
|
194
194
|
const clsAttr = cls ? ` class="${e(cls)}"` : ''
|
|
195
195
|
|
|
196
|
-
return `<
|
|
196
|
+
return `<div${clsAttr} style="width:100%;aspect-ratio:${IW}/${height}"><svg viewBox="0 0 ${IW} ${height}" width="100%" height="100%" style="display:block" role="img" aria-label="${e(ariaLabel)}">${grid}${areaPath}${line}${dots}${xlabels}</svg></div>`
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
// ─── Donut chart ──────────────────────────────────────────────────────────────
|
|
@@ -321,7 +321,9 @@ export function sparkline({
|
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
const clsAttr = cls ? ` class="${e(cls)}"` : ''
|
|
324
|
-
|
|
324
|
+
if (fluid) {
|
|
325
|
+
return `<div${clsAttr} style="width:100%;aspect-ratio:${width}/${height}"><svg viewBox="0 0 ${width} ${height}" width="100%" height="100%" style="display:block" aria-hidden="true">${areaPath}<polyline points="${points}" fill="none" stroke="${c}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>`
|
|
326
|
+
}
|
|
325
327
|
|
|
326
|
-
return `<svg${clsAttr} viewBox="0 0 ${width} ${height}" ${
|
|
328
|
+
return `<svg${clsAttr} viewBox="0 0 ${width} ${height}" width="${width}" height="${height}" aria-hidden="true">${areaPath}<polyline points="${points}" fill="none" stroke="${c}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`
|
|
327
329
|
}
|