pulse-js-framework 1.11.3 → 1.11.4

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 (48) hide show
  1. package/cli/analyze.js +21 -8
  2. package/cli/build.js +83 -56
  3. package/cli/dev.js +108 -94
  4. package/cli/docs-test.js +52 -33
  5. package/cli/index.js +81 -51
  6. package/cli/mobile.js +92 -40
  7. package/cli/release.js +64 -46
  8. package/cli/scaffold.js +14 -13
  9. package/compiler/lexer.js +55 -54
  10. package/compiler/parser/core.js +1 -0
  11. package/compiler/parser/state.js +6 -12
  12. package/compiler/parser/style.js +17 -20
  13. package/compiler/parser/view.js +1 -3
  14. package/compiler/preprocessor.js +124 -262
  15. package/compiler/sourcemap.js +10 -4
  16. package/compiler/transformer/expressions.js +122 -106
  17. package/compiler/transformer/index.js +2 -4
  18. package/compiler/transformer/style.js +74 -7
  19. package/compiler/transformer/view.js +86 -36
  20. package/loader/esbuild-plugin-server-components.js +209 -0
  21. package/loader/esbuild-plugin.js +41 -93
  22. package/loader/parcel-plugin.js +37 -97
  23. package/loader/rollup-plugin-server-components.js +30 -169
  24. package/loader/rollup-plugin.js +27 -78
  25. package/loader/shared.js +362 -0
  26. package/loader/swc-plugin.js +65 -82
  27. package/loader/vite-plugin-server-components.js +30 -171
  28. package/loader/vite-plugin.js +25 -10
  29. package/loader/webpack-loader-server-components.js +21 -134
  30. package/loader/webpack-loader.js +25 -80
  31. package/package.json +52 -12
  32. package/runtime/dom-selector.js +2 -1
  33. package/runtime/form.js +4 -3
  34. package/runtime/http.js +6 -1
  35. package/runtime/logger.js +44 -24
  36. package/runtime/router/utils.js +14 -7
  37. package/runtime/security.js +13 -1
  38. package/runtime/server-components/actions-server.js +23 -19
  39. package/runtime/server-components/error-sanitizer.js +18 -18
  40. package/runtime/server-components/security.js +41 -24
  41. package/runtime/ssr-preload.js +5 -3
  42. package/runtime/testing.js +759 -0
  43. package/runtime/utils.js +3 -2
  44. package/server/utils.js +15 -9
  45. package/sw/index.js +2 -0
  46. package/types/loaders.d.ts +1043 -0
  47. package/compiler/parser/_extract.js +0 -393
  48. package/loader/README.md +0 -509
@@ -25,44 +25,22 @@
25
25
  * import MyComponent from './MyComponent.pulse';
26
26
  *
27
27
  * Features:
28
- * - Automatic .pulse file transformation
29
- * - CSS extraction to Parcel's CSS pipeline
30
- * - Source map generation
31
- * - SASS/LESS/Stylus auto-detection and compilation
32
- * - Hot Module Replacement (HMR)
33
- * - Watch mode support
28
+ * - Automatic .pulse file transformation
29
+ * - CSS extraction to Parcel's CSS pipeline
30
+ * - Source map generation
31
+ * - SASS/LESS/Stylus auto-detection and compilation
32
+ * - Hot Module Replacement (HMR)
33
+ * - Watch mode support
34
34
  */
35
35
 
36
36
  import { compile } from '../compiler/index.js';
37
37
  import {
38
- preprocessStylesSync,
39
- isSassAvailable,
40
- isLessAvailable,
41
- isStylusAvailable,
42
- getSassVersion,
43
- getLessVersion,
44
- getStylusVersion,
45
- detectPreprocessor
46
- } from '../compiler/preprocessor.js';
47
- import { dirname } from 'path';
48
-
49
- // Cache for preprocessor availability checks
50
- let preprocessorCache = null;
51
-
52
- /**
53
- * Check available preprocessors once
54
- */
55
- function checkPreprocessors() {
56
- if (preprocessorCache) return preprocessorCache;
57
-
58
- preprocessorCache = {
59
- sass: isSassAvailable(),
60
- less: isLessAvailable(),
61
- stylus: isStylusAvailable()
62
- };
63
-
64
- return preprocessorCache;
65
- }
38
+ logPreprocessorAvailability,
39
+ extractCssFromOutput,
40
+ removeInlineStyles,
41
+ processStyles,
42
+ getPreprocessorOptions
43
+ } from './shared.js';
66
44
 
