@roots/bud-compiler 0.0.0

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/LICENSE.md ADDED
@@ -0,0 +1,19 @@
1
+ Copyright © Roots Software Foundation LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ <p align="center"><img src="https://cdn.roots.io/app/uploads/logo-bud.svg" height="100" alt="bud.js" /></p>
2
+
3
+ <p align="center">
4
+ <img alt="MIT License" src="https://img.shields.io/github/license/roots/bud?color=%23525ddc&style=flat-square" />
5
+ <img alt="npm" src="https://img.shields.io/npm/v/@roots/bud.svg?color=%23525ddc&style=flat-square" />
6
+ <img alt="Follow Roots" src="https://img.shields.io/twitter/follow/rootswp.svg?color=%23525ddc&style=flat-square" />
7
+ </p>
8
+
9
+ <h1 align="center"><strong>@roots/bud-compiler</strong></h1>
10
+
11
+ <p align="center">
12
+ Compilation handler
13
+ </p>
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ Install **@roots/bud-compiler** to your project.
20
+
21
+ Yarn:
22
+
23
+ ```sh
24
+ yarn add @roots/bud-compiler --dev
25
+ ```
26
+
27
+ npm:
28
+
29
+ ```sh
30
+ npm install @roots/bud-compiler --save-dev
31
+ ```
32
+
33
+ ## Contributing
34
+
35
+ Contributions are welcome from everyone.
36
+
37
+ We have [contribution guidelines](https://github.com/roots/guidelines/blob/master/CONTRIBUTING.md) to help you get started.
38
+
39
+ ## License
40
+
41
+ @roots/bud-compiler is licensed under MIT.
42
+
43
+ ## Community
44
+
45
+ Keep track of development and community news.
46
+
47
+ - Join us on Roots Slack by becoming a [GitHub
48
+ sponsor](https://github.com/sponsors/roots)
49
+ - Participate on the [Roots Discourse](https://discourse.roots.io/)
50
+ - Follow [@rootswp on Twitter](https://twitter.com/rootswp)
51
+ - Read and subscribe to the [Roots Blog](https://roots.io/blog/)
52
+ - Subscribe to the [Roots Newsletter](https://roots.io/subscribe/)
53
+
54
+ ## Sponsors
55
+
56
+ **Bud** is an open source project and completely free to use.
57
+
58
+ However, the amount of effort needed to maintain and develop new features and projects within the Roots ecosystem is not sustainable without proper financial backing. If you have the capability, please consider [sponsoring Roots](https://github.com/sponsors/roots).
59
+
60
+ <a href="https://k-m.com/">
61
+ <img src="https://cdn.roots.io/app/uploads/km-digital.svg" alt="KM Digital" width="200" height="150"/>
62
+ </a>
63
+ <a href="https://carrot.com/">
64
+ <img src="https://cdn.roots.io/app/uploads/carrot.svg" alt="Carrot" width="200" height="150"/>
65
+ </a>
66
+ <a href="https://wordpress.com/">
67
+ <img src="https://cdn.roots.io/app/uploads/wordpress.svg" alt="WordPress.com" width="200" height="150"/>
68
+ </a>
69
+ <a href="https://pantheon.io/">
70
+ <img src="https://cdn.roots.io/app/uploads/pantheon.svg" alt="Pantheon" width="200" height="150"/>
71
+ </a>
72
+ <a href="https://worksitesafety.ca/careers/">
73
+ <img src="https://cdn.roots.io/app/uploads/worksite-safety.svg" alt="Worksite Safety" width="200" height="150"/>
74
+ </a>
75
+ <a href="https://www.copiadigital.com/">
76
+ <img src="https://cdn.roots.io/app/uploads/copia-digital.svg" alt="Copia Digital" width="200" height="150"/>
77
+ </a>
@@ -0,0 +1,43 @@
1
+ import { Service } from '@roots/bud-framework/service';
2
+ import type { Compiler as Contract } from '@roots/bud-framework/services';
3
+ import type { ErrorWithSourceFile } from '@roots/bud-support/open';
4
+ import type webpack from '@roots/bud-support/webpack';
5
+ import type { MultiCompiler, MultiStats, StatsError } from '@roots/bud-support/webpack';
6
+ /**
7
+ * Wepback compilation controller class
8
+ */
9
+ export declare class Compiler extends Service implements Contract.Service {
10
+ /**
11
+ * Compiler implementation
12
+ */
13
+ implementation: typeof webpack;
14
+ /**
15
+ * Compiler instance
16
+ */
17
+ instance: Contract.Service[`instance`];
18
+ /**
19
+ * Compilation stats
20
+ */
21
+ stats: Contract.Service[`stats`];
22
+ /**
23
+ * Configuration
24
+ */
25
+ config: Contract.Service[`config`];
26
+ /**
27
+ * Initiates compilation
28
+ */
29
+ compile(): Promise<MultiCompiler>;
30
+ /**
31
+ * Stats handler
32
+ */
33
+ onStats(stats: MultiStats): Promise<void>;
34
+ /**
35
+ * Compiler error event
36
+ */
37
+ onError(error: Error): Promise<void>;
38
+ /**
39
+ * Parse errors from webpack stats
40
+ */
41
+ sourceErrors(errors: Array<StatsError>): Array<ErrorWithSourceFile | StatsError>;
42
+ }
43
+ //# sourceMappingURL=compiler.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compiler.service.d.ts","sourceRoot":"","sources":["../src/compiler.service.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAC,OAAO,EAAC,MAAM,8BAA8B,CAAA;AACpD,OAAO,KAAK,EAAC,QAAQ,IAAI,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AAGvE,OAAO,KAAK,EACV,mBAAmB,EAEpB,MAAM,yBAAyB,CAAA;AAGhC,OAAO,KAAK,OAAO,MAAM,4BAA4B,CAAA;AACrD,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EAEV,UAAU,EACX,MAAM,4BAA4B,CAAA;AAEnC;;GAEG;AACH,qBAAa,QAAS,SAAQ,OAAQ,YAAW,QAAQ,CAAC,OAAO;IAC/D;;OAEG;IACI,cAAc,EAAE,OAAO,OAAO,CAAA;IAErC;;OAEG;IACI,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAE7C;;OAEG;IACI,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAEvC;;OAEG;IACI,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAK;IAE9C;;OAEG;IAEU,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;IAqC9C;;OAEG;IAEU,OAAO,CAAC,KAAK,EAAE,UAAU;IAwDtC;;OAEG;IAEU,OAAO,CAAC,KAAK,EAAE,KAAK;IAuBjC;;OAEG;IAEI,YAAY,CACjB,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,GACxB,KAAK,CAAC,mBAAmB,GAAG,UAAU,CAAC;CAwC3C"}
@@ -0,0 +1,172 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { pathToFileURL } from 'node:url';
3
+ import * as App from '@roots/bud-dashboard/app';
4
+ import { Service } from '@roots/bud-framework/service';
5
+ import { bind } from '@roots/bud-support/decorators';
6
+ import { duration } from '@roots/bud-support/human-readable';
7
+ import React from '@roots/bud-support/react';
8
+ import stripAnsi from '@roots/bud-support/strip-ansi';
9
+ /**
10
+ * Wepback compilation controller class
11
+ */
12
+ export class Compiler extends Service {
13
+ constructor() {
14
+ super(...arguments);
15
+ /**
16
+ * Configuration
17
+ */
18
+ this.config = [];
19
+ }
20
+ /**
21
+ * Initiates compilation
22
+ */
23
+ async compile() {
24
+ this.implementation = await this.app.module.import(`webpack`);
25
+ this.logger.log(`imported webpack`, this.implementation.version);
26
+ this.config = !this.app.hasChildren
27
+ ? [await this.app.build.make()]
28
+ : await Promise.all(Object.values(this.app.children).map(async (child) => {
29
+ try {
30
+ return await child.build.make();
31
+ }
32
+ catch (error) {
33
+ throw error;
34
+ }
35
+ }));
36
+ await this.app.hooks.fire(`compiler.before`, this.app);
37
+ if (this.app.isCLI() && this.app.context.args.dry) {
38
+ this.app.context.logger.timeEnd(`initialize`);
39
+ this.logger.log(`running in dry mode. exiting early.`);
40
+ return;
41
+ }
42
+ this.app.context.logger.timeEnd(`initialize`);
43
+ this.instance = this.implementation(this.config);
44
+ this.instance.hooks.done.tap(this.app.label, async (stats) => {
45
+ await this.onStats(stats);
46
+ await this.app.hooks.fire(`compiler.close`, this.app);
47
+ });
48
+ await this.app.hooks.fire(`compiler.after`, this.app);
49
+ return this.instance;
50
+ }
51
+ /**
52
+ * Stats handler
53
+ */
54
+ async onStats(stats) {
55
+ const makeNoticeTitle = (child) => this.app.label !== child.name
56
+ ? `${this.app.label} (${child.name})`
57
+ : child.name;
58
+ this.stats = stats.toJson(this.app.hooks.filter(`build.stats`));
59
+ await this.app.hooks.fire(`compiler.stats`, stats);
60
+ const statsUpdate = this.app.dashboard.update(stats);
61
+ if (stats.hasErrors()) {
62
+ process.exitCode = 1;
63
+ this.stats.children = this.stats.children?.map(child => ({
64
+ ...child,
65
+ errors: this.sourceErrors(child.errors),
66
+ }));
67
+ this.stats.children
68
+ ?.filter(child => child.errorsCount > 0)
69
+ .forEach(child => {
70
+ const error = child.errors?.shift();
71
+ if (!error)
72
+ return;
73
+ this.app.notifier.notify({
74
+ title: makeNoticeTitle(child),
75
+ subtitle: error.file ? `Error in ${error.name}` : error.name,
76
+ message: stripAnsi(error.message),
77
+ open: error.file ? pathToFileURL(error.file) : ``,
78
+ group: `${this.app.label}-${child.name}`,
79
+ });
80
+ this.app.notifier.openEditor(error.file);
81
+ });
82
+ }
83
+ this.stats.children
84
+ ?.filter(child => child.errorsCount === 0)
85
+ .forEach(child => {
86
+ this.app.notifier.notify({
87
+ title: makeNoticeTitle(child),
88
+ subtitle: `Build successful`,
89
+ message: child.modules
90
+ ? `${child.modules.length} modules compiled in ${duration(child.time)}`
91
+ : `Compiled in ${duration(child.time)}`,
92
+ group: `${this.app.label}-${child.name}`,
93
+ open: this.app.server?.publicUrl.href,
94
+ });
95
+ this.app.notifier.openBrowser(this.app.server?.publicUrl.href);
96
+ });
97
+ await statsUpdate;
98
+ }
99
+ /**
100
+ * Compiler error event
101
+ */
102
+ async onError(error) {
103
+ process.exitCode = 1;
104
+ await this.app.hooks.fire(`compiler.error`, error);
105
+ this.app.isDevelopment &&
106
+ this.app.server.appliedMiddleware?.hot?.publish({ error });
107
+ this.app.notifier.notify({
108
+ subtitle: error.name,
109
+ message: error.message,
110
+ group: this.app.label,
111
+ });
112
+ await this.app.dashboard.renderer.once(React.createElement(App.Error, { name: "Compiler error", message: error.message, stack: error.stack }));
113
+ }
114
+ /**
115
+ * Parse errors from webpack stats
116
+ */
117
+ sourceErrors(errors) {
118
+ if (!errors || !errors.length)
119
+ return [];
120
+ try {
121
+ const parseError = (error) => {
122
+ let file;
123
+ const modules = this.stats.children.flatMap(child => child.modules);
124
+ const moduleIdent = error.moduleId ?? error.moduleName;
125
+ const module = modules.find(module => module?.id === moduleIdent || module?.name === moduleIdent);
126
+ if (!module) {
127
+ return error;
128
+ }
129
+ if (module.nameForCondition) {
130
+ file = module.nameForCondition;
131
+ }
132
+ else if (module.name) {
133
+ file = this.app.path(`@src`, module.name);
134
+ }
135
+ if (!file) {
136
+ return error;
137
+ }
138
+ return { ...error, name: module.name ?? error.name, file };
139
+ };
140
+ return errors?.map(parseError).filter(Boolean);
141
+ }
142
+ catch (error) {
143
+ this.app.warn(`error parsing errors`, error);
144
+ return [];
145
+ }
146
+ }
147
+ }
148
+ __decorate([
149
+ bind,
150
+ __metadata("design:type", Function),
151
+ __metadata("design:paramtypes", []),
152
+ __metadata("design:returntype", Promise)
153
+ ], Compiler.prototype, "compile", null);
154
+ __decorate([
155
+ bind,
156
+ __metadata("design:type", Function),
157
+ __metadata("design:paramtypes", [Function]),
158
+ __metadata("design:returntype", Promise)
159
+ ], Compiler.prototype, "onStats", null);
160
+ __decorate([
161
+ bind,
162
+ __metadata("design:type", Function),
163
+ __metadata("design:paramtypes", [Error]),
164
+ __metadata("design:returntype", Promise)
165
+ ], Compiler.prototype, "onError", null);
166
+ __decorate([
167
+ bind,
168
+ __metadata("design:type", Function),
169
+ __metadata("design:paramtypes", [Array]),
170
+ __metadata("design:returntype", Array)
171
+ ], Compiler.prototype, "sourceErrors", null);
172
+ //# sourceMappingURL=compiler.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compiler.service.js","sourceRoot":"","sources":["../src/compiler.service.tsx"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The bud compiler interface
3
+ *
4
+ * @see https://bud.js.org
5
+ * @see https://github.com/roots/bud
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import { Compiler } from './compiler.service.js';
10
+ export default Compiler;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAE9C,eAAe,QAAQ,CAAA"}
package/lib/index.js ADDED
@@ -0,0 +1,13 @@
1
+ // Copyright © Roots Software Foundation LLC
2
+ // Licensed under the MIT license.
3
+ /**
4
+ * The bud compiler interface
5
+ *
6
+ * @see https://bud.js.org
7
+ * @see https://github.com/roots/bud
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ import { Compiler } from './compiler.service.js';
12
+ export default Compiler;
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,kCAAkC;AAElC;;;;;;;GAOG;AAEH,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAE9C,eAAe,QAAQ,CAAA"}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@roots/bud-compiler",
3
+ "description": "Compilation handler",
4
+ "version": "0.0.0",
5
+ "homepage": "https://roots.io/bud",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/roots/bud.git",
9
+ "directory": "sources/@roots/bud-compiler"
10
+ },
11
+ "contributors": [
12
+ {
13
+ "name": "Kelly Mears",
14
+ "email": "developers@tinypixel.dev",
15
+ "url": "https://github.com/kellymears"
16
+ },
17
+ {
18
+ "name": "Ben Word",
19
+ "email": "ben@benword.com",
20
+ "url": "https://github.com/retlehs"
21
+ },
22
+ {
23
+ "name": "QWp6t",
24
+ "url": "https://github.com/QWp6t"
25
+ }
26
+ ],
27
+ "license": "MIT",
28
+ "bugs": {
29
+ "url": "https://github.com/roots/bud/issues"
30
+ },
31
+ "funding": {
32
+ "type": "github sponsors",
33
+ "url": "https://github.com/sponsors/roots"
34
+ },
35
+ "keywords": [
36
+ "bud",
37
+ "bud-framework"
38
+ ],
39
+ "engines": {
40
+ "node": ">=16"
41
+ },
42
+ "files": [
43
+ "docs",
44
+ "lib",
45
+ "src"
46
+ ],
47
+ "type": "module",
48
+ "module": "./lib/index.js",
49
+ "types": "./lib/index.d.ts",
50
+ "exports": {
51
+ ".": "./lib/index.js"
52
+ },
53
+ "typesVersions": {
54
+ "*": {
55
+ ".": [
56
+ "./lib/index.d.ts"
57
+ ]
58
+ }
59
+ },
60
+ "devDependencies": {
61
+ "@roots/bud-api": "0.0.0",
62
+ "@skypack/package-check": "0.2.2",
63
+ "@types/node": "18.11.18"
64
+ },
65
+ "dependencies": {
66
+ "@roots/bud-dashboard": "0.0.0",
67
+ "@roots/bud-framework": "0.0.0",
68
+ "@roots/bud-support": "0.0.0"
69
+ },
70
+ "volta": {
71
+ "extends": "../../../package.json"
72
+ }
73
+ }
@@ -0,0 +1,221 @@
1
+ import {pathToFileURL} from 'node:url'
2
+
3
+ import * as App from '@roots/bud-dashboard/app'
4
+ import type {Bud} from '@roots/bud-framework/bud'
5
+ import {Service} from '@roots/bud-framework/service'
6
+ import type {Compiler as Contract} from '@roots/bud-framework/services'
7
+ import {bind} from '@roots/bud-support/decorators'
8
+ import {duration} from '@roots/bud-support/human-readable'
9
+ import type {
10
+ ErrorWithSourceFile,
11
+ SourceFile,
12
+ } from '@roots/bud-support/open'
13
+ import React from '@roots/bud-support/react'
14
+ import stripAnsi from '@roots/bud-support/strip-ansi'
15
+ import type webpack from '@roots/bud-support/webpack'
16
+ import type {
17
+ MultiCompiler,
18
+ MultiStats,
19
+ StatsCompilation,
20
+ StatsError,
21
+ } from '@roots/bud-support/webpack'
22
+
23
+ /**
24
+ * Wepback compilation controller class
25
+ */
26
+ export class Compiler extends Service implements Contract.Service {
27
+ /**
28
+ * Compiler implementation
29
+ */
30
+ public implementation: typeof webpack
31
+
32
+ /**
33
+ * Compiler instance
34
+ */
35
+ public instance: Contract.Service[`instance`]
36
+
37
+ /**
38
+ * Compilation stats
39
+ */
40
+ public stats: Contract.Service[`stats`]
41
+
42
+ /**
43
+ * Configuration
44
+ */
45
+ public config: Contract.Service[`config`] = []
46
+
47
+ /**
48
+ * Initiates compilation
49
+ */
50
+ @bind
51
+ public async compile(): Promise<MultiCompiler> {
52
+ this.implementation = await this.app.module.import(`webpack`)
53
+ this.logger.log(`imported webpack`, this.implementation.version)
54
+
55
+ this.config = !this.app.hasChildren
56
+ ? [await this.app.build.make()]
57
+ : await Promise.all(
58
+ Object.values(this.app.children).map(async (child: Bud) => {
59
+ try {
60
+ return await child.build.make()
61
+ } catch (error) {
62
+ throw error
63
+ }
64
+ }),
65
+ )
66
+
67
+ await this.app.hooks.fire(`compiler.before`, this.app)
68
+
69
+ if (this.app.isCLI() && this.app.context.args.dry) {
70
+ this.app.context.logger.timeEnd(`initialize`)
71
+ this.logger.log(`running in dry mode. exiting early.`)
72
+ return
73
+ }
74
+
75
+ this.app.context.logger.timeEnd(`initialize`)
76
+
77
+ this.instance = this.implementation(this.config)
78
+
79
+ this.instance.hooks.done.tap(this.app.label, async (stats: any) => {
80
+ await this.onStats(stats)
81
+ await this.app.hooks.fire(`compiler.close`, this.app)
82
+ })
83
+
84
+ await this.app.hooks.fire(`compiler.after`, this.app)
85
+ return this.instance
86
+ }
87
+
88
+ /**
89
+ * Stats handler
90
+ */
91
+ @bind
92
+ public async onStats(stats: MultiStats) {
93
+ const makeNoticeTitle = (child: StatsCompilation) =>
94
+ this.app.label !== child.name
95
+ ? `${this.app.label} (${child.name})`
96
+ : child.name
97
+
98
+ this.stats = stats.toJson(this.app.hooks.filter(`build.stats`))
99
+
100
+ await this.app.hooks.fire(`compiler.stats`, stats)
101
+
102
+ const statsUpdate = this.app.dashboard.update(stats)
103
+
104
+ if (stats.hasErrors()) {
105
+ process.exitCode = 1
106
+
107
+ this.stats.children = this.stats.children?.map(child => ({
108
+ ...child,
109
+ errors: this.sourceErrors(child.errors),
110
+ }))
111
+
112
+ this.stats.children
113
+ ?.filter(child => child.errorsCount > 0)
114
+ .forEach(child => {
115
+ const error = child.errors?.shift()
116
+ if (!error) return
117
+ this.app.notifier.notify({
118
+ title: makeNoticeTitle(child),
119
+ subtitle: error.file ? `Error in ${error.name}` : error.name,
120
+ message: stripAnsi(error.message),
121
+ open: error.file ? pathToFileURL(error.file) : ``,
122
+ group: `${this.app.label}-${child.name}`,
123
+ })
124
+ this.app.notifier.openEditor(error.file)
125
+ })
126
+ }
127
+
128
+ this.stats.children
129
+ ?.filter(child => child.errorsCount === 0)
130
+ .forEach(child => {
131
+ this.app.notifier.notify({
132
+ title: makeNoticeTitle(child),
133
+ subtitle: `Build successful`,
134
+ message: child.modules
135
+ ? `${child.modules.length} modules compiled in ${duration(
136
+ child.time,
137
+ )}`
138
+ : `Compiled in ${duration(child.time)}`,
139
+ group: `${this.app.label}-${child.name}`,
140
+ open: this.app.server?.publicUrl.href,
141
+ })
142
+ this.app.notifier.openBrowser(this.app.server?.publicUrl.href)
143
+ })
144
+
145
+ await statsUpdate
146
+ }
147
+
148
+ /**
149
+ * Compiler error event
150
+ */
151
+ @bind
152
+ public async onError(error: Error) {
153
+ process.exitCode = 1
154
+
155
+ await this.app.hooks.fire(`compiler.error`, error)
156
+
157
+ this.app.isDevelopment &&
158
+ this.app.server.appliedMiddleware?.hot?.publish({error})
159
+
160
+ this.app.notifier.notify({
161
+ subtitle: error.name,
162
+ message: error.message,
163
+ group: this.app.label,
164
+ })
165
+
166
+ await this.app.dashboard.renderer.once(
167
+ <App.Error
168
+ name="Compiler error"
169
+ message={error.message}
170
+ stack={error.stack}
171
+ />,
172
+ )
173
+ }
174
+
175
+ /**
176
+ * Parse errors from webpack stats
177
+ */
178
+ @bind
179
+ public sourceErrors(
180
+ errors: Array<StatsError>,
181
+ ): Array<ErrorWithSourceFile | StatsError> {
182
+ if (!errors || !errors.length) return []
183
+
184
+ try {
185
+ const parseError = (
186
+ error: StatsError,
187
+ ): ErrorWithSourceFile | StatsError => {
188
+ let file: SourceFile[`file`] | undefined
189
+
190
+ const modules = this.stats.children.flatMap(child => child.modules)
191
+ const moduleIdent = error.moduleId ?? error.moduleName
192
+
193
+ const module = modules.find(
194
+ module =>
195
+ module?.id === moduleIdent || module?.name === moduleIdent,
196
+ )
197
+
198
+ if (!module) {
199
+ return error
200
+ }
201
+
202
+ if (module.nameForCondition) {
203
+ file = module.nameForCondition
204
+ } else if (module.name) {
205
+ file = this.app.path(`@src`, module.name)
206
+ }
207
+
208
+ if (!file) {
209
+ return error
210
+ }
211
+
212
+ return {...error, name: module.name ?? error.name, file}
213
+ }
214
+
215
+ return errors?.map(parseError).filter(Boolean)
216
+ } catch (error) {
217
+ this.app.warn(`error parsing errors`, error)
218
+ return []
219
+ }
220
+ }
221
+ }
@@ -0,0 +1,75 @@
1
+ import {Bud, factory} from '@repo/test-kit/bud'
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 log early exit (--dry)`, async () => {
47
+ // @ts-ignore
48
+ bud.context.args.dry = true
49
+ const logSpy = vi.spyOn(compiler.logger, `log`)
50
+ await compiler.compile()
51
+ expect(logSpy).toHaveBeenCalledTimes(2)
52
+ })
53
+
54
+ it(`should set done tap`, async () => {
55
+ try {
56
+ await compiler.compile()
57
+ expect(compiler.instance.hooks.done.tap).toHaveBeenCalledWith(
58
+ `MOCK-dev-handle`,
59
+ compiler.onStats,
60
+ )
61
+ } catch (e) {}
62
+ })
63
+
64
+ it(`has onStats fn`, () => {
65
+ expect(compiler.onStats).toBeInstanceOf(Function)
66
+ })
67
+
68
+ it(`has error handler`, () => {
69
+ expect(compiler.onError).toBeInstanceOf(Function)
70
+ })
71
+
72
+ it(`has close handler`, () => {
73
+ expect(compiler.onError).toBeInstanceOf(Function)
74
+ })
75
+ })
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ // Copyright © Roots Software Foundation LLC
2
+ // Licensed under the MIT license.
3
+
4
+ /**
5
+ * The bud compiler interface
6
+ *
7
+ * @see https://bud.js.org
8
+ * @see https://github.com/roots/bud
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+
13
+ import {Compiler} from './compiler.service.js'
14
+
15
+ export default Compiler