@roots/bud-compiler 6.13.1 → 6.14.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/lib/index.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  /**
2
- * The bud compiler interface
2
+ * @roots/bud-compiler
3
3
  *
4
4
  * @see https://bud.js.org
5
5
  * @see https://github.com/roots/bud
6
- *
7
- * @packageDocumentation
8
6
  */
9
- import { Compiler } from './compiler.service.js';
10
- import './types.js';
11
- export default Compiler;
7
+ import { Compiler } from './service.js';
8
+ declare module '@roots/bud-framework' {
9
+ interface Services {
10
+ compiler: Compiler;
11
+ }
12
+ }
13
+ export { Compiler as default };
package/lib/index.js CHANGED
@@ -1,13 +1,10 @@
1
1
  // Copyright © Roots Software Foundation LLC
2
2
  // Licensed under the MIT license.
3
3
  /**
4
- * The bud compiler interface
4
+ * @roots/bud-compiler
5
5
  *
6
6
  * @see https://bud.js.org
7
7
  * @see https://github.com/roots/bud
8
- *
9
- * @packageDocumentation
10
8
  */
11
- import { Compiler } from './compiler.service.js';
12
- import './types.js';
13
- export default Compiler;
9
+ import { Compiler } from './service.js';
10
+ export { Compiler as default };
@@ -0,0 +1,49 @@
1
+ import type { Compiler as BudCompiler } from '@roots/bud-framework';
2
+ import type { Bud } from '@roots/bud-framework';
3
+ import type { MultiCompiler, MultiStats, Stats, StatsError, Webpack } from '@roots/bud-framework/config';
4
+ import type { ErrorWithSourceFile } from '@roots/bud-support/open';
5
+ import { Service } from '@roots/bud-framework/service';
6
+ import { type BudHandler } from '@roots/bud-support/errors';
7
+ import webpack from '@roots/bud-support/webpack';
8
+ /**
9
+ * {@link BudCompiler} implementation
10
+ */
11
+ export declare class Compiler extends Service implements BudCompiler {
12
+ /**
13
+ * {@link BudCompiler.compilationStats}
14
+ */
15
+ compilationStats: BudCompiler[`compilationStats`];
16
+ /**
17
+ * {@link BudCompiler.config}
18
+ */
19
+ config: BudCompiler[`config`];
20
+ /**
21
+ * {@link BudCompiler.implementation}
22
+ */
23
+ implementation: BudCompiler[`implementation`] & typeof Webpack;
24
+ /**
25
+ * {@link BudCompiler.instance}
26
+ */
27
+ instance: BudCompiler[`instance`];
28
+ /**
29
+ * {@link BudCompiler.stats}
30
+ */
31
+ stats: BudCompiler[`stats`];
32
+ /**
33
+ * {@link BudCompiler.compile}
34
+ */
35
+ compile(bud: Bud): Promise<MultiCompiler>;
36
+ /**
37
+ * {@link BudCompiler.onError}
38
+ */
39
+ onError(error: BudHandler | webpack.WebpackError): void;
40
+ /**
41
+ * {@link BudCompiler.onStats}
42
+ */
43
+ onStats(stats: Stats & MultiStats): void;
44
+ /**
45
+ * {@link Service.register}
46
+ */
47
+ register?(bud: Bud): Promise<any>;
48
+ sourceErrors?(errors: Array<StatsError>): Array<ErrorWithSourceFile | StatsError>;
49
+ }
@@ -1,112 +1,104 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import * as App from '@roots/bud-dashboard/app';
3
+ import { cpus } from 'node:os';
4
+ import process from 'node:process';
5
+ import { pathToFileURL } from 'node:url';
6
+ import { Error } from '@roots/bud-dashboard/components/error';
4
7
  import { Service } from '@roots/bud-framework/service';
5
8
  import { bind } from '@roots/bud-support/decorators/bind';
6
- import { BudError, CompilerError } from '@roots/bud-support/errors';
9
+ import { BudError } from '@roots/bud-support/errors';
7
10
  import { duration } from '@roots/bud-support/human-readable';
8
- import * as Ink from '@roots/bud-support/ink';
11
+ import { render } from '@roots/bud-support/ink';
9
12
  import stripAnsi from '@roots/bud-support/strip-ansi';
10
- import { pathToFileURL } from 'node:url';
11
- import webpack from 'webpack';
13
+ import webpack from '@roots/bud-support/webpack';
12
14
  /**
13
- * Wepback compilation controller class
15
+ * {@link BudCompiler} implementation
14
16
  */
