bertui 1.2.0 → 1.2.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.
package/package.json
CHANGED
|
@@ -3,34 +3,129 @@ import { join, relative, dirname, extname } from 'path';
|
|
|
3
3
|
import { readdirSync, statSync, mkdirSync, writeFileSync } from 'fs';
|
|
4
4
|
import logger from '../../logger/logger.js';
|
|
5
5
|
import { replaceEnvInCode } from '../../utils/env.js';
|
|
6
|
+
import { transform } from 'lightningcss';
|
|
7
|
+
|
|
8
|
+
// ============================================
|
|
9
|
+
// CSS MODULES
|
|
10
|
+
// ============================================
|
|
11
|
+
|
|
12
|
+
function hashClassName(filename, className) {
|
|
13
|
+
const str = filename + className;
|
|
14
|
+
let hash = 0;
|
|
15
|
+
for (let i = 0; i < str.length; i++) {
|
|
16
|
+
hash = (hash << 5) - hash + str.charCodeAt(i);
|
|
17
|
+
hash |= 0;
|
|
18
|
+
}
|
|
19
|
+
return Math.abs(hash).toString(36).slice(0, 5);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function scopeCSSModule(cssText, filename) {
|
|
23
|
+
const classNames = new Set();
|
|
24
|
+
const classRegex = /\.([a-zA-Z_][a-zA-Z0-9_-]*)\s*[{,\s:]/g;
|
|
25
|
+
let match;
|
|
26
|
+
while ((match = classRegex.exec(cssText)) !== null) {
|
|
27
|
+
classNames.add(match[1]);
|
|
28
|
+
}
|
|
29
|
+
const mapping = {};
|
|
30
|
+
for (const cls of classNames) {
|
|
31
|
+
mapping[cls] = `${cls}_${hashClassName(filename, cls)}`;
|
|
32
|
+
}
|
|
33
|
+
let scopedCSS = cssText;
|
|
34
|
+
for (const [original, scoped] of Object.entries(mapping)) {
|
|
35
|
+
scopedCSS = scopedCSS.replace(
|
|
36
|
+
new RegExp(`\\.${original}(?=[\\s{,:\\[#.>+~)\\]])`, 'g'),
|
|
37
|
+
`.${scoped}`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return { mapping, scopedCSS };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function compileCSSModule(srcPath, rootBuildDir) {
|
|
44
|
+
const filename = srcPath.split('/').pop();
|
|
45
|
+
const cssText = await Bun.file(srcPath).text();
|
|
46
|
+
const { mapping, scopedCSS } = scopeCSSModule(cssText, filename);
|
|
47
|
+
|
|
48
|
+
let finalCSS = scopedCSS;
|
|
49
|
+
try {
|
|
50
|
+
const { code } = transform({
|
|
51
|
+
filename,
|
|
52
|
+
code: Buffer.from(scopedCSS),
|
|
53
|
+
minify: false,
|
|
54
|
+
drafts: { nesting: true },
|
|
55
|
+
targets: { chrome: 90 << 16 }
|
|
56
|
+
});
|
|
57
|
+
finalCSS = code.toString();
|
|
58
|
+
} catch (e) {
|
|
59
|
+
logger.warn(`LightningCSS failed for ${filename}: ${e.message}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// JS mapping → .bertuibuild/styles/home.module.css.js (for JS imports)
|
|
63
|
+
const stylesDir = join(rootBuildDir, 'styles');
|
|
64
|
+
mkdirSync(stylesDir, { recursive: true });
|
|
65
|
+
const jsContent = `// CSS Module: ${filename} — auto-generated by BertUI\nconst styles = ${JSON.stringify(mapping, null, 2)};\nexport default styles;\n`;
|
|
66
|
+
writeFileSync(join(stylesDir, filename + '.js'), jsContent);
|
|
67
|
+
|
|
68
|
+
// Scoped CSS → .bertuibuild/styles-staged/home.module.css (for css-builder.js to pick up)
|
|
69
|
+
const stagingDir = join(rootBuildDir, 'styles-staged');
|
|
70
|
+
mkdirSync(stagingDir, { recursive: true });
|
|
71
|
+
writeFileSync(join(stagingDir, filename), finalCSS);
|
|
72
|
+
|
|
73
|
+
logger.debug(`CSS Module: ${filename} → ${Object.keys(mapping).length} classes scoped`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function transformCSSModuleImports(code, outPath, rootBuildDir) {
|
|
77
|
+
const moduleImportRegex = /import\s+(\w+)\s+from\s+['"]([^'"]*\.module\.css)['"]/g;
|
|
78
|
+
const outFileDir = dirname(outPath);
|
|
79
|
+
const stylesDir = join(rootBuildDir, 'styles');
|
|
80
|
+
|
|
81
|
+
code = code.replace(moduleImportRegex, (match, varName, importPath) => {
|
|
82
|
+
const filename = importPath.split('/').pop();
|
|
83
|
+
const jsFile = join(stylesDir, filename + '.js');
|
|
84
|
+
let rel = relative(outFileDir, jsFile).replace(/\\/g, '/');
|
|
85
|
+
if (!rel.startsWith('.')) rel = './' + rel;
|
|
86
|
+
return `import ${varName} from '${rel}'`;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return code;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ============================================
|
|
93
|
+
// MAIN COMPILER
|
|
94
|
+
// ============================================
|
|
6
95
|
|
|
7
96
|
export async function compileBuildDirectory(srcDir, buildDir, root, envVars) {
|
|
8
|
-
// Create bunfig.toml in build directory
|
|
9
97
|
const bunfigContent = `
|
|
10
98
|
[build]
|
|
11
99
|
jsx = "react"
|
|
12
100
|
jsxFactory = "React.createElement"
|
|
13
101
|
jsxFragment = "React.Fragment"
|
|
14
102
|
`.trim();
|
|
15
|
-
|
|
103
|
+
|
|
16
104
|
writeFileSync(join(buildDir, 'bunfig.toml'), bunfigContent);
|
|
17
105
|
logger.info('Created bunfig.toml for classic JSX');
|
|
18
|
-
|
|
106
|
+
|
|
19
107
|
const files = readdirSync(srcDir);
|
|
20
108
|
const filesToCompile = [];
|
|
21
|
-
|
|
109
|
+
const rootBuildDir = join(root, '.bertuibuild');
|
|
110
|
+
|
|
22
111
|
for (const file of files) {
|
|
23
112
|
const srcPath = join(srcDir, file);
|
|
24
113
|
const stat = statSync(srcPath);
|
|
25
|
-
|
|
114
|
+
|
|
26
115
|
if (stat.isDirectory()) {
|
|
27
116
|
const subBuildDir = join(buildDir, file);
|
|
28
117
|
mkdirSync(subBuildDir, { recursive: true });
|
|
29
118
|
await compileBuildDirectory(srcPath, subBuildDir, root, envVars);
|
|
30
119
|
} else {
|
|
31
120
|
const ext = extname(file);
|
|
121
|
+
|
|
122
|
+
if (file.endsWith('.module.css')) {
|
|
123
|
+
await compileCSSModule(srcPath, rootBuildDir);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
32
127
|
if (ext === '.css') continue;
|
|
33
|
-
|
|
128
|
+
|
|
34
129
|
if (['.jsx', '.tsx', '.ts'].includes(ext)) {
|
|
35
130
|
filesToCompile.push({ path: srcPath, dir: buildDir, name: file, type: 'tsx' });
|
|
36
131
|
} else if (ext === '.js') {
|
|
@@ -38,58 +133,56 @@ jsxFragment = "React.Fragment"
|
|
|
38
133
|
}
|
|
39
134
|
}
|
|
40
135
|
}
|
|
41
|
-
|
|
136
|
+
|
|
42
137
|
if (filesToCompile.length === 0) return;
|
|
43
|
-
|
|
138
|
+
|
|
44
139
|
logger.info(`📦 Compiling ${filesToCompile.length} files...`);
|
|
45
|
-
|
|
140
|
+
|
|
46
141
|
for (let i = 0; i < filesToCompile.length; i++) {
|
|
47
142
|
const file = filesToCompile[i];
|
|
48
|
-
|
|
143
|
+
|
|
49
144
|
try {
|
|
50
145
|
if (file.type === 'tsx') {
|
|
51
|
-
await compileBuildFile(file.path, file.dir, file.name, root, envVars,
|
|
146
|
+
await compileBuildFile(file.path, file.dir, file.name, root, envVars, rootBuildDir);
|
|
52
147
|
} else {
|
|
53
|
-
await compileJSFile(file.path, file.dir, file.name, root, envVars);
|
|
148
|
+
await compileJSFile(file.path, file.dir, file.name, root, envVars, rootBuildDir);
|
|
54
149
|
}
|
|
55
|
-
|
|
150
|
+
|
|
56
151
|
if ((i + 1) % 10 === 0 || i === filesToCompile.length - 1) {
|
|
57
152
|
const percent = (((i + 1) / filesToCompile.length) * 100).toFixed(0);
|
|
58
153
|
logger.info(` Progress: ${i + 1}/${filesToCompile.length} (${percent}%)`);
|
|
59
154
|
}
|
|
60
|
-
|
|
155
|
+
|
|
61
156
|
} catch (error) {
|
|
62
157
|
logger.error(`Failed to compile ${file.name}: ${error.message}`);
|
|
63
158
|
}
|
|
64
159
|
}
|
|
65
|
-
|
|
160
|
+
|
|
66
161
|
logger.success(`✅ Compiled ${filesToCompile.length} files`);
|
|
67
162
|
}
|
|
68
163
|
|
|
69
|
-
async function compileBuildFile(srcPath, buildDir, filename, root, envVars,
|
|
164
|
+
async function compileBuildFile(srcPath, buildDir, filename, root, envVars, rootBuildDir) {
|
|
70
165
|
const ext = extname(filename);
|
|
71
|
-
|
|
166
|
+
|
|
72
167
|
try {
|
|
73
168
|
let code = await Bun.file(srcPath).text();
|
|
74
|
-
code = removeCSSImports(code);
|
|
75
169
|
code = replaceEnvInCode(code, envVars);
|
|
76
|
-
|
|
170
|
+
|
|
77
171
|
const outFilename = filename.replace(/\.(jsx|tsx|ts)$/, '.js');
|
|
78
172
|
const outPath = join(buildDir, outFilename);
|
|
173
|
+
|
|
174
|
+
code = transformCSSModuleImports(code, outPath, rootBuildDir);
|
|
175
|
+
code = removePlainCSSImports(code);
|
|
79
176
|
code = fixBuildImports(code, srcPath, outPath, root);
|
|
80
|
-
|
|
81
|
-
// Add React import BEFORE transpiling
|
|
177
|
+
|
|
82
178
|
if (!code.includes('import React')) {
|
|
83
179
|
code = `import React from 'react';\n${code}`;
|
|
84
180
|
}
|
|
85
|
-
|
|
86
|
-
// Use Bun.Transpiler with explicit production settings
|
|
181
|
+
|
|
87
182
|
const transpiler = new Bun.Transpiler({
|
|
88
183
|
loader: ext === '.tsx' ? 'tsx' : ext === '.ts' ? 'ts' : 'jsx',
|
|
89
184
|
target: 'browser',
|
|
90
|
-
define: {
|
|
91
|
-
'process.env.NODE_ENV': '"production"'
|
|
92
|
-
},
|
|
185
|
+
define: { 'process.env.NODE_ENV': '"production"' },
|
|
93
186
|
tsconfig: {
|
|
94
187
|
compilerOptions: {
|
|
95
188
|
jsx: 'react',
|
|
@@ -99,50 +192,50 @@ async function compileBuildFile(srcPath, buildDir, filename, root, envVars, conf
|
|
|
99
192
|
}
|
|
100
193
|
}
|
|
101
194
|
});
|
|
102
|
-
|
|
195
|
+
|
|
103
196
|
let compiled = await transpiler.transform(code);
|
|
104
|
-
|
|
105
|
-
// Verify no dev JSX leaked through
|
|
197
|
+
|
|
106
198
|
if (compiled.includes('jsxDEV')) {
|
|
107
199
|
logger.warn(`⚠️ Dev JSX detected in ${filename}, fixing...`);
|
|
108
200
|
compiled = compiled.replace(/jsxDEV/g, 'jsx');
|
|
109
201
|
}
|
|
110
|
-
|
|
202
|
+
|
|
111
203
|
compiled = fixRelativeImports(compiled);
|
|
112
204
|
await Bun.write(outPath, compiled);
|
|
113
|
-
|
|
205
|
+
|
|
114
206
|
code = null;
|
|
115
207
|
compiled = null;
|
|
116
|
-
|
|
208
|
+
|
|
117
209
|
} catch (error) {
|
|
118
210
|
logger.error(`Failed to compile ${filename}: ${error.message}`);
|
|
119
211
|
throw error;
|
|
120
212
|
}
|
|
121
213
|
}
|
|
122
214
|
|
|
123
|
-
async function compileJSFile(srcPath, buildDir, filename, root, envVars) {
|
|
215
|
+
async function compileJSFile(srcPath, buildDir, filename, root, envVars, rootBuildDir) {
|
|
124
216
|
const outPath = join(buildDir, filename);
|
|
125
217
|
let code = await Bun.file(srcPath).text();
|
|
126
|
-
code = removeCSSImports(code);
|
|
127
218
|
code = replaceEnvInCode(code, envVars);
|
|
219
|
+
code = transformCSSModuleImports(code, outPath, rootBuildDir);
|
|
220
|
+
code = removePlainCSSImports(code);
|
|
128
221
|
code = fixBuildImports(code, srcPath, outPath, root);
|
|
129
|
-
|
|
222
|
+
|
|
130
223
|
if (usesJSX(code) && !code.includes('import React')) {
|
|
131
224
|
code = `import React from 'react';\n${code}`;
|
|
132
225
|
}
|
|
133
|
-
|
|
226
|
+
|
|
134
227
|
await Bun.write(outPath, code);
|
|
135
228
|
code = null;
|
|
136
229
|
}
|
|
137
230
|
|
|
138
231
|
function usesJSX(code) {
|
|
139
|
-
return code.includes('React.createElement') ||
|
|
232
|
+
return code.includes('React.createElement') ||
|
|
140
233
|
code.includes('React.Fragment') ||
|
|
141
234
|
/<[A-Z]/.test(code);
|
|
142
235
|
}
|
|
143
236
|
|
|
144
|
-
function
|
|
145
|
-
code = code.replace(/import\s+['"][^'"]
|
|
237
|
+
function removePlainCSSImports(code) {
|
|
238
|
+
code = code.replace(/import\s+['"][^'"]*(?<!\.module)\.css['"];?\s*/g, '');
|
|
146
239
|
code = code.replace(/import\s+['"]bertui\/styles['"]\s*;?\s*/g, '');
|
|
147
240
|
return code;
|
|
148
241
|
}
|
|
@@ -152,7 +245,6 @@ function fixBuildImports(code, srcPath, outPath, root) {
|
|
|
152
245
|
const routerPath = join(buildDir, 'router.js');
|
|
153
246
|
const relativeToRouter = relative(dirname(outPath), routerPath).replace(/\\/g, '/');
|
|
154
247
|
const routerImport = relativeToRouter.startsWith('.') ? relativeToRouter : './' + relativeToRouter;
|
|
155
|
-
|
|
156
248
|
code = code.replace(/from\s+['"]bertui\/router['"]/g, `from '${routerImport}'`);
|
|
157
249
|
return code;
|
|
158
250
|
}
|
|
@@ -164,4 +256,4 @@ function fixRelativeImports(code) {
|
|
|
164
256
|
return `from '${prefix}${path}.js';`;
|
|
165
257
|
});
|
|
166
258
|
return code;
|
|
167
|
-
}
|
|
259
|
+
}
|
|
@@ -20,13 +20,14 @@ export async function discoverRoutes(pagesDir) {
|
|
|
20
20
|
|
|
21
21
|
if (['.jsx', '.tsx', '.js', '.ts'].includes(ext)) {
|
|
22
22
|
const fileName = entry.name.replace(ext, '');
|
|
23
|
+
|
|
24
|
+
// Only loading is reserved - index is a valid route (becomes /)
|
|
25
|
+
if (fileName === 'loading') continue;
|
|
26
|
+
|
|
23
27
|
let route = '/' + relativePath.replace(/\\/g, '/').replace(ext, '');
|
|
24
|
-
|
|
25
|
-
const RESERVED = ['index', 'loading'];
|
|
26
28
|
if (fileName === 'index') {
|
|
27
29
|
route = route.replace('/index', '') || '/';
|
|
28
30
|
}
|
|
29
|
-
if (RESERVED.includes(fileName)) continue;
|
|
30
31
|
|
|
31
32
|
const isDynamic = fileName.includes('[') && fileName.includes(']');
|
|
32
33
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// bertui/src/build/processors/css-builder.js - WITH SCSS + CACHING
|
|
1
|
+
// bertui/src/build/processors/css-builder.js - WITH SCSS + CACHING + CSS MODULES
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { existsSync, readdirSync, mkdirSync } from 'fs';
|
|
4
4
|
import logger from '../../logger/logger.js';
|
|
@@ -9,13 +9,14 @@ export async function buildAllCSS(root, outDir) {
|
|
|
9
9
|
const startTime = process.hrtime.bigint();
|
|
10
10
|
|
|
11
11
|
const srcStylesDir = join(root, 'src', 'styles');
|
|
12
|
+
// CSS modules scoped CSS is staged here by file-transpiler.js
|
|
13
|
+
const modulesStagingDir = join(root, '.bertuibuild', 'styles-staged');
|
|
12
14
|
const stylesOutDir = join(outDir, 'styles');
|
|
13
15
|
|
|
14
16
|
mkdirSync(stylesOutDir, { recursive: true });
|
|
15
17
|
|
|
16
|
-
// Check cache for entire CSS build
|
|
17
18
|
const cacheKey = `css-build:${root}:${Date.now()}`;
|
|
18
|
-
const cached = globalCache.get(cacheKey, { ttl: 1000 });
|
|
19
|
+
const cached = globalCache.get(cacheKey, { ttl: 1000 });
|
|
19
20
|
|
|
20
21
|
if (cached) {
|
|
21
22
|
logger.info(`⚡ Using cached CSS (${cached.files} files)`);
|
|
@@ -23,43 +24,50 @@ export async function buildAllCSS(root, outDir) {
|
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
let combinedCSS = '';
|
|
28
|
+
let fileCount = 0;
|
|
29
|
+
|
|
30
|
+
// 1. Process src/styles/ (plain CSS + SCSS)
|
|
31
|
+
if (existsSync(srcStylesDir)) {
|
|
32
|
+
await processSCSSDirectory(srcStylesDir, root);
|
|
33
|
+
const cssFiles = readdirSync(srcStylesDir).filter(f => f.endsWith('.css') && !f.endsWith('.module.css'));
|
|
34
|
+
|
|
35
|
+
logger.info(`Processing ${cssFiles.length} CSS file(s)...`);
|
|
36
|
+
|
|
37
|
+
for (const cssFile of cssFiles) {
|
|
38
|
+
const srcPath = join(srcStylesDir, cssFile);
|
|
39
|
+
const fileBuffer = await globalCache.getFile(srcPath, { logSpeed: true });
|
|
40
|
+
if (fileBuffer) {
|
|
41
|
+
const content = fileBuffer.toString('utf-8');
|
|
42
|
+
combinedCSS += `/* ${cssFile} */\n${content}\n\n`;
|
|
43
|
+
fileCount++;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
logger.info('No styles directory found');
|
|
30
48
|
}
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
49
|
+
|
|
50
|
+
// 2. Include scoped CSS from CSS modules (staged by file-transpiler.js)
|
|
51
|
+
if (existsSync(modulesStagingDir)) {
|
|
52
|
+
const moduleFiles = readdirSync(modulesStagingDir).filter(f => f.endsWith('.css'));
|
|
53
|
+
if (moduleFiles.length > 0) {
|
|
54
|
+
logger.info(`Including ${moduleFiles.length} CSS module(s)...`);
|
|
55
|
+
for (const cssFile of moduleFiles) {
|
|
56
|
+
const srcPath = join(modulesStagingDir, cssFile);
|
|
57
|
+
const content = await Bun.file(srcPath).text();
|
|
58
|
+
combinedCSS += `/* module: ${cssFile} */\n${content}\n\n`;
|
|
59
|
+
fileCount++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!combinedCSS.trim()) {
|
|
39
65
|
await Bun.write(join(stylesOutDir, 'bertui.min.css'), '/* No CSS */');
|
|
40
66
|
return;
|
|
41
67
|
}
|
|
42
|
-
|
|
43
|
-
logger.info(`Processing ${cssFiles.length} CSS file(s)...`);
|
|
44
|
-
|
|
45
|
-
let combinedCSS = '';
|
|
46
|
-
const fileContents = [];
|
|
47
|
-
|
|
48
|
-
for (const cssFile of cssFiles) {
|
|
49
|
-
const srcPath = join(srcStylesDir, cssFile);
|
|
50
|
-
|
|
51
|
-
// Use file cache
|
|
52
|
-
const fileBuffer = await globalCache.getFile(srcPath, { logSpeed: true });
|
|
53
|
-
if (fileBuffer) {
|
|
54
|
-
const content = fileBuffer.toString('utf-8');
|
|
55
|
-
fileContents.push({ filename: cssFile, content });
|
|
56
|
-
combinedCSS += `/* ${cssFile} */\n${content}\n\n`;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
68
|
+
|
|
60
69
|
const combinedPath = join(stylesOutDir, 'bertui.min.css');
|
|
61
70
|
|
|
62
|
-
// Minify with caching
|
|
63
71
|
const minifyCacheKey = `minify:${Buffer.from(combinedCSS).length}:${combinedCSS.substring(0, 100)}`;
|
|
64
72
|
let minified = globalCache.get(minifyCacheKey);
|
|
65
73
|
|
|
@@ -68,7 +76,7 @@ export async function buildAllCSS(root, outDir) {
|
|
|
68
76
|
filename: 'bertui.min.css',
|
|
69
77
|
sourceMap: false
|
|
70
78
|
});
|
|
71
|
-
globalCache.set(minifyCacheKey, minified, { ttl: 60000 });
|
|
79
|
+
globalCache.set(minifyCacheKey, minified, { ttl: 60000 });
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
await Bun.write(combinedPath, minified);
|
|
@@ -78,23 +86,20 @@ export async function buildAllCSS(root, outDir) {
|
|
|
78
86
|
const reduction = ((1 - minifiedSize / originalSize) * 100).toFixed(1);
|
|
79
87
|
|
|
80
88
|
const endTime = process.hrtime.bigint();
|
|
81
|
-
const duration = Number(endTime - startTime) / 1000;
|
|
89
|
+
const duration = Number(endTime - startTime) / 1000;
|
|
82
90
|
|
|
83
91
|
logger.success(`CSS optimized: ${(originalSize/1024).toFixed(2)}KB → ${(minifiedSize/1024).toFixed(2)}KB (-${reduction}%)`);
|
|
84
92
|
logger.info(`⚡ Processing time: ${duration.toFixed(3)}µs`);
|
|
85
93
|
|
|
86
|
-
// Cache the final result
|
|
87
94
|
globalCache.set(cacheKey, {
|
|
88
|
-
files:
|
|
95
|
+
files: fileCount,
|
|
89
96
|
content: minified,
|
|
90
97
|
size: minifiedSize
|
|
91
98
|
}, { ttl: 5000 });
|
|
92
99
|
}
|
|
93
100
|
|
|
94
|
-
// NEW: Process SCSS directory
|
|
95
101
|
async function processSCSSDirectory(stylesDir, root) {
|
|
96
102
|
try {
|
|
97
|
-
// Check if sass is installed
|
|
98
103
|
const sass = await import('sass').catch(() => null);
|
|
99
104
|
if (!sass) return;
|
|
100
105
|
|
|
@@ -109,7 +114,6 @@ async function processSCSSDirectory(stylesDir, root) {
|
|
|
109
114
|
const srcPath = join(stylesDir, file);
|
|
110
115
|
const cssPath = join(stylesDir, file.replace(/\.(scss|sass)$/, '.css'));
|
|
111
116
|
|
|
112
|
-
// Check cache
|
|
113
117
|
const fileBuffer = await globalCache.getFile(srcPath);
|
|
114
118
|
const cacheKey = `scss:${file}:${Buffer.from(fileBuffer).length}`;
|
|
115
119
|
const cached = globalCache.get(cacheKey);
|
package/src/build.js
CHANGED
|
@@ -153,7 +153,9 @@ async function bundleJavaScript(buildEntry, routerPath, outDir, envVars, buildDi
|
|
|
153
153
|
});
|
|
154
154
|
|
|
155
155
|
if (!result.success) {
|
|
156
|
-
|
|
156
|
+
console.log('RAW LOGS:', JSON.stringify(result.logs, null, 2));
|
|
157
|
+
console.log('OUTPUTS:', JSON.stringify(result.outputs?.map(o => o.path), null, 2));
|
|
158
|
+
const errors = result.logs?.map(l => l.text || l.message || JSON.stringify(l)).join('\n') || 'Unknown error';
|
|
157
159
|
throw new Error(`JavaScript bundling failed:\n${errors}`);
|
|
158
160
|
}
|
|
159
161
|
|