67
45
  /**
68
46
  * Transform function for Parcel
@@ -80,6 +58,7 @@ export async function transformPulse({ asset, logger }) {
80
58
  const {
81
59
  sourceMap = true,
82
60
  extractCss = true,
61
+ quiet = false,
83
62
  sass: sassOptions = {},
84
63
  less: lessOptions = {},
85
64
  stylus: stylusOptions = {},
@@ -87,27 +66,9 @@ export async function transformPulse({ asset, logger }) {
87
66
  } = config || {};
88
67
 
89
68
  // Log preprocessor availability once
90
- if (!checkPreprocessors._logged && verbose) {
91
- const available = checkPreprocessors();
92
- const preprocessors = [];
93
-
94
- if (available.sass) {
95
- preprocessors.push(`SASS ${getSassVersion() || 'unknown'}`);
96
- }
97
- if (available.less) {
98
- preprocessors.push(`LESS ${getLessVersion() || 'unknown'}`);
99
- }
100
- if (available.stylus) {
101
- preprocessors.push(`Stylus ${getStylusVersion() || 'unknown'}`);
102
- }
103
-
104
- if (preprocessors.length > 0) {
105
- logger.info({
106
- message: `[Pulse] Preprocessor support: ${preprocessors.join(', ')}`
107
- });
108
- }
109
-
110
- checkPreprocessors._logged = true;
69
+ if (!transformPulse._logged && verbose && !quiet) {
70
+ logPreprocessorAvailability('Pulse', { logFn: (msg) => logger.info({ message: msg }) });
71
+ transformPulse._logged = true;
111
72
  }
112
73
 
113
74
  try {
@@ -130,48 +91,31 @@ export async function transformPulse({ asset, logger }) {
130
91
  const outputMap = result.map;
131
92
 
132
93
  // Extract CSS from compiled output
133
- const stylesMatch = outputCode.match(/const styles = `([\s\S]*?)`;/);
134
-
135
- if (stylesMatch && extractCss) {
136
- let css = stylesMatch[1];
137
-
138
- // Check available preprocessors
139
- const available = checkPreprocessors();
140
- const preprocessor = detectPreprocessor(css);
141
-
142
- // Preprocess if preprocessor detected and available
143
- if (preprocessor !== 'none' && available[preprocessor]) {
144
- try {
145
- const preprocessorOptions = {
146
- sass: sassOptions,
147
- less: lessOptions,
148
- stylus: stylusOptions
149
- }[preprocessor];
150
-
151
- const preprocessed = preprocessStylesSync(css, {
152
- filename: filePath,
153
- loadPaths: [dirname(filePath), ...(preprocessorOptions.loadPaths || [])],
154
- compressed: preprocessorOptions.compressed || false,
155
- preprocessor // Force detected preprocessor
156
- });
94
+ const { css: extractedCss, found } = extractCssFromOutput(outputCode);
157
95
 
158
- css = preprocessed.css;
159
-
160
- // Log preprocessor usage in verbose mode
161
- if (preprocessorOptions.verbose || verbose) {
162
- logger.verbose({
163
- message: `[Pulse] Compiled ${preprocessor.toUpperCase()} in ${filePath}`
164
- });
165
- }
166
- } catch (preprocessorError) {
167
- // Emit warning but continue with original CSS
168
- logger.warn({
169
- message: `${preprocessor.toUpperCase()} compilation warning: ${preprocessorError.message}`,
170
- filePath
96
+ if (found && extractCss) {
97
+ const styleResult = processStyles(extractedCss, filePath, { sassOptions, lessOptions, stylusOptions });
98
+
99
+ // Log preprocessor usage in verbose mode
100
+ if (styleResult.preprocessor && styleResult.preprocessor !== 'none') {
101
+ const opts = getPreprocessorOptions(styleResult.preprocessor, { sassOptions, lessOptions, stylusOptions });
102
+ if (opts && (opts.verbose || verbose)) {
103
+ logger.verbose({
104
+ message: `[Pulse] Compiled ${styleResult.preprocessor.toUpperCase()} in ${filePath}`
171
105
  });
172
106
  }
173
107
  }
174
108
 
109
+ if (styleResult.warning) {
110
+ // Emit warning but continue with original CSS
111
+ logger.warn({
112
+ message: styleResult.warning,
113
+ filePath
114
+ });
115
+ }
116
+
117
+ const css = styleResult.css;
118
+
175
119
  // Create a CSS asset for Parcel to process
176
120
  // This allows Parcel's CSS pipeline to handle minification, autoprefixing, etc.
177
121
  asset.addDependency({
@@ -187,11 +131,7 @@ export async function transformPulse({ asset, logger }) {
187
131
  });
188
132
 
189
133
  // Remove inline CSS injection from output
190
- // Match the entire styles section and replace it
191
- outputCode = outputCode.replace(
192
- /\/\/ Styles[\s\S]*?\/\/ Inject styles[\s\S]*?document\.head\.appendChild\(styleEl\);/,
193
- '// Styles extracted to CSS asset'
194
- );
134
+ outputCode = removeInlineStyles(outputCode, '// Styles extracted to CSS asset');
195
135
  }
196
136
 
197
137
  // Set asset type and content
@@ -27,24 +27,24 @@
27
27
  * @module pulse-js-framework/loader/rollup-plugin-server-components
28
28
  */
