@roots/bud-cache 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,84 @@
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-cache</strong></h1>
10
+
11
+ <p align="center">
12
+ Config caching
13
+ </p>
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ Install **@roots/bud-cache** to your project.
20
+
21
+ Yarn:
22
+
23
+ ```sh
24
+ yarn add @roots/bud-cache --dev
25
+ ```
26
+
27
+ npm:
28
+
29
+ ```sh
30
+ npm install @roots/bud-cache --save-dev
31
+ ```
32
+
33
+ ## Exports
34
+
35
+ | Signifier | Description |
36
+ | :-------------------------------------------- | :---------------------------------------------------- |
37
+ | `@roots/bud-cache` | The `bud.cache` service |
38
+ | `@roots/bud-cache/invalidate-cache-extension` | Extension which invalidates cache during build errors |
39
+
40
+ ## Contributing
41
+
42
+ Contributions are welcome from everyone.
43
+
44
+ We have [contribution guidelines](https://github.com/roots/guidelines/blob/master/CONTRIBUTING.md) to help you get started.
45
+
46
+ ## License
47
+
48
+ @roots/bud-cache is licensed under MIT.
49
+
50
+ ## Community
51
+
52
+ Keep track of development and community news.
53
+
54
+ - Join us on Roots Slack by becoming a [GitHub
55
+ sponsor](https://github.com/sponsors/roots)
56
+ - Participate on the [Roots Discourse](https://discourse.roots.io/)
57
+ - Follow [@rootswp on Twitter](https://twitter.com/rootswp)
58
+ - Read and subscribe to the [Roots Blog](https://roots.io/blog/)
59
+ - Subscribe to the [Roots Newsletter](https://roots.io/subscribe/)
60
+
61
+ ## Sponsors
62
+
63
+ **Bud** is an open source project and completely free to use.
64
+
65
+ 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).
66
+
67
+ <a href="https://k-m.com/">
68
+ <img src="https://cdn.roots.io/app/uploads/km-digital.svg" alt="KM Digital" width="200" height="150"/>
69
+ </a>
70
+ <a href="https://carrot.com/">
71
+ <img src="https://cdn.roots.io/app/uploads/carrot.svg" alt="Carrot" width="200" height="150"/>
72
+ </a>
73
+ <a href="https://wordpress.com/">
74
+ <img src="https://cdn.roots.io/app/uploads/wordpress.svg" alt="WordPress.com" width="200" height="150"/>
75
+ </a>
76
+ <a href="https://pantheon.io/">
77
+ <img src="https://cdn.roots.io/app/uploads/pantheon.svg" alt="Pantheon" width="200" height="150"/>
78
+ </a>
79
+ <a href="https://worksitesafety.ca/careers/">
80
+ <img src="https://cdn.roots.io/app/uploads/worksite-safety.svg" alt="Worksite Safety" width="200" height="150"/>
81
+ </a>
82
+ <a href="https://www.copiadigital.com/">
83
+ <img src="https://cdn.roots.io/app/uploads/copia-digital.svg" alt="Copia Digital" width="200" height="150"/>
84
+ </a>
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: Exports
3
+ ---
4
+
5
+ | Signifier | Description |
6
+ | :-------------------------------------------- | :---------------------------------------------------- |
7
+ | `@roots/bud-cache` | The `bud.cache` service |
8
+ | `@roots/bud-cache/invalidate-cache-extension` | Extension which invalidates cache during build errors |
package/lib/index.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Caching service
3
+ *
4
+ * @see {@link https://bud.js.org}
5
+ * @see {@link https://github.com/roots/bud}
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import './types.js';
10
+ import Cache from './service/index.js';
11
+ export default Cache;
12
+ //# 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,YAAY,CAAA;AAEnB,OAAO,KAAK,MAAM,oBAAoB,CAAA;AAEtC,eAAe,KAAK,CAAA"}
package/lib/index.js ADDED
@@ -0,0 +1,14 @@
1
+ // Copyright © Roots Software Foundation LLC
2
+ // Licensed under the MIT license.
3
+ /**
4
+ * Caching service
5
+ *
6
+ * @see {@link https://bud.js.org}
7
+ * @see {@link https://github.com/roots/bud}
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ import './types.js';
12
+ import Cache from './service/index.js';
13
+ export default Cache;
14
+ //# 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,YAAY,CAAA;AAEnB,OAAO,KAAK,MAAM,oBAAoB,CAAA;AAEtC,eAAe,KAAK,CAAA"}
@@ -0,0 +1,22 @@
1
+ import type { Bud } from '@roots/bud-framework';
2
+ import { Extension } from '@roots/bud-framework/extension';
3
+ /**
4
+ * Cache invalidation extension
5
+ *
6
+ * @remarks
7
+ * Certain webpack components such as `eslint-webpack-plugin` and
8
+ * `ts-loader` have issues with fs caching. This extension writes a file
9
+ * to the cache directory which is used to invalidate the cache before
10
+ * webpack is invoked on subsequent builds
11
+ */
12
+ export default class InvalidateCacheExtension extends Extension {
13
+ /**
14
+ * Invalidation file path
15
+ */
16
+ get invalidationFile(): string;
17
+ /**
18
+ * `register` callback
19
+ */
20
+ register(bud: Bud): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/invalidate-cache/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAC,SAAS,EAAC,MAAM,gCAAgC,CAAA;AAIxD;;;;;;;;GAQG;AAEH,MAAM,CAAC,OAAO,OAAO,wBAAyB,SAAQ,SAAS;IAC7D;;OAEG;IACH,IAAW,gBAAgB,IAAI,MAAM,CAEpC;IAED;;OAEG;IAEmB,QAAQ,CAAC,GAAG,EAAE,GAAG;CA0BxC"}
@@ -0,0 +1,59 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { join } from 'node:path';
3
+ import { Extension } from '@roots/bud-framework/extension';
4
+ import { bind, label } from '@roots/bud-framework/extension/decorators';
5
+ import stripAnsi from 'strip-ansi';
6
+ /**
7
+ * Cache invalidation extension
8
+ *
9
+ * @remarks
10
+ * Certain webpack components such as `eslint-webpack-plugin` and
11
+ * `ts-loader` have issues with fs caching. This extension writes a file
12
+ * to the cache directory which is used to invalidate the cache before
13
+ * webpack is invoked on subsequent builds
14
+ */
15
+ let InvalidateCacheExtension = class InvalidateCacheExtension extends Extension {
16
+ /**
17
+ * Invalidation file path
18
+ */
19
+ get invalidationFile() {
20
+ return join(this.app.cache.cacheDirectory, `error.json`);
21
+ }
22
+ /**
23
+ * `register` callback
24
+ */
25
+ async register(bud) {
26
+ const invalidate = await bud.fs?.exists(this.invalidationFile);
27
+ if (invalidate || (bud.isCLI() && bud.context.args.flush)) {
28
+ await bud.fs.remove(this.invalidationFile);
29
+ await bud.fs.remove(bud.cache.cacheDirectory);
30
+ }
31
+ bud.after(async () => {
32
+ bud.compiler.instance.hooks.done.tap(this.label, async (compiler) => {
33
+ try {
34
+ if (!compiler.hasErrors())
35
+ return;
36
+ await bud.fs.json.write(this.invalidationFile, {
37
+ hash: compiler.hash,
38
+ errors: compiler.stats.flatMap(stats => stats
39
+ .toString({ preset: `errors-warnings`, colors: false })
40
+ .split(/\n/)
41
+ .map(stripAnsi)),
42
+ });
43
+ }
44
+ catch (e) { }
45
+ });
46
+ });
47
+ }
48
+ };
49
+ __decorate([
50
+ bind,
51
+ __metadata("design:type", Function),
52
+ __metadata("design:paramtypes", [Function]),
53
+ __metadata("design:returntype", Promise)
54
+ ], InvalidateCacheExtension.prototype, "register", null);
55
+ InvalidateCacheExtension = __decorate([
56
+ label(`@roots/bud-cache/invalidate-cache`)
57
+ ], InvalidateCacheExtension);
58
+ export default InvalidateCacheExtension;
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/invalidate-cache/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAG9B,OAAO,EAAC,SAAS,EAAC,MAAM,gCAAgC,CAAA;AACxD,OAAO,EAAC,IAAI,EAAE,KAAK,EAAC,MAAM,2CAA2C,CAAA;AACrE,OAAO,SAAS,MAAM,YAAY,CAAA;AAElC;;;;;;;;GAQG;AAEY,IAAM,wBAAwB,GAA9B,MAAM,wBAAyB,SAAQ,SAAS;IAC7D;;OAEG;IACH,IAAW,gBAAgB;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,YAAY,CAAC,CAAA;IAC1D,CAAC;IAED;;OAEG;IAEmB,AAAN,KAAK,CAAC,QAAQ,CAAC,GAAQ;QACrC,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAE9D,IAAI,UAAU,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;YACzD,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;YAC1C,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;SAC9C;QAED,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE;YACnB,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAC,QAAQ,EAAC,EAAE;gBAChE,IAAI;oBACF,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE;wBAAE,OAAM;oBAEjC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,EAAE;wBAC7C,IAAI,EAAE,QAAQ,CAAC,IAAI;wBACnB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CACrC,KAAK;6BACF,QAAQ,CAAC,EAAC,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,KAAK,EAAC,CAAC;6BACpD,KAAK,CAAC,IAAI,CAAC;6BACX,GAAG,CAAC,SAAS,CAAC,CAClB;qBACF,CAAC,CAAA;iBACH;gBAAC,OAAO,CAAC,EAAE,GAAE;YAChB,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;CACF,CAAA;AA1BuB;IADrB,IAAI;;;;wDA0BJ;AArCkB,wBAAwB;IAD5C,KAAK,CAAC,mCAAmC,CAAC;GACtB,wBAAwB,CAsC5C;eAtCoB,wBAAwB"}
@@ -0,0 +1,46 @@
1
+ import type { Bud } from '@roots/bud-framework';
2
+ import { Service } from '@roots/bud-framework/service';
3
+ import type * as Services from '@roots/bud-framework/services';
4
+ import type { Configuration } from '@roots/bud-support/webpack';
5
+ /**
6
+ * Cache service class
7
+ */
8
+ export default class Cache extends Service implements Services.Cache.Service {
9
+ /**
10
+ * Enabled
11
+ */
12
+ enabled: boolean;
13
+ /**
14
+ * Type
15
+ */
16
+ get name(): string;
17
+ set name(name: string);
18
+ /**
19
+ * Type
20
+ */
21
+ get type(): 'memory' | 'filesystem';
22
+ set type(type: 'memory' | 'filesystem');
23
+ /**
24
+ * version
25
+ */
26
+ get version(): string;
27
+ set version(version: string);
28
+ /**
29
+ * Cache directory
30
+ */
31
+ get cacheDirectory(): string;
32
+ set cacheDirectory(directory: string);
33
+ /**
34
+ * Webpack configuration
35
+ */
36
+ get configuration(): Configuration[`cache`];
37
+ /**
38
+ * {@link Extension.booted}
39
+ */
40
+ booted?(bud: Bud): Promise<void>;
41
+ /**
42
+ * Flush cache
43
+ */
44
+ flush(): Promise<void>;
45
+ }
46
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAC,OAAO,EAAC,MAAM,8BAA8B,CAAA;AACpD,OAAO,KAAK,KAAK,QAAQ,MAAM,+BAA+B,CAAA;AAI9D,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAA;AAI7D;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,KACnB,SAAQ,OACR,YAAW,QAAQ,CAAC,KAAK,CAAC,OAAO;IAEjC;;OAEG;IACI,OAAO,EAAE,OAAO,CAAO;IAE9B;;OAEG;IACH,IAAW,IAAI,IAAI,MAAM,CAKxB;IACD,IAAW,IAAI,CAAC,IAAI,EAAE,MAAM,EAE3B;IAED;;OAEG;IACH,IAAW,IAAI,IAAI,QAAQ,GAAG,YAAY,CAOzC;IAED,IAAW,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,YAAY,EAE5C;IAED;;OAEG;IACH,IAAW,OAAO,IAAI,MAAM,CAc3B;IACD,IAAW,OAAO,CAAC,OAAO,EAAE,MAAM,EAEjC;IAED;;OAEG;IACH,IAAW,cAAc,IAAI,MAAM,CAKlC;IACD,IAAW,cAAc,CAAC,SAAS,EAAE,MAAM,EAE1C;IAED;;OAEG;IACH,IAAW,aAAa,IAAI,aAAa,CAAC,OAAO,CAAC,CAejD;IAED;;OAEG;IAEmB,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG;IAKtC;;OAEG;IAEU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGpC"}
@@ -0,0 +1,107 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { createHash } from 'node:crypto';
3
+ import { Service } from '@roots/bud-framework/service';
4
+ import { bind } from '@roots/bud-support/decorators';
5
+ import isString from '@roots/bud-support/lodash/isString';
6
+ import join from '@roots/bud-support/lodash/join';
7
+ import InvalidateCacheExtension from '../invalidate-cache/index.js';
8
+ /**
9
+ * Cache service class
10
+ */
11
+ export default class Cache extends Service {
12
+ constructor() {
13
+ super(...arguments);
14
+ /**
15
+ * Enabled
16
+ */
17
+ this.enabled = true;
18
+ }
19
+ /**
20
+ * Type
21
+ */
22
+ get name() {
23
+ return this.app.hooks.filter(`build.cache.name`, this.app.hooks.filter(`build.name`, this.app.context.label));
24
+ }
25
+ set name(name) {
26
+ this.app.hooks.on(`build.cache.name`, name);
27
+ }
28
+ /**
29
+ * Type
30
+ */
31
+ get type() {
32
+ return this.app.hooks.filter(`build.cache.type`, this.app.isCLI() && isString(this.app.context.args.cache)
33
+ ? this.app.context.args.cache
34
+ : `filesystem`);
35
+ }
36
+ set type(type) {
37
+ this.app.hooks.on(`build.cache.type`, type);
38
+ }
39
+ /**
40
+ * version
41
+ */
42
+ get version() {
43
+ const args = this.app.fs.json.stringify(this.app.isCLI() ? this.app.context.args : {});
44
+ const files = Object.values(this.app.context.config ?? {}).filter(file => file?.bud && file.sha1);
45
+ return this.app.hooks.filter(`build.cache.version`, createHash(`sha1`)
46
+ .update(join(args, ...files.map(({ module: { sha1 } }) => sha1)))
47
+ .digest(`base64`));
48
+ }
49
+ set version(version) {
50
+ this.app.hooks.on(`build.cache.version`, version);
51
+ }
52
+ /**
53
+ * Cache directory
54
+ */
55
+ get cacheDirectory() {
56
+ return this.app.hooks.filter(`build.cache.cacheDirectory`, this.app.path(`@storage`, this.app.label, `cache`, this.app.mode));
57
+ }
58
+ set cacheDirectory(directory) {
59
+ this.app.hooks.on(`build.cache.cacheDirectory`, directory);
60
+ }
61
+ /**
62
+ * Webpack configuration
63
+ */
64
+ get configuration() {
65
+ if (this.enabled !== true)
66
+ return false;
67
+ return this.type === `memory`
68
+ ? true
69
+ : {
70
+ name: this.name,
71
+ type: this.type,
72
+ store: `pack`,
73
+ allowCollectingMemory: true,
74
+ cacheDirectory: this.cacheDirectory,
75
+ idleTimeout: 10000,
76
+ idleTimeoutForInitialStore: 0,
77
+ profile: true,
78
+ version: this.version,
79
+ };
80
+ }
81
+ /**
82
+ * {@link Extension.booted}
83
+ */
84
+ async booted(bud) {
85
+ await bud.extensions.add(InvalidateCacheExtension);
86
+ this.app.success(`cache initialized`);
87
+ }
88
+ /**
89
+ * Flush cache
90
+ */
91
+ async flush() {
92
+ await this.app.fs.remove(this.cacheDirectory);
93
+ }
94
+ }
95
+ __decorate([
96
+ bind,
97
+ __metadata("design:type", Function),
98
+ __metadata("design:paramtypes", [Function]),
99
+ __metadata("design:returntype", Promise)
100
+ ], Cache.prototype, "booted", null);
101
+ __decorate([
102
+ bind,
103
+ __metadata("design:type", Function),
104
+ __metadata("design:paramtypes", []),
105
+ __metadata("design:returntype", Promise)
106
+ ], Cache.prototype, "flush", null);
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"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"}
package/lib/types.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type InvalidateCacheExtension from './invalidate-cache/index.js';
2
+ declare module '@roots/bud-framework' {
3
+ interface Modules {
4
+ '@roots/bud-cache/invalidate-cache': InvalidateCacheExtension;
5
+ }
6
+ }
7
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,wBAAwB,MAAM,6BAA6B,CAAA;AAEvE,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,OAAO;QACf,mCAAmC,EAAE,wBAAwB,CAAA;KAC9D;CACF"}
package/lib/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@roots/bud-cache",
3
+ "description": "Config caching",
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-cache"
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
+ "exports": {
49
+ ".": {
50
+ "types": "./lib/index.d.ts",
51
+ "import": "./lib/index.js"
52
+ },
53
+ "./service": {
54
+ "types": "./lib/service/index.js",
55
+ "import": "./lib/service.js"
56
+ },
57
+ "./invalidate-cache": {
58
+ "types": "./lib/invalidate-cache/index.d.ts",
59
+ "import": "./lib/invalidate-cache/index.js"
60
+ },
61
+ "./types": {
62
+ "types": "./lib/types.d.ts",
63
+ "import": "./lib/types.js"
64
+ }
65
+ },
66
+ "typesVersions": {
67
+ "*": {
68
+ ".": [
69
+ "./lib/index.d.ts"
70
+ ],
71
+ "./service": [
72
+ "./lib/service.d.ts"
73
+ ],
74
+ "./types": [
75
+ "./lib/types.d.ts"
76
+ ]
77
+ }
78
+ },
79
+ "module": "./lib/index.js",
80
+ "types": "./lib/index.d.ts",
81
+ "devDependencies": {
82
+ "@skypack/package-check": "0.2.2"
83
+ },
84
+ "dependencies": {
85
+ "@roots/bud-framework": "0.0.0",
86
+ "@roots/bud-support": "0.0.0",
87
+ "strip-ansi": "7.0.1"
88
+ },
89
+ "volta": {
90
+ "extends": "../../../package.json"
91
+ }
92
+ }
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ // Copyright © Roots Software Foundation LLC
2
+ // Licensed under the MIT license.
3
+
4
+ /**
5
+ * Caching service
6
+ *
7
+ * @see {@link https://bud.js.org}
8
+ * @see {@link https://github.com/roots/bud}
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+
13
+ import './types.js'
14
+
15
+ import Cache from './service/index.js'
16
+
17
+ export default Cache
@@ -0,0 +1,56 @@
1
+ import {join} from 'node:path'
2
+
3
+ import type {Bud} from '@roots/bud-framework'
4
+ import {Extension} from '@roots/bud-framework/extension'
5
+ import {bind, label} from '@roots/bud-framework/extension/decorators'
6
+ import stripAnsi from 'strip-ansi'
7
+
8
+ /**
9
+ * Cache invalidation extension
10
+ *
11
+ * @remarks
12
+ * Certain webpack components such as `eslint-webpack-plugin` and
13
+ * `ts-loader` have issues with fs caching. This extension writes a file
14
+ * to the cache directory which is used to invalidate the cache before
15
+ * webpack is invoked on subsequent builds
16
+ */
17
+ @label(`@roots/bud-cache/invalidate-cache`)
18
+ export default class InvalidateCacheExtension extends Extension {
19
+ /**
20
+ * Invalidation file path
21
+ */
22
+ public get invalidationFile(): string {
23
+ return join(this.app.cache.cacheDirectory, `error.json`)
24
+ }
25
+
26
+ /**
27
+ * `register` callback
28
+ */
29
+ @bind
30
+ public override async register(bud: Bud) {
31
+ const invalidate = await bud.fs?.exists(this.invalidationFile)
32
+
33
+ if (invalidate || (bud.isCLI() && bud.context.args.flush)) {
34
+ await bud.fs.remove(this.invalidationFile)
35
+ await bud.fs.remove(bud.cache.cacheDirectory)
36
+ }
37
+
38
+ bud.after(async () => {
39
+ bud.compiler.instance.hooks.done.tap(this.label, async compiler => {
40
+ try {
41
+ if (!compiler.hasErrors()) return
42
+
43
+ await bud.fs.json.write(this.invalidationFile, {
44
+ hash: compiler.hash,
45
+ errors: compiler.stats.flatMap(stats =>
46
+ stats
47
+ .toString({preset: `errors-warnings`, colors: false})
48
+ .split(/\n/)
49
+ .map(stripAnsi),
50
+ ),
51
+ })
52
+ } catch (e) {}
53
+ })
54
+ })
55
+ }
56
+ }
@@ -0,0 +1,125 @@
1
+ import {createHash} from 'node:crypto'
2
+
3
+ import type {Bud} from '@roots/bud-framework'
4
+ import {Service} from '@roots/bud-framework/service'
5
+ import type * as Services from '@roots/bud-framework/services'
6
+ import {bind} from '@roots/bud-support/decorators'
7
+ import isString from '@roots/bud-support/lodash/isString'
8
+ import join from '@roots/bud-support/lodash/join'
9
+ import type {Configuration} from '@roots/bud-support/webpack'
10
+
11
+ import InvalidateCacheExtension from '../invalidate-cache/index.js'
12
+
13
+ /**
14
+ * Cache service class
15
+ */
16
+ export default class Cache
17
+ extends Service
18
+ implements Services.Cache.Service
19
+ {
20
+ /**
21
+ * Enabled
22
+ */
23
+ public enabled: boolean = true
24
+
25
+ /**
26
+ * Type
27
+ */
28
+ public get name(): string {
29
+ return this.app.hooks.filter(
30
+ `build.cache.name`,
31
+ this.app.hooks.filter(`build.name`, this.app.context.label),
32
+ )
33
+ }
34
+ public set name(name: string) {
35
+ this.app.hooks.on(`build.cache.name`, name)
36
+ }
37
+
38
+ /**
39
+ * Type
40
+ */
41
+ public get type(): 'memory' | 'filesystem' {
42
+ return this.app.hooks.filter(
43
+ `build.cache.type`,
44
+ this.app.isCLI() && isString(this.app.context.args.cache)
45
+ ? this.app.context.args.cache
46
+ : `filesystem`,
47
+ )
48
+ }
49
+
50
+ public set type(type: 'memory' | 'filesystem') {
51
+ this.app.hooks.on(`build.cache.type`, type)
52
+ }
53
+
54
+ /**
55
+ * version
56
+ */
57
+ public get version(): string {
58
+ const args = this.app.fs.json.stringify(
59
+ this.app.isCLI() ? this.app.context.args : {},
60
+ )
61
+ const files = Object.values(this.app.context.config ?? {}).filter(
62
+ file => file?.bud && file.sha1,
63
+ )
64
+
65
+ return this.app.hooks.filter(
66
+ `build.cache.version`,
67
+ createHash(`sha1`)
68
+ .update(join(args, ...files.map(({module: {sha1}}) => sha1)))
69
+ .digest(`base64`),
70
+ )
71
+ }
72
+ public set version(version: string) {
73
+ this.app.hooks.on(`build.cache.version`, version)
74
+ }
75
+
76
+ /**
77
+ * Cache directory
78
+ */
79
+ public get cacheDirectory(): string {
80
+ return this.app.hooks.filter(
81
+ `build.cache.cacheDirectory`,
82
+ this.app.path(`@storage`, this.app.label, `cache`, this.app.mode),
83
+ )
84
+ }
85
+ public set cacheDirectory(directory: string) {
86
+ this.app.hooks.on(`build.cache.cacheDirectory`, directory)
87
+ }
88
+
89
+ /**
90
+ * Webpack configuration
91
+ */
92
+ public get configuration(): Configuration[`cache`] {
93
+ if (this.enabled !== true) return false
94
+ return this.type === `memory`
95
+ ? true
96
+ : {
97
+ name: this.name,
98
+ type: this.type,
99
+ store: `pack` as `pack`,
100
+ allowCollectingMemory: true,
101
+ cacheDirectory: this.cacheDirectory,
102
+ idleTimeout: 10000,
103
+ idleTimeoutForInitialStore: 0,
104
+ profile: true,
105
+ version: this.version,
106
+ }
107
+ }
108
+
109
+ /**
110
+ * {@link Extension.booted}
111
+ */
112
+ @bind
113
+ public override async booted?(bud: Bud) {
114
+ await bud.extensions.add(InvalidateCacheExtension)
115
+ this.app.success(`cache initialized`)
116
+ }
117
+
118
+ /**
119
+ * Flush cache
120
+ */
121
+ @bind
122
+ public async flush(): Promise<void> {
123
+ await this.app.fs.remove(this.cacheDirectory)
124
+ }
125
+ }
package/src/types.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type InvalidateCacheExtension from './invalidate-cache/index.js'
2
+
3
+ declare module '@roots/bud-framework' {
4
+ interface Modules {
5
+ '@roots/bud-cache/invalidate-cache': InvalidateCacheExtension
6
+ }
7
+ }