1 | /*
|
---|
2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
3 | Author Tobias Koppers @sokra
|
---|
4 | */
|
---|
5 |
|
---|
6 | "use strict";
|
---|
7 |
|
---|
8 | const { AsyncParallelHook, AsyncSeriesBailHook, SyncHook } = require("tapable");
|
---|
9 | const {
|
---|
10 | makeWebpackError,
|
---|
11 | makeWebpackErrorCallback
|
---|
12 | } = require("./HookWebpackError");
|
---|
13 |
|
---|
14 | /** @typedef {import("./WebpackError")} WebpackError */
|
---|
15 |
|
---|
16 | /**
|
---|
17 | * @typedef {object} Etag
|
---|
18 | * @property {function(): string} toString
|
---|
19 | */
|
---|
20 |
|
---|
21 | /**
|
---|
22 | * @template T
|
---|
23 | * @callback CallbackCache
|
---|
24 | * @param {WebpackError | null} err
|
---|
25 | * @param {T=} result
|
---|
26 | * @returns {void}
|
---|
27 | */
|
---|
28 |
|
---|
29 | /**
|
---|
30 | * @callback GotHandler
|
---|
31 | * @param {any} result
|
---|
32 | * @param {function(Error=): void} callback
|
---|
33 | * @returns {void}
|
---|
34 | */
|
---|
35 |
|
---|
36 | /**
|
---|
37 | * @param {number} times times
|
---|
38 | * @param {function(Error=): void} callback callback
|
---|
39 | * @returns {function(Error=): void} callback
|
---|
40 | */
|
---|
41 | const needCalls = (times, callback) => err => {
|
---|
42 | if (--times === 0) {
|
---|
43 | return callback(err);
|
---|
44 | }
|
---|
45 | if (err && times > 0) {
|
---|
46 | times = 0;
|
---|
47 | return callback(err);
|
---|
48 | }
|
---|
49 | };
|
---|
50 |
|
---|
51 | class Cache {
|
---|
52 | constructor() {
|
---|
53 | this.hooks = {
|
---|
54 | /** @type {AsyncSeriesBailHook<[string, Etag | null, GotHandler[]], any>} */
|
---|
55 | get: new AsyncSeriesBailHook(["identifier", "etag", "gotHandlers"]),
|
---|
56 | /** @type {AsyncParallelHook<[string, Etag | null, any]>} */
|
---|
57 | store: new AsyncParallelHook(["identifier", "etag", "data"]),
|
---|
58 | /** @type {AsyncParallelHook<[Iterable<string>]>} */
|
---|
59 | storeBuildDependencies: new AsyncParallelHook(["dependencies"]),
|
---|
60 | /** @type {SyncHook<[]>} */
|
---|
61 | beginIdle: new SyncHook([]),
|
---|
62 | /** @type {AsyncParallelHook<[]>} */
|
---|
63 | endIdle: new AsyncParallelHook([]),
|
---|
64 | /** @type {AsyncParallelHook<[]>} */
|
---|
65 | shutdown: new AsyncParallelHook([])
|
---|
66 | };
|
---|
67 | }
|
---|
68 |
|
---|
69 | /**
|
---|
70 | * @template T
|
---|
71 | * @param {string} identifier the cache identifier
|
---|
72 | * @param {Etag | null} etag the etag
|
---|
73 | * @param {CallbackCache<T>} callback signals when the value is retrieved
|
---|
74 | * @returns {void}
|
---|
75 | */
|
---|
76 | get(identifier, etag, callback) {
|
---|
77 | /** @type {GotHandler[]} */
|
---|
78 | const gotHandlers = [];
|
---|
79 | this.hooks.get.callAsync(identifier, etag, gotHandlers, (err, result) => {
|
---|
80 | if (err) {
|
---|
81 | callback(makeWebpackError(err, "Cache.hooks.get"));
|
---|
82 | return;
|
---|
83 | }
|
---|
84 | if (result === null) {
|
---|
85 | result = undefined;
|
---|
86 | }
|
---|
87 | if (gotHandlers.length > 1) {
|
---|
88 | const innerCallback = needCalls(gotHandlers.length, () =>
|
---|
89 | callback(null, result)
|
---|
90 | );
|
---|
91 | for (const gotHandler of gotHandlers) {
|
---|
92 | gotHandler(result, innerCallback);
|
---|
93 | }
|
---|
94 | } else if (gotHandlers.length === 1) {
|
---|
95 | gotHandlers[0](result, () => callback(null, result));
|
---|
96 | } else {
|
---|
97 | callback(null, result);
|
---|
98 | }
|
---|
99 | });
|
---|
100 | }
|
---|
101 |
|
---|
102 | /**
|
---|
103 | * @template T
|
---|
104 | * @param {string} identifier the cache identifier
|
---|
105 | * @param {Etag | null} etag the etag
|
---|
106 | * @param {T} data the value to store
|
---|
107 | * @param {CallbackCache<void>} callback signals when the value is stored
|
---|
108 | * @returns {void}
|
---|
109 | */
|
---|
110 | store(identifier, etag, data, callback) {
|
---|
111 | this.hooks.store.callAsync(
|
---|
112 | identifier,
|
---|
113 | etag,
|
---|
114 | data,
|
---|
115 | makeWebpackErrorCallback(callback, "Cache.hooks.store")
|
---|
116 | );
|
---|
117 | }
|
---|
118 |
|
---|
119 | /**
|
---|
120 | * After this method has succeeded the cache can only be restored when build dependencies are
|
---|
121 | * @param {Iterable<string>} dependencies list of all build dependencies
|
---|
122 | * @param {CallbackCache<void>} callback signals when the dependencies are stored
|
---|
123 | * @returns {void}
|
---|
124 | */
|
---|
125 | storeBuildDependencies(dependencies, callback) {
|
---|
126 | this.hooks.storeBuildDependencies.callAsync(
|
---|
127 | dependencies,
|
---|
128 | makeWebpackErrorCallback(callback, "Cache.hooks.storeBuildDependencies")
|
---|
129 | );
|
---|
130 | }
|
---|
131 |
|
---|
132 | /**
|
---|
133 | * @returns {void}
|
---|
134 | */
|
---|
135 | beginIdle() {
|
---|
136 | this.hooks.beginIdle.call();
|
---|
137 | }
|
---|
138 |
|
---|
139 | /**
|
---|
140 | * @param {CallbackCache<void>} callback signals when the call finishes
|
---|
141 | * @returns {void}
|
---|
142 | */
|
---|
143 | endIdle(callback) {
|
---|
144 | this.hooks.endIdle.callAsync(
|
---|
145 | makeWebpackErrorCallback(callback, "Cache.hooks.endIdle")
|
---|
146 | );
|
---|
147 | }
|
---|
148 |
|
---|
149 | /**
|
---|
150 | * @param {CallbackCache<void>} callback signals when the call finishes
|
---|
151 | * @returns {void}
|
---|
152 | */
|
---|
153 | shutdown(callback) {
|
---|
154 | this.hooks.shutdown.callAsync(
|
---|
155 | makeWebpackErrorCallback(callback, "Cache.hooks.shutdown")
|
---|
156 | );
|
---|
157 | }
|
---|
158 | }
|
---|
159 |
|
---|
160 | Cache.STAGE_MEMORY = -10;
|
---|
161 | Cache.STAGE_DEFAULT = 0;
|
---|
162 | Cache.STAGE_DISK = 10;
|
---|
163 | Cache.STAGE_NETWORK = 20;
|
---|
164 |
|
---|
165 | module.exports = Cache;
|
---|