@roots/bud-compiler 2023.7.20-622 → 2023.7.23-80

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/lib/service.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { Bud } from '@roots/bud-framework';
3
3
  import type { MultiCompiler, MultiStats, Stats, StatsError, Webpack } from '@roots/bud-framework/config';
4
4
  import type { ErrorWithSourceFile } from '@roots/bud-support/open';
5
5
  import { Service } from '@roots/bud-framework/service';
6
- import { type BudErrorClass } from '@roots/bud-support/errors';
6
+ import { BudError } from '@roots/bud-support/errors';
7
7
  import webpack from '@roots/bud-support/webpack';
8
8
  /**
9
9
  * {@link BudCompiler} implementation
@@ -36,7 +36,7 @@ export declare class Compiler extends Service implements BudCompiler {
36
36
  /**
37
37
  * {@link BudCompiler.onError}
38
38
  */
39
- onError(error: BudErrorClass | webpack.WebpackError): void;
39
+ onError(error: BudError | webpack.WebpackError): void;
40
40
  /**
41
41
  * {@link BudCompiler.onStats}
42
42
  */
package/lib/service.js CHANGED
@@ -9,6 +9,8 @@ import { bind } from '@roots/bud-support/decorators/bind';
9
9
  import { BudError } from '@roots/bud-support/errors';
10
10
  import { duration } from '@roots/bud-support/human-readable';
11
11
  import { render } from '@roots/bud-support/ink';
12
+ import isNull from '@roots/bud-support/lodash/isNull';
13
+ import isString from '@roots/bud-support/lodash/isString';
12
14
  import stripAnsi from '@roots/bud-support/strip-ansi';
13
15
  import webpack from '@roots/bud-support/webpack';
14
16
  /**
@@ -41,13 +43,10 @@ export class Compiler extends Service {
41
43
  async compile(bud) {
42
44
  this.config = !bud.hasChildren
43
45
  ? [await bud.build.make()]
44
- : await Promise.all(Object.values(bud.children).map(async (child) => await child.build.make().catch(error => {
46
+ : await Promise.all(Object.values(bud.children).map(async (child) => child.build.make().catch(error => {
45
47
  throw error;
46
48
  })));
47
- const cores = Math.max(cpus().length, 1);
48
- const compilations = Math.max(Object.keys(bud.children ?? []).length, 1);
49
- const parallelism = Math.max(Math.floor(cores / compilations), 1);
50
- this.config.parallelism = parallelism;
49
+ this.config.parallelism = Math.max(cpus().length - 1, 1);
51
50
  this.logger.info(`parallel compilations: ${this.config.parallelism}`);
52
51
  await bud.hooks.fire(`compiler.before`, bud).catch(error => {
53
52
  throw error;
@@ -58,7 +57,7 @@ export class Compiler extends Service {
58
57
  this.instance = this.implementation(this.config);
59
58
  }
60
59
  catch (error) {
61
- throw BudError.normalize(error);
60
+ this.onError(error);
62
61
  }
63
62
  this.instance.hooks.done.tap(bud.label, (stats) => {
64
63
  this.onStats(stats);
@@ -73,6 +72,8 @@ export class Compiler extends Service {
73
72
  */