29
29
 
30
- import { writeFileSync, mkdirSync } from 'fs';
31
- import { dirname, relative, posix } from 'path';
30
+ import { relative } from 'path';
32
31
  import {
33
32
  getComponentTypeFromSource
34
33
  } from '../compiler/directives.js';
34
+ import {
35
+ extractImports, createImportViolationError, buildManifest, writeManifestToDiskAsync,
36
+ DIRECTIVE_REGEX, COMPONENT_ID_REGEX, EXPORT_CONST_REGEX, CLIENT_CHUNK_PREFIX,
37
+ DEFAULT_MANIFEST_PATH, DEFAULT_MANIFEST_FILENAME
38
+ } from './shared.js';
35
39
 
36
40
  /**
37
41
  * Default options for Server Components plugin
38
42
  */
39
43
  const DEFAULT_OPTIONS = {
40
- // Output directory for client manifest
41
- manifestPath: 'dist/.pulse-manifest.json',
42
-
43
- // Public base path for chunk URLs (empty for relative paths)
44
+ manifestPath: DEFAULT_MANIFEST_PATH,
44
45
  base: '',
45
-
46
- // Custom manifest filename
47
- manifestFilename: '.pulse-manifest.json'
46
+ manifestFilename: DEFAULT_MANIFEST_FILENAME,
47
+ quiet: false
48
48
  };
49
49
 
50
50
  /**
@@ -97,12 +97,12 @@ export default function pulseServerComponentsPlugin(options = {}) {
97
97
 
98
98
  // Check if this module exports a Client Component
99
99
  // Look for: __directive: "use client"
100
- const directiveMatch = code.match(/__directive:\s*["']use client["']/);
100
+ const directiveMatch = code.match(DIRECTIVE_REGEX);
101
101
 
102
102
  if (directiveMatch) {
103
103
  // Extract component ID from export
104
- const exportMatch = code.match(/export const (\w+) = \{/);
105
- const componentIdMatch = code.match(/__componentId:\s*["'](\w+)["']/);
104
+ const exportMatch = code.match(EXPORT_CONST_REGEX);
105
+ const componentIdMatch = code.match(COMPONENT_ID_REGEX);
106
106
 
107
107
  const componentId = componentIdMatch ? componentIdMatch[1] : (exportMatch ? exportMatch[1] : null);
108
108
 
@@ -113,7 +113,9 @@ export default function pulseServerComponentsPlugin(options = {}) {
113
113
  chunk: null // Will be filled in during generateBundle
114
114
  });
115
115
 
116
- console.log(`[Pulse Server Components] Detected Client Component: ${componentId} (${relative(process.cwd(), id)})`);
116
+ if (!config.quiet) {
117
+ console.log(`[Pulse Server Components] Detected Client Component: ${componentId} (${relative(process.cwd(), id)})`);
118
+ }
117
119
  }
118
120
  }
119
121
 
@@ -164,7 +166,7 @@ export default function pulseServerComponentsPlugin(options = {}) {
164
166
  for (const [componentId, info] of clientComponents.entries()) {
165
167
  if (id === info.file) {
166
168
  // Create a separate chunk for this Client Component
167
- return `client-${componentId}`;
169
+ return `${CLIENT_CHUNK_PREFIX}${componentId}`;
168
170
  }
169
171
  }
170
172
 
@@ -201,36 +203,21 @@ export default function pulseServerComponentsPlugin(options = {}) {
201
203
  // Check if this chunk corresponds to a Client Component
202
204
  for (const [componentId, info] of clientComponents.entries()) {
203
205
  // Match by chunk name or by checking if the component file is in the chunk
204
- if (chunk.name === `client-${componentId}` ||
206
+ if (chunk.name === `${CLIENT_CHUNK_PREFIX}${componentId}` ||
205
207
  (chunk.facadeModuleId && chunk.facadeModuleId === info.file)) {
206
208
 
207
209
  // Store the chunk filename
208
210
  info.chunk = fileName;
209
211
 
210
- console.log(`[Pulse Server Components] Mapped ${componentId} → ${fileName}`);
212
+ if (!config.quiet) {
213
+ console.log(`[Pulse Server Components] Mapped ${componentId} → ${fileName}`);
214
+ }
211
215
  }
212
216
  }
213
217
  }
214
218
  }
215
219
 
216
- // Build client manifest
217
- const manifest = {
218
- version: '1.0',
219
- components: {}
220
- };
221
-
222
- for (const [componentId, info] of clientComponents.entries()) {
223
- if (info.chunk) {
224
- const base = config.base || '';
225
- const chunkUrl = posix.join(base, info.chunk);
226
-
227
- manifest.components[componentId] = {
228
- id: componentId,
229
- chunk: chunkUrl,
230
- exports: ['default', componentId]
231
- };
232
- }
233
- }
220
+ const manifest = buildManifest(clientComponents, config);
234
221
 
235
222
  // Emit manifest as JSON asset
236
223
  const manifestJson = JSON.stringify(manifest, null, 2);
@@ -241,151 +228,25 @@ export default function pulseServerComponentsPlugin(options = {}) {
241
228
  source: manifestJson
242
229
  });
243
230
 
244
- console.log(`[Pulse Server Components] Generated client manifest with ${clientComponents.size} components`);
231
+ if (!config.quiet) {
232
+ console.log(`[Pulse Server Components] Generated client manifest with ${clientComponents.size} components`);
233
+ }
245
234
  },
246
235
 
247
236
  /**
248
- * Write manifest to file system after build completes
237
+ * Write manifest to file system after build completes (async)
249
238
  */
