@teambit/workspace 0.0.750 → 0.0.753
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/dist/capsule.cmd.d.ts +2 -3
- package/dist/capsule.cmd.js +4 -6
- package/dist/capsule.cmd.js.map +1 -1
- package/dist/install.cmd.d.ts +0 -1
- package/dist/install.cmd.js +0 -1
- package/dist/install.cmd.js.map +1 -1
- package/dist/link/link.cmd.d.ts +1 -1
- package/dist/link/link.cmd.js +3 -5
- package/dist/link/link.cmd.js.map +1 -1
- package/dist/uninstall.cmd.d.ts +0 -1
- package/dist/uninstall.cmd.js +0 -1
- package/dist/uninstall.cmd.js.map +1 -1
- package/dist/update.cmd.d.ts +0 -1
- package/dist/update.cmd.js +0 -1
- package/dist/update.cmd.js.map +1 -1
- package/dist/watch/watch.cmd.d.ts +2 -3
- package/dist/watch/watch.cmd.js +15 -6
- package/dist/watch/watch.cmd.js.map +1 -1
- package/dist/watch/watcher.d.ts +27 -8
- package/dist/watch/watcher.js +136 -44
- package/dist/watch/watcher.js.map +1 -1
- package/install.cmd.tsx +0 -1
- package/link/link.cmd.ts +3 -3
- package/package-tar/teambit-workspace-0.0.753.tgz +0 -0
- package/package.json +31 -31
- package/{preview-1654226751250.js → preview-1654572446572.js} +2 -2
- package/uninstall.cmd.tsx +0 -1
- package/update.cmd.tsx +0 -1
- package/watch/watch.cmd.tsx +25 -6
- package/watch/watcher.ts +104 -40
- package/package-tar/teambit-workspace-0.0.750.tgz +0 -0
package/watch/watcher.ts
CHANGED
|
@@ -42,8 +42,11 @@ export type WatchOptions = {
|
|
|
42
42
|
preCompile?: boolean; // whether compile all components before start watching
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
const DEBOUNCE_WAIT_MS = 100;
|
|
46
|
+
|
|
45
47
|
export class Watcher {
|
|
46
48
|
private fsWatcher: FSWatcher;
|
|
49
|
+
private changedFilesPerComponent: { [componentId: string]: string[] } = {};
|
|
47
50
|
constructor(
|
|
48
51
|
private workspace: Workspace,
|
|
49
52
|
private pubsub: PubsubMain,
|
|
@@ -78,16 +81,22 @@ export class Watcher {
|
|
|
78
81
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
79
82
|
watcher.on('change', async (filePath) => {
|
|
80
83
|
const startTime = new Date().getTime();
|
|
81
|
-
const
|
|
84
|
+
const { files, results, debounced, failureMsg } = await this.handleChange(filePath, opts?.initiator);
|
|
85
|
+
if (debounced) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
82
88
|
const duration = new Date().getTime() - startTime;
|
|
83
|
-
msgs?.onChange(
|
|
89
|
+
msgs?.onChange(files, results, this.verbose, duration, failureMsg);
|
|
84
90
|
});
|
|
85
91
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
86
92
|
watcher.on('add', async (filePath) => {
|
|
87
93
|
const startTime = new Date().getTime();
|
|
88
|
-
const
|
|
94
|
+
const { files, results, debounced, failureMsg } = await this.handleChange(filePath, opts?.initiator);
|
|
95
|
+
if (debounced) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
89
98
|
const duration = new Date().getTime() - startTime;
|
|
90
|
-
msgs?.onAdd(
|
|
99
|
+
msgs?.onAdd(files, results, this.verbose, duration, failureMsg);
|
|
91
100
|
});
|
|
92
101
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
93
102
|
watcher.on('unlink', async (p) => {
|
|
@@ -101,28 +110,102 @@ export class Watcher {
|
|
|
101
110
|
});
|
|
102
111
|
}
|
|
103
112
|
|
|
104
|
-
|
|
113
|
+
/**
|
|
114
|
+
* some actions trigger multiple files changes at (almost) the same time. e.g. "git pull".
|
|
115
|
+
* this causes some performance and instability issues. a debouncing mechanism was implemented to help with this.
|
|
116
|
+
* the way how it works is that the first file of the same component starts the execution with a delay (e.g. 200ms).
|
|
117
|
+
* if, in the meanwhile, another file of the same component was changed, it won't start a new execution, instead,
|
|
118
|
+
* it'll only add the file to `this.changedFilesPerComponent` prop.
|
|
119
|
+
* once the execution starts, it'll delete this component-id from the `this.changedFilesPerComponent` array,
|
|
120
|
+
* indicating the next file-change to start a new execution.
|
|
121
|
+
*
|
|
122
|
+
* implementation wise, `lodash.debounce` doesn't help here, because:
|
|
123
|
+
* A) it doesn't return the results, unless "leading" option is true. here, it must be false, otherwise, it'll start
|
|
124
|
+
* the execution immediately.
|
|
125
|
+
* B) it debounces the method regardless the param passes to it. so it'll disregard the component-id and will delay
|
|
126
|
+
* other components undesirably.
|
|
127
|
+
*
|
|
128
|
+
*/
|
|
129
|
+
private async handleChange(
|
|
130
|
+
filePath: string,
|
|
131
|
+
initiator?: CompilationInitiator
|
|
132
|
+
): Promise<{
|
|
133
|
+
results: OnComponentEventResult[];
|
|
134
|
+
files?: string[];
|
|
135
|
+
failureMsg?: string;
|
|
136
|
+
debounced?: boolean;
|
|
137
|
+
}> {
|
|
105
138
|
try {
|
|
106
139
|
if (filePath.endsWith(BIT_MAP)) {
|
|
107
140
|
const buildResults = await this.handleBitmapChanges();
|
|
108
|
-
|
|
109
|
-
return buildResults;
|
|
141
|
+
loader.stop();
|
|
142
|
+
return { results: buildResults, files: [filePath] };
|
|
110
143
|
}
|
|
111
|
-
const componentId =
|
|
144
|
+
const componentId = this.getComponentIdByPath(filePath);
|
|
112
145
|
if (!componentId) {
|
|
113
|
-
|
|
114
|
-
|
|
146
|
+
const failureMsg = `file ${filePath} is not part of any component, ignoring it`;
|
|
147
|
+
logger.debug(failureMsg);
|
|
148
|
+
loader.stop();
|
|
149
|
+
return { results: [], files: [filePath], failureMsg };
|
|
115
150
|
}
|
|
116
151
|
|
|
117
|
-
const
|
|
118
|
-
this.
|
|
119
|
-
|
|
152
|
+
const compIdStr = componentId.toString();
|
|
153
|
+
if (this.changedFilesPerComponent[compIdStr]) {
|
|
154
|
+
this.changedFilesPerComponent[compIdStr].push(filePath);
|
|
155
|
+
loader.stop();
|
|
156
|
+
return { results: [], debounced: true };
|
|
157
|
+
}
|
|
158
|
+
this.changedFilesPerComponent[compIdStr] = [filePath];
|
|
159
|
+
await this.sleep(DEBOUNCE_WAIT_MS);
|
|
160
|
+
const files = this.changedFilesPerComponent[compIdStr];
|
|
161
|
+
delete this.changedFilesPerComponent[compIdStr];
|
|
162
|
+
|
|
163
|
+
const buildResults = await this.triggerCompChanges(componentId, files, initiator);
|
|
164
|
+
const failureMsg = buildResults.length
|
|
165
|
+
? undefined
|
|
166
|
+
: `files ${files.join(', ')} are inside the component ${compIdStr} but configured to be ignored`;
|
|
167
|
+
loader.stop();
|
|
168
|
+
return { results: buildResults, files, failureMsg };
|
|
120
169
|
} catch (err: any) {
|
|
121
170
|
const msg = `watcher found an error while handling ${filePath}`;
|
|
122
171
|
logger.error(msg, err);
|
|
123
172
|
logger.console(`${msg}, ${err.message}`);
|
|
173
|
+
loader.stop();
|
|
174
|
+
return { results: [], files: [filePath], failureMsg: err.message };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private async sleep(ms: number) {
|
|
179
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* if a file was added/remove, once the component is loaded, it changes .bitmap, and then the
|
|
184
|
+
* entire cache is invalidated and the consumer is reloaded.
|
|
185
|
+
* when a file just changed, no need to reload the consumer, it is enough to just delete the
|
|
186
|
+
* component from the cache (both, workspace and consumer)
|
|
187
|
+
*/
|
|
188
|
+
private async triggerCompChanges(
|
|
189
|
+
componentId: ComponentID,
|
|
190
|
+
files: string[],
|
|
191
|
+
initiator?: CompilationInitiator
|
|
192
|
+
): Promise<OnComponentEventResult[]> {
|
|
193
|
+
this.workspace.clearComponentCache(componentId);
|
|
194
|
+
const component = await this.workspace.get(componentId);
|
|
195
|
+
const componentMap: ComponentMap = component.state._consumer.componentMap;
|
|
196
|
+
const compFiles = files.filter((filePath) => {
|
|
197
|
+
const relativeFile = this.getRelativePathLinux(filePath);
|
|
198
|
+
const isCompFile = Boolean(componentMap.getFilesRelativeToConsumer().find((p) => p === relativeFile));
|
|
199
|
+
if (!isCompFile) {
|
|
200
|
+
logger.debug(`file ${filePath} is inside the component ${componentId.toString()} but configured to be ignored`);
|
|
201
|
+
}
|
|
202
|
+
return isCompFile;
|
|
203
|
+
});
|
|
204
|
+
if (!compFiles.length) {
|
|
124
205
|
return [];
|
|
125
206
|
}
|
|
207
|
+
const buildResults = await this.executeWatchOperationsOnComponent(componentId, compFiles, true, initiator);
|
|
208
|
+
return buildResults;
|
|
126
209
|
}
|
|
127
210
|
|
|
128
211
|
/**
|
|
@@ -188,11 +271,7 @@ export class Watcher {
|
|
|
188
271
|
logger.console(`\n${msg}: ${err.message || err}`);
|
|
189
272
|
return [];
|
|
190
273
|
}
|
|
191
|
-
|
|
192
|
-
return buildResults;
|
|
193
|
-
}
|
|
194
|
-
logger.console(`${idStr} doesn't have a compiler, nothing to build`);
|
|
195
|
-
return [];
|
|
274
|
+
return buildResults;
|
|
196
275
|
}
|
|
197
276
|
|
|
198
277
|
private creatOnComponentRemovedEvent(idStr) {
|
|
@@ -207,11 +286,6 @@ export class Watcher {
|
|
|
207
286
|
return new OnComponentAddEvent(Date.now(), idStr, hook);
|
|
208
287
|
}
|
|
209
288
|
|
|
210
|
-
private completeWatch() {
|
|
211
|
-
loader.stop();
|
|
212
|
-
return [];
|
|
213
|
-
}
|
|
214
|
-
|
|
215
289
|
private isComponentWatchedExternally(componentId: ComponentID) {
|
|
216
290
|
const watcherData = this.multipleWatchers.find((m) => m.componentIds.find((id) => id.isEqual(componentId._legacy)));
|
|
217
291
|
if (watcherData) {
|
|
@@ -221,29 +295,19 @@ export class Watcher {
|
|
|
221
295
|
return false;
|
|
222
296
|
}
|
|
223
297
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
* entire cache is invalidated and the consumer is reloaded.
|
|
227
|
-
* when a file just changed, no need to reload the consumer, it is enough to just delete the
|
|
228
|
-
* component from the cache (both, workspace and consumer)
|
|
229
|
-
*/
|
|
230
|
-
private async getComponentIdAndClearItsCache(filePath: string): Promise<ComponentID | null> {
|
|
231
|
-
const relativeFile = pathNormalizeToLinux(this.consumer.getPathRelativeToConsumer(filePath));
|
|
298
|
+
private getComponentIdByPath(filePath: string): ComponentID | null {
|
|
299
|
+
const relativeFile = this.getRelativePathLinux(filePath);
|
|
232
300
|
const trackDir = this.findTrackDirByFilePathRecursively(relativeFile);
|
|
233
301
|
if (!trackDir) {
|
|
234
302
|
// the file is not part of any component. If it was a new component, or a new file of
|
|
235
303
|
// existing component, then, handleBitmapChanges() should deal with it.
|
|
236
304
|
return null;
|
|
237
305
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
return componentId;
|
|
244
|
-
}
|
|
245
|
-
// the file is inside the component dir but it's ignored. (e.g. it's in IGNORE_LIST)
|
|
246
|
-
return null;
|
|
306
|
+
return this.trackDirs[trackDir];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private getRelativePathLinux(filePath: string) {
|
|
310
|
+
return pathNormalizeToLinux(this.consumer.getPathRelativeToConsumer(filePath));
|
|
247
311
|
}
|
|
248
312
|
|
|
249
313
|
private findTrackDirByFilePathRecursively(filePath: string): string | null {
|
|
Binary file
|