74
73
  onError(error) {
75
74
  process.exitCode = 1;
75
+ if (!error)
76
+ return;
76
77
  this.app.server?.appliedMiddleware?.hot?.publish({ error });
77
78
  this.app.notifier?.notify({
78
79
  group: this.app.label,
@@ -157,27 +158,38 @@ export class Compiler extends Service {
157
158
  if (!errors || !errors.length)
158
159
  return [];
159
160
  try {
160
- const parseError = (error) => {
161
+ return errors
162
+ ?.map((error) => {
161
163
  let file;
162
- const moduleIdent = error.moduleId ?? error.moduleName;
164
+ let module;
165
+ const ident = error.moduleId ?? error.moduleName;
163
166
  /**
164
167
  * In a perfect world webpack plugins would use the
165
168
  * `nameForCondition` property to identify the module.
166
169
  */
167
- let module = this.compilationStats.children
168
- .flatMap(child => child?.modules)
169
- .find(module => module?.id === moduleIdent || module?.name === moduleIdent);
170
+ if (ident) {
171
+ module = this.compilationStats.children
172
+ .flatMap(child => child?.modules)
173
+ .find(module => [module?.id, module?.name].includes(ident));
174
+ }
170
175
  /**
171
176
  * If the module is not found, we try to parse the error message
172
177
  */
173
- if (!moduleIdent) {
174
- const stylelintExtracted = error.message.match(/file:\/\/(.*)\x07(.*)\x1B]8;;/);
175
- if (stylelintExtracted?.[1]) {
176
- module = {
177
- name: stylelintExtracted[2] ?? stylelintExtracted[1],
178
- nameForCondition: stylelintExtracted[1],
179
- };
180
- }
178
+ if (!ident && error.message?.includes(`[stylelint]`)) {
179
+ // try to get the origin of the stylelint error,
180
+ // which is contained in the second line of the error message
181
+ const unparsedOrigin = error.message?.split(`\n`)?.[1];
182
+ // if the origin is not a string or too long, we return the error as-is
183
+ if (!isString(unparsedOrigin) || unparsedOrigin.length > 100)
184
+ return error;
185
+ // extract absolute path and context relative name of module
186
+ const styleError = unparsedOrigin.match(/file:\/\/(.*)\x07(.*)\x1B]8;;/);
187
+ if (isNull(styleError))
188
+ return error;
189
+ // get parts of matched error
190
+ const [, file, name] = styleError;
191
+ // return enriched error
192
+ return { ...error, file, name, nameForCondition: file };
181
193
  }
182
194
  /**
183
195
  * If the module is still not found, we return the error as-is
@@ -194,14 +206,13 @@ export class Compiler extends Service {
194
206
  else if (module.name) {
195
207
  file = this.app.path(`@src`, module.name);
196
208
  }
197
- return !file
198
- ? { ...error, name: module.name ?? error.name }
199
- : { ...error, file, name: module.name ?? error.name };
200
- };
201
- return errors?.map(parseError).filter(Boolean);
209
+ const name = module.name ?? error.name ?? `error`;
210
+ return { ...error, file, name };
211
+ })
212
+ .filter(Boolean);
202
213
  }
203
214
  catch (error) {
204
- this.logger.warn(`error parsing errors`, error);
215
+ this.logger.warn(`Problem parsing errors. This probably won't break anything but please report it: https://github.com/roots/bud/issues/new`, error);
205
216
  return errors;
206
217
  }
207
218
  }
@@ -245,16 +256,12 @@ const statsOptions = {
245
256
  cachedAssets: true,
246
257
  cachedModules: true,
247
258
  entrypoints: true,
248
- errorDetails: false,
249
259
  errors: true,
250
260
  errorsCount: true,
251
- errorStack: false,
252
261
  hash: true,
253
262
  modules: true,
254
263
  name: true,
255
264
  outputPath: true,
256
- reasons: false,
257
- runtime: true,
258
265
  timings: true,
259
266
  warnings: true,
260
267
  warningsCount: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roots/bud-compiler",
3
- "version": "2023.7.20-622",
3
+ "version": "2023.7.23-80",
4
4
  "description": "Compilation handler",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -61,15 +61,15 @@
61
61
  "types": "./lib/index.d.ts",
62
62
  "module": "./lib/index.js",
63
63
  "devDependencies": {
64
- "@roots/bud-api": "2023.7.20-622",
64
+ "@roots/bud-api": "2023.7.23-80",
65
65
  "@skypack/package-check": "0.2.2",
66
66
  "@types/node": "18.16.19",
67
67
  "@types/react": "18.2.15"
68
68
  },
69
69
  "dependencies": {
70
- "@roots/bud-dashboard": "2023.7.20-622",
71
- "@roots/bud-framework": "2023.7.20-622",
72
- "@roots/bud-support": "2023.7.20-622",
70
+ "@roots/bud-dashboard": "2023.7.23-80",
71
+ "@roots/bud-framework": "2023.7.23-80",
72
+ "@roots/bud-support": "2023.7.23-80",
73
73
  "react": "18.2.0",
74
74
  "tslib": "2.6.0"
75
75
  },
package/src/service.tsx CHANGED
@@ -20,9 +20,11 @@ import {pathToFileURL} from 'node:url'
20
20
  import {Error} from '@roots/bud-dashboard/components/error'
21
21
  import {Service} from '@roots/bud-framework/service'
22
22
  import {bind} from '@roots/bud-support/decorators/bind'
23
- import {BudError, type BudErrorClass} from '@roots/bud-support/errors'
23
+ import {BudError} from '@roots/bud-support/errors'
24
24
  import {duration} from '@roots/bud-support/human-readable'
25
25
  import {render} from '@roots/bud-support/ink'
26
+ import isNull from '@roots/bud-support/lodash/isNull'
27
+ import isString from '@roots/bud-support/lodash/isString'
26
28
  import stripAnsi from '@roots/bud-support/strip-ansi'
27
29
  import webpack from '@roots/bud-support/webpack'
28
30
 
@@ -63,22 +65,14 @@ export class Compiler extends Service implements BudCompiler {
63
65
  this.config = !bud.hasChildren
64
66
  ? [await bud.build.make()]
65
67
  : await Promise.all(
66
- Object.values(bud.children).map(
67
- async (child: Bud) =>
68
- await child.build.make().catch(error => {
69
- throw error
70
- }),
68
+ Object.values(bud.children).map(async (child: Bud) =>
69
+ child.build.make().catch(error => {
70
+ throw error
71
+ }),
71
72
  ),
72
73
  )
73
74
 
74
- const cores = Math.max(cpus().length, 1)
75
- const compilations = Math.max(
76
- Object.keys(bud.children ?? []).length,
77
- 1,
78
- )
79
- const parallelism = Math.max(Math.floor(cores / compilations), 1)
80
-
81
- this.config.parallelism = parallelism
75
+ this.config.parallelism = Math.max(cpus().length - 1, 1)
82
76
  this.logger.info(`parallel compilations: ${this.config.parallelism}`)
83
77
 
84
78
  await bud.hooks.fire(`compiler.before`, bud).catch(error => {
@@ -91,12 +85,11 @@ export class Compiler extends Service implements BudCompiler {
91
85
  try {
92
86
  this.instance = this.implementation(this.config)
93
87
  } catch (error) {
94
- throw BudError.normalize(error)
88
+ this.onError(error)
95
89
  }
96
90
 
97
91
  this.instance.hooks.done.tap(bud.label, (stats: any) => {
98
92
  this.onStats(stats)
99
-
100
93
  bud.hooks.fire(`compiler.done`, bud, this.stats).catch(error => {
101
94
  throw error
102
95
  })
@@ -109,8 +102,9 @@ export class Compiler extends Service implements BudCompiler {
109
102
  * {@link BudCompiler.onError}
110
103
  */
111
104
  @bind
112
- public onError(error: BudErrorClass | webpack.WebpackError) {
105
+ public onError(error: BudError | webpack.WebpackError) {
113
106
  process.exitCode = 1
107
+ if (!error) return
114
108
 
115
109
  this.app.server?.appliedMiddleware?.hot?.publish({error})
116
110
 
@@ -217,63 +211,71 @@ export class Compiler extends Service implements BudCompiler {
217
211
  if (!errors || !errors.length) return []
218
212
 
219
213
  try {
220
- const parseError = (
221
- error: StatsError,
222
- ): ErrorWithSourceFile | StatsError => {
223
- let file: SourceFile[`file`] | undefined
224
-
225
- const moduleIdent = error.moduleId ?? error.moduleName
226
-
227
- /**
228
- * In a perfect world webpack plugins would use the
229
- * `nameForCondition` property to identify the module.
230
- */
231
- let module = this.compilationStats.children
232
- .flatMap(child => child?.modules)
233
- .find(
234
- module =>
235
- module?.id === moduleIdent || module?.name === moduleIdent,
236
- )
237
-
238
- /**
239
- * If the module is not found, we try to parse the error message
240
- */
241
- if (!moduleIdent) {
242
- const stylelintExtracted = error.message.match(
243
- /file:\/\/(.*)\x07(.*)\x1B]8;;/,
244
- )
245
-
246
- if (stylelintExtracted?.[1]) {
247
- module = {
248
- name: stylelintExtracted[2] ?? stylelintExtracted[1],
249
- nameForCondition: stylelintExtracted[1],
250
- }
214
+ return errors
215
+ ?.map((error: StatsError): ErrorWithSourceFile | StatsError => {
216
+ let file: SourceFile[`file`] | undefined
217
+ let module: undefined | Webpack.StatsModule
218
+
219
+ const ident = error.moduleId ?? error.moduleName
220
+
221
+ /**
222
+ * In a perfect world webpack plugins would use the
223
+ * `nameForCondition` property to identify the module.
224
+ */
225
+ if (ident) {
226
+ module = this.compilationStats.children
227
+ .flatMap(child => child?.modules)
228
+ .find(module => [module?.id, module?.name].includes(ident))
251
229
  }
252
- }
253
230
 
254
- /**
255
- * If the module is still not found, we return the error as-is
256
- */
257
- if (!module) return error
258
-
259
- /**
260
- * We'll prefer the `nameForCondition` property if it exists,
261
- * otherwise we'll use the `name` property.
262
- */
263
- if (module.nameForCondition) {
264
- file = module.nameForCondition
265
- } else if (module.name) {
266
- file = this.app.path(`@src`, module.name)
267
- }
231
+ /**
232
+ * If the module is not found, we try to parse the error message
233
+ */
234
+ if (!ident && error.message?.includes(`[stylelint]`)) {
235
+ // try to get the origin of the stylelint error,
236
+ // which is contained in the second line of the error message
237
+ const unparsedOrigin = error.message?.split(`\n`)?.[1]
238
+
239
+ // if the origin is not a string or too long, we return the error as-is
240
+ if (!isString(unparsedOrigin) || unparsedOrigin.length > 100)
241
+ return error
242
+
243
+ // extract absolute path and context relative name of module
244
+ const styleError = unparsedOrigin.match(
245
+ /file:\/\/(.*)\x07(.*)\x1B]8;;/,
246
+ )
247
+ if (isNull(styleError)) return error
248
+
249
+ // get parts of matched error
250
+ const [, file, name] = styleError
251
+ // return enriched error
252
+ return {...error, file, name, nameForCondition: file}
253
+ }
268
254
 
269
- return !file
270
- ? {...error, name: module.name ?? error.name}
271
- : {...error, file, name: module.name ?? error.name}
272
- }
255
+ /**
256
+ * If the module is still not found, we return the error as-is
257
+ */
258
+ if (!module) return error
259
+
260
+ /**
261
+ * We'll prefer the `nameForCondition` property if it exists,
262
+ * otherwise we'll use the `name` property.
263
+ */
264
+ if (module.nameForCondition) {
265
+ file = module.nameForCondition
266
+ } else if (module.name) {
267
+ file = this.app.path(`@src`, module.name)
268
+ }
273
269
 
274
- return errors?.map(parseError).filter(Boolean)
270
+ const name = module.name ?? error.name ?? `error`
271
+ return {...error, file, name}
272
+ })
273
+ .filter(Boolean)
275
274
  } catch (error) {
276
- this.logger.warn(`error parsing errors`, error)
275
+ this.logger.warn(
276
+ `Problem parsing errors. This probably won't break anything but please report it: https://github.com/roots/bud/issues/new`,
277
+ error,
278
+ )
277
279
  return errors
278
280
  }
279
281
  }
@@ -288,16 +290,12 @@ const statsOptions = {
288
290
  cachedAssets: true,
289
291
  cachedModules: true,
290
292
  entrypoints: true,
291
- errorDetails: false,
292
293
  errors: true,
293
294
  errorsCount: true,
294
- errorStack: false,
295
295
  hash: true,
296
296
  modules: true,
297
297
  name: true,
298
298
  outputPath: true,
299
- reasons: false,
300
- runtime: true,
301
299
  timings: true,
302
300
  warnings: true,
303
301
  warningsCount: true,