749 lines
20 KiB
JavaScript
749 lines
20 KiB
JavaScript
import os from "node:os";
|
||
|
||
import fs from "node:fs";
|
||
import matter from "gray-matter";
|
||
import lodash from "@11ty/lodash-custom";
|
||
import { TemplatePath } from "@11ty/eleventy-utils";
|
||
import debugUtil from "debug";
|
||
|
||
import TemplateData from "./Data/TemplateData.js";
|
||
import TemplateRender from "./TemplateRender.js";
|
||
import EleventyBaseError from "./Errors/EleventyBaseError.js";
|
||
import EleventyErrorUtil from "./Errors/EleventyErrorUtil.js";
|
||
import eventBus from "./EventBus.js";
|
||
|
||
import { withResolvers } from "./Util/PromiseUtil.js";
|
||
|
||
const { set: lodashSet } = lodash;
|
||
const debug = debugUtil("Eleventy:TemplateContent");
|
||
const debugDev = debugUtil("Dev:Eleventy:TemplateContent");
|
||
|
||
class TemplateContentFrontMatterError extends EleventyBaseError {}
|
||
class TemplateContentCompileError extends EleventyBaseError {}
|
||
class TemplateContentRenderError extends EleventyBaseError {}
|
||
|
||
class TemplateContent {
|
||
#initialized = false;
|
||
#config;
|
||
#templateRender;
|
||
#preprocessorEngine;
|
||
#extensionMap;
|
||
#configOptions;
|
||
|
||
constructor(inputPath, templateConfig) {
|
||
if (!templateConfig || templateConfig.constructor.name !== "TemplateConfig") {
|
||
throw new Error("Missing or invalid `templateConfig` argument");
|
||
}
|
||
this.eleventyConfig = templateConfig;
|
||
this.inputPath = inputPath;
|
||
}
|
||
|
||
async asyncTemplateInitialization() {
|
||
if (!this.hasTemplateRender()) {
|
||
await this.getTemplateRender();
|
||
}
|
||
|
||
if (this.#initialized) {
|
||
return;
|
||
}
|
||
this.#initialized = true;
|
||
|
||
let preprocessorEngineName = this.templateRender.getPreprocessorEngineName();
|
||
if (preprocessorEngineName && this.templateRender.engine.getName() !== preprocessorEngineName) {
|
||
let engine = await this.templateRender.getEngineByName(preprocessorEngineName);
|
||
this.#preprocessorEngine = engine;
|
||
}
|
||
}
|
||
|
||
resetCachedTemplate({ eleventyConfig }) {
|
||
this.eleventyConfig = eleventyConfig;
|
||
}
|
||
|
||
get dirs() {
|
||
return this.eleventyConfig.directories;
|
||
}
|
||
|
||
get inputDir() {
|
||
return this.dirs.input;
|
||
}
|
||
|
||
get outputDir() {
|
||
return this.dirs.output;
|
||
}
|
||
|
||
getResetTypes(types) {
|
||
if (types) {
|
||
return Object.assign(
|
||
{
|
||
data: false,
|
||
read: false,
|
||
render: false,
|
||
},
|
||
types,
|
||
);
|
||
}
|
||
|
||
return {
|
||
data: true,
|
||
read: true,
|
||
render: true,
|
||
};
|
||
}
|
||
|
||
// Called during an incremental build when the template instance is cached but needs to be reset because it has changed
|
||
resetCaches(types) {
|
||
types = this.getResetTypes(types);
|
||
|
||
if (types.read) {
|
||
delete this.readingPromise;
|
||
delete this.inputContent;
|
||
delete this._frontMatterDataCache;
|
||
}
|
||
if (types.render) {
|
||
this.#templateRender = undefined;
|
||
}
|
||
}
|
||
|
||
get extensionMap() {
|
||
if (!this.#extensionMap) {
|
||
throw new Error("Internal error: Missing `extensionMap` in TemplateContent.");
|
||
}
|
||
return this.#extensionMap;
|
||
}
|
||
|
||
set extensionMap(map) {
|
||
this.#extensionMap = map;
|
||
}
|
||
|
||
set eleventyConfig(config) {
|
||
this.#config = config;
|
||
|
||
if (this.#config.constructor.name === "TemplateConfig") {
|
||
this.#configOptions = this.#config.getConfig();
|
||
} else {
|
||
throw new Error("Tried to get an TemplateConfig but none was found.");
|
||
}
|
||
}
|
||
|
||
get eleventyConfig() {
|
||
if (this.#config.constructor.name === "TemplateConfig") {
|
||
return this.#config;
|
||
}
|
||
throw new Error("Tried to get an TemplateConfig but none was found.");
|
||
}
|
||
|
||
get config() {
|
||
if (this.#config.constructor.name === "TemplateConfig" && !this.#configOptions) {
|
||
this.#configOptions = this.#config.getConfig();
|
||
}
|
||
|
||
return this.#configOptions;
|
||
}
|
||
|
||
get bench() {
|
||
return this.config.benchmarkManager.get("Aggregate");
|
||
}
|
||
|
||
get engine() {
|
||
return this.templateRender.engine;
|
||
}
|
||
|
||
get templateRender() {
|
||
if (!this.hasTemplateRender()) {
|
||
throw new Error(`\`templateRender\` has not yet initialized on ${this.inputPath}`);
|
||
}
|
||
|
||
return this.#templateRender;
|
||
}
|
||
|
||
hasTemplateRender() {
|
||
return !!this.#templateRender;
|
||
}
|
||
|
||
async getTemplateRender() {
|
||
if (!this.#templateRender) {
|
||
this.#templateRender = new TemplateRender(this.inputPath, this.eleventyConfig);
|
||
this.#templateRender.extensionMap = this.extensionMap;
|
||
|
||
return this.#templateRender.init().then(() => {
|
||
return this.#templateRender;
|
||
});
|
||
}
|
||
|
||
return this.#templateRender;
|
||
}
|
||
|
||
// For monkey patchers
|
||
get frontMatter() {
|
||
if (this.frontMatterOverride) {
|
||
return this.frontMatterOverride;
|
||
} else {
|
||
throw new Error(
|
||
"Unfortunately you’re using code that monkey patched some Eleventy internals and it isn’t async-friendly. Change your code to use the async `read()` method on the template instead!",
|
||
);
|
||
}
|
||
}
|
||
|
||
// For monkey patchers
|
||
set frontMatter(contentOverride) {
|
||
this.frontMatterOverride = contentOverride;
|
||
}
|
||
|
||
getInputPath() {
|
||
return this.inputPath;
|
||
}
|
||
|
||
getInputDir() {
|
||
return this.inputDir;
|
||
}
|
||
|
||
isVirtualTemplate() {
|
||
let def = this.getVirtualTemplateDefinition();
|
||
return !!def;
|
||
}
|
||
|
||
getVirtualTemplateDefinition() {
|
||
let inputDirRelativeInputPath =
|
||
this.eleventyConfig.directories.getInputPathRelativeToInputDirectory(this.inputPath);
|
||
return this.config.virtualTemplates[inputDirRelativeInputPath];
|
||
}
|
||
|
||
async #read() {
|
||
let content = await this.inputContent;
|
||
|
||
if (content || content === "") {
|
||
let tr = await this.getTemplateRender();
|
||
if (tr.engine.useJavaScriptImport()) {
|
||
return {
|
||
data: {},
|
||
content,
|
||
};
|
||
}
|
||
|
||
let options = this.config.frontMatterParsingOptions || {};
|
||
let fm;
|
||
try {
|
||
// Added in 3.0, passed along to front matter engines
|
||
options.filePath = this.inputPath;
|
||
fm = matter(content, options);
|
||
} catch (e) {
|
||
throw new TemplateContentFrontMatterError(
|
||
`Having trouble reading front matter from template ${this.inputPath}`,
|
||
e,
|
||
);
|
||
}
|
||
|
||
if (options.excerpt && fm.excerpt) {
|
||
let excerptString = fm.excerpt + (options.excerpt_separator || "---");
|
||
if (fm.content.startsWith(excerptString + os.EOL)) {
|
||
// with an os-specific newline after excerpt separator
|
||
fm.content = fm.excerpt.trim() + "\n" + fm.content.slice((excerptString + os.EOL).length);
|
||
} else if (fm.content.startsWith(excerptString + "\n")) {
|
||
// with a newline (\n) after excerpt separator
|
||
// This is necessary for some git configurations on windows
|
||
fm.content = fm.excerpt.trim() + "\n" + fm.content.slice((excerptString + 1).length);
|
||
} else if (fm.content.startsWith(excerptString)) {
|
||
// no newline after excerpt separator
|
||
fm.content = fm.excerpt + fm.content.slice(excerptString.length);
|
||
}
|
||
|
||
// alias, defaults to page.excerpt
|
||
let alias = options.excerpt_alias || "page.excerpt";
|
||
lodashSet(fm.data, alias, fm.excerpt);
|
||
}
|
||
|
||
// For monkey patchers that used `frontMatter` 🤧
|
||
// https://github.com/11ty/eleventy/issues/613#issuecomment-999637109
|
||
// https://github.com/11ty/eleventy/issues/2710#issuecomment-1373854834
|
||
// Removed this._frontMatter monkey patcher help in 3.0.0-alpha.7
|
||
|
||
return fm;
|
||
} else {
|
||
return {
|
||
data: {},
|
||
content: "",
|
||
excerpt: "",
|
||
};
|
||
}
|
||
}
|
||
|
||
async read() {
|
||
if (!this.readingPromise) {
|
||
if (!this.inputContent) {
|
||
// @cachedproperty
|
||
this.inputContent = this.getInputContent();
|
||
}
|
||
|
||
// @cachedproperty
|
||
this.readingPromise = this.#read();
|
||
}
|
||
|
||
return this.readingPromise;
|
||
}
|
||
|
||
/* Incremental builds cache the Template instances (in TemplateWriter) but
|
||
* these template specific caches are important for Pagination */
|
||
static cache(path, content) {
|
||
this._inputCache.set(TemplatePath.absolutePath(path), content);
|
||
}
|
||
|
||
static getCached(path) {
|
||
return this._inputCache.get(TemplatePath.absolutePath(path));
|
||
}
|
||
|
||
static deleteFromInputCache(path) {
|
||
this._inputCache.delete(TemplatePath.absolutePath(path));
|
||
}
|
||
|
||
// Used via clone
|
||
setInputContent(content) {
|
||
this.inputContent = content;
|
||
}
|
||
|
||
async getInputContent() {
|
||
let tr = await this.getTemplateRender();
|
||
|
||
let virtualTemplateDefinition = this.getVirtualTemplateDefinition();
|
||
if (virtualTemplateDefinition) {
|
||
let { content } = virtualTemplateDefinition;
|
||
return content;
|
||
}
|
||
|
||
if (
|
||
tr.engine.useJavaScriptImport() &&
|
||
typeof tr.engine.getInstanceFromInputPath === "function"
|
||
) {
|
||
return tr.engine.getInstanceFromInputPath(this.inputPath);
|
||
}
|
||
|
||
if (!tr.engine.needsToReadFileContents()) {
|
||
return "";
|
||
}
|
||
|
||
let templateBenchmark = this.bench.get("Template Read");
|
||
templateBenchmark.before();
|
||
|
||
let content;
|
||
|
||
if (this.config.useTemplateCache) {
|
||
content = TemplateContent.getCached(this.inputPath);
|
||
}
|
||
|
||
if (!content && content !== "") {
|
||
let contentBuffer = fs.readFileSync(this.inputPath);
|
||
|
||
content = contentBuffer.toString("utf8");
|
||
|
||
if (this.config.useTemplateCache) {
|
||
TemplateContent.cache(this.inputPath, content);
|
||
}
|
||
}
|
||
|
||
templateBenchmark.after();
|
||
|
||
return content;
|
||
}
|
||
|
||
async _testGetFrontMatter() {
|
||
let fm = this.frontMatterOverride ? this.frontMatterOverride : await this.read();
|
||
|
||
return fm;
|
||
}
|
||
|
||
async getPreRender() {
|
||
let fm = this.frontMatterOverride ? this.frontMatterOverride : await this.read();
|
||
|
||
return fm.content;
|
||
}
|
||
|
||
async #getFrontMatterData() {
|
||
let fm = await this.read();
|
||
|
||
// gray-matter isn’t async-friendly but can return a promise from custom front matter
|
||
if (fm.data instanceof Promise) {
|
||
fm.data = await fm.data;
|
||
}
|
||
|
||
let tr = await this.getTemplateRender();
|
||
let extraData = await tr.engine.getExtraDataFromFile(this.inputPath);
|
||
|
||
let virtualTemplateDefinition = this.getVirtualTemplateDefinition();
|
||
let virtualTemplateData;
|
||
if (virtualTemplateDefinition) {
|
||
virtualTemplateData = virtualTemplateDefinition.data;
|
||
}
|
||
|
||
let data = Object.assign(fm.data, extraData, virtualTemplateData);
|
||
|
||
TemplateData.cleanupData(data, {
|
||
file: this.inputPath,
|
||
isVirtualTemplate: Boolean(virtualTemplateData),
|
||
});
|
||
|
||
return {
|
||
data,
|
||
excerpt: fm.excerpt,
|
||
};
|
||
}
|
||
|
||
async getFrontMatterData() {
|
||
if (!this._frontMatterDataCache) {
|
||
// @cachedproperty
|
||
this._frontMatterDataCache = this.#getFrontMatterData();
|
||
}
|
||
|
||
return this._frontMatterDataCache;
|
||
}
|
||
|
||
async getEngineOverride() {
|
||
return this.getFrontMatterData().then((data) => {
|
||
return data[this.config.keys.engineOverride];
|
||
});
|
||
}
|
||
|
||
// checks engines
|
||
isTemplateCacheable() {
|
||
if (this.#preprocessorEngine) {
|
||
return this.#preprocessorEngine.cacheable;
|
||
}
|
||
return this.engine.cacheable;
|
||
}
|
||
|
||
_getCompileCache(str) {
|
||
// Caches used to be bifurcated based on engine name, now they’re based on inputPath
|
||
// TODO does `cacheable` need to help inform whether a cache is used here?
|
||
let inputPathMap = TemplateContent._compileCache.get(this.inputPath);
|
||
if (!inputPathMap) {
|
||
inputPathMap = new Map();
|
||
TemplateContent._compileCache.set(this.inputPath, inputPathMap);
|
||
}
|
||
|
||
let cacheable = this.isTemplateCacheable();
|
||
let { useCache, key } = this.engine.getCompileCacheKey(str, this.inputPath);
|
||
|
||
// We also tie the compile cache key to the UserConfig instance, to alleviate issues with global template cache
|
||
// Better to move the cache to the Eleventy instance instead, no?
|
||
// (This specifically failed I18nPluginTest cases with filters being cached across tests and not having access to each plugin’s options)
|
||
key = this.eleventyConfig.userConfig._getUniqueId() + key;
|
||
|
||
return [cacheable, key, inputPathMap, useCache];
|
||
}
|
||
|
||
async compile(str, options = {}) {
|
||
let { type, bypassMarkdown, engineOverride } = options;
|
||
|
||
// Must happen before cacheable fetch below
|
||
// Likely only necessary for Eleventy Layouts, see TemplateMap->initDependencyMap
|
||
await this.asyncTemplateInitialization();
|
||
|
||
// this.templateRender is guaranteed here
|
||
let tr = await this.getTemplateRender();
|
||
if (engineOverride !== undefined) {
|
||
debugDev("%o overriding template engine to use %o", this.inputPath, engineOverride);
|
||
await tr.setEngineOverride(engineOverride, bypassMarkdown);
|
||
} else {
|
||
tr.setUseMarkdown(!bypassMarkdown);
|
||
}
|
||
if (bypassMarkdown && !this.engine.needsCompilation(str)) {
|
||
return function () {
|
||
return str;
|
||
};
|
||
}
|
||
|
||
debugDev("%o compile() using engine: %o", this.inputPath, tr.engineName);
|
||
|
||
try {
|
||
let res;
|
||
if (this.config.useTemplateCache) {
|
||
let [cacheable, key, cache, useCache] = this._getCompileCache(str);
|
||
if (cacheable && key) {
|
||
if (useCache && cache.has(key)) {
|
||
this.bench.get("(count) Template Compile Cache Hit").incrementCount();
|
||
return cache.get(key);
|
||
}
|
||
|
||
this.bench.get("(count) Template Compile Cache Miss").incrementCount();
|
||
|
||
// Compile cache is cleared when the resource is modified (below)
|
||
|
||
// Compilation is async, so we eagerly cache a Promise that eventually
|
||
// resolves to the compiled function
|
||
let withRes = withResolvers();
|
||
res = withRes.resolve;
|
||
|
||
cache.set(key, withRes.promise);
|
||
}
|
||
}
|
||
|
||
let typeStr = type ? ` ${type}` : "";
|
||
let templateBenchmark = this.bench.get(`Template Compile${typeStr}`);
|
||
let inputPathBenchmark = this.bench.get(`> Compile${typeStr} > ${this.inputPath}`);
|
||
templateBenchmark.before();
|
||
inputPathBenchmark.before();
|
||
|
||
let fn = await tr.getCompiledTemplate(str);
|
||
inputPathBenchmark.after();
|
||
templateBenchmark.after();
|
||
debugDev("%o getCompiledTemplate function created", this.inputPath);
|
||
if (this.config.useTemplateCache && res) {
|
||
res(fn);
|
||
}
|
||
return fn;
|
||
} catch (e) {
|
||
let [cacheable, key, cache] = this._getCompileCache(str);
|
||
if (cacheable && key) {
|
||
cache.delete(key);
|
||
}
|
||
debug(`Having trouble compiling template ${this.inputPath}: %O`, str);
|
||
throw new TemplateContentCompileError(
|
||
`Having trouble compiling template ${this.inputPath}`,
|
||
e,
|
||
);
|
||
}
|
||
}
|
||
|
||
getParseForSymbolsFunction(str) {
|
||
let engine = this.engine;
|
||
|
||
// Don’t use markdown as the engine to parse for symbols
|
||
// TODO pass in engineOverride here
|
||
if (this.#preprocessorEngine) {
|
||
engine = this.#preprocessorEngine;
|
||
}
|
||
|
||
if ("parseForSymbols" in engine) {
|
||
return () => {
|
||
if (Array.isArray(str)) {
|
||
return str
|
||
.filter((entry) => typeof entry === "string")
|
||
.map((entry) => engine.parseForSymbols(entry))
|
||
.flat();
|
||
}
|
||
if (typeof str === "string") {
|
||
return engine.parseForSymbols(str);
|
||
}
|
||
return [];
|
||
};
|
||
}
|
||
}
|
||
|
||
// used by computed data or for permalink functions
|
||
async _renderFunction(fn, ...args) {
|
||
let mixins = Object.assign({}, this.config.javascriptFunctions);
|
||
let result = await fn.call(mixins, ...args);
|
||
|
||
// normalize Buffer away if returned from permalink
|
||
if (Buffer.isBuffer(result)) {
|
||
return result.toString();
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
async renderComputedData(str, data) {
|
||
if (typeof str === "function") {
|
||
return this._renderFunction(str, data);
|
||
}
|
||
|
||
return this._render(str, data, {
|
||
type: "Computed Data",
|
||
bypassMarkdown: true,
|
||
});
|
||
}
|
||
|
||
async renderPermalink(permalink, data) {
|
||
let tr = await this.getTemplateRender();
|
||
let permalinkCompilation = tr.engine.permalinkNeedsCompilation(permalink);
|
||
|
||
// No string compilation:
|
||
// ({ compileOptions: { permalink: "raw" }})
|
||
// These mean `permalink: false`, which is no file system writing:
|
||
// ({ compileOptions: { permalink: false }})
|
||
// ({ compileOptions: { permalink: () => false }})
|
||
// ({ compileOptions: { permalink: () => (() = > false) }})
|
||
if (permalinkCompilation === false && typeof permalink !== "function") {
|
||
return permalink;
|
||
}
|
||
|
||
/* Custom `compile` function for permalinks, usage:
|
||
permalink: function(permalinkString, inputPath) {
|
||
return async function(data) {
|
||
return "THIS IS MY RENDERED PERMALINK";
|
||
}
|
||
}
|
||
*/
|
||
if (permalinkCompilation && typeof permalinkCompilation === "function") {
|
||
permalink = await this._renderFunction(permalinkCompilation, permalink, this.inputPath);
|
||
}
|
||
|
||
// Raw permalink function (in the app code data cascade)
|
||
if (typeof permalink === "function") {
|
||
return this._renderFunction(permalink, data);
|
||
}
|
||
|
||
return this._render(permalink, data, {
|
||
type: "Permalink",
|
||
bypassMarkdown: true,
|
||
});
|
||
}
|
||
|
||
async render(str, data, bypassMarkdown) {
|
||
return this._render(str, data, {
|
||
type: "Content",
|
||
bypassMarkdown,
|
||
});
|
||
}
|
||
|
||
_getPaginationLogSuffix(data) {
|
||
let suffix = [];
|
||
if ("pagination" in data) {
|
||
suffix.push(" (");
|
||
if (data.pagination.pages) {
|
||
suffix.push(
|
||
`${data.pagination.pages.length} page${data.pagination.pages.length !== 1 ? "s" : ""}`,
|
||
);
|
||
} else {
|
||
suffix.push("Pagination");
|
||
}
|
||
suffix.push(")");
|
||
}
|
||
return suffix.join("");
|
||
}
|
||
|
||
async _render(str, data, options = {}) {
|
||
let { bypassMarkdown, type } = options;
|
||
|
||
try {
|
||
if (bypassMarkdown && !this.engine.needsCompilation(str)) {
|
||
return str;
|
||
}
|
||
|
||
let fn = await this.compile(str, {
|
||
bypassMarkdown,
|
||
engineOverride: data[this.config.keys.engineOverride],
|
||
type,
|
||
});
|
||
|
||
if (fn === undefined) {
|
||
return;
|
||
} else if (typeof fn !== "function") {
|
||
throw new Error(`The \`compile\` function did not return a function. Received ${fn}`);
|
||
}
|
||
|
||
// Benchmark
|
||
let templateBenchmark = this.bench.get("Render");
|
||
let inputPathBenchmark = this.bench.get(
|
||
`> Render${type ? ` ${type}` : ""} > ${this.inputPath}${this._getPaginationLogSuffix(data)}`,
|
||
);
|
||
|
||
templateBenchmark.before();
|
||
if (inputPathBenchmark) {
|
||
inputPathBenchmark.before();
|
||
}
|
||
|
||
let rendered = await fn(data);
|
||
|
||
if (inputPathBenchmark) {
|
||
inputPathBenchmark.after();
|
||
}
|
||
templateBenchmark.after();
|
||
debugDev("%o getCompiledTemplate called, rendered content created", this.inputPath);
|
||
return rendered;
|
||
} catch (e) {
|
||
if (EleventyErrorUtil.isPrematureTemplateContentError(e)) {
|
||
return Promise.reject(e);
|
||
} else {
|
||
let tr = await this.getTemplateRender();
|
||
let engine = tr.getReadableEnginesList();
|
||
debug(`Having trouble rendering ${engine} template ${this.inputPath}: %O`, str);
|
||
return Promise.reject(
|
||
new TemplateContentRenderError(
|
||
`Having trouble rendering ${engine} template ${this.inputPath}`,
|
||
e,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
getExtensionEntries() {
|
||
return this.engine.extensionEntries;
|
||
}
|
||
|
||
isFileRelevantToThisTemplate(incrementalFile, metadata = {}) {
|
||
// always relevant if incremental file not set (build everything)
|
||
if (!incrementalFile) {
|
||
return true;
|
||
}
|
||
|
||
let hasDependencies = this.engine.hasDependencies(incrementalFile);
|
||
|
||
let isRelevant = this.engine.isFileRelevantTo(this.inputPath, incrementalFile);
|
||
|
||
debug(
|
||
"Test dependencies to see if %o is relevant to %o: %o",
|
||
this.inputPath,
|
||
incrementalFile,
|
||
isRelevant,
|
||
);
|
||
|
||
let extensionEntries = this.getExtensionEntries().filter((entry) => !!entry.isIncrementalMatch);
|
||
if (extensionEntries.length) {
|
||
for (let entry of extensionEntries) {
|
||
if (
|
||
entry.isIncrementalMatch.call(
|
||
{
|
||
inputPath: this.inputPath,
|
||
isFullTemplate: metadata.isFullTemplate,
|
||
isFileRelevantToInputPath: isRelevant,
|
||
doesFileHaveDependencies: hasDependencies,
|
||
},
|
||
incrementalFile,
|
||
)
|
||
) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
} else {
|
||
// Not great way of building all templates if this is a layout, include, JS dependency.
|
||
// TODO improve this for default template syntaxes
|
||
|
||
// This is the fallback way of determining if something is incremental (no isIncrementalMatch available)
|
||
// This will be true if the inputPath and incrementalFile are the same
|
||
if (isRelevant) {
|
||
return true;
|
||
}
|
||
|
||
// only return true here if dependencies are not known
|
||
if (!hasDependencies && !metadata.isFullTemplate) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
TemplateContent._inputCache = new Map();
|
||
TemplateContent._compileCache = new Map();
|
||
eventBus.on("eleventy.resourceModified", (path) => {
|
||
// delete from input cache
|
||
TemplateContent.deleteFromInputCache(path);
|
||
|
||
// delete from compile cache
|
||
let normalized = TemplatePath.addLeadingDotSlash(path);
|
||
let compileCache = TemplateContent._compileCache.get(normalized);
|
||
if (compileCache) {
|
||
compileCache.clear();
|
||
}
|
||
});
|
||
|
||
// Used when the configuration file reset https://github.com/11ty/eleventy/issues/2147
|
||
eventBus.on("eleventy.compileCacheReset", () => {
|
||
TemplateContent._compileCache = new Map();
|
||
});
|
||
|
||
export default TemplateContent;
|