15
17
  export class Compiler extends Service {
16
18
  /**
17
- * Configuration
19
+ * {@link BudCompiler.compilationStats}
20
+ */
21
+ compilationStats;
22
+ /**
23
+ * {@link BudCompiler.config}
18
24
  */
19
25
  config = [];
20
26
  /**
21
- * Compiler implementation
27
+ * {@link BudCompiler.implementation}
22
28
  */
23
29
  implementation;
24
30
  /**
25
- * Compiler instance
31
+ * {@link BudCompiler.instance}
26
32
  */
27
33
  instance;
28
34
  /**
29
- * Compilation stats
35
+ * {@link BudCompiler.stats}
30
36
  */
31
37
  stats;
32
38
  /**
33
- * Initiates compilation
39
+ * {@link BudCompiler.compile}
34
40
  */
35
- async compile() {
36
- const compilerPath = await this.app.module.resolve(`webpack`, import.meta.url);
37
- this.implementation = await this.app.module.import(compilerPath, import.meta.url);
38
- this.logger.log(`imported webpack`, this.implementation.version);
39
- this.config = !this.app.hasChildren
40
- ? [await this.app.build.make()]
41
- : await Promise.all(Object.values(this.app.children).map(async (child) => {
42
- try {
43
- return await child.build.make();
44
- }
45
- catch (error) {
46
- throw error;
47
- }
48
- }));
49
- await this.app.hooks.fire(`compiler.before`, this.app);
41
+ async compile(bud) {
42
+ this.config = !bud.hasChildren
43
+ ? [await bud.build.make()]
44
+ : await Promise.all(Object.values(bud.children).map(async (child) => await child.build.make().catch(error => {
45
+ throw error;
46
+ })));
47
+ this.config.parallelism = Math.min(cpus().length - 1, 1);
48
+ await bud.hooks.fire(`compiler.before`, bud).catch(error => {
49
+ throw error;
50
+ });
50
51
  this.logger.timeEnd(`initialize`);
51
- this.logger.await(`compilation`);
52
- this.instance = this.implementation(this.config);
53
- this.instance.hooks.done.tap(this.app.label, async (stats) => {
54
- await this.onStats(stats);
55
- await this.app.hooks.fire(`compiler.close`, this.app);
52
+ this.app.dashboard.updateStatus(`compiling`);
53
+ try {
54
+ this.instance = this.implementation(this.config);
55
+ }
56
+ catch (error) {
57
+ throw BudError.normalize(error);
58
+ }
59
+ this.instance.hooks.done.tap(bud.label, (stats) => {
60
+ this.onStats(stats);
61
+ bud.hooks.fire(`compiler.done`, bud, this.stats).catch(error => {
62
+ throw error;
63
+ });
56
64
  });
57
- await this.app.hooks.fire(`compiler.after`, this.app);
58
65
  return this.instance;
59
66
  }
60
67
  /**
61
- * Compiler error event
68
+ * {@link BudCompiler.onError}
62
69
  */
63
- async onError(error) {
70
+ onError(error) {
64
71
  process.exitCode = 1;
65
- await this.app.hooks.fire(`compiler.error`, error);
66
- this.app.isDevelopment &&
67
- this.app.server.appliedMiddleware?.hot?.publish({ error });
68
- try {
69
- this.app.notifier.notify({
70
- group: this.app.label,
71
- message: error.message,
72
- subtitle: error.name,
73
- });
74
- }
75
- catch (error) {
76
- this.logger.error(error);
77
- }
78
- try {
79
- Ink.render(_jsx(App.Error, { error: new CompilerError(error.message, {
80
- props: {
81
- details: `This error was thrown by the webpack compiler itself. It is not the same as a syntax error. It is likely a missing or unresolvable build dependency.`,
82
- docs: new URL(`https://bud.js.org/`),
83
- issues: new URL(`https://github.com/roots/bud/search?q=is:issue+"compiler" in:title`),
84
- stack: error.stack,
85
- thrownBy: `webpack`,
86
- },
87
- }) }));
72
+ this.app.server?.appliedMiddleware?.hot?.publish({ error });
73
+ this.app.notifier?.notify({
74
+ group: this.app.label,
75
+ message: error.message,
76
+ subtitle: error.name,
77
+ });
78
+ if (`isBudError` in error) {
79
+ render(_jsx(Error, { error: error }));
88
80
  }
89
- catch (error) {
90
- throw BudError.normalize(error);
81
+ else {
82
+ render(_jsx(Error, { error: BudError.normalize(error) }));
91
83
  }
92
84
  }
93
85
  /**
94
- * Stats handler
86
+ * {@link BudCompiler.onStats}
95
87
  */
96
- async onStats(stats) {
88
+ onStats(stats) {
97
89
  const makeNoticeTitle = (child) => this.app.label !== child.name
98
90
  ? `${this.app.label} (${child.name})`
99
91
  : child.name;
100
- this.stats = stats.toJson(this.app.hooks.filter(`build.stats`));
101
- await this.app.hooks.fire(`compiler.stats`, stats);
102
- const statsUpdate = this.app.dashboard.update(stats);
92
+ this.stats = stats;
93
+ this.compilationStats = stats.toJson(statsOptions);
94
+ this.app.dashboard.updateStats(this.compilationStats);
103
95
  if (stats.hasErrors()) {
104
96
  process.exitCode = 1;
105
- this.stats.children = this.stats.children?.map(child => ({
97
+ this.compilationStats.children = this.compilationStats.children?.map(child => ({
106
98
  ...child,
107
99
  errors: this.sourceErrors(child.errors),
108
100
  }));
109
- this.stats.children
101
+ this.compilationStats.children
110
102
  ?.filter(child => child.errorsCount > 0)
111
103
  .forEach(child => {
112
104
  try {
@@ -127,7 +119,7 @@ export class Compiler extends Service {
127
119
  }
128
120
  });
129
121
  }
130
- this.stats.children
122
+ this.compilationStats.children
131
123
  ?.filter(child => child.errorsCount === 0)
132
124
  .forEach(child => {
133
125
  try {
@@ -146,33 +138,38 @@ export class Compiler extends Service {
146
138
  this.logger.error(error);
147
139
  }
148
140
  });
149
- await statsUpdate;
150
141
  }
151
142
  /**
152
- * Parse errors from webpack stats
143
+ * {@link Service.register}
153
144
  */
145
+ async register(bud) {
146
+ this.implementation = await bud.module
147
+ .import(`@roots/bud-support/webpack`, import.meta.url)
148
+ .catch(error => {
149
+ throw BudError.normalize(error);
150
+ });
151
+ }
154
152
  sourceErrors(errors) {
155
153
  if (!errors || !errors.length)
156
154
  return [];
157
155
  try {
158
156
  const parseError = (error) => {
159
157
  let file;
160
- const modules = this.stats.children.flatMap(child => child.modules);
161
158
  const moduleIdent = error.moduleId ?? error.moduleName;
162
- const module = modules.find(module => module?.id === moduleIdent || module?.name === moduleIdent);
163
- if (!module) {
159
+ const module = this.compilationStats.children
160
+ .flatMap(child => child?.modules)
161
+ .find(module => module?.id === moduleIdent || module?.name === moduleIdent);
162
+ if (!module)
164
163
  return error;
165
- }
166
164
  if (module.nameForCondition) {
167
165
  file = module.nameForCondition;
168
166
  }
169
167
  else if (module.name) {
170
168
  file = this.app.path(`@src`, module.name);
171
169
  }
172
- if (!file) {
173
- return error;
174
- }
175
- return { ...error, file, name: module.name ?? error.name };
170
+ return !file
171
+ ? { ...error, name: module.name ?? error.name }
172
+ : { ...error, file, name: module.name ?? error.name };
176
173
  };
177
174
  return errors?.map(parseError).filter(Boolean);
178
175
  }
@@ -185,24 +182,55 @@ export class Compiler extends Service {
185
182
  __decorate([
186
183
  bind,
187
184
  __metadata("design:type", Function),
188
- __metadata("design:paramtypes", []),
185
+ __metadata("design:paramtypes", [Function]),
189
186
  __metadata("design:returntype", Promise)
190
187
  ], Compiler.prototype, "compile", null);
191
188
  __decorate([
192
189
  bind,
193
190
  __metadata("design:type", Function),
194
- __metadata("design:paramtypes", [Error]),
195
- __metadata("design:returntype", Promise)
191
+ __metadata("design:paramtypes", [Object]),
192
+ __metadata("design:returntype", void 0)
196
193
  ], Compiler.prototype, "onError", null);
197
194
  __decorate([
198
195
  bind,
199
196
  __metadata("design:type", Function),
200
197
  __metadata("design:paramtypes", [Function]),
201
- __metadata("design:returntype", Promise)
198
+ __metadata("design:returntype", void 0)
202
199
  ], Compiler.prototype, "onStats", null);
200
+ __decorate([
201
+ bind,
202
+ __metadata("design:type", Function),
203
+ __metadata("design:paramtypes", [Function]),
204
+ __metadata("design:returntype", Promise)
205
+ ], Compiler.prototype, "register", null);
203
206
  __decorate([
204
207
  bind,
205
208
  __metadata("design:type", Function),
206
209
  __metadata("design:paramtypes", [Array]),
207
210
  __metadata("design:returntype", Array)
208
211
  ], Compiler.prototype, "sourceErrors", null);
212
+ const statsOptions = {
213
+ all: false,
214
+ children: {
215
+ all: false,
216
+ assets: true,
217
+ cached: true,
218
+ cachedAssets: true,
219
+ cachedModules: true,
220
+ entrypoints: true,
221
+ errorDetails: false,
222
+ errors: true,
223
+ errorsCount: true,
224
+ errorStack: false,
225
+ hash: true,
226
+ modules: true,
227
+ name: true,
228
+ outputPath: true,
229
+ reasons: false,
230
+ runtime: true,
231
+ timings: true,
232
+ warnings: true,
233
+ warningsCount: true,
234
+ },
235
+ name: true,
236
+ };
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@roots/bud-compiler",
3
- "version": "6.13.1",
3
+ "version": "6.14.1",
4
4
  "description": "Compilation handler",
5
5
  "engines": {
6
6
  "node": ">=16"
7
7
  },
8
8
  "contributors": [
9
9
  {
10
- "name": "Kelly Mears",
11
10
  "email": "developers@tinypixel.dev",
11
+ "name": "Kelly Mears",
12
12
  "url": "https://github.com/kellymears"
13
13
  },
14
14
  {
15
- "name": "Ben Word",
16
15
  "email": "ben@benword.com",
16
+ "name": "Ben Word",
17
17
  "url": "https://github.com/retlehs"
18
18
  },
19
19
  {
@@ -21,8 +21,8 @@
21
21
  "url": "https://github.com/QWp6t"
22
22
  },
23
23
  {
24
- "name": "Brandon",
25
24
  "email": "brandon@tendency.me",
25
+ "name": "Brandon",
26
26
  "url": "https://github.com/Log1x"
27
27
  }
28
28
  ],
@@ -49,40 +49,29 @@
49
49
  ],
50
50
  "type": "module",
51
51
  "exports": {
52
- ".": {
53
- "import": "./lib/index.js",
54
- "default": "./lib/index.js"
55
- },
56
- "./types": {
57
- "import": "./lib/types.js",
58
- "default": "./lib/types.js"
59
- }
52
+ ".": "./lib/index.js"
60
53
  },
61
54
  "typesVersions": {
62
55
  "*": {
63
56
  ".": [
64
57
  "./lib/index.d.ts"
65
- ],
66
- "types": [
67
- "./lib/types.d.ts"
68
58
  ]
69
59
  }
70
60
  },
71
61
  "types": "./lib/index.d.ts",
72
62
  "module": "./lib/index.js",
73
63
  "devDependencies": {
74
- "@roots/bud-api": "6.13.1",
64
+ "@roots/bud-api": "6.14.1",
75
65
  "@skypack/package-check": "0.2.2",
76
- "@types/node": "18.16.16",
77
- "@types/react": "18.2.9"
66
+ "@types/node": "18.16.18",
67
+ "@types/react": "18.2.14"
78
68
  },
79
69
  "dependencies": {
80
- "@roots/bud-dashboard": "6.13.1",
81
- "@roots/bud-framework": "6.13.1",
82
- "@roots/bud-support": "6.13.1",
70
+ "@roots/bud-dashboard": "6.14.1",
71
+ "@roots/bud-framework": "6.14.1",
72
+ "@roots/bud-support": "6.14.1",
83
73
  "react": "18.2.0",
84
- "tslib": "2.5.3",
85
- "webpack": "5.86.0"
74
+ "tslib": "2.6.0"
86
75
  },
87
76
  "volta": {
88
77
  "extends": "../../../package.json"
package/src/index.ts CHANGED
@@ -2,15 +2,18 @@
2
2
  // Licensed under the MIT license.
3
3
 
4
4
  /**
5
- * The bud compiler interface
5
+ * @roots/bud-compiler
6
6
  *
7
7
  * @see https://bud.js.org
8
8
  * @see https://github.com/roots/bud
9
- *
10
- * @packageDocumentation
11
9
  */
12
10
 
13
- import {Compiler} from './compiler.service.js'
14
- import './types.js'
11
+ import {Compiler} from './service.js'
12
+
13
+ declare module '@roots/bud-framework' {
14
+ interface Services {
15
+ compiler: Compiler
16
+ }
17
+ }
15
18
 
16
- export default Compiler
19
+ export {Compiler as default}
@@ -0,0 +1,269 @@
1
+ import type {Compiler as BudCompiler} from '@roots/bud-framework'
2
+ import type {Bud} from '@roots/bud-framework'
3
+ import type {
4
+ MultiCompiler,
5
+ MultiStats,
6
+ Stats,
7
+ StatsCompilation,
8
+ StatsError,
9
+ Webpack,
10
+ } from '@roots/bud-framework/config'
11
+ import type {
12
+ ErrorWithSourceFile,
13
+ SourceFile,
14
+ } from '@roots/bud-support/open'
15
+
16
+ import {cpus} from 'node:os'
17
+ import process from 'node:process'
18
+ import {pathToFileURL} from 'node:url'
19
+
20
+ import {Error} from '@roots/bud-dashboard/components/error'
21
+ import {Service} from '@roots/bud-framework/service'
22
+ import {bind} from '@roots/bud-support/decorators/bind'
23
+ import {BudError, type BudHandler} from '@roots/bud-support/errors'
24
+ import {duration} from '@roots/bud-support/human-readable'
25
+ import {render} from '@roots/bud-support/ink'
26
+ import stripAnsi from '@roots/bud-support/strip-ansi'
27
+ import webpack from '@roots/bud-support/webpack'
28
+
29
+ /**
30
+ * {@link BudCompiler} implementation
31
+ */
32
+ export class Compiler extends Service implements BudCompiler {
33
+ /**
34
+ * {@link BudCompiler.compilationStats}
35
+ */
36
+ public compilationStats: BudCompiler[`compilationStats`]
37
+
38
+ /**
39
+ * {@link BudCompiler.config}
40
+ */
41
+ public config: BudCompiler[`config`] = []
42
+
43
+ /**
44
+ * {@link BudCompiler.implementation}
45
+ */
46
+ public implementation: BudCompiler[`implementation`] & typeof Webpack
47
+
48
+ /**
49
+ * {@link BudCompiler.instance}
50
+ */
51
+ public instance: BudCompiler[`instance`]
52
+
53
+ /**
54
+ * {@link BudCompiler.stats}
55
+ */
56
+ public stats: BudCompiler[`stats`]
57
+
58
+ /**
59
+ * {@link BudCompiler.compile}
60
+ */
61
+ @bind
62
+ public async compile(bud: Bud): Promise<MultiCompiler> {
63
+ this.config = !bud.hasChildren
64
+ ? [await bud.build.make()]
65
+ : await Promise.all(
66
+ Object.values(bud.children).map(
67
+ async (child: Bud) =>
68
+ await child.build.make().catch(error => {
69
+ throw error
70
+ }),
71
+ ),
72
+ )
73
+ this.config.parallelism = Math.min(cpus().length - 1, 1)
74
+
75
+ await bud.hooks.fire(`compiler.before`, bud).catch(error => {
76
+ throw error
77
+ })
78
+
79
+ this.logger.timeEnd(`initialize`)
80
+ this.app.dashboard.updateStatus(`compiling`)
81
+
82
+ try {
83
+ this.instance = this.implementation(this.config)
84
+ } catch (error) {
85
+ throw BudError.normalize(error)
86
+ }
87
+
88
+ this.instance.hooks.done.tap(bud.label, (stats: any) => {
89
+ this.onStats(stats)
90
+
91
+ bud.hooks.fire(`compiler.done`, bud, this.stats).catch(error => {
92
+ throw error
93
+ })
94
+ })
95
+
96
+ return this.instance
97
+ }
98
+
99
+ /**
100
+ * {@link BudCompiler.onError}
101
+ */
102
+ @bind
103
+ public onError(error: BudHandler | webpack.WebpackError) {
104
+ process.exitCode = 1
105
+
106
+ this.app.server?.appliedMiddleware?.hot?.publish({error})
107
+
108
+ this.app.notifier?.notify({
109
+ group: this.app.label,
110
+ message: error.message,
111
+ subtitle: error.name,
112
+ })
113
+
114
+ if (`isBudError` in error) {
115
+ render(<Error error={error} />)
116
+ } else {
117
+ render(<Error error={BudError.normalize(error)} />)
118
+ }
119
+ }
120
+
121
+ /**
122
+ * {@link BudCompiler.onStats}
123
+ */
124
+ @bind
125
+ public onStats(stats: Stats & MultiStats) {
126
+ const makeNoticeTitle = (child: StatsCompilation) =>
127
+ this.app.label !== child.name
128
+ ? `${this.app.label} (${child.name})`
129
+ : child.name
130
+
131
+ this.stats = stats
132
+
133
+ this.compilationStats = stats.toJson(statsOptions)
134
+
135
+ this.app.dashboard.updateStats(this.compilationStats)
136
+
137
+ if (stats.hasErrors()) {
138
+ process.exitCode = 1
139
+
140
+ this.compilationStats.children = this.compilationStats.children?.map(
141
+ child => ({
142
+ ...child,
143
+ errors: this.sourceErrors(child.errors),
144
+ }),
145
+ )
146
+
147
+ this.compilationStats.children
148
+ ?.filter(child => child.errorsCount > 0)
149
+ .forEach(child => {
150
+ try {
151
+ const error = child.errors?.shift()
152
+ if (!error) return
153
+
154
+ this.app.notifier.notify({
155
+ group: `${this.app.label}-${child.name}`,
156
+ message: stripAnsi(error.message),
157
+ open: error.file ? pathToFileURL(error.file) : ``,
158
+ subtitle: error.file ? `Error in ${error.name}` : error.name,
159
+ title: makeNoticeTitle(child),
160
+ })
161
+ this.app.notifier.openEditor(error.file)
162
+ } catch (error) {
163
+ this.logger.error(error)
164
+ }
165
+ })
166
+ }
167
+
168
+ this.compilationStats.children
169
+ ?.filter(child => child.errorsCount === 0)
170
+ .forEach(child => {
171
+ try {
172
+ this.app.notifier.notify({
173
+ group: `${this.app.label}-${child.name}`,
174
+ message: child.modules
175
+ ? `${child.modules.length} modules compiled in ${duration(
176
+ child.time,
177
+ )}`
178
+ : `Compiled in ${duration(child.time)}`,
179
+ open: this.app.server?.publicUrl.href,
180
+ subtitle: `Build successful`,
181
+ title: makeNoticeTitle(child),
182
+ })
183
+
184
+ this.app.notifier.openBrowser(this.app.server?.publicUrl.href)
185
+ } catch (error) {
186
+ this.logger.error(error)
187
+ }
188
+ })
189
+ }
190
+
191
+ /**
192
+ * {@link Service.register}
193
+ */
194
+ @bind
195
+ public override async register?(bud: Bud): Promise<any> {
196
+ this.implementation = await bud.module
197
+ .import(`@roots/bud-support/webpack`, import.meta.url)
198
+ .catch(error => {
199
+ throw BudError.normalize(error)
200
+ })
201
+ }
202
+
203
+ @bind
204
+ public sourceErrors?(
205
+ errors: Array<StatsError>,
206
+ ): Array<ErrorWithSourceFile | StatsError> {
207
+ if (!errors || !errors.length) return []
208
+
209
+ try {
210
+ const parseError = (
211
+ error: StatsError,
212
+ ): ErrorWithSourceFile | StatsError => {
213
+ let file: SourceFile[`file`] | undefined
214
+
215
+ const moduleIdent = error.moduleId ?? error.moduleName
216
+
217
+ const module = this.compilationStats.children
218
+ .flatMap(child => child?.modules)
219
+ .find(
220
+ module =>
221
+ module?.id === moduleIdent || module?.name === moduleIdent,
222
+ )
223
+
224
+ if (!module) return error
225
+
226
+ if (module.nameForCondition) {
227
+ file = module.nameForCondition
228
+ } else if (module.name) {
229
+ file = this.app.path(`@src`, module.name)
230
+ }
231
+
232
+ return !file
233
+ ? {...error, name: module.name ?? error.name}
234
+ : {...error, file, name: module.name ?? error.name}
235
+ }
236
+
237
+ return errors?.map(parseError).filter(Boolean)
238
+ } catch (error) {
239
+ this.app.warn(`error parsing errors`, error)
240
+ return []
241
+ }
242
+ }
243
+ }
244
+
245
+ const statsOptions = {
246
+ all: false,
247
+ children: {
248
+ all: false,
249
+ assets: true,
250
+ cached: true,
251
+ cachedAssets: true,
252
+ cachedModules: true,
253
+ entrypoints: true,
254
+ errorDetails: false,
255
+ errors: true,
256
+ errorsCount: true,
257
+ errorStack: false,
258
+ hash: true,
259
+ modules: true,
260
+ name: true,
261
+ outputPath: true,
262
+ reasons: false,
263
+ runtime: true,
264
+ timings: true,
265
+ warnings: true,
266
+ warningsCount: true,
267
+ },
268
+ name: true,
269
+ }
@@ -1,42 +0,0 @@
1
- import type { MultiCompiler, MultiStats, StatsError } from '@roots/bud-framework/config';
2
- import type { Compiler as Contract } from '@roots/bud-framework/services';
3
- import type { ErrorWithSourceFile } from '@roots/bud-support/open';
4
- import { Service } from '@roots/bud-framework/service';
5
- import webpack from 'webpack';
6
- /**
7
- * Wepback compilation controller class
8
- */
9
- export declare class Compiler extends Service implements Contract.Service {
10
- /**
11
- * Configuration
12
- */
13
- config: Contract.Service[`config`];
14
- /**
15
- * Compiler implementation
16
- */
17
- implementation: typeof webpack;
18
- /**
19
- * Compiler instance
20
- */
21
- instance: Contract.Service[`instance`];
22
- /**
23
- * Compilation stats
24
- */
25
- stats: Contract.Service[`stats`];
26
- /**
27
- * Initiates compilation
28
- */
29
- compile(): Promise<MultiCompiler>;
30
- /**
31
- * Compiler error event
32
- */
33
- onError(error: Error): Promise<void>;
34
- /**
35
- * Stats handler
36
- */
37
- onStats(stats: MultiStats): Promise<void>;
38
- /**
39
- * Parse errors from webpack stats
40
- */
41
- sourceErrors(errors: Array<StatsError>): Array<ErrorWithSourceFile | StatsError>;
42
- }
package/lib/types.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export {};
2
- /**
3
- * @package @roots/bud-compiler
4
- */
package/lib/types.js DELETED
@@ -1,4 +0,0 @@
1
- export {};
2
- /**
3
- * @package @roots/bud-compiler
4
- */
@@ -1,252 +0,0 @@
1
- import type {Bud} from '@roots/bud-framework'
2
- import type {
3
- MultiCompiler,
4
- MultiStats,
5
- StatsCompilation,
6
- StatsError,
7
- } from '@roots/bud-framework/config'
8
- import type {Compiler as Contract} from '@roots/bud-framework/services'
9
- import type {
10
- ErrorWithSourceFile,
11
- SourceFile,
12
- } from '@roots/bud-support/open'
13
-
14
- import * as App from '@roots/bud-dashboard/app'
15
- import {Service} from '@roots/bud-framework/service'
16
- import {bind} from '@roots/bud-support/decorators/bind'
17
- import {BudError, CompilerError} from '@roots/bud-support/errors'
18
- import {duration} from '@roots/bud-support/human-readable'
19
- import * as Ink from '@roots/bud-support/ink'
20
- import stripAnsi from '@roots/bud-support/strip-ansi'
21
- import {pathToFileURL} from 'node:url'
22
- import webpack from 'webpack'
23
-
24
- /**
25
- * Wepback compilation controller class
26
- */
27
- export class Compiler extends Service implements Contract.Service {
28
- /**
29
- * Configuration
30
- */
31
- public config: Contract.Service[`config`] = []
32
-
33
- /**
34
- * Compiler implementation
35
- */
36
- public implementation: typeof webpack
37
-
38
- /**
39
- * Compiler instance
40
- */
41
- public instance: Contract.Service[`instance`]
42
-
43
- /**
44
- * Compilation stats
45
- */
46
- public stats: Contract.Service[`stats`]
47
-
48
- /**
49
- * Initiates compilation
50
- */
51
- @bind
52
- public async compile(): Promise<MultiCompiler> {
53
- const compilerPath = await this.app.module.resolve(
54
- `webpack`,
55
- import.meta.url,
56
- )
57
- this.implementation = await this.app.module.import(
58
- compilerPath,
59
- import.meta.url,
60
- )
61
- this.logger.log(`imported webpack`, this.implementation.version)
62
-
63
- this.config = !this.app.hasChildren
64
- ? [await this.app.build.make()]
65
- : await Promise.all(
66
- Object.values(this.app.children).map(async (child: Bud) => {
67
- try {
68
- return await child.build.make()
69
- } catch (error) {
70
- throw error
71
- }
72
- }),
73
- )
74
-
75
- await this.app.hooks.fire(`compiler.before`, this.app)
76
-
77
- this.logger.timeEnd(`initialize`)
78
-
79
- this.logger.await(`compilation`)
80
-
81
- this.instance = this.implementation(this.config)
82
- this.instance.hooks.done.tap(this.app.label, async (stats: any) => {
83
- await this.onStats(stats)
84
- await this.app.hooks.fire(`compiler.close`, this.app)
85
- })
86
-
87
- await this.app.hooks.fire(`compiler.after`, this.app)
88
-
89
- return this.instance
90
- }
91
-
92
- /**
93
- * Compiler error event
94
- */
95
- @bind
96
- public async onError(error: Error) {
97
- process.exitCode = 1
98
-
99
- await this.app.hooks.fire(`compiler.error`, error)
100
-
101
- this.app.isDevelopment &&
102
- this.app.server.appliedMiddleware?.hot?.publish({error})
103
-
104
- try {
105
- this.app.notifier.notify({
106
- group: this.app.label,
107
- message: error.message,
108
- subtitle: error.name,
109
- })
110
- } catch (error) {
111
- this.logger.error(error)
112
- }
113
-
114
- try {
115
- Ink.render(
116
- <App.Error
117
- error={
118
- new CompilerError(error.message, {
119
- props: {
120
- details: `This error was thrown by the webpack compiler itself. It is not the same as a syntax error. It is likely a missing or unresolvable build dependency.`,
121
- docs: new URL(`https://bud.js.org/`),
122
- issues: new URL(
123
- `https://github.com/roots/bud/search?q=is:issue+"compiler" in:title`,
124
- ),
125
- stack: error.stack,
126
- thrownBy: `webpack`,
127
- },
128
- })
129
- }
130
- />,
131
- )
132
- } catch (error) {
133
- throw BudError.normalize(error)
134
- }
135
- }
136
-
137
- /**
138
- * Stats handler
139
- */
140
- @bind
141
- public async onStats(stats: MultiStats) {
142
- const makeNoticeTitle = (child: StatsCompilation) =>
143
- this.app.label !== child.name
144
- ? `${this.app.label} (${child.name})`
145
- : child.name
146
-
147
- this.stats = stats.toJson(this.app.hooks.filter(`build.stats`))
148
-
149
- await this.app.hooks.fire(`compiler.stats`, stats)
150
-
151
- const statsUpdate = this.app.dashboard.update(stats)
152
-
153
- if (stats.hasErrors()) {
154
- process.exitCode = 1
155
-
156
- this.stats.children = this.stats.children?.map(child => ({
157
- ...child,
158
- errors: this.sourceErrors(child.errors),
159
- }))
160
-
161
- this.stats.children
162
- ?.filter(child => child.errorsCount > 0)
163
- .forEach(child => {
164
- try {
165
- const error = child.errors?.shift()
166
- if (!error) return
167
-
168
- this.app.notifier.notify({
169
- group: `${this.app.label}-${child.name}`,
170
- message: stripAnsi(error.message),
171
- open: error.file ? pathToFileURL(error.file) : ``,
172
- subtitle: error.file ? `Error in ${error.name}` : error.name,
173
- title: makeNoticeTitle(child),
174
- })
175
- this.app.notifier.openEditor(error.file)
176
- } catch (error) {
177
- this.logger.error(error)
178
- }
179
- })
180
- }
181
-
182
- this.stats.children
183
- ?.filter(child => child.errorsCount === 0)
184
- .forEach(child => {
185
- try {
186
- this.app.notifier.notify({
187
- group: `${this.app.label}-${child.name}`,
188
- message: child.modules
189
- ? `${child.modules.length} modules compiled in ${duration(
190
- child.time,
191
- )}`
192
- : `Compiled in ${duration(child.time)}`,
193
- open: this.app.server?.publicUrl.href,
194
- subtitle: `Build successful`,
195
- title: makeNoticeTitle(child),
196
- })
197
- this.app.notifier.openBrowser(this.app.server?.publicUrl.href)
198
- } catch (error) {
199
- this.logger.error(error)
200
- }
201
- })
202
-
203
- await statsUpdate
204
- }
205
-
206
- /**
207
- * Parse errors from webpack stats
208
- */
209
- @bind
210
- public sourceErrors(
211
- errors: Array<StatsError>,
212
- ): Array<ErrorWithSourceFile | StatsError> {
213
- if (!errors || !errors.length) return []
214
-
215
- try {
216
- const parseError = (
217
- error: StatsError,
218
- ): ErrorWithSourceFile | StatsError => {
219
- let file: SourceFile[`file`] | undefined
220
-
221
- const modules = this.stats.children.flatMap(child => child.modules)
222
- const moduleIdent = error.moduleId ?? error.moduleName
223
-
224
- const module = modules.find(
225
- module =>
226
- module?.id === moduleIdent || module?.name === moduleIdent,
227
- )
228
-
229
- if (!module) {
230
- return error
231
- }
232
-
233
- if (module.nameForCondition) {
234
- file = module.nameForCondition
235
- } else if (module.name) {
236
- file = this.app.path(`@src`, module.name)
237
- }
238
-
239
- if (!file) {
240
- return error
241
- }
242
-
243
- return {...error, file, name: module.name ?? error.name}
244
- }
245
-
246
- return errors?.map(parseError).filter(Boolean)
247
- } catch (error) {
248
- this.app.warn(`error parsing errors`, error)
249
- return []
250
- }
251
- }
252
- }
@@ -1,67 +0,0 @@
1
- import {Bud, factory} from '@repo/test-kit'
2
- import {beforeEach, describe, expect, it, vi} from 'vitest'
3
-
4
- import Compiler from './index.js'
5
-
6
- describe(`@roots/bud-compiler`, function () {
7
- let bud: Bud
8
- let compiler: Compiler
9
-
10
- beforeEach(async () => {
11
- vi.clearAllMocks()
12
-
13
- bud = await factory({mode: `development`})
14
- compiler = new Compiler(() => bud)
15
- })
16
-
17
- it(`has compile fn`, () => {
18
- expect(compiler.compile).toBeInstanceOf(Function)
19
- })
20
-
21
- it(`should call logger.log`, async () => {
22
- const logSpy = vi.spyOn(compiler.logger, `log`)
23
- await compiler.compile()
24
- expect(logSpy).toHaveBeenCalled()
25
- })
26
-
27
- it(`should have config with array length 1`, async () => {
28
- await compiler.compile()
29
- expect(compiler.config).toHaveLength(1)
30
- })
31
-
32
- it(`should have config with array length 2 when hasChildren is true`, async () => {
33
- // @ts-ignore
34
- await bud.make(`foo`)
35
- await bud.make(`bar`)
36
-
37
- compiler.app.children = {
38
- foo: compiler.app,
39
- bar: compiler.app,
40
- }
41
-
42
- await compiler.compile()
43
- expect(compiler.config).toHaveLength(2)
44
- })
45
-
46
- it(`should set done tap`, async () => {
47
- try {
48
- await compiler.compile()
49
- expect(compiler.instance.hooks.done.tap).toHaveBeenCalledWith(
50
- `MOCK-dev-handle`,
51
- compiler.onStats,
52
- )
53
- } catch (e) {}
54
- })
55
-
56
- it(`has onStats fn`, () => {
57
- expect(compiler.onStats).toBeInstanceOf(Function)
58
- })
59
-
60
- it(`has error handler`, () => {
61
- expect(compiler.onError).toBeInstanceOf(Function)
62
- })
63
-
64
- it(`has close handler`, () => {
65
- expect(compiler.onError).toBeInstanceOf(Function)
66
- })
67
- })
package/src/types.ts DELETED
@@ -1,3 +0,0 @@
1
- /**
2
- * @package @roots/bud-compiler
3
- */