Skip to content

Commit a1ec64a

Browse files
authored
feat: upgrade @parcel/watcher to support glob expression (#2180)
1 parent 3d6634f commit a1ec64a

5 files changed

Lines changed: 14 additions & 139 deletions

File tree

packages/core-browser/src/core-preferences.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const FILES_DEFAULTS = {
1818
filesWatcherExclude: {
1919
'**/.git/objects/**': true,
2020
'**/.git/subtree-cache/**': true,
21-
'**/node_modules/**': true,
21+
'**/node_modules/**/*': true,
2222
'**/.hg/store/**': true,
2323
},
2424
filesExclude: {

packages/file-service/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"@opensumi/ide-core-common": "workspace:*",
2222
"@opensumi/ide-core-node": "workspace:*",
2323
"@opensumi/ide-logs": "workspace:*",
24-
"@parcel/watcher": "2.0.6",
24+
"@parcel/watcher": "2.1.0",
2525
"drivelist": "^6.4.3",
2626
"file-type": "^12.0.0",
2727
"trash": "^5.2.0",

packages/file-service/src/node/file-service-watcher.ts

Lines changed: 4 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import paths, { isAbsolute } from 'path';
1+
import paths from 'path';
22

33
import ParcelWatcher from '@parcel/watcher';
44
import * as fs from 'fs-extra';
@@ -14,8 +14,6 @@ import {
1414
isWindows,
1515
URI,
1616
isLinux,
17-
strings,
18-
path,
1917
ILogService,
2018
SupportLogNamespace,
2119
ILogServiceManager,
@@ -25,9 +23,6 @@ import { FileChangeType, FileSystemWatcherClient, IFileSystemWatcherServer, Watc
2523

2624
import { FileChangeCollection } from './file-change-collection';
2725

28-
const { rtrim } = strings;
29-
const { Path } = path;
30-
3126
export interface WatcherOptions {
3227
excludesPattern: ParsedPattern[];
3328
excludes: string[];
@@ -37,18 +32,6 @@ export interface WatcherOptions {
3732
export class ParcelWatcherServer implements IFileSystemWatcherServer {
3833
private static readonly PARCEL_WATCHER_BACKEND = isWindows ? 'windows' : isLinux ? 'inotify' : 'fs-events';
3934

40-
private static readonly GLOB_MARKERS = {
41-
Star: '*',
42-
GlobStar: '**',
43-
GlobStarPosix: '**/**',
44-
GlobStarWindows: '**\\**',
45-
GlobStarPathStartPosix: '**/',
46-
GlobStarPathEndPosix: '/**',
47-
StarPathEndPosix: '/*',
48-
GlobStarPathStartWindows: '**\\',
49-
GlobStarPathEndWindows: '\\**',
50-
};
51-
5235
private static WATCHER_HANDLERS = new Map<
5336
number,
5437
{ path: string; handlers: ParcelWatcher.SubscribeCallback[]; disposable: IDisposable }
@@ -184,113 +167,8 @@ export class ParcelWatcherServer implements IFileSystemWatcherServer {
184167
return events;
185168
}
186169

187-
// ref: https://github.com/microsoft/vscode/blob/2a63d7baf2db7eabf141f876581ea4c808a6b8e4/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts#L170
188-
protected toExcludePaths(path: string, excludes: string[] | undefined): string[] | undefined {
189-
if (!Array.isArray(excludes)) {
190-
return undefined;
191-
}
192-
193-
const excludePaths = new Set<string>();
194-
195-
// Parcel watcher currently does not support glob patterns
196-
// for native exclusions. As long as that is the case, try
197-
// to convert exclude patterns into absolute paths that the
198-
// watcher supports natively to reduce the overhead at the
199-
// level of the file watcher as much as possible.
200-
// Refs: https://github.com/parcel-bundler/watcher/issues/64
201-
for (const exclude of excludes) {
202-
const isGlob = exclude.includes(ParcelWatcherServer.GLOB_MARKERS.Star);
203-
204-
// Glob pattern: check for typical patterns and convert
205-
let normalizedExclude: string | undefined;
206-
if (isGlob) {
207-
// Examples: **, **/**, **\**
208-
if (
209-
exclude === ParcelWatcherServer.GLOB_MARKERS.GlobStar ||
210-
exclude === ParcelWatcherServer.GLOB_MARKERS.GlobStarPosix ||
211-
exclude === ParcelWatcherServer.GLOB_MARKERS.GlobStarWindows
212-
) {
213-
normalizedExclude = path;
214-
}
215-
216-
// Examples:
217-
// - **/node_modules/**
218-
// - **/.git/objects/**
219-
// - **/build-folder
220-
// - output/**
221-
else {
222-
const startsWithGlobStar =
223-
exclude.startsWith(ParcelWatcherServer.GLOB_MARKERS.GlobStarPathStartPosix) ||
224-
exclude.startsWith(ParcelWatcherServer.GLOB_MARKERS.GlobStarPathStartWindows);
225-
const endsWithGlobStar =
226-
exclude.endsWith(ParcelWatcherServer.GLOB_MARKERS.GlobStarPathEndPosix) ||
227-
exclude.endsWith(ParcelWatcherServer.GLOB_MARKERS.GlobStarPathEndWindows);
228-
if (startsWithGlobStar || endsWithGlobStar) {
229-
if (startsWithGlobStar && endsWithGlobStar) {
230-
normalizedExclude = exclude.substring(
231-
ParcelWatcherServer.GLOB_MARKERS.GlobStarPathStartPosix.length,
232-
exclude.length - ParcelWatcherServer.GLOB_MARKERS.GlobStarPathEndPosix.length,
233-
);
234-
} else if (startsWithGlobStar) {
235-
normalizedExclude = exclude.substring(ParcelWatcherServer.GLOB_MARKERS.GlobStarPathStartPosix.length);
236-
} else {
237-
normalizedExclude = exclude.substring(
238-
0,
239-
exclude.length - ParcelWatcherServer.GLOB_MARKERS.GlobStarPathEndPosix.length,
240-
);
241-
}
242-
}
243-
244-
// Support even more glob patterns on Linux where we know
245-
// that each folder requires a file handle to watch.
246-
// Examples:
247-
// - node_modules/* (full form: **/node_modules/*/**)
248-
if (isLinux && normalizedExclude) {
249-
const endsWithStar = normalizedExclude?.endsWith(ParcelWatcherServer.GLOB_MARKERS.StarPathEndPosix);
250-
if (endsWithStar) {
251-
normalizedExclude = normalizedExclude.substring(
252-
0,
253-
normalizedExclude.length - ParcelWatcherServer.GLOB_MARKERS.StarPathEndPosix.length,
254-
);
255-
}
256-
}
257-
}
258-
}
259-
260-
// Not a glob pattern, take as is
261-
else {
262-
normalizedExclude = exclude;
263-
}
264-
265-
if (!normalizedExclude || normalizedExclude.includes(ParcelWatcherServer.GLOB_MARKERS.Star)) {
266-
continue; // skip for parcel (will be applied later by our glob matching)
267-
}
268-
269-
// Absolute path: normalize to watched path and
270-
// exclude if not a parent of it otherwise.
271-
if (isAbsolute(normalizedExclude)) {
272-
const base = new Path(normalizedExclude);
273-
if (!base.isEqualOrParent(new Path(path))) {
274-
continue; // exclude points to path outside of watched folder, ignore
275-
}
276-
// convert to relative path to ensure we
277-
// get the correct path casing going forward
278-
normalizedExclude = normalizedExclude.substr(path.length);
279-
}
280-
281-
// Finally take as relative path joined to watched path
282-
excludePaths.add(rtrim(new Path(path).join(normalizedExclude).toString(), Path.separator));
283-
}
284-
285-
if (excludePaths.size > 0) {
286-
return Array.from(excludePaths);
287-
}
288-
289-
return undefined;
290-
}
291-
292170
private getDefaultWatchExclude() {
293-
return ['**/.git/objects/**', '**/.git/subtree-cache/**', '**/node_modules/**', '**/.hg/store/**'];
171+
return ['**/.git/objects/**', '**/.git/subtree-cache/**', '**/node_modules/**/*', '**/.hg/store/**'];
294172
}
295173

296174
protected async start(
@@ -303,18 +181,13 @@ export class ParcelWatcherServer implements IFileSystemWatcherServer {
303181
return disposables;
304182
}
305183
const realPath = await fs.realpath(basePath);
306-
const ignore = this.toExcludePaths(
307-
realPath,
308-
this.excludes.concat(rawOptions?.excludes || this.getDefaultWatchExclude()),
309-
);
310-
311184
const tryWatchDir = async (maxRetries = 3, retryDelay = 1000) => {
312185
for (let times = 0; times < maxRetries; times++) {
313186
try {
314187
return await ParcelWatcher.subscribe(
315188
realPath,
316189
(err, events: ParcelWatcher.Event[]) => {
317-
// 对于超过5000数量的 events 做屏蔽优化,避免潜在的卡死问题
190+
// 对于超过 5000 数量的 events 做屏蔽优化,避免潜在的卡死问题
318191
if (events.length > 5000) {
319192
// FIXME: 研究此处屏蔽的影响,考虑下阈值应该设置多少,或者更加优雅的方式
320193
return;
@@ -329,7 +202,7 @@ export class ParcelWatcherServer implements IFileSystemWatcherServer {
329202
},
330203
{
331204
backend: ParcelWatcherServer.PARCEL_WATCHER_BACKEND,
332-
ignore,
205+
ignore: this.excludes.concat(rawOptions?.excludes || this.getDefaultWatchExclude()),
333206
},
334207
);
335208
} catch (e) {

tools/electron/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"license": "ISC",
3838
"dependencies": {
3939
"@opensumi/vscode-ripgrep": "^1.4.0",
40-
"@parcel/watcher": "2.0.6",
40+
"@parcel/watcher": "2.1.0",
4141
"node-gyp": "^9.3.0",
4242
"node-pty": "0.11.0-beta19",
4343
"spdlog": "^0.9.0",

yarn.lock

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2968,7 +2968,7 @@ __metadata:
29682968
"@opensumi/ide-core-node": "workspace:*"
29692969
"@opensumi/ide-dev-tool": "workspace:*"
29702970
"@opensumi/ide-logs": "workspace:*"
2971-
"@parcel/watcher": 2.0.6
2971+
"@parcel/watcher": 2.1.0
29722972
drivelist: ^6.4.3
29732973
file-type: ^12.0.0
29742974
trash: ^5.2.0
@@ -3623,14 +3623,16 @@ __metadata:
36233623
languageName: node
36243624
linkType: hard
36253625

3626-
"@parcel/watcher@npm:2.0.6":
3627-
version: 2.0.6
3628-
resolution: "@parcel/watcher@npm:2.0.6"
3626+
"@parcel/watcher@npm:2.1.0":
3627+
version: 2.1.0
3628+
resolution: "@parcel/watcher@npm:2.1.0"
36293629
dependencies:
3630+
is-glob: ^4.0.3
3631+
micromatch: ^4.0.5
36303632
node-addon-api: ^3.2.1
36313633
node-gyp: latest
36323634
node-gyp-build: ^4.3.0
3633-
checksum: 5bcd03804cdacabcc4dfbe47c3893ecfc045578dd9077d0c84bf3fd314becc429c10a8d0afcf5e262dd7a181054f331c48b13856738df8b93e8e49381dd7c4e3
3635+
checksum: 17f512ad6d5dbb40053ceea7091f8af754afc63786b8f050b225b89a8ba24900468aad8bc4edb25c0349b4c0c8d061f50aa19242c0af52cbc30e6ebf50c7bf4c
36343636
languageName: node
36353637
linkType: hard
36363638

0 commit comments

Comments
 (0)