Skip to content

Commit e664d23

Browse files
committed
Fixes #3442
1 parent f65c10f commit e664d23

File tree

9 files changed

+326
-272
lines changed

9 files changed

+326
-272
lines changed

package-lock.json

Lines changed: 112 additions & 196 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
"dependencies": {
135135
"@11ty/dependency-tree": "^4.0.0",
136136
"@11ty/dependency-tree-esm": "^2.0.0",
137-
"@11ty/eleventy-dev-server": "^2.0.8",
137+
"@11ty/eleventy-dev-server": "3.0.0-alpha.1",
138138
"@11ty/eleventy-plugin-bundle": "^3.0.6",
139139
"@11ty/eleventy-utils": "^2.0.7",
140140
"@11ty/gray-matter": "^2.0.0",
@@ -144,7 +144,7 @@
144144
"@11ty/recursive-copy": "^4.0.2",
145145
"@sindresorhus/slugify": "^2.2.1",
146146
"bcp-47-normalize": "^2.3.0",
147-
"chokidar": "^3.6.0",
147+
"chokidar": "^4.0.3",
148148
"debug": "^4.4.1",
149149
"dependency-graph": "^1.0.0",
150150
"entities": "^6.0.1",
@@ -163,5 +163,8 @@
163163
"posthtml-match-helper": "^2.0.3",
164164
"semver": "^7.7.2",
165165
"tinyglobby": "^0.2.14"
166+
},
167+
"overrides": {
168+
"chokidar": "$chokidar"
166169
}
167170
}

src/Eleventy.js

Lines changed: 72 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { TemplatePath } from "@11ty/eleventy-utils";
66
import { Core } from "./Core.js";
77
import EleventyServe from "./EleventyServe.js";
88
import EleventyWatch from "./EleventyWatch.js";
9-
import EleventyWatchTargets from "./EleventyWatchTargets.js";
9+
import WatchTargets from "./EleventyWatchTargets.js";
1010
import EleventyBaseError from "./Errors/EleventyBaseError.js";
1111

1212
// Utils
@@ -55,8 +55,8 @@ export default class Eleventy extends Core {
5555
this.watchManager = new EleventyWatch();
5656

5757
/** @type {object} */
58-
this.watchTargets = new EleventyWatchTargets(this.eleventyConfig);
59-
this.watchTargets.addAndMakeGlob(this.config.additionalWatchTargets);
58+
this.watchTargets = new WatchTargets(this.eleventyConfig);
59+
this.watchTargets.add(this.config.additionalWatchTargets);
6060
}
6161

