@webmate-studio/builder 0.2.19 → 0.2.20

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/bundler.js +45 -25
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webmate-studio/builder",
3
- "version": "0.2.19",
3
+ "version": "0.2.20",
4
4
  "type": "module",
5
5
  "description": "Webmate Studio Component Builder",
6
6
  "keywords": [
package/src/bundler.js CHANGED
@@ -3,6 +3,17 @@ import esbuildSvelte from 'esbuild-svelte';
3
3
  import fs from 'fs/promises';
4
4
  import path from 'path';
5
5
  import pc from 'picocolors';
6
+ import crypto from 'crypto';
7
+
8
+ /**
9
+ * Generate content hash for asset file
10
+ * @param {Buffer} content - File content as buffer
11
+ * @param {number} length - Hash length (default: 8)
12
+ * @returns {string} - Content hash (hex)
13
+ */
14
+ function generateAssetHash(content, length = 8) {
15
+ return crypto.createHash('sha256').update(content).digest('hex').substring(0, length);
16
+ }
6
17
 
7
18
  /**
8
19
  * Bundle island JavaScript files with esbuild
@@ -71,39 +82,48 @@ export async function bundleIsland(islandPath, outputPath, options = {}) {
71
82
  '__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': 'false'
72
83
  },
73
84
  plugins: [
74
- // Image to base64 data URL loader
75
- // esbuild's 'dataurl' loader fails for:
76
- // - SVG: generates invalid data:image/svg+xml,<?xml... (unescaped XML)
77
- // - JPG/PNG/etc: generates invalid data:image/jpeg,���� (raw binary instead of base64)
78
- // Solution: Custom loader that properly base64 encodes ALL image formats
85
+ // Asset URL resolver with content hashing
86
+ // Instead of base64 encoding (bad for large images, no caching, huge bundles),
87
+ // we use asset markers with content hashes that get resolved at runtime:
88
+ // - wm dev: /assets/{componentName}/{filename} (no hash in dev)
89
+ // - CMS: /api/components/proxy/organization-components/{uuid}/assets/{filename}.{hash}.{ext}
79
90
  {
80
- name: 'image-base64-dataurl',
91
+ name: 'asset-url-resolver',
81
92
  setup(build) {
82
93
  // Handle all image formats
83
94
  build.onLoad({ filter: /\.(svg|jpg|jpeg|png|gif|webp)$/i }, async (args) => {
84
- const ext = args.path.split('.').pop().toLowerCase();
85
- const mimeTypes = {
86
- svg: 'image/svg+xml',
87
- jpg: 'image/jpeg',
88
- jpeg: 'image/jpeg',
89
- png: 'image/png',
90
- gif: 'image/gif',
91
- webp: 'image/webp'
92
- };
93
-
94
- // Read file as binary buffer
95
+ // Read file to generate content hash
95
96
  const buffer = await fs.readFile(args.path);
96
- // Convert to base64 string (pure ASCII, safe for JavaScript)
97
- const base64 = buffer.toString('base64');
98
- const mimeType = mimeTypes[ext] || 'application/octet-stream';
97
+ const hash = generateAssetHash(buffer);
98
+
99
+ // Get relative path from component directory
100
+ // Example: /full/path/components/Hero/assets/logo.svg
101
+ // → Find "assets/" segment and extract path from there
102
+ const assetPath = args.path;
103
+ const assetsIndex = assetPath.lastIndexOf('/assets/');
104
+
105
+ if (assetsIndex === -1) {
106
+ throw new Error(`Asset must be in "assets/" directory: ${assetPath}`);
107
+ }
108
+
109
+ // Extract relative path from assets/ onwards
110
+ // Example: assets/logo.svg
111
+ const relativePath = assetPath.substring(assetsIndex + 1); // +1 to keep "assets/"
112
+
113
+ // Parse filename and extension
114
+ const filename = path.basename(relativePath);
115
+ const ext = path.extname(filename);
116
+ const nameWithoutExt = path.basename(filename, ext);
117
+ const dir = path.dirname(relativePath);
99
118
 
100
- // Build the complete data URL
101
- const dataUrl = `data:${mimeType};base64,${base64}`;
119
+ // Build hashed filename: logo.abc123.svg
120
+ const hashedFilename = `${nameWithoutExt}.${hash}${ext}`;
121
+ const hashedPath = path.join(dir, hashedFilename);
102
122
 
103
- // Return as a raw JavaScript module with template literal to preserve exact bytes
104
- // Using template literal ensures no escaping or encoding happens
123
+ // Return as asset marker (will be resolved at runtime)
124
+ // Runtime resolver will replace __ASSET__: with correct base path
105
125
  return {
106
- contents: `export default \`${dataUrl}\`;`,
126
+ contents: `export default "__ASSET__:${hashedPath}";`,
107
127
  loader: 'js'
108
128
  };
109
129
  });