250
- closeBundle() {
239
+ async closeBundle() {
251
240
  // Skip if no Client Components detected
252
241
  if (clientComponents.size === 0) {
253
242
  return;
254
243
  }
255
244
 
256
- // Build manifest object
257
- const manifest = {
258
- version: '1.0',
259
- components: {}
260
- };
261
-
262
- for (const [componentId, info] of clientComponents.entries()) {
263
- if (info.chunk) {
264
- const base = config.base || '';
265
- const chunkUrl = posix.join(base, info.chunk);
266
-
267
- manifest.components[componentId] = {
268
- id: componentId,
269
- chunk: chunkUrl,
270
- exports: ['default', componentId]
271
- };
272
- }
273
- }
274
-
275
- // Write to file system (in addition to emitted asset)
276
- if (config.manifestPath) {
277
- try {
278
- const manifestDir = dirname(config.manifestPath);
279
- mkdirSync(manifestDir, { recursive: true });
280
- writeFileSync(config.manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');
281
- console.log(`[Pulse Server Components] Manifest written to ${config.manifestPath}`);
282
- } catch (error) {
283
- console.warn(`[Pulse Server Components] Failed to write manifest: ${error.message}`);
284
- }
285
- }
245
+ const manifest = buildManifest(clientComponents, config);
246
+ await writeManifestToDiskAsync(manifest, config);
286
247
  }
287
248
  };
288
249
  }
289
250
 
