-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheleventy.config.js
More file actions
178 lines (159 loc) · 7.72 KB
/
Copy patheleventy.config.js
File metadata and controls
178 lines (159 loc) · 7.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
const yaml = require("js-yaml");
const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
// ---- Edition switch -------------------------------------------------------
// One repo, two editions. Pick with EDITION=com|org (default: org).
// EDITION=org -> imqueue.org, "Terminal" skin, output _site-org
// EDITION=com -> imqueue.com, "Flux" skin, output _site-com
const EDITION = (process.env.EDITION || "org").toLowerCase();
const isCom = EDITION === "com";
const SKIN = isCom ? "flux" : "terminal";
const SITE_URL = isCom ? "https://imqueue.com" : "https://imqueue.org";
const OTHER_URL = isCom ? "https://imqueue.org" : "https://imqueue.com";
const OUTPUT = isCom ? "_site-com" : "_site-org";
module.exports = function (eleventyConfig) {
const markdownIt = require("markdown-it");
const mdAnchor = require("markdown-it-anchor");
const mdToc = require("markdown-it-table-of-contents");
const mdAttrs = require("markdown-it-attrs");
const md = markdownIt({ html: true, linkify: false, typographer: false })
.use(mdAttrs)
.use(mdAnchor, { permalink: false, tabIndex: false })
.use(mdToc, {
includeLevel: [2, 3],
containerHeaderHtml: undefined,
markerPattern: /^\[\[toc\]\]/im,
});
eleventyConfig.setLibrary("md", md);
eleventyConfig.addPlugin(syntaxHighlight);
// Standard LiquidJS: quoted/variable partials + comma-separated include args.
eleventyConfig.setLiquidOptions({
dynamicPartials: true,
jekyllInclude: false,
strictFilters: false,
});
eleventyConfig.addDataExtension("yml", (contents) => yaml.load(contents));
// Edition-wide values available in every template.
eleventyConfig.addGlobalData("edition", EDITION);
eleventyConfig.addGlobalData("skin", SKIN);
eleventyConfig.addGlobalData("siteUrl", SITE_URL);
eleventyConfig.addGlobalData("otherUrl", OTHER_URL);
eleventyConfig.addGlobalData("siteName", "@imqueue");
// ---- SEO defaults (per edition) -----------------------------------------
// Page front matter can override `keywords`, `ogType`, `ogImage` and
// `description`; these are the site-wide fallbacks head.html reaches for.
const ORG_KEYWORDS = [
"@imqueue", "imqueue", "Node.js message queue", "TypeScript RPC",
"message queue RPC", "RPC over Redis", "Redis message queue",
"microservices framework", "Node.js microservices",
"TypeScript microservices", "service-oriented architecture", "SOA",
"inter-service communication", "self-describing services",
"typed RPC framework", "distributed systems", "message broker",
"scalable back-end services", "GraphQL microservices",
].join(", ");
const COM_KEYWORDS = [
"@imqueue commercial license", "imqueue license",
"GPL-3.0 commercial license", "dual license", "closed-source license",
"commercial support", "SLA support", "Node.js microservices support",
"TypeScript RPC framework", "message queue RPC", "enterprise microservices",
"commercial license Node.js framework",
].join(", ");
eleventyConfig.addGlobalData("siteKeywords", isCom ? COM_KEYWORDS : ORG_KEYWORDS);
eleventyConfig.addGlobalData("siteImage", `${SITE_URL}/images/og-${EDITION}.png`);
eleventyConfig.addGlobalData("siteLocale", "en_US");
eleventyConfig.addGlobalData("themeColor", isCom ? "#0c0a17" : "#0a0e0d");
eleventyConfig.addGlobalData("twitterHandle", "@imqueue");
// Build only the active edition's pages.
eleventyConfig.ignores.add(isCom ? "src/org/**" : "src/com/**");
// Markdown content pages (docs/tutorial/cli/get-started) — used to emit
// per-page ".md" mirrors and the concatenated llms-full.txt. Excludes the
// generated API reference, which is HTML-only and too large/thin to mirror.
eleventyConfig.addCollection("contentMd", (api) =>
api.getAll().filter(
(item) =>
item.inputPath.endsWith(".md") &&
!(item.url || "").includes("/api/") &&
!item.data.draft
)
);
// Blog posts (.org only) — src/org/blog/posts/*.md, newest→oldest by date.
// Drafts (front matter `draft: true`) build to their URL but are kept out of
// the index listing.
eleventyConfig.addCollection("posts", (api) =>
api
.getFilteredByGlob("src/org/blog/posts/*.md")
.filter((item) => !item.data.draft)
.sort((a, b) => b.date - a.date)
);
// Posts written by a given author slug (newest first).
eleventyConfig.addFilter("byAuthor", (posts, slug) =>
(posts || []).filter((p) => p.data.author === slug)
);
// Look up a single author record by slug from the authors data list.
eleventyConfig.addFilter("authorBySlug", (authors, slug) =>
(authors || []).find((a) => a.slug === slug)
);
// Related posts: others sharing the most `topics` with the current one,
// newest first as the tie-breaker; falls back to filling with recent posts.
eleventyConfig.addFilter("related", (posts, currentUrl, topics, limit) => {
const want = new Set(topics || []);
const others = (posts || []).filter((p) => p.url !== currentUrl);
const scored = others
.map((p) => ({
p,
score: (p.data.topics || []).filter((t) => want.has(t)).length,
}))
.sort((a, b) => b.score - a.score || b.p.date - a.p.date);
const n = limit || 5;
const picked = scored.filter((x) => x.score > 0).slice(0, n).map((x) => x.p);
if (picked.length < n) {
for (const x of scored) {
if (picked.length >= n) break;
if (!picked.includes(x.p)) picked.push(x.p);
}
}
return picked;
});
// Reverse mesh: given a list of topics (declared by a docs/tutorial/cli area),
// return the blog posts sharing the most topics, newest first. Drafts excluded.
// Unlike `related` it does NOT backfill — a docs page only links posts that are
// genuinely on-topic (empty result -> the "From the blog" block is omitted).
eleventyConfig.addFilter("postsByTopics", (posts, topics, limit) => {
const want = new Set(topics || []);
if (!want.size) return [];
return (posts || [])
.filter((p) => !p.data.draft)
.map((p) => ({ p, score: (p.data.topics || []).filter((t) => want.has(t)).length }))
.filter((x) => x.score > 0)
.sort((a, b) => b.score - a.score || b.p.date - a.p.date)
.slice(0, limit || 4)
.map((x) => x.p);
});
// Static assets: shared first, then the active edition's theme css (same /css dir).
eleventyConfig.addPassthroughCopy({ "src/_shared/fonts": "fonts" });
eleventyConfig.addPassthroughCopy({ "src/_shared/css": "css" });
eleventyConfig.addPassthroughCopy({ "src/_shared/js": "js" });
eleventyConfig.addPassthroughCopy({ [`src/${EDITION}/css`]: "css" });
eleventyConfig.addPassthroughCopy({ [`src/${EDITION}/js`]: "js" });
eleventyConfig.addPassthroughCopy({ "images": "images" });
eleventyConfig.addPassthroughCopy({ [`src/${EDITION}/favicon.svg`]: "favicon.svg" });
eleventyConfig.addPassthroughCopy({ [`src/${EDITION}/favicon.ico`]: "favicon.ico" });
// robots.txt + sitemap.xml are generated per edition (see src/robots.liquid,
// src/sitemap.liquid) so each domain advertises its own sitemap URL.
// Per-edition _redirects (Cloudflare Pages). imqueue.com 301s legacy content
// paths to imqueue.org; imqueue.org 301s retired versioned API URLs to /latest/.
eleventyConfig.addPassthroughCopy({ [`src/${EDITION}/_redirects`]: "_redirects" });
// API reference (current + kept archives) is now generated as native Eleventy
// pages under src/org/api/**; the old standalone TypeDoc HTML passthrough is
// gone. Regenerate with `npm run build-docs` (latest) / `gen-api-archive` (old).
return {
dir: {
input: "src",
output: OUTPUT,
includes: "_shared/_includes",
layouts: "_shared/_includes",
data: "_data",
},
markdownTemplateEngine: "liquid",
htmlTemplateEngine: "liquid",
};
};