@ox-content/vite-plugin 0.11.0 → 0.12.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/dist/index.cjs +226 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +227 -4
- package/dist/index.js.map +1 -1
- package/dist/tabs.js +1 -1
- package/dist/tabs2.cjs +12 -0
- package/dist/tabs2.cjs.map +1 -1
- package/dist/tabs2.js +7 -1
- package/dist/tabs2.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -8340,7 +8340,7 @@ function createVueCompilerPlugin() {
|
|
|
8340
8340
|
filename: id,
|
|
8341
8341
|
id
|
|
8342
8342
|
});
|
|
8343
|
-
if (templateResult.errors.length > 0) throw new Error(`[ox-content:og-image] Vue template compilation errors in ${id}: ${templateResult.errors.join(", ")}`);
|
|
8343
|
+
if (templateResult.errors.length > 0) throw new Error(`[ox-content:og-image] Vue template compilation errors in ${id}: ${templateResult.errors.map(String).join(", ")}`);
|
|
8344
8344
|
scriptCode = `${templateResult.code}\nexport default { render }`;
|
|
8345
8345
|
}
|
|
8346
8346
|
const isTs = !!(descriptor.scriptSetup?.lang === "ts" || descriptor.script?.lang === "ts");
|
|
@@ -8678,6 +8678,12 @@ function getComponentName(el) {
|
|
|
8678
8678
|
}
|
|
8679
8679
|
let islandCounter = 0;
|
|
8680
8680
|
/**
|
|
8681
|
+
* Reset island counter (for testing).
|
|
8682
|
+
*/
|
|
8683
|
+
function resetIslandCounter() {
|
|
8684
|
+
islandCounter = 0;
|
|
8685
|
+
}
|
|
8686
|
+
/**
|
|
8681
8687
|
* Rehype plugin to transform Island components.
|
|
8682
8688
|
*/
|
|
8683
8689
|
function rehypeIslands(collectedIslands) {
|
|
@@ -8771,7 +8777,7 @@ function generateHydrationScript(components) {
|
|
|
8771
8777
|
if (components.length === 0) return "";
|
|
8772
8778
|
return `
|
|
8773
8779
|
import { initIslands } from '@ox-content/islands';
|
|
8774
|
-
${components.map((name
|
|
8780
|
+
${components.map((name) => `import ${name} from './${name}';`).join("\n")}
|
|
8775
8781
|
|
|
8776
8782
|
const components = {
|
|
8777
8783
|
${components.join(",\n ")}
|
|
@@ -10406,6 +10412,207 @@ export default { search, searchOptions, loadIndex };
|
|
|
10406
10412
|
`;
|
|
10407
10413
|
}
|
|
10408
10414
|
|
|
10415
|
+
//#endregion
|
|
10416
|
+
//#region src/dev-server.ts
|
|
10417
|
+
/**
|
|
10418
|
+
* Dev server middleware for ox-content SSG.
|
|
10419
|
+
*
|
|
10420
|
+
* Serves fully-rendered HTML pages (with navigation, theme, etc.)
|
|
10421
|
+
* during `vite dev`, matching the SSG build output.
|
|
10422
|
+
*/
|
|
10423
|
+
/** File extensions to skip in the middleware. */
|
|
10424
|
+
const SKIP_EXTENSIONS = new Set([
|
|
10425
|
+
".js",
|
|
10426
|
+
".ts",
|
|
10427
|
+
".css",
|
|
10428
|
+
".scss",
|
|
10429
|
+
".less",
|
|
10430
|
+
".svg",
|
|
10431
|
+
".png",
|
|
10432
|
+
".jpg",
|
|
10433
|
+
".jpeg",
|
|
10434
|
+
".gif",
|
|
10435
|
+
".webp",
|
|
10436
|
+
".ico",
|
|
10437
|
+
".woff",
|
|
10438
|
+
".woff2",
|
|
10439
|
+
".ttf",
|
|
10440
|
+
".eot",
|
|
10441
|
+
".json",
|
|
10442
|
+
".map",
|
|
10443
|
+
".mp4",
|
|
10444
|
+
".webm",
|
|
10445
|
+
".mp3",
|
|
10446
|
+
".pdf"
|
|
10447
|
+
]);
|
|
10448
|
+
/** Vite internal URL prefixes to skip. */
|
|
10449
|
+
const VITE_INTERNAL_PREFIXES = [
|
|
10450
|
+
"/@vite/",
|
|
10451
|
+
"/@fs/",
|
|
10452
|
+
"/@id/",
|
|
10453
|
+
"/__"
|
|
10454
|
+
];
|
|
10455
|
+
/**
|
|
10456
|
+
* Check if a request URL should be skipped by the dev server middleware.
|
|
10457
|
+
*/
|
|
10458
|
+
function shouldSkip(url) {
|
|
10459
|
+
for (const prefix of VITE_INTERNAL_PREFIXES) if (url.startsWith(prefix)) return true;
|
|
10460
|
+
if (url.includes("/node_modules/")) return true;
|
|
10461
|
+
const extMatch = url.match(/\.([a-zA-Z0-9]+)(?:\?|$)/);
|
|
10462
|
+
if (extMatch) {
|
|
10463
|
+
const ext = "." + extMatch[1].toLowerCase();
|
|
10464
|
+
if (SKIP_EXTENSIONS.has(ext)) return true;
|
|
10465
|
+
}
|
|
10466
|
+
return false;
|
|
10467
|
+
}
|
|
10468
|
+
/**
|
|
10469
|
+
* Resolve a request URL to a markdown file path.
|
|
10470
|
+
* Returns null if no matching file exists.
|
|
10471
|
+
*/
|
|
10472
|
+
async function resolveMarkdownFile(url, srcDir) {
|
|
10473
|
+
let pathname = url.split("?")[0].split("#")[0];
|
|
10474
|
+
if (pathname.endsWith("/index.html")) pathname = pathname.slice(0, -11) || "/";
|
|
10475
|
+
if (pathname !== "/" && pathname.endsWith("/")) pathname = pathname.slice(0, -1);
|
|
10476
|
+
let relativePath;
|
|
10477
|
+
if (pathname === "/") relativePath = "index.md";
|
|
10478
|
+
else relativePath = pathname.slice(1) + ".md";
|
|
10479
|
+
const filePath = path$1.join(srcDir, relativePath);
|
|
10480
|
+
try {
|
|
10481
|
+
await fs_promises.access(filePath);
|
|
10482
|
+
return filePath;
|
|
10483
|
+
} catch {
|
|
10484
|
+
const indexPath = path$1.join(srcDir, pathname === "/" ? "" : pathname.slice(1), "index.md");
|
|
10485
|
+
try {
|
|
10486
|
+
await fs_promises.access(indexPath);
|
|
10487
|
+
return indexPath;
|
|
10488
|
+
} catch {
|
|
10489
|
+
return null;
|
|
10490
|
+
}
|
|
10491
|
+
}
|
|
10492
|
+
}
|
|
10493
|
+
/**
|
|
10494
|
+
* Inject Vite HMR client script into the HTML.
|
|
10495
|
+
*/
|
|
10496
|
+
function injectViteHmrClient(html) {
|
|
10497
|
+
return html.replace("</head>", "<script type=\"module\" src=\"/@vite/client\"><\/script>\n<script type=\"module\">\nif (import.meta.hot) {\n import.meta.hot.on('ox-content:update', () => {\n location.reload();\n });\n}\n<\/script>\n</head>");
|
|
10498
|
+
}
|
|
10499
|
+
/**
|
|
10500
|
+
* Create a dev server cache instance.
|
|
10501
|
+
*/
|
|
10502
|
+
function createDevServerCache() {
|
|
10503
|
+
return {
|
|
10504
|
+
navGroups: null,
|
|
10505
|
+
pages: /* @__PURE__ */ new Map(),
|
|
10506
|
+
siteName: null
|
|
10507
|
+
};
|
|
10508
|
+
}
|
|
10509
|
+
/**
|
|
10510
|
+
* Invalidate navigation cache (called on file add/unlink).
|
|
10511
|
+
*/
|
|
10512
|
+
function invalidateNavCache(cache) {
|
|
10513
|
+
cache.navGroups = null;
|
|
10514
|
+
cache.pages.clear();
|
|
10515
|
+
}
|
|
10516
|
+
/**
|
|
10517
|
+
* Invalidate page cache for a specific file (called on file change).
|
|
10518
|
+
*/
|
|
10519
|
+
function invalidatePageCache(cache, filePath) {
|
|
10520
|
+
cache.pages.delete(filePath);
|
|
10521
|
+
}
|
|
10522
|
+
/**
|
|
10523
|
+
* Resolve site name from options or package.json.
|
|
10524
|
+
*/
|
|
10525
|
+
async function resolveSiteName(options, root) {
|
|
10526
|
+
if (options.ssg.siteName) return options.ssg.siteName;
|
|
10527
|
+
try {
|
|
10528
|
+
const pkgPath = path$1.join(root, "package.json");
|
|
10529
|
+
const pkg = JSON.parse(await fs_promises.readFile(pkgPath, "utf-8"));
|
|
10530
|
+
if (pkg.name) return formatTitle(pkg.name);
|
|
10531
|
+
} catch {}
|
|
10532
|
+
return "Documentation";
|
|
10533
|
+
}
|
|
10534
|
+
/**
|
|
10535
|
+
* Render a single markdown page to full HTML.
|
|
10536
|
+
*/
|
|
10537
|
+
async function renderPage$1(filePath, options, navGroups, siteName, base, root) {
|
|
10538
|
+
const srcDir = path$1.resolve(root, options.srcDir);
|
|
10539
|
+
require_tabs.resetTabGroupCounter();
|
|
10540
|
+
resetIslandCounter();
|
|
10541
|
+
const result = await transformMarkdown(await fs_promises.readFile(filePath, "utf-8"), filePath, options, {
|
|
10542
|
+
convertMdLinks: true,
|
|
10543
|
+
baseUrl: base,
|
|
10544
|
+
sourcePath: filePath
|
|
10545
|
+
});
|
|
10546
|
+
let transformedHtml = result.html;
|
|
10547
|
+
const { html: protectedHtml, svgs: mermaidSvgs } = protectMermaidSvgs(transformedHtml);
|
|
10548
|
+
transformedHtml = protectedHtml;
|
|
10549
|
+
transformedHtml = await transformAllPlugins(transformedHtml, {
|
|
10550
|
+
tabs: true,
|
|
10551
|
+
youtube: true,
|
|
10552
|
+
github: true,
|
|
10553
|
+
ogp: true,
|
|
10554
|
+
mermaid: true,
|
|
10555
|
+
githubToken: process.env.GITHUB_TOKEN
|
|
10556
|
+
});
|
|
10557
|
+
if (hasIslands(transformedHtml)) transformedHtml = (await transformIslands(transformedHtml)).html;
|
|
10558
|
+
transformedHtml = restoreMermaidSvgs(transformedHtml, mermaidSvgs);
|
|
10559
|
+
const title = extractTitle$1(transformedHtml, result.frontmatter);
|
|
10560
|
+
const description = result.frontmatter.description;
|
|
10561
|
+
let entryPage;
|
|
10562
|
+
if (result.frontmatter.layout === "entry") entryPage = {
|
|
10563
|
+
hero: result.frontmatter.hero,
|
|
10564
|
+
features: result.frontmatter.features
|
|
10565
|
+
};
|
|
10566
|
+
let html = await generateHtmlPage({
|
|
10567
|
+
title,
|
|
10568
|
+
description,
|
|
10569
|
+
content: transformedHtml,
|
|
10570
|
+
toc: result.toc,
|
|
10571
|
+
frontmatter: result.frontmatter,
|
|
10572
|
+
path: getUrlPath$1(filePath, srcDir),
|
|
10573
|
+
href: getUrlPath$1(filePath, srcDir) || "/",
|
|
10574
|
+
entryPage
|
|
10575
|
+
}, navGroups, siteName, base, options.ssg.ogImage, options.ssg.theme);
|
|
10576
|
+
html = injectViteHmrClient(html);
|
|
10577
|
+
return html;
|
|
10578
|
+
}
|
|
10579
|
+
/**
|
|
10580
|
+
* Create the dev server middleware for SSG page serving.
|
|
10581
|
+
*/
|
|
10582
|
+
function createDevServerMiddleware(options, root, cache) {
|
|
10583
|
+
const srcDir = path$1.resolve(root, options.srcDir);
|
|
10584
|
+
const base = options.base.endsWith("/") ? options.base : options.base + "/";
|
|
10585
|
+
return async (req, res, next) => {
|
|
10586
|
+
const url = req.url;
|
|
10587
|
+
if (!url) return next();
|
|
10588
|
+
let routeUrl = url;
|
|
10589
|
+
if (base !== "/" && routeUrl.startsWith(base)) routeUrl = "/" + routeUrl.slice(base.length);
|
|
10590
|
+
if (shouldSkip(routeUrl)) return next();
|
|
10591
|
+
const filePath = await resolveMarkdownFile(routeUrl, srcDir);
|
|
10592
|
+
if (!filePath) return next();
|
|
10593
|
+
try {
|
|
10594
|
+
const cached = cache.pages.get(filePath);
|
|
10595
|
+
if (cached) {
|
|
10596
|
+
res.setHeader("Content-Type", "text/html");
|
|
10597
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
10598
|
+
res.end(cached);
|
|
10599
|
+
return;
|
|
10600
|
+
}
|
|
10601
|
+
if (!cache.siteName) cache.siteName = await resolveSiteName(options, root);
|
|
10602
|
+
if (!cache.navGroups) cache.navGroups = buildNavItems(await collectMarkdownFiles$1(srcDir), srcDir, base, ".html");
|
|
10603
|
+
const html = await renderPage$1(filePath, options, cache.navGroups, cache.siteName, base, root);
|
|
10604
|
+
cache.pages.set(filePath, html);
|
|
10605
|
+
res.setHeader("Content-Type", "text/html");
|
|
10606
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
10607
|
+
res.end(html);
|
|
10608
|
+
} catch (err) {
|
|
10609
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10610
|
+
console.error(`[ox-content:dev] Failed to render ${filePath}:`, message);
|
|
10611
|
+
next();
|
|
10612
|
+
}
|
|
10613
|
+
};
|
|
10614
|
+
}
|
|
10615
|
+
|
|
10409
10616
|
//#endregion
|
|
10410
10617
|
//#region src/og-viewer.ts
|
|
10411
10618
|
/**
|
|
@@ -10731,7 +10938,7 @@ function createOgViewerPlugin(options) {
|
|
|
10731
10938
|
res.end(html);
|
|
10732
10939
|
} catch (err) {
|
|
10733
10940
|
res.statusCode = 500;
|
|
10734
|
-
res.end(`OG Viewer error: ${err}`);
|
|
10941
|
+
res.end(`OG Viewer error: ${err instanceof Error ? err.message : String(err)}`);
|
|
10735
10942
|
}
|
|
10736
10943
|
return;
|
|
10737
10944
|
}
|
|
@@ -11405,8 +11612,24 @@ function oxContent(options = {}) {
|
|
|
11405
11612
|
});
|
|
11406
11613
|
}
|
|
11407
11614
|
};
|
|
11615
|
+
const ssgDevCache = createDevServerCache();
|
|
11408
11616
|
const ssgPlugin = {
|
|
11409
11617
|
name: "ox-content:ssg",
|
|
11618
|
+
configureServer(devServer) {
|
|
11619
|
+
if (!resolvedOptions.ssg.enabled) return;
|
|
11620
|
+
const root = config?.root || process.cwd();
|
|
11621
|
+
const srcDir = path$1.resolve(root, resolvedOptions.srcDir);
|
|
11622
|
+
devServer.middlewares.use(createDevServerMiddleware(resolvedOptions, root, ssgDevCache));
|
|
11623
|
+
devServer.watcher.on("add", (file) => {
|
|
11624
|
+
if (file.startsWith(srcDir) && file.endsWith(".md")) invalidateNavCache(ssgDevCache);
|
|
11625
|
+
});
|
|
11626
|
+
devServer.watcher.on("unlink", (file) => {
|
|
11627
|
+
if (file.startsWith(srcDir) && file.endsWith(".md")) invalidateNavCache(ssgDevCache);
|
|
11628
|
+
});
|
|
11629
|
+
devServer.watcher.on("change", (file) => {
|
|
11630
|
+
if (file.startsWith(srcDir) && file.endsWith(".md")) invalidatePageCache(ssgDevCache, file);
|
|
11631
|
+
});
|
|
11632
|
+
},
|
|
11410
11633
|
async closeBundle() {
|
|
11411
11634
|
if (!resolvedOptions.ssg.enabled) return;
|
|
11412
11635
|
const root = config?.root || process.cwd();
|