Skip to content

Commit

Permalink
Use new aliases feature of Eleventy Dev Server to implement for-fre…
Browse files Browse the repository at this point in the history
…e passthrough copy. Passthrough copy now no longer triggers a build during --serve or --watch. Instead, the Dev Server now serves these files directly from the project directory. Changes to passthrough copy files (despite skipping a build) *will* trigger a page reload in your browser.

Related to 11ty/eleventy-dev-server#12

Fixes #2456
  • Loading branch information
zachleat committed Jun 23, 2022
1 parent d628e33 commit 93ff7cc
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 15 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
},
"dependencies": {
"@11ty/dependency-tree": "^2.0.1",
"@11ty/eleventy-dev-server": "^1.0.0-canary.9",
"@11ty/eleventy-dev-server": "^1.0.0-canary.11",
"@11ty/eleventy-utils": "^1.0.1",
"@iarna/toml": "^2.2.5",
"@sindresorhus/slugify": "^1.1.2",
Expand Down
35 changes: 34 additions & 1 deletion src/Eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ class Eleventy {
);
this.eleventyFiles.setPassthroughAll(this.isPassthroughAll);
this.eleventyFiles.setInput(this.inputDir, this.input);
this.eleventyFiles.setRunMode(this.runMode);
this.eleventyFiles.extensionMap = this.extensionMap;
this.eleventyFiles.init();

Expand Down Expand Up @@ -535,7 +536,7 @@ Verbose Output: ${this.verboseMode}`);
* Updates the run mode of Eleventy.
*
* @method
* @param {String} runMode - One of "watch" or "serve"
* @param {String} runMode - One of "build", "watch", or "serve"
*/
setRunMode(runMode) {
this.runMode = runMode;
Expand Down Expand Up @@ -881,6 +882,22 @@ Arguments:
);
}

async triggerServerReload(changedFiles) {
let onlyApplyingCssChanges =
changedFiles.filter((entry) => entry.endsWith(".css")).length ===
changedFiles.length;

// returns a promise
return this.eleventyServe.reload({
files: changedFiles,
subtype: onlyApplyingCssChanges ? "css" : undefined,
build: {
// As of right now this is only used for the passthrough copy watcher so templates are unnecessary
templates: [],
},
});
}

/**
* Start the watching of files.
*
Expand Down Expand Up @@ -960,13 +977,29 @@ Arguments:
await watchRun(path);
});

// Separate watcher for passthrough copy, we only want to trigger a server reload for changes to these files
this.passthroughWatcher = chokidar.watch(
this.eleventyFiles.getGlobWatcherFilesForPassthroughCopy(),
this.getChokidarConfig()
);
this.passthroughWatcher.on("change", async (path) => {
this.logger.forceLog(`Passthrough copy file changed: ${path}`);
this.triggerServerReload([path]);
});

this.passthroughWatcher.on("add", async (path) => {
this.logger.forceLog(`Passthrough copy file added: ${path}`);
this.triggerServerReload([path]);
});

process.on("SIGINT", () => this.stopWatch());
}

stopWatch() {
debug("Cleaning up chokidar and server instances, if they exist.");
this.eleventyServe.close();
this.watcher.close();
this.passthroughWatcher.close();
process.exit();
}

Expand Down
21 changes: 17 additions & 4 deletions src/EleventyFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ class EleventyFiles {
return this._extensionMap;
}

setRunMode(runMode) {
this.runMode = runMode;
}

setPassthroughAll(passthroughAll) {
this.passthroughAll = !!passthroughAll;
}
Expand All @@ -153,6 +157,7 @@ class EleventyFiles {
let mgr = new TemplatePassthroughManager(this.eleventyConfig);
mgr.setInputDir(this.inputDir);
mgr.setOutputDir(this.outputDir);
mgr.setRunMode(this.runMode);
mgr.extensionMap = this.extensionMap;
this.passthroughManager = mgr;
}
Expand Down Expand Up @@ -421,10 +426,18 @@ class EleventyFiles {

/* For `eleventy --watch` */
getGlobWatcherFiles() {
// TODO is it better to tie the includes and data to specific file extensions or keep the **?
return this.validTemplateGlobs
.concat(this.passthroughGlobs)
.concat(this._getIncludesAndDataDirs());
// TODO improvement: tie the includes and data to specific file extensions (currently using `**`)
let directoryGlobs = this._getIncludesAndDataDirs();

// TODO config API method to revert to previous passthrough copy behavior
// return this.validTemplateGlobs.concat(this.passthroughGlobs).concat(directoryGlobs);

return this.validTemplateGlobs.concat(directoryGlobs);
}

/* For `eleventy --watch` */
getGlobWatcherFilesForPassthroughCopy() {
return this.passthroughGlobs;
}

/* For `eleventy --watch` */
Expand Down
10 changes: 10 additions & 0 deletions src/EleventyServe.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,18 @@ class EleventyServe {

set eleventyConfig(config) {
this._eleventyConfig = config;
this._eleventyConfig.userConfig.events.on(
"eleventy.passthrough",
({ map }) => {
// for-free passthrough copy
if ("setAliases" in this.server) {
this.server.setAliases(map);
}
}
);
}

// TODO this doesn’t seem to be used internally
setOutputDir(outputDir) {
this.outputDir = outputDir;
}
Expand Down
24 changes: 20 additions & 4 deletions src/TemplatePassthrough.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ class TemplatePassthrough {
this.isDryRun = !!isDryRun;
}

setRunMode(runMode) {
this.runMode = runMode;
}

setIsIncremental(isIncremental) {
this.isIncremental = isIncremental;
}
Expand Down Expand Up @@ -176,7 +180,10 @@ class TemplatePassthrough {
});
}

const copyOptions = {
debug("Copying %o", this.inputPath);
let fileMap = await this.getFileMap();

let copyOptions = {
overwrite: true,
dot: true,
junk: false,
Expand All @@ -186,10 +193,19 @@ class TemplatePassthrough {
// e.g. `{ filePaths: [ './img/coolkid.jpg' ], relativePaths: [ '' ] }`
};

debug("Copying %o", this.inputPath);
let fileMap = await this.getFileMap();

let promises = fileMap.map((entry) => {
// For-free passthrough copy
if (this.runMode === "serve" || this.runMode === "watch") {
let aliasMap = {};
aliasMap[entry.inputPath] = entry.outputPath;

return Promise.resolve({
count: 0,
map: aliasMap,
});
}

// Copy the files (only in build mode)
return this.copy(entry.inputPath, entry.outputPath, copyOptions);
});

Expand Down
32 changes: 29 additions & 3 deletions src/TemplatePassthroughManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ class TemplatePassthroughManager {
this.isDryRun = !!isDryRun;
}

setRunMode(runMode) {
this.runMode = runMode;
}

setIncrementalFile(path) {
if (path) {
this.incrementalFile = path;
Expand Down Expand Up @@ -108,7 +112,11 @@ class TemplatePassthroughManager {
this.inputDir,
this.config
);

inst.setIsIncremental(isIncremental);
inst.setDryRun(this.isDryRun);
inst.setRunMode(this.runMode);

return inst;
}

Expand All @@ -121,8 +129,6 @@ class TemplatePassthroughManager {

let { inputPath } = pass.getPath();

pass.setDryRun(this.isDryRun);

// TODO https://github.com/11ty/eleventy/issues/2452
// De-dupe both the input and output paired together to avoid the case
// where an input/output pair has been added via multiple passthrough methods (glob, file suffix, etc)
Expand Down Expand Up @@ -260,6 +266,22 @@ class TemplatePassthroughManager {
return normalizedPaths;
}

// keys: output
// values: input
getAliasesFromPassthroughResults(result) {
let entries = {};
for (let entry of result) {
for (let src in entry.map) {
let dest = TemplatePath.stripLeadingSubPath(
entry.map[src],
this.outputDir
);
entries["/" + dest] = src;
}
}
return entries;
}

// Performance note: these can actually take a fair bit of time, but aren’t a
// bottleneck to eleventy. The copies are performed asynchronously and don’t affect eleventy
// write times in a significant way.
Expand All @@ -278,7 +300,11 @@ class TemplatePassthroughManager {

return Promise.all(
passthroughs.map((pass) => this.copyPassthrough(pass))
).then((result) => {
).then(async (result) => {
await this.config.events.emit("eleventy.passthrough", {
map: this.getAliasesFromPassthroughResults(result),
});

debug(`TemplatePassthrough copy finished. Current count: ${this.count}`);
return result;
});
Expand Down
10 changes: 8 additions & 2 deletions test/EleventyFilesTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,10 +362,13 @@ test("Glob Watcher Files with File Extension Passthroughs", async (t) => {

t.deepEqual(evf.getGlobWatcherFiles(), [
"./test/stubs/**/*.njk",
"./test/stubs/**/*.png",
"./test/stubs/_includes/**",
"./test/stubs/_data/**",
]);

t.deepEqual(evf.getGlobWatcherFilesForPassthroughCopy(), [
"./test/stubs/**/*.png",
]);
});

test("Glob Watcher Files with Config Passthroughs (one template format)", async (t) => {
Expand All @@ -388,10 +391,13 @@ test("Glob Watcher Files with Config Passthroughs (one template format)", async

t.deepEqual(evf.getGlobWatcherFiles(), [
"./test/stubs/**/*.njk",
"./test/stubs/img/**",
"./test/stubs/_includes/**",
"./test/stubs/_data/**",
]);

t.deepEqual(evf.getGlobWatcherFilesForPassthroughCopy(), [
"./test/stubs/img/**",
]);
});

test("Glob Watcher Files with Config Passthroughs (no template formats)", async (t) => {
Expand Down

0 comments on commit 93ff7cc

Please sign in to comment.