bunki 0.18.0 → 0.18.5

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/README.md CHANGED
@@ -541,6 +541,54 @@ This is useful for:
541
541
  - Testing uploads for specific years
542
542
  - Managing large image collections across multiple uploads
543
543
 
544
+ #### `--content-assets`
545
+
546
+ Upload images that are co-located with markdown files instead of the top-level `assets/` directory.
547
+
548
+ When content is organized with images living alongside the markdown:
549
+
550
+ ```
551
+ content/
552
+ ├── 2024/
553
+ │ └── _assets/
554
+ │ ├── paris-cafe.webp
555
+ │ └── eiffel-tower.webp
556
+ └── 2025/
557
+ └── _assets/
558
+ └── tokyo-ramen.webp
559
+ ```
560
+
561
+ Run:
562
+
563
+ ```bash
564
+ bunki images:push --content-assets
565
+ ```
566
+
567
+ This uploads each file with the S3 key `{year}/{filename}` — the `_assets/` segment is stripped. For example, `content/2024/_assets/paris-cafe.webp` becomes key `2024/paris-cafe.webp`, accessible at `https://cdn.example.com/2024/paris-cafe.webp`.
568
+
569
+ > [!IMPORTANT]
570
+ > Always use CDN URLs in your markdown, not relative `_assets/` paths. Relative paths cause the image files to be bundled into your Cloudflare Workers deployment instead of served from R2.
571
+
572
+ ```markdown
573
+ <!-- ❌ Causes image to be bundled into Workers -->
574
+ ![Paris](../2024/_assets/paris-cafe.webp)
575
+
576
+ <!-- ✅ Served from R2 CDN -->
577
+ ![Paris](https://cdn.example.com/2024/paris-cafe.webp)
578
+ ```
579
+
580
+ #### `--content-assets-dir <dir>`
581
+
582
+ Override the assets subdirectory name. Defaults to `_assets` (or `contentAssets.assetsDir` in `bunki.config.ts`).
583
+
584
+ ```bash
585
+ # Use _images instead of _assets
586
+ bunki images:push --content-assets --content-assets-dir _images
587
+
588
+ # Use any custom name
589
+ bunki images:push --content-assets --content-assets-dir media
590
+ ```
591
+
544
592
  ### Complete Examples
545
593
 
546
594
  #### Cloudflare R2 Setup
@@ -746,6 +794,56 @@ Ensure all required environment variables are set. Check `bunki.config.ts` and y
746
794
 
747
795
  ### Advanced Configuration
748
796
 
797
+ #### Content Assets Configuration
798
+
799
+ Configure co-located content assets in `bunki.config.ts`:
800
+
801
+ ```typescript
802
+ import { SiteConfig } from "bunki";
803
+
804
+ export default (): SiteConfig => ({
805
+ title: "My Blog",
806
+ baseUrl: "https://example.com",
807
+ domain: "example.com",
808
+
809
+ // Default S3 config (used by bunki images:push)
810
+ s3: {
811
+ accessKeyId: process.env.S3_ACCESS_KEY_ID || "",
812
+ secretAccessKey: process.env.S3_SECRET_ACCESS_KEY || "",
813
+ bucket: "my-site-assets",
814
+ endpoint: process.env.S3_ENDPOINT,
815
+ region: "auto",
816
+ publicUrl: "https://assets.example.com",
817
+ },
818
+
819
+ // Content assets: images stored alongside markdown in content/{year}/_images/
820
+ contentAssets: {
821
+ // Directory name within content/{year}/ (default: "_assets")
822
+ assetsDir: "_images",
823
+
824
+ // Optional: use a separate R2 bucket for content assets
825
+ s3: {
826
+ accessKeyId: process.env.IMG_ACCESS_KEY_ID || "",
827
+ secretAccessKey: process.env.IMG_SECRET_ACCESS_KEY || "",
828
+ bucket: "my-blog-images",
829
+ endpoint: process.env.S3_ENDPOINT,
830
+ region: "auto",
831
+ publicUrl: "https://img.example.com",
832
+ },
833
+ },
834
+ });
835
+ ```
836
+
837
+ Then upload content assets:
838
+
839
+ ```bash
840
+ # Uses contentAssets.assetsDir and contentAssets.s3 from config
841
+ bunki images:push --content-assets
842
+
843
+ # Override the directory name at the CLI level
844
+ bunki images:push --content-assets --content-assets-dir _media
845
+ ```
846
+
749
847
  #### Custom Domain per Bucket
