@kenjura/ursa 0.76.0 → 0.77.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/CHANGELOG.md +35 -17
- package/meta/default.css +33 -0
- package/meta/templates/default-template/default.css +1268 -0
- package/meta/{default-template.html → templates/default-template/index.html} +15 -0
- package/meta/{menu.js → templates/default-template/menu.js} +1 -1
- package/meta/templates/default-template/sectionify.js +46 -0
- package/meta/{widgets.js → templates/default-template/widgets.js} +126 -0
- package/package.json +1 -1
- package/src/dev.js +73 -28
- package/src/helper/assetBundler.js +471 -0
- package/src/helper/build/autoIndex.js +24 -23
- package/src/helper/build/cacheBust.js +79 -0
- package/src/helper/build/navCache.js +4 -0
- package/src/helper/build/templates.js +176 -19
- package/src/helper/build/watchCache.js +7 -0
- package/src/helper/customMenu.js +4 -2
- package/src/helper/dependencyTracker.js +269 -0
- package/src/helper/findStyleCss.js +29 -0
- package/src/helper/portUtils.js +132 -0
- package/src/jobs/generate.js +228 -60
- package/src/serve.js +446 -162
- package/meta/character-sheet.css +0 -50
- /package/meta/{goudy_bookletter_1911-webfont.woff → shared/goudy_bookletter_1911-webfont.woff} +0 -0
- /package/meta/{character-sheet/css → templates/character-sheet-template}/character-sheet.css +0 -0
- /package/meta/{character-sheet/js → templates/character-sheet-template}/components.js +0 -0
- /package/meta/{cssui.bundle.min.css → templates/character-sheet-template/cssui.bundle.min.css} +0 -0
- /package/meta/{character-sheet-template.html → templates/character-sheet-template/index.html} +0 -0
- /package/meta/{character-sheet/js → templates/character-sheet-template}/main.js +0 -0
- /package/meta/{character-sheet/js → templates/character-sheet-template}/model.js +0 -0
- /package/meta/{search.js → templates/default-template/search.js} +0 -0
- /package/meta/{sticky.js → templates/default-template/sticky.js} +0 -0
- /package/meta/{toc-generator.js → templates/default-template/toc-generator.js} +0 -0
- /package/meta/{toc.js → templates/default-template/toc.js} +0 -0
- /package/meta/{template2.html → templates/template2/index.html} +0 -0
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
<button class="widget-button" data-widget="recent-activity" data-widget-side="left" aria-label="Recent Activity" title="Recent Activity">
|
|
17
17
|
<span class="widget-icon">🕒</span>
|
|
18
18
|
</button>
|
|
19
|
+
<button class="widget-button" data-widget="suggested" data-widget-side="left" aria-label="Suggested Content" title="Suggested Content">
|
|
20
|
+
<span class="widget-icon">⭐</span>
|
|
21
|
+
</button>
|
|
22
|
+
</div>
|
|
23
|
+
<div id="ursa-update-indicator" class="ursa-update-indicator" style="display:none;" title="Updating...">
|
|
24
|
+
<div class="ursa-spinner"></div>
|
|
19
25
|
</div>
|
|
20
26
|
</div>
|
|
21
27
|
|
|
@@ -55,6 +61,15 @@
|
|
|
55
61
|
<!-- Populated by JavaScript -->
|
|
56
62
|
</div>
|
|
57
63
|
</div>
|
|
64
|
+
<div id="widget-content-suggested" class="widget-content" data-widget="suggested">
|
|
65
|
+
<div class="widget-header">
|
|
66
|
+
<span class="widget-header-title">Suggested</span>
|
|
67
|
+
<button class="widget-close-btn" aria-label="Close">✕</button>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="suggested-content-list">
|
|
70
|
+
<!-- Populated by JavaScript -->
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
58
73
|
</div>
|
|
59
74
|
|
|
60
75
|
<!-- Widget dropdown panel for RIGHT-side widgets -->
|
|
@@ -11,7 +11,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
11
11
|
const navMain = document.querySelector('nav#nav-main');
|
|
12
12
|
const navMainTop = document.querySelector('nav#nav-main-top');
|
|
13
13
|
const menuPosition = document.body.dataset.menuPosition || 'top';
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
// If menu position is top (default), handle differently
|
|
16
16
|
if (menuPosition === 'top') {
|
|
17
17
|
initTopMenu();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
2
|
+
const article = document.querySelector('article#main-content');
|
|
3
|
+
if (!article) return;
|
|
4
|
+
|
|
5
|
+
const children = Array.from(article.children);
|
|
6
|
+
let sections = [];
|
|
7
|
+
let currentSection = document.createElement('section');
|
|
8
|
+
currentSection.classList.add('sectionOuter');
|
|
9
|
+
|
|
10
|
+
for (let i = 0; i < children.length; i++) {
|
|
11
|
+
const el = children[i];
|
|
12
|
+
// Skip breadcrumb nav — it stays outside sections
|
|
13
|
+
if (el.classList && el.classList.contains('breadcrumbs')) continue;
|
|
14
|
+
if (el.tagName === 'H1' && currentSection.childNodes.length > 0) {
|
|
15
|
+
sections.push(currentSection);
|
|
16
|
+
currentSection = document.createElement('section');
|
|
17
|
+
currentSection.classList.add('sectionOuter');
|
|
18
|
+
}
|
|
19
|
+
currentSection.appendChild(el);
|
|
20
|
+
}
|
|
21
|
+
if (currentSection.childNodes.length > 0) {
|
|
22
|
+
sections.push(currentSection);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Preserve breadcrumb nav before clearing
|
|
26
|
+
const breadcrumbs = article.querySelector('.breadcrumbs');
|
|
27
|
+
|
|
28
|
+
// Remove all existing children
|
|
29
|
+
while (article.firstChild) {
|
|
30
|
+
article.removeChild(article.firstChild);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Re-insert breadcrumbs at the top, outside any section
|
|
34
|
+
if (breadcrumbs) {
|
|
35
|
+
article.appendChild(breadcrumbs);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Append new sections
|
|
39
|
+
sections.forEach(section => article.appendChild(section));
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
// Optional: Add section numbers or other decorations
|
|
43
|
+
Array.from(article.querySelectorAll('section.sectionOuter')).forEach((section, index) => {
|
|
44
|
+
section.style.setProperty('--section-index', index + 1);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -111,6 +111,10 @@ class WidgetManager {
|
|
|
111
111
|
|
|
112
112
|
// Initialize recent activity widget
|
|
113
113
|
this.initRecentActivityWidget();
|
|
114
|
+
|
|
115
|
+
// Track current page view and initialize suggested content widget
|
|
116
|
+
this.trackPageView();
|
|
117
|
+
this.initSuggestedWidget();
|
|
114
118
|
|
|
115
119
|
// Restore saved widget states from localStorage
|
|
116
120
|
this.restoreState();
|
|
@@ -567,6 +571,128 @@ class WidgetManager {
|
|
|
567
571
|
if (months < 12) return `${months}mo ago`;
|
|
568
572
|
return `${years}y ago`;
|
|
569
573
|
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Track current page view in localStorage.
|
|
577
|
+
* Stores a map of URL → { count, lastVisit, title }
|
|
578
|
+
*/
|
|
579
|
+
trackPageView() {
|
|
580
|
+
const url = window.location.pathname;
|
|
581
|
+
// Skip tracking for index/home pages to keep suggestions more focused
|
|
582
|
+
if (url === '/' || url === '/index.html') return;
|
|
583
|
+
|
|
584
|
+
const STORAGE_KEY = 'ursa-page-views';
|
|
585
|
+
const MAX_TRACKED_PAGES = 100; // Limit storage size
|
|
586
|
+
|
|
587
|
+
try {
|
|
588
|
+
let pageViews = {};
|
|
589
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
590
|
+
if (stored) {
|
|
591
|
+
pageViews = JSON.parse(stored);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Get page title from the document
|
|
595
|
+
const title = document.title || url;
|
|
596
|
+
|
|
597
|
+
// Update or create entry for this page
|
|
598
|
+
if (pageViews[url]) {
|
|
599
|
+
pageViews[url].count += 1;
|
|
600
|
+
pageViews[url].lastVisit = Date.now();
|
|
601
|
+
pageViews[url].title = title;
|
|
602
|
+
} else {
|
|
603
|
+
pageViews[url] = {
|
|
604
|
+
count: 1,
|
|
605
|
+
lastVisit: Date.now(),
|
|
606
|
+
title: title
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Prune oldest entries if we exceed the limit
|
|
611
|
+
const entries = Object.entries(pageViews);
|
|
612
|
+
if (entries.length > MAX_TRACKED_PAGES) {
|
|
613
|
+
// Sort by lastVisit and keep only the most recent
|
|
614
|
+
entries.sort((a, b) => b[1].lastVisit - a[1].lastVisit);
|
|
615
|
+
pageViews = Object.fromEntries(entries.slice(0, MAX_TRACKED_PAGES));
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(pageViews));
|
|
619
|
+
} catch (e) {
|
|
620
|
+
// localStorage not available or quota exceeded
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Initialize the Suggested Content widget.
|
|
626
|
+
* Shows frequently viewed pages based on localStorage tracking.
|
|
627
|
+
*/
|
|
628
|
+
initSuggestedWidget() {
|
|
629
|
+
const container = document.querySelector('.suggested-content-list');
|
|
630
|
+
if (!container) return;
|
|
631
|
+
|
|
632
|
+
const STORAGE_KEY = 'ursa-page-views';
|
|
633
|
+
const MAX_SUGGESTIONS = 10;
|
|
634
|
+
const currentUrl = window.location.pathname;
|
|
635
|
+
|
|
636
|
+
try {
|
|
637
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
638
|
+
if (!stored) {
|
|
639
|
+
container.innerHTML = '<div class="suggested-empty">Visit more pages to see suggestions</div>';
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const pageViews = JSON.parse(stored);
|
|
644
|
+
const entries = Object.entries(pageViews);
|
|
645
|
+
|
|
646
|
+
if (entries.length === 0) {
|
|
647
|
+
container.innerHTML = '<div class="suggested-empty">Visit more pages to see suggestions</div>';
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Filter out current page and sort by view count (descending)
|
|
652
|
+
const sorted = entries
|
|
653
|
+
.filter(([url]) => url !== currentUrl)
|
|
654
|
+
.sort((a, b) => {
|
|
655
|
+
// Primary sort: view count (descending)
|
|
656
|
+
const countDiff = b[1].count - a[1].count;
|
|
657
|
+
if (countDiff !== 0) return countDiff;
|
|
658
|
+
// Secondary sort: last visit (descending)
|
|
659
|
+
return b[1].lastVisit - a[1].lastVisit;
|
|
660
|
+
})
|
|
661
|
+
.slice(0, MAX_SUGGESTIONS);
|
|
662
|
+
|
|
663
|
+
if (sorted.length === 0) {
|
|
664
|
+
container.innerHTML = '<div class="suggested-empty">Visit more pages to see suggestions</div>';
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
container.innerHTML = '';
|
|
669
|
+
const ul = document.createElement('ul');
|
|
670
|
+
ul.className = 'suggested-items';
|
|
671
|
+
|
|
672
|
+
for (const [url, data] of sorted) {
|
|
673
|
+
const li = document.createElement('li');
|
|
674
|
+
li.className = 'suggested-item';
|
|
675
|
+
|
|
676
|
+
const a = document.createElement('a');
|
|
677
|
+
a.href = url;
|
|
678
|
+
a.className = 'suggested-link';
|
|
679
|
+
a.textContent = data.title || url;
|
|
680
|
+
|
|
681
|
+
const meta = document.createElement('span');
|
|
682
|
+
meta.className = 'suggested-meta';
|
|
683
|
+
meta.textContent = `${data.count} view${data.count !== 1 ? 's' : ''}`;
|
|
684
|
+
meta.title = `Last visited: ${new Date(data.lastVisit).toLocaleString()}`;
|
|
685
|
+
|
|
686
|
+
li.appendChild(a);
|
|
687
|
+
li.appendChild(meta);
|
|
688
|
+
ul.appendChild(li);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
container.appendChild(ul);
|
|
692
|
+
} catch (e) {
|
|
693
|
+
container.innerHTML = '<div class="suggested-empty">Unable to load suggestions</div>';
|
|
694
|
+
}
|
|
695
|
+
}
|
|
570
696
|
}
|
|
571
697
|
|
|
572
698
|
// Initialize widgets when DOM is ready
|
package/package.json
CHANGED
package/src/dev.js
CHANGED
|
@@ -33,9 +33,12 @@ import { extractImageReferences } from "./helper/imageExtractor.js";
|
|
|
33
33
|
import { recurse } from "./helper/recursive-readdir.js";
|
|
34
34
|
import { isFolderHidden, clearConfigCache } from "./helper/folderConfig.js";
|
|
35
35
|
import { extractSections } from "./helper/sectionExtractor.js";
|
|
36
|
-
import { getTemplates, getMenu, findAllCustomMenus, getCustomMenuForFile, getTransformedMetadata, getFooter, toTitleCase, addTrailingSlash, generateAutoIndexHtmlFromSource } from "./helper/build/index.js";
|
|
36
|
+
import { getTemplates, getMenu, findAllCustomMenus, getCustomMenuForFile, getTransformedMetadata, getFooter, toTitleCase, addTrailingSlash, generateAutoIndexHtmlFromSource, copyMetaAssets } from "./helper/build/index.js";
|
|
37
37
|
import { findCustomMenu, extractMenuFrontmatter, parseCustomMenu, combineAutoAndManualMenu } from "./helper/customMenu.js";
|
|
38
38
|
import { getAndIncrementBuildId } from "./helper/ursaConfig.js";
|
|
39
|
+
import { resolvePort } from "./helper/portUtils.js";
|
|
40
|
+
import { findAllStyleCss } from "./helper/findStyleCss.js";
|
|
41
|
+
import { bundleMetaTemplateAssets, generateSeparateCssTags, generateSeparateJsTags, clearMetaBundleCache } from "./helper/assetBundler.js";
|
|
39
42
|
|
|
40
43
|
// Dev mode state
|
|
41
44
|
const devState = {
|
|
@@ -266,6 +269,23 @@ function findNearestMenu(dirPath) {
|
|
|
266
269
|
return null;
|
|
267
270
|
}
|
|
268
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Find all style.css files from docroot to dirPath (all levels)
|
|
274
|
+
*/
|
|
275
|
+
async function findAllStyles(dirPath) {
|
|
276
|
+
const { stylePathMap, source } = devState;
|
|
277
|
+
|
|
278
|
+
// Use a separate cache key to avoid collision with findNearestStyle
|
|
279
|
+
const cacheKey = `all:${dirPath}`;
|
|
280
|
+
if (stylePathMap.has(cacheKey)) {
|
|
281
|
+
return stylePathMap.get(cacheKey);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const stylePaths = await findAllStyleCss(dirPath, source);
|
|
285
|
+
stylePathMap.set(cacheKey, stylePaths);
|
|
286
|
+
return stylePaths;
|
|
287
|
+
}
|
|
288
|
+
|
|
269
289
|
/**
|
|
270
290
|
* Find the nearest style.css
|
|
271
291
|
*/
|
|
@@ -440,35 +460,40 @@ async function wrapInTemplate(body, title, fileMeta, urlPath, sourcePath) {
|
|
|
440
460
|
throw new Error(`Template not found: ${requestedTemplateName || 'default-template'}`);
|
|
441
461
|
}
|
|
442
462
|
|
|
443
|
-
// Find
|
|
463
|
+
// Find all style.css files from docroot to current dir and serve as separate tags
|
|
464
|
+
// (Serve/dev mode: separate tags per level for individual invalidation)
|
|
444
465
|
let styleLink = "";
|
|
445
466
|
try {
|
|
446
467
|
const styleDir = sourcePath ? dirname(sourcePath) : source;
|
|
447
|
-
const
|
|
448
|
-
if (
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
468
|
+
const cssPaths = await findAllStyles(styleDir);
|
|
469
|
+
if (cssPaths.length > 0) {
|
|
470
|
+
// Copy all CSS files to output
|
|
471
|
+
for (const cssPath of cssPaths) {
|
|
472
|
+
const cssOutputPath = cssPath.replace(source, output);
|
|
473
|
+
const cssContent = await readFile(cssPath, 'utf8');
|
|
474
|
+
await outputFile(cssOutputPath, cssContent);
|
|
475
|
+
}
|
|
476
|
+
styleLink = generateSeparateCssTags(cssPaths, source);
|
|
456
477
|
}
|
|
457
478
|
} catch (e) {
|
|
458
479
|
// Ignore CSS errors
|
|
459
480
|
}
|
|
460
481
|
|
|
461
|
-
// Find all script.js files from docroot to current dir and
|
|
482
|
+
// Find all script.js files from docroot to current dir and serve as separate external tags
|
|
483
|
+
// (Serve/dev mode: separate tags per level for individual invalidation)
|
|
462
484
|
let customScript = "";
|
|
463
485
|
try {
|
|
464
486
|
const scriptDir = sourcePath ? dirname(sourcePath) : source;
|
|
465
487
|
const scriptPaths = await findAllScripts(scriptDir);
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const
|
|
469
|
-
|
|
488
|
+
if (scriptPaths.length > 0) {
|
|
489
|
+
// Copy all script files to output so they can be served
|
|
490
|
+
for (const scriptPath of scriptPaths) {
|
|
491
|
+
const scriptOutputPath = scriptPath.replace(source, output);
|
|
492
|
+
const scriptContent = await readFile(scriptPath, 'utf8');
|
|
493
|
+
await outputFile(scriptOutputPath, scriptContent);
|
|
494
|
+
}
|
|
495
|
+
customScript = generateSeparateJsTags(scriptPaths, source);
|
|
470
496
|
}
|
|
471
|
-
customScript = scriptTags.join('\n');
|
|
472
497
|
} catch (e) {
|
|
473
498
|
// Ignore script errors
|
|
474
499
|
}
|
|
@@ -617,9 +642,10 @@ async function buildBackgroundCaches() {
|
|
|
617
642
|
await findNearestStyle(dir);
|
|
618
643
|
}
|
|
619
644
|
|
|
620
|
-
// 7. Pre-load templates
|
|
645
|
+
// 7. Pre-load templates and re-bundle meta assets
|
|
621
646
|
console.log(' 📄 Pre-loading templates...');
|
|
622
|
-
|
|
647
|
+
const rawTemplatesBg = await getTemplates(meta);
|
|
648
|
+
devState.templates = await bundleMetaTemplateAssets(rawTemplatesBg, meta, resolve(output, 'public'), { minify: true, sourcemap: false });
|
|
623
649
|
|
|
624
650
|
// 8. Build footer
|
|
625
651
|
console.log(' 📝 Building footer...');
|
|
@@ -724,15 +750,20 @@ export async function dev({
|
|
|
724
750
|
console.log(`🎨 Meta: ${metaDir}`);
|
|
725
751
|
console.log(`📤 Output: ${outputDir}`);
|
|
726
752
|
console.log('━'.repeat(50));
|
|
727
|
-
|
|
753
|
+
|
|
754
|
+
// Resolve port (prompt user if occupied)
|
|
755
|
+
port = await resolvePort(port);
|
|
756
|
+
|
|
728
757
|
// Create output directory and copy meta files
|
|
729
758
|
await mkdir(outputDir, { recursive: true });
|
|
730
759
|
const publicDir = join(outputDir, 'public');
|
|
731
760
|
await mkdir(publicDir, { recursive: true });
|
|
732
|
-
await
|
|
761
|
+
await copyMetaAssets(metaDir, publicDir);
|
|
733
762
|
|
|
734
|
-
// Pre-load templates for
|
|
735
|
-
|
|
763
|
+
// Pre-load templates and bundle meta assets (minify without obfuscation for debuggability)
|
|
764
|
+
let rawTemplates = await getTemplates(metaDir);
|
|
765
|
+
devState.templates = await bundleMetaTemplateAssets(rawTemplates, metaDir, publicDir, { minify: true, sourcemap: false });
|
|
766
|
+
console.log('📦 Meta template assets bundled');
|
|
736
767
|
|
|
737
768
|
// Start server immediately
|
|
738
769
|
const app = express();
|
|
@@ -950,20 +981,29 @@ export async function dev({
|
|
|
950
981
|
devState.menuReady = false;
|
|
951
982
|
await buildBackgroundCaches();
|
|
952
983
|
} else if (isCssChange) {
|
|
953
|
-
// Copy CSS to output
|
|
984
|
+
// Copy CSS to output and clear style cache so next render picks up changes
|
|
985
|
+
devState.stylePathMap.clear();
|
|
954
986
|
try {
|
|
955
987
|
const relativePath = name.replace(sourceDir, '');
|
|
956
988
|
const outputPath = join(outputDir, relativePath);
|
|
957
989
|
const content = await readFile(name, 'utf8');
|
|
958
990
|
await outputFile(outputPath, content);
|
|
959
|
-
console.log(`✅ Copied ${relativePath}`);
|
|
991
|
+
console.log(`✅ Copied ${relativePath} (style cache cleared)`);
|
|
960
992
|
} catch (e) {
|
|
961
993
|
console.error(`Error copying CSS: ${e.message}`);
|
|
962
994
|
}
|
|
963
995
|
} else if (isScriptChange) {
|
|
964
|
-
//
|
|
996
|
+
// Copy script to output and clear script cache so next render picks up changes
|
|
965
997
|
devState.scriptPathMap.clear();
|
|
966
|
-
|
|
998
|
+
try {
|
|
999
|
+
const relativePath = name.replace(sourceDir, '');
|
|
1000
|
+
const outputPath = join(outputDir, relativePath);
|
|
1001
|
+
const content = await readFile(name, 'utf8');
|
|
1002
|
+
await outputFile(outputPath, content);
|
|
1003
|
+
console.log(`✅ Copied ${relativePath} (script cache cleared)`);
|
|
1004
|
+
} catch (e) {
|
|
1005
|
+
console.error(`Error copying script: ${e.message}`);
|
|
1006
|
+
}
|
|
967
1007
|
} else if (isComponentChange) {
|
|
968
1008
|
// Component files (.tsx, .jsx, .ts) may be imported by MDX files
|
|
969
1009
|
// Clear all MDX document caches so they re-compile with the updated component
|
|
@@ -1009,7 +1049,12 @@ export async function dev({
|
|
|
1009
1049
|
// Watch meta directory for template changes
|
|
1010
1050
|
watch(metaDir, { recursive: true }, async (evt, name) => {
|
|
1011
1051
|
console.log(`🎨 Meta changed: ${name}`);
|
|
1012
|
-
|
|
1052
|
+
clearMetaBundleCache();
|
|
1053
|
+
const rawMetaTemplates = await getTemplates(metaDir);
|
|
1054
|
+
// Re-copy meta files and re-bundle
|
|
1055
|
+
const pubDir = join(outputDir, 'public');
|
|
1056
|
+
await copyMetaAssets(metaDir, pubDir);
|
|
1057
|
+
devState.templates = await bundleMetaTemplateAssets(rawMetaTemplates, metaDir, pubDir, { minify: true, sourcemap: false });
|
|
1013
1058
|
broadcast('reload', { file: name });
|
|
1014
1059
|
});
|
|
1015
1060
|
|