290
- // ============================================================================
291
- // Helper Functions
292
- // ============================================================================
293
-
294
- /**
295
- * Extract import statements from source code
296
- * @param {string} code - Source code
297
- * @returns {Array<string>} Import sources
298
- */
299
- function extractImports(code) {
300
- const imports = [];
301
-
302
- // Match ES6 import statements
303
- const importRegex = /import\s+(?:{[^}]*}|[\w$]+|\*\s+as\s+[\w$]+)\s+from\s+['"]([^'"]+)['"]/g;
304
- let match;
305
-
306
- while ((match = importRegex.exec(code)) !== null) {
307
- imports.push(match[1]);
308
- }
309
-
310
- // Match dynamic imports
311
- const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
312
- while ((match = dynamicImportRegex.exec(code)) !== null) {
313
- imports.push(match[1]);
314
- }
315
-
316
- return imports;
317
- }
318
-
319
- /**
320
- * Create import violation error message
321
- * @param {string} clientPath - Client Component path
322
- * @param {string} serverPath - Server Component path
323
- * @param {string} importSource - Import statement source
324
- * @returns {string} Error message
325
- */
326
- function createImportViolationError(clientPath, serverPath, importSource) {
327
- const clientRelative = relative(process.cwd(), clientPath);
328
- const serverRelative = relative(process.cwd(), serverPath);
329
-
330
- return `
331
- [Pulse] Import Violation: Client Component cannot import Server Component
332
- at ${clientRelative}
333
- importing ${importSource}
334
- resolved to ${serverRelative}
335
-
336
- Client Components can only import:
337
- • Other Client Components ('use client')
338
- • Shared utilities (no directive)
339
- • Third-party packages
340
-
341
- → Move shared logic to a Client Component
342
- → Use Server Actions for server-side operations
343
- → Create a wrapper Client Component that calls Server Actions
344
-
345
- See: https://pulse-js.fr/server-components#import-rules
346
- `.trim();
347
- }
348
-
349
- /**
350
- * Helper function to load client manifest (for SSR)
351
- *
352
- * @param {string} manifestPath - Path to manifest file
353
- * @returns {Object} Client manifest
354
- *
355
- * @example
356
- * import { loadClientManifest } from 'pulse-js-framework/rollup/server-components';
357
- *
358
- * const manifest = loadClientManifest('./dist/.pulse-manifest.json');
359
- * // Use manifest for SSR: renderServerComponent(Component, props, { clientManifest: manifest.components })
360
- */
361
- export function loadClientManifest(manifestPath) {
362
- try {
363
- const { readFileSync } = require('fs');
364
- const content = readFileSync(manifestPath, 'utf-8');
365
- return JSON.parse(content);
366
- } catch (error) {
367
- console.warn(`Failed to load client manifest from ${manifestPath}:`, error.message);
368
- return { version: '1.0', components: {} };
369
- }
370
- }
371
-
372
- /**
373
- * Helper function to get client component chunk URL
374
- *
375
- * @param {Object} manifest - Client manifest
376
- * @param {string} componentId - Component ID
377
- * @returns {string|null} Chunk URL or null if not found
378
- */
379
- export function getComponentChunk(manifest, componentId) {
380
- return manifest.components[componentId]?.chunk || null;
381
- }
382
-
383
- /**
384
- * Helper function to get all client component IDs
385
- *
386
- * @param {Object} manifest - Client manifest
387
- * @returns {Set<string>} Set of component IDs
388
- */
389
- export function getClientComponentIds(manifest) {
390
- return new Set(Object.keys(manifest.components));
391
- }
251
+ // Re-export shared manifest helpers
252
+ export { loadClientManifest, getComponentChunk, getClientComponentIds } from './shared.js';
@@ -29,34 +29,12 @@
29
29
 
30
30
  import { compile } from '../compiler/index.js';
31
31
  import {
32
- preprocessStylesSync,
33
- isSassAvailable,
34
- isLessAvailable,
35
- isStylusAvailable,
36
- getSassVersion,
37
- getLessVersion,
38
- getStylusVersion,
39
- detectPreprocessor
40
- } from '../compiler/preprocessor.js';
41
- import { dirname } from 'path';
42
-
43
- // Cache for preprocessor availability checks
44
- let preprocessorCache = null;
45
-
46
- /**
47
- * Check available preprocessors once
48
- */
49
- function checkPreprocessors() {
50
- if (preprocessorCache) return preprocessorCache;
51
-
52
- preprocessorCache = {
53
- sass: isSassAvailable(),
54
- less: isLessAvailable(),
55
- stylus: isStylusAvailable()
56
- };
57
-
58
- return preprocessorCache;
59
- }
32
+ logPreprocessorAvailability,
33
+ extractCssFromOutput,
34
+ removeInlineStyles,
35
+ processStyles,
36
+ getPreprocessorOptions
37
+ } from './shared.js';
60
38
 