6262
/**
@@ -113,9 +113,12 @@ export default class Eleventy extends Core {
113113

114114
shouldTriggerConfigReset(changedFiles) {
115115
let configFilePaths = new Set(this.eleventyConfig.getLocalProjectConfigFiles());
116-
let resetConfigGlobs = EleventyWatchTargets.normalizeToGlobs(
116+
117+
// https://www.11ty.dev/docs/watch-serve/#reset-configuration
118+
let resetConfigGlobs = WatchTargets.normalizeToGlobs(
117119
Array.from(this.eleventyConfig.userConfig.watchTargetsConfigReset),
118120
);
121+
119122
for (let filePath of changedFiles) {
120123
if (configFilePaths.has(filePath)) {
121124
return true;
@@ -152,7 +155,7 @@ export default class Eleventy extends Core {
152155
);
153156
}
154157

155-
async #watch(isResetConfig = false) {
158+
async #rewatch(isResetConfig = false) {
156159
if (this.watchManager.isBuildRunning()) {
157160
return;
158161
}
@@ -185,7 +188,9 @@ export default class Eleventy extends Core {
185188
await this.#initWatchDependencies();
186189

187190
// Add new deps to chokidar
188-
this.watcher.add(this.watchTargets.getNewTargetsSinceLastReset());
191+
let newWatchTargets = this.watchTargets.getNewTargetsSinceLastReset();
192+
// TODO chokidar
193+
this.watcher.add(newWatchTargets);
189194

190195
// Is a CSS input file and is not in the includes folder
191196
// TODO check output path file extension of this template (not input path)
@@ -249,7 +254,7 @@ export default class Eleventy extends Core {
249254
queueSize !== 1 ? "s" : ""
250255
})`,
251256
);
252-
await this.#watch();
257+
await this.#rewatch();
253258
} else {
254259
this.logger.log("Watching…");
255260
}
@@ -328,30 +333,56 @@ export default class Eleventy extends Core {
328333
);
329334
}
330335

336+
getWatchedFiles() {
337+
throw new Error(
338+
"Eleventy#getWatchedFiles() has been removed in Eleventy v4. Use Eleventy#getWatchedTargets().targets instead.",
339+
);
340+
}
341+
331342
/**
332-
* Returns all watched files.
343+
* Returns all watched paths
333344
*
334345
* @async
335346
* @method
336-
* @returns {Promise<Array>} targets - The watched files.
347+
* @returns {Object} containing `cwd` string, `targets` file paths, and `ignores` globs Array
337348
*/
338-
async getWatchedFiles() {
339-
return this.watchTargets.getTargets();
340-
}
349+
async getWatchedTargets() {
350+
let rawWatchedGlobs = await this.watchTargets.getTargets();
341351

342-
getChokidarConfig() {
343352
let ignores = this.eleventyFiles.getGlobWatcherIgnores();
353+
354+
// Remap all paths to `cwd` if in play (Issue #3854)
355+
let remapper = new GlobRemap(rawWatchedGlobs);
356+
let cwd = remapper.getCwd();
357+
358+
if (cwd) {
359+
rawWatchedGlobs = remapper.getInput().map((entry) => {
360+
return TemplatePath.stripLeadingDotSlash(entry);
361+
});
362+
ignores = remapper.getRemapped(ignores || []);
363+
}
364+
365+
ignores = ignores.map((entry) => {
366+
return TemplatePath.stripLeadingDotSlash(entry);
367+
});
368+
344369
debug("Ignoring watcher changes to: %o", ignores);
345370

371+
return {
372+
cwd,
373+
targets: rawWatchedGlobs,
374+
ignores,
375+
};
376+
}
377+
378+
getChokidarConfig() {
346379
let configOptions = this.config.chokidarConfig;
347380

348-
// can’t override these yet
349-
// TODO maybe if array, merge the array?
381+
// unsupported: using your own `ignored`
350382
delete configOptions.ignored;
351383

352384
return Object.assign(
353385
{
354-
ignored: ignores,
355386
ignoreInitial: true,
356387
awaitWriteFinish: {
357388
stabilityThreshold: 150,
@@ -384,7 +415,7 @@ export default class Eleventy extends Core {
384415
}
385416

386417
// Note that watching indirectly depends on this for fetching dependencies from JS files
387-
// See: TemplateWriter:pathCache and EleventyWatchTargets
418+
// See: TemplateWriter:pathCache and WatchTargets
388419
await this.write();
389420

390421
let initWatchBench = this.watcherBench.get("Start up --watch");
@@ -393,28 +424,28 @@ export default class Eleventy extends Core {
393424
await this.initWatch();
394425

395426
// TODO improve unwatching if JS dependencies are removed (or files are deleted)
396-
let rawFiles = await this.getWatchedFiles();
397-
debug("Watching for changes to: %o", rawFiles);
427+
let { targets, cwd, ignores } = await this.getWatchedTargets();
428+
debug("Watching for changes to: %o", targets);
398429

399430
let options = this.getChokidarConfig();
400431

401-
// Remap all paths to `cwd` if in play (Issue #3854)
402-
let remapper = new GlobRemap(rawFiles);
403-
let cwd = remapper.getCwd();
404-
405432
if (cwd) {
406433
options.cwd = cwd;
434+
}
407435

408-
rawFiles = remapper.getInput().map((entry) => {
409-
return TemplatePath.stripLeadingDotSlash(entry);
410-
});
436+
debug("Ignoring watcher changes to: %o", ignores);
411437

412-
options.ignored = remapper.getRemapped(options.ignored || []).map((entry) => {
413-
return TemplatePath.stripLeadingDotSlash(entry);
414-
});
415-
}
438+
options.alwaysStat = true;
439+
options.ignored = (path, stats) => {
440+
if (stats?.isFile()) {
441+
let isMatch = this.watchTargets.isWatchMatch(path, ignores);
442+
if (!isMatch) {
443+
return true;
444+
}
445+
}
446+
};
416447

417-
let watcher = chokidar.watch(rawFiles, options);
448+
let watcher = chokidar.watch(targets, options);
418449

419450
initWatchBench.after();
420451

@@ -436,7 +467,7 @@ export default class Eleventy extends Core {
436467
let { promise, resolve, reject } = withResolvers();
437468

438469
watchDelay = setTimeout(async () => {
439-
this.#watch(isResetConfig).then(resolve, reject);
470+
this.#rewatch(isResetConfig).then(resolve, reject);
440471
}, this.config.watchThrottleWaitTime);
441472

442473
await promise;
@@ -456,7 +487,9 @@ export default class Eleventy extends Core {
456487
watcher.on("change", async (path) => {
457488
// Emulated passthrough copy logs from the server
458489
if (!this.eleventyServe.isEmulatedPassthroughCopyMatch(path)) {
459-
this.logger.forceLog(`File changed: ${TemplatePath.standardizeFilePath(path)}`);
490+
this.logger.forceLog(
491+
`File changed: ${TemplatePath.stripLeadingDotSlash(TemplatePath.standardizeFilePath(path))}`,
492+
);
460493
}
461494

462495
await watchRun(path);
@@ -465,15 +498,19 @@ export default class Eleventy extends Core {
465498
watcher.on("add", async (path) => {
466499
// Emulated passthrough copy logs from the server
467500
if (!this.eleventyServe.isEmulatedPassthroughCopyMatch(path)) {
468-
this.logger.forceLog(`File added: ${TemplatePath.standardizeFilePath(path)}`);
501+
this.logger.forceLog(
502+
`File added: ${TemplatePath.stripLeadingDotSlash(TemplatePath.standardizeFilePath(path))}`,
503+
);
469504
}
470505

471506
this.fileSystemSearch.add(path);
472507
await watchRun(path);
473508
});
474509

475510
watcher.on("unlink", async (path) => {
476-
this.logger.forceLog(`File deleted: ${TemplatePath.standardizeFilePath(path)}`);
511+
this.logger.forceLog(
512+
`File deleted: ${TemplatePath.stripLeadingDotSlash(TemplatePath.standardizeFilePath(path))}`,
513+
);
477514
this.fileSystemSearch.delete(path);
478515
await watchRun(path);
479516
});

src/EleventyServe.js

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import assert from "node:assert";
21
import debugUtil from "debug";
3-
import { Merge, DeepCopy, TemplatePath } from "@11ty/eleventy-utils";
4-
5-
function deepEqual(actual, expected) {
6-
try {
7-
assert.deepStrictEqual(actual, expected);
8-
return false;
9-
} catch (e) {
10-
return true;
11-
}
2+
import { Merge, TemplatePath } from "@11ty/eleventy-utils";
3+
4+
function stringifyOptions(options) {
5+
return JSON.stringify(options, function replacer(key, value) {
6+
if (typeof value === "function") {
7+
return value.toString();
8+
}
9+
10+
return value;
11+
});
1212
}
1313

1414
import EleventyBaseError from "./Errors/EleventyBaseError.js";
@@ -34,6 +34,7 @@ const DEFAULT_SERVER_OPTIONS = {
3434

3535
class EleventyServe {
3636
#eleventyConfig;
37+
#savedConfigOptions;
3738

3839
constructor() {
3940
this.logger = new ConsoleLogger();
@@ -170,7 +171,7 @@ class EleventyServe {
170171
this.config.serverOptions,
171172
);
172173

173-
this._savedConfigOptions = DeepCopy({}, this.config.serverOptions);
174+
this.#savedConfigOptions = this.config.serverOptions;
174175

175176
if (!this._initOptionsFetched && this.getSetupCallback()) {
176177
throw new Error(
@@ -261,6 +262,7 @@ class EleventyServe {
261262
if (this._server) {
262263
await this._server.close();
263264

265+
console.log("Server closed.");
264266
this._server = undefined;
265267
}
266268
}
@@ -309,7 +311,9 @@ class EleventyServe {
309311
}
310312

311313
hasOptionsChanged() {
312-
return !deepEqual(this.config.serverOptions, this._savedConfigOptions);
314+
return (
315+
stringifyOptions(this.config.serverOptions) !== stringifyOptions(this.#savedConfigOptions)
316+
);
313317
}
314318

315319
// Live reload the server

0 commit comments

Comments
 (0)