@apleasantview/eleventy-plugin-baseline 0.1.0-next.32 → 0.1.0-next.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/debug.js +18 -3
- package/core/filters/isString.js +5 -0
- package/core/filters/markdown.js +6 -0
- package/core/filters/related-posts.js +6 -0
- package/core/helpers.js +6 -97
- package/core/logging.js +2 -2
- package/core/modules.js +0 -4
- package/core/shortcodes/image.js +162 -144
- package/eleventy.config.js +34 -22
- package/modules/assets-core/plugins/assets-core.js +126 -13
- package/modules/assets-esbuild/{filters/inline-esbuild.js → process.js} +10 -1
- package/modules/assets-postcss/process.js +49 -0
- package/modules/head-core/drivers/posthtml-head-elements.js +13 -18
- package/modules/head-core/plugins/head-core.js +19 -1
- package/modules/head-core/utils/head-utils.js +76 -10
- package/modules/multilang-core/plugins/multilang-core.js +26 -9
- package/modules/navigator-core/plugins/navigator-core.js +19 -1
- package/modules/navigator-core/templates/navigator-core.html +4 -4
- package/modules/sitemap-core/plugins/sitemap-core.js +23 -0
- package/modules/sitemap-core/templates/sitemap-core.html +27 -18
- package/modules/sitemap-core/templates/sitemap-index.html +1 -1
- package/package.json +1 -1
- package/modules/assets-esbuild/plugins/assets-esbuild.js +0 -71
- package/modules/assets-postcss/filters/inline-postcss.js +0 -38
- package/modules/assets-postcss/plugins/assets-postcss.js +0 -75
|
@@ -1,16 +1,38 @@
|
|
|
1
|
-
import Merge from '@11ty/eleventy-utils
|
|
2
|
-
import { TemplatePath } from '@11ty/eleventy-utils';
|
|
1
|
+
import { Merge, TemplatePath } from '@11ty/eleventy-utils';
|
|
3
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Return the first value that is neither undefined nor null.
|
|
5
|
+
* @param {...*} values
|
|
6
|
+
* @returns {*}
|
|
7
|
+
*/
|
|
4
8
|
const pick = (...values) => values.find((v) => v !== undefined && v !== null);
|
|
5
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Normalize a path prefix to match Eleventy's URL behavior.
|
|
12
|
+
* Returns empty string for root ('/'), otherwise the normalized prefix.
|
|
13
|
+
* @param {string} [pathPrefix='']
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
6
16
|
const normalizePathPrefix = (pathPrefix = '') => {
|
|
7
|
-
// Align with Eleventy’s normalizeUrlPath behavior
|
|
8
17
|
const normalized = TemplatePath.normalizeUrlPath('/', pathPrefix);
|
|
9
|
-
return normalized === '/' ? '' : normalized;
|
|
18
|
+
return normalized === '/' ? '' : normalized;
|
|
10
19
|
};
|
|
11
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Test whether a URL is absolute (has a scheme or is protocol-relative).
|
|
23
|
+
* @param {string} [url='']
|
|
24
|
+
* @returns {boolean}
|
|
25
|
+
*/
|
|
12
26
|
const isAbsoluteUrl = (url = '') => /^[a-z][a-z\d+\-.]*:\/\//i.test(url) || url.startsWith('//');
|
|
13
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Build an absolute URL from siteUrl + pathPrefix + relative URL.
|
|
30
|
+
* Returns the input unchanged if already absolute or empty.
|
|
31
|
+
* @param {string} siteUrl - Site root (e.g. 'https://example.com').
|
|
32
|
+
* @param {string} pathPrefix - Eleventy path prefix.
|
|
33
|
+
* @param {string} url - The URL to resolve.
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
14
36
|
const absoluteUrl = (siteUrl, pathPrefix, url) => {
|
|
15
37
|
if (!url) return url;
|
|
16
38
|
if (isAbsoluteUrl(url)) return url;
|
|
@@ -19,6 +41,19 @@ const absoluteUrl = (siteUrl, pathPrefix, url) => {
|
|
|
19
41
|
return siteUrl ? `${siteUrl.replace(/\/+$/, '')}${joined}` : joined;
|
|
20
42
|
};
|
|
21
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Merge site defaults, user overrides, and computed values into a raw head object.
|
|
46
|
+
* The result contains all head sections (meta, link, OG, twitter, etc.) before
|
|
47
|
+
* deduplication and flattening.
|
|
48
|
+
* @param {Object} site - Site-level data (site.yaml / site.json).
|
|
49
|
+
* @param {Object} user - Page-level head overrides (the `head` data key).
|
|
50
|
+
* @param {Object} page - Eleventy page object.
|
|
51
|
+
* @param {string} title - Resolved page title.
|
|
52
|
+
* @param {string} description - Resolved description.
|
|
53
|
+
* @param {boolean} noindex - Whether to set noindex/nofollow.
|
|
54
|
+
* @param {string} url - Canonical URL.
|
|
55
|
+
* @returns {Object} Merged head object.
|
|
56
|
+
*/
|
|
22
57
|
const mergeBaseHead = (site, user, page, title, description, noindex, url) => {
|
|
23
58
|
return Merge(
|
|
24
59
|
{},
|
|
@@ -54,6 +89,15 @@ const mergeBaseHead = (site, user, page, title, description, noindex, url) => {
|
|
|
54
89
|
);
|
|
55
90
|
};
|
|
56
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Resolve the canonical URL for a page. Uses an explicit canonical from head
|
|
94
|
+
* data if present, otherwise derives it from the page URL or content map.
|
|
95
|
+
* @param {Object} head - Head data (may contain a canonical property).
|
|
96
|
+
* @param {Object} page - Eleventy page object.
|
|
97
|
+
* @param {Object} contentMap - Cached inputPathToUrl / urlToInputPath maps.
|
|
98
|
+
* @param {Object} [env] - Environment options (siteUrl, pathPrefix, verbose).
|
|
99
|
+
* @returns {string|undefined} Absolute canonical URL, or undefined if unresolvable.
|
|
100
|
+
*/
|
|
57
101
|
const resolveCanonical = (head, page, contentMap, env = {}) => {
|
|
58
102
|
const { siteUrl, pathPrefix = '', pageUrlOverride, verbose } = env;
|
|
59
103
|
const explicit = pick(head.canonical);
|
|
@@ -74,6 +118,12 @@ const resolveCanonical = (head, page, contentMap, env = {}) => {
|
|
|
74
118
|
return absoluteUrl(siteUrl, pathPrefix, url);
|
|
75
119
|
};
|
|
76
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Deduplicate meta tags. Last-wins by key (charset, name, property, http-equiv).
|
|
123
|
+
* Preserves insertion order after dedup.
|
|
124
|
+
* @param {Array<Object>} [arr=[]] - Array of meta tag objects.
|
|
125
|
+
* @returns {Array<Object>}
|
|
126
|
+
*/
|
|
77
127
|
const dedupeMeta = (arr = []) => {
|
|
78
128
|
const seen = new Set();
|
|
79
129
|
const out = [];
|
|
@@ -95,6 +145,11 @@ const dedupeMeta = (arr = []) => {
|
|
|
95
145
|
return out.reverse();
|
|
96
146
|
};
|
|
97
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Deduplicate link tags by rel+href. Last-wins, preserves insertion order.
|
|
150
|
+
* @param {Array<Object>} [links=[]] - Array of link tag objects.
|
|
151
|
+
* @returns {Array<Object>}
|
|
152
|
+
*/
|
|
98
153
|
const dedupeLink = (links = []) => {
|
|
99
154
|
const seen = new Set();
|
|
100
155
|
const out = [];
|
|
@@ -108,8 +163,15 @@ const dedupeLink = (links = []) => {
|
|
|
108
163
|
return out.reverse();
|
|
109
164
|
};
|
|
110
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Flatten a merged head object into the shape posthtml-head-elements expects.
|
|
168
|
+
* Deduplicates meta and link tags, separates social meta, and prepends
|
|
169
|
+
* structured data as a JSON-LD script.
|
|
170
|
+
* @param {Object} [head={}] - Merged head object from mergeBaseHead.
|
|
171
|
+
* @param {string} canonical - Resolved canonical URL.
|
|
172
|
+
* @returns {Object} Flat head spec keyed by element type (meta, title, link, script, etc.).
|
|
173
|
+
*/
|
|
111
174
|
const flattenHead = (head = {}, canonical) => {
|
|
112
|
-
// base/meta first, keep OG/Twitter last by placing them in a separate meta bucket
|
|
113
175
|
const baseMeta = dedupeMeta([...(head.meta || []), ...(head.miscMeta || [])]);
|
|
114
176
|
|
|
115
177
|
const socialMeta = dedupeMeta([
|
|
@@ -150,6 +212,14 @@ const flattenHead = (head = {}, canonical) => {
|
|
|
150
212
|
};
|
|
151
213
|
};
|
|
152
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Build the complete head spec for a page. This is the main entry point —
|
|
217
|
+
* resolves title, description, canonical, merges everything, and flattens.
|
|
218
|
+
* Called from both the computed global data and the PostHTML transform fallback.
|
|
219
|
+
* @param {Object} [data={}] - Full Eleventy data cascade for the page.
|
|
220
|
+
* @param {Object} [env={}] - Environment options (userKey, contentMap, siteUrl, pathPrefix, verbose).
|
|
221
|
+
* @returns {Object} Flat head spec ready for posthtml-head-elements.
|
|
222
|
+
*/
|
|
153
223
|
const buildHead = (data = {}, env = {}) => {
|
|
154
224
|
const { userKey = 'head', contentMap = {}, siteUrl, pathPrefix } = env;
|
|
155
225
|
const site = data.site || {};
|
|
@@ -176,8 +246,4 @@ const buildHead = (data = {}, env = {}) => {
|
|
|
176
246
|
return flattenHead(merged, canonical);
|
|
177
247
|
};
|
|
178
248
|
|
|
179
|
-
|
|
180
|
-
return buildHead(context, { ...env, contentMap });
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
export { pick, resolveCanonical, flattenHead, buildHead, buildHeadSpec, absoluteUrl };
|
|
249
|
+
export { pick, resolveCanonical, flattenHead, buildHead, absoluteUrl };
|
|
@@ -5,12 +5,21 @@ import i18nTranslationIn from '../filters/i18n-translation-in.js';
|
|
|
5
5
|
import i18nDefaultTranslation from '../filters/i18n-default-translation.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* eleventy-plugin-multilang-core
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
*
|
|
10
|
+
* Language infrastructure for multilingual sites. Normalizes language metadata,
|
|
11
|
+
* builds a translations map keyed by translationKey + lang, and exposes
|
|
12
|
+
* relational filters for cross-language lookups. Wraps Eleventy's built-in
|
|
13
|
+
* I18nPlugin with stricter language validation.
|
|
14
|
+
*
|
|
15
|
+
* Depends on: Eleventy I18nPlugin (built-in), @11ty/eleventy-utils (DeepCopy).
|
|
16
|
+
* No cross-module dependencies. Sitemap-core receives language config via
|
|
17
|
+
* options at registration time, not through imports.
|
|
18
|
+
*
|
|
19
|
+
* Options:
|
|
20
|
+
* - defaultLanguage (string, default 'en'): fallback language code.
|
|
21
|
+
* - languages (array|object): allowed languages. Pages with unlisted langs are skipped.
|
|
22
|
+
* - verbose (boolean, default false): warn on unknown language codes.
|
|
14
23
|
*
|
|
15
24
|
* @param { import("@11ty/eleventy/src/UserConfig.js").default } eleventyConfig
|
|
16
25
|
*/
|
|
@@ -22,12 +31,13 @@ export default function multilangCore(eleventyConfig, options = {}) {
|
|
|
22
31
|
...options
|
|
23
32
|
};
|
|
24
33
|
|
|
34
|
+
// Register Eleventy's built-in I18nPlugin for locale-aware URL resolution.
|
|
25
35
|
eleventyConfig.addPlugin(I18nPlugin, {
|
|
26
36
|
defaultLanguage: userOptions.defaultLanguage,
|
|
27
37
|
errorMode: 'allow-fallback'
|
|
28
38
|
});
|
|
29
39
|
|
|
30
|
-
//
|
|
40
|
+
// Build a set of allowed language codes for validation during collection building.
|
|
31
41
|
const normalizeLang = (lang) => (lang || '').toLowerCase().trim();
|
|
32
42
|
const allowedLanguages = new Set(
|
|
33
43
|
Array.isArray(userOptions.languages)
|
|
@@ -35,6 +45,8 @@ export default function multilangCore(eleventyConfig, options = {}) {
|
|
|
35
45
|
: Object.keys(userOptions.languages || {}).map(normalizeLang)
|
|
36
46
|
);
|
|
37
47
|
|
|
48
|
+
// Computed locale data: every page gets a page.locale object with its
|
|
49
|
+
// resolved lang, translationKey, and whether it's the default language.
|
|
38
50
|
eleventyConfig.addGlobalData('eleventyComputed.page.locale', () => {
|
|
39
51
|
return (data) => {
|
|
40
52
|
const lang = normalizeLang(data.lang || data.language || userOptions.defaultLanguage);
|
|
@@ -49,6 +61,8 @@ export default function multilangCore(eleventyConfig, options = {}) {
|
|
|
49
61
|
};
|
|
50
62
|
});
|
|
51
63
|
|
|
64
|
+
// Build both the map (keyed by translationKey → lang) and the flat list.
|
|
65
|
+
// Shared logic for both collections — called once per collection registration.
|
|
52
66
|
const buildTranslations = (collection) => {
|
|
53
67
|
const map = {};
|
|
54
68
|
const list = [];
|
|
@@ -84,17 +98,20 @@ export default function multilangCore(eleventyConfig, options = {}) {
|
|
|
84
98
|
return { map, list };
|
|
85
99
|
};
|
|
86
100
|
|
|
87
|
-
//
|
|
101
|
+
// --- Collections ---
|
|
102
|
+
|
|
103
|
+
// Map form: translationsMap[translationKey][lang] → page metadata.
|
|
88
104
|
eleventyConfig.addCollection('translationsMap', (collection) => {
|
|
89
105
|
return buildTranslations(collection).map;
|
|
90
106
|
});
|
|
91
107
|
|
|
92
|
-
//
|
|
108
|
+
// Flat list: all translatable pages with locale data attached.
|
|
93
109
|
eleventyConfig.addCollection('translations', (collection) => {
|
|
94
110
|
return buildTranslations(collection).list;
|
|
95
111
|
});
|
|
96
112
|
|
|
97
|
-
// Filters
|
|
113
|
+
// --- Filters ---
|
|
114
|
+
// Relational helpers for cross-language lookups in templates.
|
|
98
115
|
eleventyConfig.addFilter('i18nTranslationsFor', i18nTranslationsFor);
|
|
99
116
|
eleventyConfig.addFilter('i18nTranslationIn', i18nTranslationIn);
|
|
100
117
|
eleventyConfig.addFilter('i18nDefaultTranslation', i18nDefaultTranslation);
|
|
@@ -5,6 +5,20 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = path.dirname(__filename);
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* eleventy-plugin-navigator-core
|
|
10
|
+
*
|
|
11
|
+
* Debug tooling. Exposes the full Nunjucks environment and template context
|
|
12
|
+
* as globals so templates can inspect what data is available at render time.
|
|
13
|
+
* Optionally registers a virtual /navigator-core.html page that dumps
|
|
14
|
+
* everything in a readable format.
|
|
15
|
+
*
|
|
16
|
+
* No dependencies on other modules or core utilities. Standalone.
|
|
17
|
+
*
|
|
18
|
+
* Options:
|
|
19
|
+
* - enableNavigatorTemplate (boolean|[boolean, number]): register the debug page.
|
|
20
|
+
* Pass [true, depth] to control inspector depth (default 2).
|
|
21
|
+
*/
|
|
8
22
|
/** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
|
|
9
23
|
export default function navigatorCore(eleventyConfig, options = {}) {
|
|
10
24
|
const raw = options.enableNavigatorTemplate;
|
|
@@ -16,6 +30,9 @@ export default function navigatorCore(eleventyConfig, options = {}) {
|
|
|
16
30
|
inspectorDepth: inspectorDepth ?? 2
|
|
17
31
|
};
|
|
18
32
|
|
|
33
|
+
// --- Globals ---
|
|
34
|
+
// _navigator: the full Nunjucks runtime environment (this).
|
|
35
|
+
// _context: the template context object (this.ctx) — what templates actually see.
|
|
19
36
|
eleventyConfig.addNunjucksGlobal('_navigator', function () {
|
|
20
37
|
return this;
|
|
21
38
|
});
|
|
@@ -23,8 +40,9 @@ export default function navigatorCore(eleventyConfig, options = {}) {
|
|
|
23
40
|
return this.ctx;
|
|
24
41
|
});
|
|
25
42
|
|
|
43
|
+
// --- Virtual debug template ---
|
|
26
44
|
if (userOptions.enableNavigatorTemplate) {
|
|
27
|
-
// Read
|
|
45
|
+
// Read synchronously — Nunjucks virtual template registration is sync-only.
|
|
28
46
|
const templatePath = path.join(__dirname, '../templates/navigator-core.html');
|
|
29
47
|
const virtualTemplateContent = fs.readFileSync(templatePath, 'utf-8');
|
|
30
48
|
eleventyConfig.addTemplate('navigator-core.html', virtualTemplateContent, {
|
|
@@ -42,7 +42,7 @@ permalink: /navigator-core.html
|
|
|
42
42
|
<details>
|
|
43
43
|
<summary><strong>{{ key }}</strong></summary>
|
|
44
44
|
{% if value | isString %}
|
|
45
|
-
<pre>{{ value
|
|
45
|
+
<pre>{{ value }}</pre>
|
|
46
46
|
{% else %}
|
|
47
47
|
<pre>{{ value | _inspect({ depth: inspectorDepth }) }}</pre>
|
|
48
48
|
{% endif %}
|
|
@@ -56,9 +56,9 @@ permalink: /navigator-core.html
|
|
|
56
56
|
history.back();
|
|
57
57
|
});
|
|
58
58
|
</script>
|
|
59
|
+
<footer>
|
|
60
|
+
<div class="_navigator__wrapper"><small>Navigator Core — Eleventy Plugin Baseline</small></div>
|
|
61
|
+
</footer>
|
|
59
62
|
</body>
|
|
60
|
-
<footer>
|
|
61
|
-
<div class="_navigator__wrapper"><small>Navigator Core — Eleventy Plugin Baseline</small></div>
|
|
62
|
-
</footer>
|
|
63
63
|
|
|
64
64
|
</html>
|
|
@@ -5,6 +5,23 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = path.dirname(__filename);
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* eleventy-plugin-sitemap-core
|
|
10
|
+
*
|
|
11
|
+
* Generates XML sitemaps. Adds a computed page.sitemap object to every page
|
|
12
|
+
* (with ignore/changefreq/priority), then registers virtual templates for
|
|
13
|
+
* the sitemap XML. In multilingual mode, produces per-language sitemaps plus
|
|
14
|
+
* a sitemap index. Pages opt out via noindex in data.
|
|
15
|
+
*
|
|
16
|
+
* No cross-module dependencies. Receives multilingual config (languages,
|
|
17
|
+
* multilingual flag) via options at registration time — does not import
|
|
18
|
+
* from multilang-core.
|
|
19
|
+
*
|
|
20
|
+
* Options:
|
|
21
|
+
* - enableSitemapTemplate (boolean, default true): register virtual sitemap templates.
|
|
22
|
+
* - multilingual (boolean): force multilingual mode. Auto-detected from languages if omitted.
|
|
23
|
+
* - languages (array|object): language codes. Determines per-language sitemap generation.
|
|
24
|
+
*/
|
|
8
25
|
/** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
|
|
9
26
|
export default function sitemapCore(eleventyConfig, options = {}) {
|
|
10
27
|
const userOptions = {
|
|
@@ -13,6 +30,8 @@ export default function sitemapCore(eleventyConfig, options = {}) {
|
|
|
13
30
|
languages: options.languages
|
|
14
31
|
};
|
|
15
32
|
|
|
33
|
+
// Computed sitemap data: every page gets a page.sitemap object.
|
|
34
|
+
// Pages set noindex in frontmatter or site data to be excluded.
|
|
16
35
|
eleventyConfig.addGlobalData('eleventyComputed.page.sitemap', () => {
|
|
17
36
|
return (data) => ({
|
|
18
37
|
ignore: data.noindex ?? data.page?.noindex ?? data.site?.noindex ?? false,
|
|
@@ -21,6 +40,10 @@ export default function sitemapCore(eleventyConfig, options = {}) {
|
|
|
21
40
|
});
|
|
22
41
|
});
|
|
23
42
|
|
|
43
|
+
// --- Virtual sitemap templates ---
|
|
44
|
+
// Read template sources synchronously (same constraint as navigator-core).
|
|
45
|
+
// In multilingual mode: one sitemap per language + a sitemap index.
|
|
46
|
+
// In single-language mode: one flat sitemap at /sitemap.xml.
|
|
24
47
|
if (userOptions.enableSitemapTemplate) {
|
|
25
48
|
const templatePath = path.join(__dirname, '../templates/sitemap-core.html');
|
|
26
49
|
const indexTemplatePath = path.join(__dirname, '../templates/sitemap-index.html');
|
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
|
2
2
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
3
|
-
{%- if not site.noindex
|
|
4
|
-
{%- for item in collections.all
|
|
5
|
-
{%- if not item.data.eleventyExcludeFromCollections and (not item.data.sitemap or item.data.sitemap.ignore != true) and item.data.noindex != true
|
|
6
|
-
{%- set pageLang = item.data.lang or site.defaultLanguage
|
|
7
|
-
{%- if (not isMultilingual) or (not sitemapLang) or (pageLang == sitemapLang)
|
|
8
|
-
{%- set absoluteUrl = item.url | htmlBaseUrl
|
|
9
|
-
{%- set lastmod = item.data.sitemap and item.data.sitemap.lastmod or item.date
|
|
3
|
+
{%- if not site.noindex %}
|
|
4
|
+
{%- for item in collections.all %}
|
|
5
|
+
{%- if not item.data.eleventyExcludeFromCollections and (not item.data.sitemap or item.data.sitemap.ignore != true) and item.data.noindex != true %}
|
|
6
|
+
{%- set pageLang = item.data.lang or site.defaultLanguage %}
|
|
7
|
+
{%- if (not isMultilingual) or (not sitemapLang) or (pageLang == sitemapLang) %}
|
|
8
|
+
{%- set absoluteUrl = item.url | htmlBaseUrl %}
|
|
9
|
+
{%- set lastmod = item.data.sitemap and item.data.sitemap.lastmod or item.date %}
|
|
10
10
|
<url>
|
|
11
11
|
<loc>{{ absoluteUrl }}</loc>
|
|
12
|
-
{%- if lastmod
|
|
13
|
-
|
|
14
|
-
{%-
|
|
15
|
-
{%- if item.data.
|
|
16
|
-
{
|
|
12
|
+
{%- if lastmod %}
|
|
13
|
+
<lastmod>{{ date.toUTCISO(lastmod) }}</lastmod>
|
|
14
|
+
{%- endif %}
|
|
15
|
+
{%- if item.data.sitemap and item.data.sitemap.changefreq %}
|
|
16
|
+
<changefreq>{{ item.data.sitemap.changefreq }}</changefreq>
|
|
17
|
+
{%- endif %}
|
|
18
|
+
{%- if item.data.sitemap and item.data.sitemap.priority is defined %}
|
|
19
|
+
<priority>{{ item.data.sitemap.priority }}</priority>
|
|
20
|
+
{%- endif %}
|
|
21
|
+
{%- if item.data.translationKey and collections.translationsMap and collections.translationsMap[item.data.translationKey] %}
|
|
22
|
+
{%- for language, entry in collections.translationsMap[item.data.translationKey] %}
|
|
17
23
|
<xhtml:link rel="alternate" hreflang="{{ entry.lang }}" href="{{ entry.url | htmlBaseUrl }}" />
|
|
18
|
-
{%-
|
|
19
|
-
{
|
|
24
|
+
{%- if entry.isDefaultLang %}
|
|
25
|
+
<xhtml:link rel="alternate" hreflang="x-default" href="{{ entry.url | htmlBaseUrl }}" />
|
|
26
|
+
{%- endif %}
|
|
27
|
+
{%- endfor %}
|
|
28
|
+
{%- endif %}
|
|
20
29
|
</url>
|
|
21
|
-
{%- endif
|
|
22
|
-
{%- endif
|
|
23
|
-
{%- endfor
|
|
24
|
-
{%- endif
|
|
30
|
+
{%- endif %}
|
|
31
|
+
{%- endif %}
|
|
32
|
+
{%- endfor %}
|
|
33
|
+
{%- endif %}
|
|
25
34
|
</urlset>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
|
2
2
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
3
3
|
{%- if not site.noindex %}
|
|
4
|
-
{%- set langs = _baseline.languages
|
|
4
|
+
{%- set langs = _baseline.languages %}
|
|
5
5
|
{%- if langs %}
|
|
6
6
|
{%- for lang, cfg in langs %}
|
|
7
7
|
<sitemap>
|
package/package.json
CHANGED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import * as esbuild from 'esbuild';
|
|
3
|
-
import { resolveAssetsDir } from '../../../core/helpers.js';
|
|
4
|
-
import inlineESbuild from '../filters/inline-esbuild.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* assets-esbuild
|
|
8
|
-
*
|
|
9
|
-
* - Registers `js` as a template format and bundles/minifies `index.js` entries under the resolved assets `js` dir.
|
|
10
|
-
* - Registers `inlineESbuild` filter to inline arbitrary JS by bundling it with esbuild.
|
|
11
|
-
* - Filters the `all` collection to drop `11tydata.js` files (added by the `js` template format).
|
|
12
|
-
*
|
|
13
|
-
* Options:
|
|
14
|
-
* - minify (boolean, default true): pass-through to esbuild minify flag.
|
|
15
|
-
* - target (string|string[], default "es2020"): pass-through to esbuild target.
|
|
16
|
-
*/
|
|
17
|
-
/** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
|
|
18
|
-
export default function assetsESBuild(eleventyConfig, options = {}) {
|
|
19
|
-
const defaultOptions = { minify: true, target: 'es2020' };
|
|
20
|
-
const { assetsDir } = resolveAssetsDir(
|
|
21
|
-
eleventyConfig.dir?.input || './',
|
|
22
|
-
eleventyConfig.dir?.output || './',
|
|
23
|
-
eleventyConfig.dir?.assets || 'assets'
|
|
24
|
-
);
|
|
25
|
-
const jsDir = `${assetsDir}js/`;
|
|
26
|
-
const userOptions = { ...defaultOptions, ...options };
|
|
27
|
-
|
|
28
|
-
eleventyConfig.addTemplateFormats('js');
|
|
29
|
-
|
|
30
|
-
eleventyConfig.addExtension('js', {
|
|
31
|
-
outputFileExtension: 'js',
|
|
32
|
-
useLayouts: false,
|
|
33
|
-
compile: async function (_inputContent, inputPath) {
|
|
34
|
-
if (
|
|
35
|
-
inputPath.includes('11tydata.js') ||
|
|
36
|
-
!inputPath.startsWith(jsDir) ||
|
|
37
|
-
path.basename(inputPath) !== 'index.js'
|
|
38
|
-
) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return async () => {
|
|
43
|
-
let result = await esbuild.build({
|
|
44
|
-
entryPoints: [inputPath],
|
|
45
|
-
bundle: true,
|
|
46
|
-
minify: userOptions.minify,
|
|
47
|
-
target: userOptions.target,
|
|
48
|
-
write: false
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
return result.outputFiles[0].text;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// Filter to inline a bundled entry; supports callback style (Nunjucks/Liquid) and Promise return.
|
|
57
|
-
eleventyConfig.addAsyncFilter('inlineESbuild', async function (jsFilePath, callback) {
|
|
58
|
-
const done = typeof callback === 'function' ? callback : null;
|
|
59
|
-
try {
|
|
60
|
-
const js = await inlineESbuild(jsFilePath);
|
|
61
|
-
const html = `<script>${js}</script>`;
|
|
62
|
-
if (done) return done(null, html);
|
|
63
|
-
return html;
|
|
64
|
-
} catch {
|
|
65
|
-
// Non-fatal fallback: return an error comment wrapped in script tags.
|
|
66
|
-
const html = `<script>/* Error processing JS */</script>`;
|
|
67
|
-
if (done) return done(null, html);
|
|
68
|
-
return html;
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import postcss from 'postcss';
|
|
3
|
-
import loadPostCSSConfig from 'postcss-load-config';
|
|
4
|
-
import fallbackPostCSSConfig from '../fallback/postcss.config.js';
|
|
5
|
-
|
|
6
|
-
// Resolve user PostCSS config from the project root (cwd), not the Eleventy input dir.
|
|
7
|
-
const configRoot = process.cwd();
|
|
8
|
-
|
|
9
|
-
export default async function inlinePostCSS(cssFilePath) {
|
|
10
|
-
try {
|
|
11
|
-
let cssContent = await fs.readFile(cssFilePath, 'utf8');
|
|
12
|
-
|
|
13
|
-
let plugins;
|
|
14
|
-
let options;
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
// Prefer the consuming project's PostCSS config (postcss.config.* or package.json#postcss).
|
|
18
|
-
({ plugins, options } = await loadPostCSSConfig({}, configRoot));
|
|
19
|
-
} catch {
|
|
20
|
-
// If none is found, fall back to the bundled Baseline config to keep builds working.
|
|
21
|
-
const { plugins: fallbackPlugins, ...fallbackOptions } = fallbackPostCSSConfig;
|
|
22
|
-
plugins = fallbackPlugins;
|
|
23
|
-
options = fallbackOptions;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let result = await postcss(plugins).process(cssContent, {
|
|
27
|
-
from: cssFilePath,
|
|
28
|
-
map: options?.map
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Return raw CSS; markup wrapping is handled in the plugin registration.
|
|
32
|
-
return result.css;
|
|
33
|
-
} catch (error) {
|
|
34
|
-
console.error(error);
|
|
35
|
-
// Surface a safe CSS string so the caller can decide how to wrap it.
|
|
36
|
-
return '/* Error processing CSS */';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import postcss from 'postcss';
|
|
3
|
-
import loadPostCSSConfig from 'postcss-load-config';
|
|
4
|
-
import fallbackPostCSSConfig from '../fallback/postcss.config.js';
|
|
5
|
-
import inlinePostCSS from '../filters/inline-postcss.js';
|
|
6
|
-
import { resolveAssetsDir } from '../../../core/helpers.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* assets-postcss
|
|
10
|
-
*
|
|
11
|
-
* - Registers `css` as a template format and processes `index.css` entries under the resolved assets `css` dir with PostCSS.
|
|
12
|
-
* - Registers `inlinePostCSS` filter to inline arbitrary CSS by processing it with PostCSS.
|
|
13
|
-
* - No module-specific options (inherits global Baseline verbose only).
|
|
14
|
-
*/
|
|
15
|
-
/** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
|
|
16
|
-
export default function assetsPostCSS(eleventyConfig) {
|
|
17
|
-
const { assetsDir } = resolveAssetsDir(
|
|
18
|
-
eleventyConfig.dir?.input || './',
|
|
19
|
-
eleventyConfig.dir?.output || './',
|
|
20
|
-
eleventyConfig.dir?.assets || 'assets'
|
|
21
|
-
);
|
|
22
|
-
const cssDir = `${assetsDir}css/`;
|
|
23
|
-
|
|
24
|
-
// Resolve user PostCSS config from the project root (cwd), not the Eleventy input dir.
|
|
25
|
-
const configRoot = process.cwd();
|
|
26
|
-
|
|
27
|
-
eleventyConfig.addTemplateFormats('css');
|
|
28
|
-
|
|
29
|
-
eleventyConfig.addExtension('css', {
|
|
30
|
-
outputFileExtension: 'css',
|
|
31
|
-
useLayouts: false,
|
|
32
|
-
compile: async function (_inputContent, inputPath) {
|
|
33
|
-
if (!inputPath.startsWith(cssDir) || path.basename(inputPath) !== 'index.css') {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return async () => {
|
|
38
|
-
let plugins;
|
|
39
|
-
let options;
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
// Prefer the consuming project's PostCSS config (postcss.config.* or package.json#postcss).
|
|
43
|
-
({ plugins, options } = await loadPostCSSConfig({}, configRoot));
|
|
44
|
-
} catch {
|
|
45
|
-
// If none is found, fall back to the bundled Baseline config to keep builds working.
|
|
46
|
-
({ plugins, ...options } = fallbackPostCSSConfig);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const result = await postcss(plugins).process(_inputContent, {
|
|
50
|
-
from: inputPath,
|
|
51
|
-
map: options?.map,
|
|
52
|
-
...options
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
return result.css;
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Filter to inline a bundled entry; supports callback style (Nunjucks/Liquid) and Promise return.
|
|
61
|
-
eleventyConfig.addAsyncFilter('inlinePostCSS', async function (cssFilePath, callback) {
|
|
62
|
-
const done = typeof callback === 'function' ? callback : null;
|
|
63
|
-
try {
|
|
64
|
-
const css = await inlinePostCSS(cssFilePath);
|
|
65
|
-
const html = `<style>${css}</style>`;
|
|
66
|
-
if (done) return done(null, html);
|
|
67
|
-
return html;
|
|
68
|
-
} catch {
|
|
69
|
-
// Keep behavior non-fatal: return a styled error comment instead of throwing.
|
|
70
|
-
const html = `<style>/* Error processing CSS */</style>`;
|
|
71
|
-
if (done) return done(null, html);
|
|
72
|
-
return html;
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|