@x-wave/blog 2.0.0 → 2.1.1

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.
@@ -0,0 +1,84 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { discoverBlogPosts } from './blog-discovery.js';
4
+ import { createStaticGenPlugin } from './static-gen-plugin.js';
5
+ /**
6
+ * Read all MDX files from a docs directory
7
+ * @param docsDir - Path to the docs directory
8
+ * @returns Object mapping file paths to content loaders
9
+ */
10
+ function readMdxFiles(docsDir) {
11
+ const mdxFiles = {};
12
+ function walkDir(dir, relativePath = '') {
13
+ if (!fs.existsSync(dir))
14
+ return;
15
+ const files = fs.readdirSync(dir);
16
+ for (const file of files) {
17
+ const fullPath = path.join(dir, file);
18
+ const relPath = path.join(relativePath, file);
19
+ const stat = fs.statSync(fullPath);
20
+ if (stat.isDirectory()) {
21
+ walkDir(fullPath, relPath);
22
+ }
23
+ else if (file.endsWith('.mdx')) {
24
+ // Create a lazy loader function
25
+ mdxFiles[path.join(docsDir, relPath)] = async () => fs.readFileSync(fullPath, 'utf-8');
26
+ }
27
+ }
28
+ }
29
+ walkDir(docsDir);
30
+ return mdxFiles;
31
+ }
32
+ /**
33
+ * Setup static site generation for blog posts
34
+ *
35
+ * This is a convenience function that handles the entire SSG setup process.
36
+ * It discovers blog posts from your docs directory and creates a Vite plugin.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * import { setupSSG } from '@x-wave/blog/vite-config'
41
+ *
42
+ * export default defineConfig(async (env) => {
43
+ * const ssgPlugin = env.command === 'build'
44
+ * ? await setupSSG({
45
+ * docsPath: 'src/docs',
46
+ * outputDir: 'dist/docs',
47
+ * metaTagsOptions: {
48
+ * baseUrl: 'https://example.com',
49
+ * siteName: 'My Documentation',
50
+ * }
51
+ * })
52
+ * : undefined
53
+ *
54
+ * return {
55
+ * plugins: [react(), ssgPlugin].filter(Boolean),
56
+ * // ... rest of config
57
+ * }
58
+ * })
59
+ * ```
60
+ */
61
+ export async function setupSSG(options) {
62
+ try {
63
+ const { docsPath, outputDir = 'dist/docs', metaTagsOptions = {} } = options;
64
+ const mdxFiles = readMdxFiles(docsPath);
65
+ const { posts } = await discoverBlogPosts(mdxFiles, {
66
+ blogContentPath: docsPath,
67
+ });
68
+ if (posts.length === 0) {
69
+ console.log('📝 No blog posts found, SSG disabled');
70
+ return undefined;
71
+ }
72
+ console.log(`📝 Discovered ${posts.length} blog posts for SSG`);
73
+ return createStaticGenPlugin({
74
+ posts,
75
+ outputDir,
76
+ metaTagsOptions,
77
+ });
78
+ }
79
+ catch (error) {
80
+ console.warn('⚠️ SSG initialization failed:', error);
81
+ return undefined;
82
+ }
83
+ }
84
+ //# sourceMappingURL=setup-ssg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-ssg.js","sourceRoot":"","sources":["../src/setup-ssg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAW9D;;;;GAIG;AACH,SAAS,YAAY,CAAC,OAAe;IACpC,MAAM,QAAQ,GAA0C,EAAE,CAAA;IAE1D,SAAS,OAAO,CAAC,GAAW,EAAE,YAAY,GAAG,EAAE;QAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAM;QAE/B,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;QAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;YACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;YAC7C,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAElC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YAC3B,CAAC;iBAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClC,gCAAgC;gBAChC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,IAAI,EAAE,CAClD,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YACpC,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,CAAA;IAChB,OAAO,QAAQ,CAAA;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC7B,OAAwB;IAExB,IAAI,CAAC;QACJ,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAG,WAAW,EAAE,eAAe,GAAG,EAAE,EAAE,GAAG,OAAO,CAAA;QAE3E,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;QACvC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,iBAAiB,CAAC,QAAQ,EAAE;YACnD,eAAe,EAAE,QAAQ;SACzB,CAAC,CAAA;QAEF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;YACnD,OAAO,SAAS,CAAA;QACjB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,CAAC,MAAM,qBAAqB,CAAC,CAAA;QAE/D,OAAO,qBAAqB,CAAC;YAC5B,KAAK;YACL,SAAS;YACT,eAAe;SACf,CAAC,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAA;QACrD,OAAO,SAAS,CAAA;IACjB,CAAC;AACF,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { Plugin } from 'vite';
2
+ import { type MetaTagsOptions } from './meta-tags.js';
3
+ import type { BlogPostMetadata, BlogSSGConfig } from './types.js';
4
+ export interface StaticGenPluginOptions extends BlogSSGConfig {
5
+ /** Blog posts to generate static pages for */
6
+ posts: BlogPostMetadata[];
7
+ /** Meta tag generation options */
8
+ metaTagsOptions?: MetaTagsOptions;
9
+ /** Reference to original index.html path */
10
+ indexHtmlPath?: string;
11
+ }
12
+ /**
13
+ * Vite plugin for static site generation of blog posts
14
+ *
15
+ * Generates individual HTML files for each blog post with injected meta tags
16
+ * These files are created after the main build completes
17
+ */
18
+ export declare function createStaticGenPlugin(options: StaticGenPluginOptions): Plugin;
19
+ //# sourceMappingURL=static-gen-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-gen-plugin.d.ts","sourceRoot":"","sources":["../src/static-gen-plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEjE,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC5D,8CAA8C;IAC9C,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACzB,kCAAkC;IAClC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,4CAA4C;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CA4E7E"}
@@ -0,0 +1,56 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { generateHtmlWithMetaTags } from './meta-tags.js';
4
+ /**
5
+ * Vite plugin for static site generation of blog posts
6
+ *
7
+ * Generates individual HTML files for each blog post with injected meta tags
8
+ * These files are created after the main build completes
9
+ */
10
+ export function createStaticGenPlugin(options) {
11
+ let config;
12
+ const { posts, outputDir = 'dist/docs', metaTagsOptions = {}, indexHtmlPath = 'index.html', } = options;
13
+ return {
14
+ name: 'vite-plugin-blog-static-gen',
15
+ configResolved(resolvedConfig) {
16
+ config = resolvedConfig;
17
+ },
18
+ async generateBundle() {
19
+ // This hook runs during the bundle generation phase
20
+ // We'll actually write files in writeBundle to ensure index.html exists
21
+ },
22
+ async writeBundle() {
23
+ if (!posts || posts.length === 0) {
24
+ console.log('📝 No blog posts to generate static files for');
25
+ return;
26
+ }
27
+ try {
28
+ // Read the generated index.html
29
+ const indexHtmlPath_ = path.resolve(config.build.outDir, 'index.html');
30
+ if (!fs.existsSync(indexHtmlPath_)) {
31
+ console.warn(`⚠️ Index HTML not found at ${indexHtmlPath_}, skipping static generation`);
32
+ return;
33
+ }
34
+ const indexHtmlContent = fs.readFileSync(indexHtmlPath_, 'utf-8');
35
+ console.log(`📝 Generating static pages for ${posts.length} blog posts...`);
36
+ // Create static HTML file for each blog post
37
+ for (const post of posts) {
38
+ const htmlWithMeta = generateHtmlWithMetaTags(indexHtmlContent, post, metaTagsOptions);
39
+ // Create directory structure: dist/docs/[language]/[slug]/index.html
40
+ const postDir = path.resolve(config.build.outDir, post.language, post.slug);
41
+ fs.mkdirSync(postDir, { recursive: true });
42
+ // Write the static HTML file
43
+ const htmlPath = path.resolve(postDir, 'index.html');
44
+ fs.writeFileSync(htmlPath, htmlWithMeta, 'utf-8');
45
+ console.log(` ✓ Generated ${post.language}/${post.slug}/`);
46
+ }
47
+ console.log(`✨ Static generation complete for ${posts.length} blog posts`);
48
+ }
49
+ catch (error) {
50
+ console.error('❌ Error generating static blog posts:', error);
51
+ throw error;
52
+ }
53
+ },
54
+ };
55
+ }
56
+ //# sourceMappingURL=static-gen-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-gen-plugin.js","sourceRoot":"","sources":["../src/static-gen-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,wBAAwB,EAAwB,MAAM,gBAAgB,CAAA;AAY/E;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAA+B;IACpE,IAAI,MAAW,CAAA;IACf,MAAM,EACL,KAAK,EACL,SAAS,GAAG,WAAW,EACvB,eAAe,GAAG,EAAE,EACpB,aAAa,GAAG,YAAY,GAC5B,GAAG,OAAO,CAAA;IAEX,OAAO;QACN,IAAI,EAAE,6BAA6B;QAEnC,cAAc,CAAC,cAAc;YAC5B,MAAM,GAAG,cAAc,CAAA;QACxB,CAAC;QAED,KAAK,CAAC,cAAc;YACnB,oDAAoD;YACpD,wEAAwE;QACzE,CAAC;QAED,KAAK,CAAC,WAAW;YAChB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;gBAC5D,OAAM;YACP,CAAC;YAED,IAAI,CAAC;gBACJ,gCAAgC;gBAChC,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;gBACtE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;oBACpC,OAAO,CAAC,IAAI,CACX,+BAA+B,cAAc,8BAA8B,CAC3E,CAAA;oBACD,OAAM;gBACP,CAAC;gBAED,MAAM,gBAAgB,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;gBAEjE,OAAO,CAAC,GAAG,CACV,kCAAkC,KAAK,CAAC,MAAM,gBAAgB,CAC9D,CAAA;gBAED,6CAA6C;gBAC7C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBAC1B,MAAM,YAAY,GAAG,wBAAwB,CAC5C,gBAAgB,EAChB,IAAI,EACJ,eAAe,CACf,CAAA;oBAED,qEAAqE;oBACrE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAC3B,MAAM,CAAC,KAAK,CAAC,MAAM,EACnB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,IAAI,CACT,CAAA;oBAED,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;oBAE1C,6BAA6B;oBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;oBACpD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,CAAA;oBAEjD,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,CAAA;gBAC5D,CAAC;gBAED,OAAO,CAAC,GAAG,CACV,oCAAoC,KAAK,CAAC,MAAM,aAAa,CAC7D,CAAA;YACF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAA;gBAC7D,MAAM,KAAK,CAAA;YACZ,CAAC;QACF,CAAC;KACD,CAAA;AACF,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared types for blog SSG functionality
3
+ */
4
+ export interface BlogPostMetadata {
5
+ slug: string;
6
+ title: string;
7
+ description?: string;
8
+ ogImage?: string;
9
+ keywords?: string[] | string;
10
+ date?: string;
11
+ author?: string;
12
+ language: string;
13
+ filePath: string;
14
+ }
15
+ export interface BlogDiscoveryResult {
16
+ posts: BlogPostMetadata[];
17
+ postsByLanguage: Record<string, BlogPostMetadata[]>;
18
+ postsBySlug: Record<string, BlogPostMetadata>;
19
+ }
20
+ export interface BlogSSGConfig {
21
+ /** Path to blog MDX files relative to app root */
22
+ blogContentPath?: string;
23
+ /** Whether to generate static files */
24
+ generateStatic?: boolean;
25
+ /** Output directory for generated blog posts */
26
+ outputDir?: string;
27
+ /** Base path for blog routes */
28
+ basePath?: string;
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACzB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAA;IACnD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;CAC7C;AAED,MAAM,WAAW,aAAa;IAC7B,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,uCAAuC;IACvC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;CACjB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared types for blog SSG functionality
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}