Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache intermediate NJK template compiles #1529

Merged
merged 10 commits into from
Feb 6, 2021
3 changes: 2 additions & 1 deletion src/Eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const deleteRequireCache = require("./Util/DeleteRequireCache");
const config = require("./Config");
const bench = require("./BenchmarkManager");
const debug = require("debug")("Eleventy");
const eventBus = require("./EventBus");

/**
* @module 11ty/eleventy/Eleventy
Expand Down Expand Up @@ -449,7 +450,7 @@ Arguments:
* @param {String} changedFilePath - File that triggered a re-run (added or modified)
*/
async _addFileToWatchQueue(changedFilePath) {
TemplateContent.deleteCached(changedFilePath);
eventBus.emit("resourceModified", changedFilePath);
this.watchManager.addToPendingQueue(changedFilePath);
}

Expand Down
35 changes: 24 additions & 11 deletions src/Engines/Nunjucks.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ const TemplateEngine = require("./TemplateEngine");
const TemplatePath = require("../TemplatePath");
const EleventyErrorUtil = require("../EleventyErrorUtil");
const EleventyBaseError = require("../EleventyBaseError");
const eventBus = require("../EventBus");

/*
* This IFFE applies a monkey-patch to Nunjucks internals to cache
* The IFFE below apply a monkey-patch to Nunjucks internals to cache
* compiled templates and re-use them where possible.
*/
(function () {
Expand All @@ -24,6 +25,17 @@ const EleventyBaseError = require("../EleventyBaseError");
].join(" :: ");
};

let evictByPath = (path) => {
let keys = templateCache.keys();
// Likely to be slow; do we care?
for (let k of keys) {
if (k.indexOf(path) >= 0) {
templateCache.delete(k);
}
}
};
eventBus.on("resourceModified", evictByPath);

let _compile = NunjucksLib.Template.prototype._compile;
NunjucksLib.Template.prototype._compile = function _wrap_compile(...args) {
if (!this.compiled && !this.tmplProps && templateCache.has(getKey(this))) {
Expand Down Expand Up @@ -109,16 +121,17 @@ class Nunjucks extends TemplateEngine {
}

setLibrary(env) {
this.njkEnv =
env ||
new NunjucksLib.Environment(
new NunjucksLib.FileSystemLoader(
[super.getIncludesDir(), TemplatePath.getWorkingDir()],
{
noCache: true,
}
)
);
let fsLoader = new NunjucksLib.FileSystemLoader([
super.getIncludesDir(),
TemplatePath.getWorkingDir(),
]);
this.njkEnv = env || new NunjucksLib.Environment(fsLoader);
// Correct, but overbroad. Better would be to evict more granularly, but
// resolution from paths isn't straightforward.
eventBus.on("resourceModified", (path) => {
this.njkEnv.invalidateCache();
});

this.setEngineLib(this.njkEnv);

this.addFilters(this.config.nunjucksFilters);
Expand Down
17 changes: 17 additions & 0 deletions src/EventBus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const EventEmitter = require("./Util/AsyncEventEmitter");
const debug = require("debug")("Eleventy:EventBus");

/**
* @module 11ty/eleventy/EventBus
*/

debug("Setting up global EventBus.");
/**
* Provides a global event bus that modules deep down in the stack can
* subscribe to from a global singleton for decoupled pub/sub.
* @type * {module:11ty/eleventy/Util/AsyncEventEmitter~AsyncEventEmitter}
*/
let bus = new EventEmitter();
bus.setMaxListeners(100);

module.exports = bus;
4 changes: 4 additions & 0 deletions src/TemplateContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const config = require("./Config");
const debug = require("debug")("Eleventy:TemplateContent");
const debugDev = require("debug")("Dev:Eleventy:TemplateContent");
const bench = require("./BenchmarkManager").get("Aggregate");
const eventBus = require("./EventBus");

class TemplateContentFrontMatterError extends EleventyBaseError {}
class TemplateContentCompileError extends EleventyBaseError {}
Expand Down Expand Up @@ -277,5 +278,8 @@ class TemplateContent {

TemplateContent._inputCache = new Map();
TemplateContent._compileEngineCache = new Map();
eventBus.on("resourceModified", (path) => {
TemplateContent.deleteCached(path);
});

module.exports = TemplateContent;
28 changes: 18 additions & 10 deletions test/TemplateTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2049,11 +2049,9 @@ test("Engine Singletons", async (t) => {
});

test("Make sure layout cache takes new changes during watch (nunjucks)", async (t) => {
await fsp.writeFile(
"./test/stubs-layout-cache/_includes/include-script-1.js",
`alert("hi");`,
{ encoding: "utf8" }
);
let filePath = "./test/stubs-layout-cache/_includes/include-script-1.js";

await fsp.writeFile(filePath, `alert("hi");`, { encoding: "utf8" });

let tmpl = getNewTemplate(
"./test/stubs-layout-cache/test.njk",
Expand All @@ -2065,13 +2063,23 @@ test("Make sure layout cache takes new changes during watch (nunjucks)", async (

t.is((await tmpl.render(data)).trim(), '<script>alert("hi");</script>');

await fsp.writeFile(
"./test/stubs-layout-cache/_includes/include-script-1.js",
`alert("bye");`,
{ encoding: "utf8" }
);
let eventBus = require("../src/EventBus");
let chokidar = require("chokidar");
let watcher = chokidar.watch(filePath, { interval: 10, persistent: true });
watcher.on("change", (path, stats) => {
eventBus.emit("resourceModified", path);
});

await fsp.writeFile(filePath, `alert("bye");`, { encoding: "utf8" });
slightlyoff marked this conversation as resolved.
Show resolved Hide resolved

// Give Chokidar time to see the change;
await new Promise((res, rej) => {
setTimeout(res, 200);
});

t.is((await tmpl.render(data)).trim(), '<script>alert("bye");</script>');

await watcher.close();
});

test("Make sure layout cache takes new changes during watch (liquid)", async (t) => {
Expand Down