750
848
 
751
849
  If you have multiple S3 buckets with different custom domains:
@@ -806,10 +904,12 @@ Bunki supports incremental builds for significantly faster rebuild times during
806
904
  ### Performance Impact
807
905
 
808
906
  **Large site example (455 posts):**
907
+
809
908
  - Full build: 3,128ms
810
909
  - Incremental build (no changes): 985ms (**3.2x faster**)
811
910
 
812
911
  **Speedup breakdown:**
912
+
813
913
  - Markdown parsing: 1,202ms → 55ms (**22x faster**)
814
914
  - CSS processing: 1,024ms → 1ms (**1024x faster**)
815
915
  - Overall: **68% faster builds**
@@ -873,11 +973,13 @@ echo ".bunki-cache.json" >> .gitignore
873
973
  ### When to Use
874
974
 
875
975
  **Recommended for:**
976
+
876
977
  - Large sites (100+ posts)
877
978
  - Development workflow with frequent rebuilds
878
979
  - Sites with slow CSS processing (Tailwind, PostCSS)
879
980
 
880
981
  **Not needed for:**
982
+
881
983
  - Small sites (<50 posts) - already fast enough
882
984
  - CI/CD builds - prefer clean full builds
883
985
  - Production deployments - always use full builds
@@ -912,6 +1014,7 @@ Version 2.0.0 cache structure:
912
1014
  ### Future Optimizations
913
1015
 
914
1016
  Current implementation (v0.18.0) optimizes parsing and CSS processing. Future versions may add:
1017
+
915
1018
  - Selective page regeneration (only rebuild changed posts)
916
1019
  - Incremental sitemap/RSS updates
917
1020
  - Smart index page regeneration
@@ -1092,7 +1195,20 @@ bunki/
1092
1195
 
1093
1196
  ## Changelog
1094
1197
 
1095
- ### v0.18.0 (Current)
1198
+ ### v0.18.1 (Current)
1199
+
1200
+ - **Page Generation Optimization**: Cache JSON-LD schemas and metadata during initialization
1201
+ - Eliminates 910 redundant operations per build (455 posts × 2)
1202
+ - `extractFirstImageUrl()` called once during initialization, cached in `post.image`
1203
+ - Word count calculated once, cached in `post.wordCount`
1204
+ - JSON-LD schemas pre-generated and cached in `post.jsonLd`
1205
+ - Removed duplicate schema generation from page and feed generators
1206
+ - **Deployment Optimization**: All deploy commands now use incremental builds by default
1207
+ - `deploy:all` now builds incrementally for faster deployments
1208
+ - Individual site deployments also use incremental builds
1209
+ - Full builds available via `build:full` when needed
1210
+
1211
+ ### v0.18.0
1096
1212
 
1097
1213
  - **Incremental Builds**: Smart caching for 3.2x faster development builds
1098
1214
  - File change detection using content hashing and modification times
@@ -7,9 +7,11 @@ interface ImagesPushDeps {
7
7
  }
8
8
  export declare function handleImagesPushCommand(options: {
9
9
  domain?: string;
10
- images: string;
10
+ images?: string;
11
11
  outputJson?: string;
12
12
  minYear?: string;
13
+ contentAssets?: boolean;
14
+ contentAssetsDir?: string;
13
15
  }, deps?: ImagesPushDeps): Promise<void>;
14
16
  export declare function registerImagesPushCommand(program: Command): Command;
15
17
  export {};
@@ -0,0 +1,9 @@
1
+ import { Command } from "commander";
2
+ export declare function handleValidateMediaCommand(options: {
3
+ contentDir?: string;
4
+ fix?: boolean;
5
+ }, deps?: {
6
+ logger: Console;
7
+ exit: (code: number) => never;
8
+ }): Promise<void>;
9
+ export declare function registerValidateMediaCommand(program: Command): Command;