61
39
  /**
62
40
  * Create Pulse Rollup plugin
@@ -67,6 +45,7 @@ export default function pulsePlugin(options = {}) {
67
45
  exclude = /node_modules/,
68
46
  sourceMap = true,
69
47
  extractCss = null, // Path to output CSS file, or null for inline
48
+ quiet = false,
70
49
  sass: sassOptions = {},
71
50
  less: lessOptions = {},
72
51
  stylus: stylusOptions = {}
@@ -89,22 +68,9 @@ export default function pulsePlugin(options = {}) {
89
68
  accumulatedCss = '';
90
69
  cssEmitted = false;
91
70
 
92
- // Check preprocessor availability
93
- const available = checkPreprocessors();
94
- const preprocessors = [];
95
-
96
- if (available.sass) {
97
- preprocessors.push(`SASS ${getSassVersion() || 'unknown'}`);
98
- }
99
- if (available.less) {
100
- preprocessors.push(`LESS ${getLessVersion() || 'unknown'}`);
101
- }
102
- if (available.stylus) {
103
- preprocessors.push(`Stylus ${getStylusVersion() || 'unknown'}`);
104
- }
105
-
106
- if (preprocessors.length > 0) {
107
- console.log(`[Pulse Rollup] Preprocessor support: ${preprocessors.join(', ')}`);
71
+ // Log preprocessor availability
72
+ if (!quiet) {
73
+ logPreprocessorAvailability('Pulse Rollup');
108
74
  }
109
75
  },
110
76
 
@@ -155,40 +121,24 @@ export default function pulsePlugin(options = {}) {
155
121
  let outputMap = result.map;
156
122
 
157
123
  // Extract CSS from compiled output
158
- const stylesMatch = outputCode.match(/const styles = `([\s\S]*?)`;/);
124
+ const { css: extractedCss, found: cssFound } = extractCssFromOutput(outputCode);
159
125
 
160
- if (stylesMatch) {
161
- let css = stylesMatch[1];
162
-
163
- // Check available preprocessors
164
- const available = checkPreprocessors();
165
- const preprocessor = detectPreprocessor(css);
126
+ if (cssFound) {
127
+ let css = extractedCss;
166
128
 
167
129
  // Preprocess if preprocessor detected and available
168
- if (preprocessor !== 'none' && available[preprocessor]) {
169
- try {
170
- const preprocessorOptions = {
171
- sass: sassOptions,
172
- less: lessOptions,
173
- stylus: stylusOptions
174
- }[preprocessor];
175
-
176
- const preprocessed = preprocessStylesSync(css, {
177
- filename: id,
178
- loadPaths: [dirname(id), ...(preprocessorOptions.loadPaths || [])],
179
- compressed: preprocessorOptions.compressed || false,
180
- preprocessor // Force detected preprocessor
181
- });
130
+ const styleResult = processStyles(css, id, { sassOptions, lessOptions, stylusOptions });
131
+ css = styleResult.css;
182
132
 
183
- css = preprocessed.css;
133
+ if (styleResult.warning) {
134
+ this.warn(styleResult.warning);
135
+ }
184
136
 
185
- // Log preprocessor usage in verbose mode
186
- if (preprocessorOptions.verbose) {
187
- console.log(`[Pulse] Compiled ${preprocessor.toUpperCase()} in ${id}`);
188
- }
189
- } catch (preprocessorError) {
190
- // Emit warning but continue with original CSS
191
- this.warn(`${preprocessor.toUpperCase()} compilation warning: ${preprocessorError.message}`);
137
+ // Log preprocessor usage in verbose mode
138
+ if (styleResult.preprocessor !== 'none') {
139
+ const preprocessorOptions = getPreprocessorOptions(styleResult.preprocessor, { sassOptions, lessOptions, stylusOptions });
140
+ if (preprocessorOptions?.verbose) {
141
+ console.log(`[Pulse] Compiled ${styleResult.preprocessor.toUpperCase()} in ${id}`);
192
142
  }
193
143
  }
194
144
 
@@ -197,10 +147,7 @@ export default function pulsePlugin(options = {}) {
197
147
  accumulatedCss += `/* ${id} */\n${css}\n\n`;
198
148
 
199
149
  // Remove inline CSS injection from output
200
- outputCode = outputCode.replace(
201
- /\/\/ Styles\nconst styles = `[\s\S]*?`;\n\/\/ Inject styles\nconst styleEl = document\.createElement\("style"\);\nstyleEl\.textContent = styles;\ndocument\.head\.appendChild\(styleEl\);/,
202
- '// Styles extracted to CSS file'
203
- );
150
+ outputCode = removeInlineStyles(outputCode, '// Styles extracted to CSS file');
204
151
  }
205
152
  // else: keep inline CSS injection
206
153
  }
@@ -226,7 +173,9 @@ export default function pulsePlugin(options = {}) {
226
173
  source: accumulatedCss
227
174
  });
228
175
  cssEmitted = true;
229
- console.log(`[Pulse] Emitted CSS to ${extractCss}`);
176
+ if (!quiet) {
177
+ console.log(`[Pulse] Emitted CSS to ${extractCss}`);
178
+ }
230
179
  }
231
180
  }
232
181
  };