basecampjs 0.0.11 → 0.0.13
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/index.js +62 -20
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -23,10 +23,11 @@ const md = new MarkdownIt({ html: true, linkify: true, typographer: true });
|
|
|
23
23
|
|
|
24
24
|
const defaultConfig = {
|
|
25
25
|
siteName: "Campsite",
|
|
26
|
+
siteUrl: "https://example.com",
|
|
26
27
|
srcDir: "src",
|
|
27
28
|
outDir: "dist",
|
|
28
29
|
templateEngine: "nunjucks",
|
|
29
|
-
|
|
30
|
+
frontmatter: true,
|
|
30
31
|
minifyCSS: false,
|
|
31
32
|
minifyHTML: false,
|
|
32
33
|
cacheBustAssets: false,
|
|
@@ -38,6 +39,7 @@ const defaultConfig = {
|
|
|
38
39
|
inputFormats: [".jpg", ".jpeg", ".png"],
|
|
39
40
|
preserveOriginal: true
|
|
40
41
|
},
|
|
42
|
+
port: 4173,
|
|
41
43
|
integrations: { nunjucks: true, liquid: false, mustache: false, vue: false, alpine: false }
|
|
42
44
|
};
|
|
43
45
|
|
|
@@ -388,6 +390,26 @@ function createLiquidEnv(layoutsDir, pagesDir, srcDir, partialsDir) {
|
|
|
388
390
|
});
|
|
389
391
|
}
|
|
390
392
|
|
|
393
|
+
async function loadMustachePartials(partialsDir) {
|
|
394
|
+
const partials = {};
|
|
395
|
+
if (!existsSync(partialsDir)) return partials;
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
const files = await walkFiles(partialsDir);
|
|
399
|
+
await Promise.all(files.map(async (file) => {
|
|
400
|
+
if (extname(file).toLowerCase() === ".mustache") {
|
|
401
|
+
const content = await readFile(file, "utf8");
|
|
402
|
+
const partialName = basename(file, ".mustache");
|
|
403
|
+
partials[partialName] = content;
|
|
404
|
+
}
|
|
405
|
+
}));
|
|
406
|
+
} catch (err) {
|
|
407
|
+
console.error(kolor.yellow(`Warning: Failed to load Mustache partials: ${err.message}`));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return partials;
|
|
411
|
+
}
|
|
412
|
+
|
|
391
413
|
function toUrlPath(outRel) {
|
|
392
414
|
const normalized = outRel.replace(/\\/g, "/");
|
|
393
415
|
let path = `/${normalized}`;
|
|
@@ -416,7 +438,7 @@ function shouldRenderMarkdown(frontmatter, config, defaultValue) {
|
|
|
416
438
|
return defaultValue;
|
|
417
439
|
}
|
|
418
440
|
|
|
419
|
-
async function renderWithLayout(layoutName, html, ctx, env, liquidEnv, layoutsDir) {
|
|
441
|
+
async function renderWithLayout(layoutName, html, ctx, env, liquidEnv, layoutsDir, partials = {}) {
|
|
420
442
|
if (!layoutName) return html;
|
|
421
443
|
const ext = extname(layoutName).toLowerCase();
|
|
422
444
|
const layoutCtx = {
|
|
@@ -438,7 +460,7 @@ async function renderWithLayout(layoutName, html, ctx, env, liquidEnv, layoutsDi
|
|
|
438
460
|
const layoutPath = join(layoutsDir, layoutName);
|
|
439
461
|
if (existsSync(layoutPath)) {
|
|
440
462
|
const layoutTemplate = await readFile(layoutPath, "utf8");
|
|
441
|
-
return Mustache.render(layoutTemplate, layoutCtx);
|
|
463
|
+
return Mustache.render(layoutTemplate, layoutCtx, partials);
|
|
442
464
|
}
|
|
443
465
|
}
|
|
444
466
|
|
|
@@ -446,20 +468,25 @@ async function renderWithLayout(layoutName, html, ctx, env, liquidEnv, layoutsDi
|
|
|
446
468
|
return html;
|
|
447
469
|
}
|
|
448
470
|
|
|
449
|
-
async function renderPage(filePath, { pagesDir, layoutsDir, outDir, env, liquidEnv, config, data }) {
|
|
471
|
+
async function renderPage(filePath, { pagesDir, layoutsDir, outDir, env, liquidEnv, config, data, partialsDir }) {
|
|
450
472
|
const rel = relative(pagesDir, filePath);
|
|
451
473
|
const ext = extname(filePath).toLowerCase();
|
|
452
474
|
const outRel = rel.replace(/\.liquid(\.html)?$/i, ".html").replace(ext, ".html");
|
|
453
475
|
const outPath = join(outDir, outRel);
|
|
454
476
|
const path = toUrlPath(outRel);
|
|
455
477
|
await ensureDir(dirname(outPath));
|
|
478
|
+
|
|
479
|
+
// Load Mustache partials if needed
|
|
480
|
+
const partials = (ext === ".mustache" || (await readFile(filePath, "utf8")).match(/layout:.*\.mustache/))
|
|
481
|
+
? await loadMustachePartials(partialsDir)
|
|
482
|
+
: {};
|
|
456
483
|
|
|
457
484
|
if (ext === ".md") {
|
|
458
485
|
const raw = await readFile(filePath, "utf8");
|
|
459
486
|
const parsed = matter(raw);
|
|
460
487
|
const html = md.render(parsed.content);
|
|
461
488
|
const ctx = pageContext(parsed.data, html, config, rel, data, path);
|
|
462
|
-
const rendered = await renderWithLayout(parsed.data.layout, html, ctx, env, liquidEnv, layoutsDir);
|
|
489
|
+
const rendered = await renderWithLayout(parsed.data.layout, html, ctx, env, liquidEnv, layoutsDir, partials);
|
|
463
490
|
await writeFile(outPath, rendered, "utf8");
|
|
464
491
|
return;
|
|
465
492
|
}
|
|
@@ -473,7 +500,7 @@ async function renderPage(filePath, { pagesDir, layoutsDir, outDir, env, liquidE
|
|
|
473
500
|
if (shouldRenderMarkdown(parsed.data, config, false)) {
|
|
474
501
|
pageHtml = md.render(pageHtml);
|
|
475
502
|
}
|
|
476
|
-
const rendered = await renderWithLayout(parsed.data.layout, pageHtml, ctx, env, liquidEnv, layoutsDir);
|
|
503
|
+
const rendered = await renderWithLayout(parsed.data.layout, pageHtml, ctx, env, liquidEnv, layoutsDir, partials);
|
|
477
504
|
await writeFile(outPath, rendered, "utf8");
|
|
478
505
|
return;
|
|
479
506
|
}
|
|
@@ -486,7 +513,7 @@ async function renderPage(filePath, { pagesDir, layoutsDir, outDir, env, liquidE
|
|
|
486
513
|
if (shouldRenderMarkdown(parsed.data, config, false)) {
|
|
487
514
|
pageHtml = md.render(pageHtml);
|
|
488
515
|
}
|
|
489
|
-
const rendered = await renderWithLayout(parsed.data.layout, pageHtml, ctx, env, liquidEnv, layoutsDir);
|
|
516
|
+
const rendered = await renderWithLayout(parsed.data.layout, pageHtml, ctx, env, liquidEnv, layoutsDir, partials);
|
|
490
517
|
await writeFile(outPath, rendered, "utf8");
|
|
491
518
|
return;
|
|
492
519
|
}
|
|
@@ -495,11 +522,11 @@ async function renderPage(filePath, { pagesDir, layoutsDir, outDir, env, liquidE
|
|
|
495
522
|
const raw = await readFile(filePath, "utf8");
|
|
496
523
|
const parsed = matter(raw);
|
|
497
524
|
const ctx = pageContext(parsed.data, parsed.content, config, rel, data, path);
|
|
498
|
-
let pageHtml = Mustache.render(parsed.content, ctx);
|
|
525
|
+
let pageHtml = Mustache.render(parsed.content, ctx, partials);
|
|
499
526
|
if (shouldRenderMarkdown(parsed.data, config, false)) {
|
|
500
527
|
pageHtml = md.render(pageHtml);
|
|
501
528
|
}
|
|
502
|
-
const rendered = await renderWithLayout(parsed.data.layout, pageHtml, ctx, env, liquidEnv, layoutsDir);
|
|
529
|
+
const rendered = await renderWithLayout(parsed.data.layout, pageHtml, ctx, env, liquidEnv, layoutsDir, partials);
|
|
503
530
|
await writeFile(outPath, rendered, "utf8");
|
|
504
531
|
return;
|
|
505
532
|
}
|
|
@@ -512,7 +539,7 @@ async function renderPage(filePath, { pagesDir, layoutsDir, outDir, env, liquidE
|
|
|
512
539
|
if (shouldRenderMarkdown(parsed.data, config, false)) {
|
|
513
540
|
pageHtml = md.render(pageHtml);
|
|
514
541
|
}
|
|
515
|
-
const rendered = await renderWithLayout(parsed.data.layout, pageHtml, ctx, env, liquidEnv, layoutsDir);
|
|
542
|
+
const rendered = await renderWithLayout(parsed.data.layout, pageHtml, ctx, env, liquidEnv, layoutsDir, partials);
|
|
516
543
|
await writeFile(outPath, rendered, "utf8");
|
|
517
544
|
return;
|
|
518
545
|
}
|
|
@@ -602,7 +629,7 @@ async function cacheBustAssets(outDir) {
|
|
|
602
629
|
return assetMap;
|
|
603
630
|
}
|
|
604
631
|
|
|
605
|
-
async function build(cwdArg = cwd) {
|
|
632
|
+
async function build(cwdArg = cwd, options = {}) {
|
|
606
633
|
const config = await loadConfig(cwdArg);
|
|
607
634
|
const srcDir = resolve(cwdArg, config.srcDir || "src");
|
|
608
635
|
const pagesDir = join(srcDir, "pages");
|
|
@@ -635,7 +662,9 @@ async function build(cwdArg = cwd) {
|
|
|
635
662
|
await cleanDir(outDir);
|
|
636
663
|
await copyPublic(publicDir, outDir, config.excludeFiles);
|
|
637
664
|
|
|
638
|
-
|
|
665
|
+
// Only compress photos during production builds, not during dev mode
|
|
666
|
+
const shouldCompressPhotos = options.skipImageCompression !== true && config.compressPhotos;
|
|
667
|
+
if (shouldCompressPhotos) {
|
|
639
668
|
await processImages(outDir, config);
|
|
640
669
|
}
|
|
641
670
|
|
|
@@ -645,19 +674,22 @@ async function build(cwdArg = cwd) {
|
|
|
645
674
|
return;
|
|
646
675
|
}
|
|
647
676
|
|
|
648
|
-
await Promise.all(files.map((file) => renderPage(file, { pagesDir, layoutsDir, outDir, env, liquidEnv, config, data })));
|
|
677
|
+
await Promise.all(files.map((file) => renderPage(file, { pagesDir, layoutsDir, outDir, env, liquidEnv, config, data, partialsDir })));
|
|
649
678
|
|
|
650
|
-
|
|
679
|
+
// Skip minification and cache busting in dev mode for faster rebuilds
|
|
680
|
+
const isDevMode = options.devMode === true;
|
|
681
|
+
|
|
682
|
+
if (!isDevMode && config.minifyCSS) {
|
|
651
683
|
await minifyCSSFiles(outDir);
|
|
652
684
|
console.log(kolor.green("CSS minified"));
|
|
653
685
|
}
|
|
654
686
|
|
|
655
|
-
if (config.minifyHTML) {
|
|
687
|
+
if (!isDevMode && config.minifyHTML) {
|
|
656
688
|
await minifyHTMLFiles(outDir, config);
|
|
657
689
|
console.log(kolor.green("HTML minified"));
|
|
658
690
|
}
|
|
659
691
|
|
|
660
|
-
if (config.cacheBustAssets) {
|
|
692
|
+
if (!isDevMode && config.cacheBustAssets) {
|
|
661
693
|
console.log(kolor.cyan("Cache-busting assets..."));
|
|
662
694
|
const assetMap = await cacheBustAssets(outDir);
|
|
663
695
|
const assetCount = Object.keys(assetMap).length;
|
|
@@ -668,6 +700,14 @@ async function build(cwdArg = cwd) {
|
|
|
668
700
|
}
|
|
669
701
|
}
|
|
670
702
|
|
|
703
|
+
// Generate robots.txt dynamically if it doesn't exist in public directory
|
|
704
|
+
const publicRobotsTxt = join(publicDir, "robots.txt");
|
|
705
|
+
const distRobotsTxt = join(outDir, "robots.txt");
|
|
706
|
+
if (!existsSync(publicRobotsTxt) && !existsSync(distRobotsTxt)) {
|
|
707
|
+
const robotsTxt = `User-agent: *\nAllow: /\n\nSitemap: ${config.siteUrl}/sitemap.xml\n`;
|
|
708
|
+
await writeFile(distRobotsTxt, robotsTxt, "utf8");
|
|
709
|
+
}
|
|
710
|
+
|
|
671
711
|
console.log(kolor.green(`Built ${files.length} page(s) → ${relative(cwdArg, outDir)}`));
|
|
672
712
|
}
|
|
673
713
|
|
|
@@ -740,7 +780,8 @@ async function dev(cwdArg = cwd) {
|
|
|
740
780
|
}
|
|
741
781
|
building = true;
|
|
742
782
|
try {
|
|
743
|
-
|
|
783
|
+
// Skip image compression, minification, and cache busting during dev mode for faster rebuilds
|
|
784
|
+
await build(cwdArg, { skipImageCompression: true, devMode: true });
|
|
744
785
|
} catch (err) {
|
|
745
786
|
console.error(kolor.red(`Build failed: ${err.message}`));
|
|
746
787
|
} finally {
|
|
@@ -767,7 +808,7 @@ async function dev(cwdArg = cwd) {
|
|
|
767
808
|
runBuild();
|
|
768
809
|
});
|
|
769
810
|
|
|
770
|
-
serve(outDir);
|
|
811
|
+
serve(outDir, config.port || 4173);
|
|
771
812
|
}
|
|
772
813
|
|
|
773
814
|
function slugify(text) {
|
|
@@ -1413,7 +1454,7 @@ async function preview() {
|
|
|
1413
1454
|
const config = await loadConfig(cwd);
|
|
1414
1455
|
const outDir = resolve(cwd, config.outDir || "dist");
|
|
1415
1456
|
console.log(kolor.cyan(kolor.bold("🔥 Starting preview server...\n")));
|
|
1416
|
-
serve(outDir);
|
|
1457
|
+
serve(outDir, config.port || 4173);
|
|
1417
1458
|
}
|
|
1418
1459
|
|
|
1419
1460
|
async function main() {
|
|
@@ -1459,13 +1500,14 @@ async function main() {
|
|
|
1459
1500
|
if (!existsSync(outDir)) {
|
|
1460
1501
|
await build();
|
|
1461
1502
|
}
|
|
1462
|
-
serve(outDir);
|
|
1503
|
+
serve(outDir, config.port || 4173);
|
|
1463
1504
|
break;
|
|
1464
1505
|
}
|
|
1465
1506
|
case "preview":
|
|
1466
1507
|
await preview();
|
|
1467
1508
|
break;
|
|
1468
1509
|
case "clean":
|
|
1510
|
+
case "cleanup":
|
|
1469
1511
|
await clean();
|
|
1470
1512
|
break;
|
|
1471
1513
|
case "check":
|