@duffcloudservices/cms 0.9.0 → 0.11.0
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/README.md +59 -2
- package/dist/chunk-DAYLLSEE.js +3 -0
- package/dist/{chunk-KCWMS7P4.js.map → chunk-DAYLLSEE.js.map} +1 -1
- package/dist/{chunk-UPAMLKOQ.js → chunk-F3EIWEZD.js} +158 -11
- package/dist/chunk-F3EIWEZD.js.map +1 -0
- package/dist/index.d.ts +74 -6
- package/dist/index.js +88 -6
- package/dist/index.js.map +1 -1
- package/dist/plugins/index.d.ts +114 -4
- package/dist/plugins/index.js +418 -107
- package/dist/plugins/index.js.map +1 -1
- package/dist/seo/index.d.ts +132 -226
- package/dist/seo/index.js +2 -2
- package/dist/spliceHeadHtml-CsBEucGy.d.ts +254 -0
- package/dist/{vitepressTransform-DeEzgGWU.d.ts → vitepressTransform-DfmABXmK.d.ts} +53 -2
- package/package.json +14 -2
- package/src/components/DcsCallButton.test.ts +126 -0
- package/src/components/DcsCallButton.vue +185 -0
- package/src/components/DcsReviewShowcase.vue +13 -2
- package/src/components/LiteMediaEmbed.test.ts +229 -0
- package/src/components/LiteMediaEmbed.vue +399 -0
- package/src/composables/useMediaCarousel.ts +6 -1
- package/src/composables/useReviewContent.test.ts +86 -0
- package/src/composables/useReviewContent.ts +34 -2
- package/src/composables/useSiteVisitorSession.test.ts +120 -0
- package/src/composables/useSiteVisitorSession.ts +160 -0
- package/dist/chunk-KCWMS7P4.js +0 -3
- package/dist/chunk-UPAMLKOQ.js.map +0 -1
package/dist/plugins/index.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import { buildSitemapXml, isHandAuthoredRobotsAcceptable, buildRobotsTxt, buildLlmsTxt, matchesExcludedGlob, breadcrumbTrailFromRoute, findReviewItemsForPage, buildHeadTags, spliceHeadHtml, loadPagesManifest } from '../chunk-
|
|
2
|
-
export { buildVitePressSeoHead, createSeoTransformPageData, defaultRelativePathToRoute } from '../chunk-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import { buildSitemapXml, isHandAuthoredRobotsAcceptable, buildRobotsTxt, buildLlmsTxt, matchesExcludedGlob, breadcrumbTrailFromRoute, findReviewItemsForPage, findBusinessLicense, buildHeadTags, spliceHeadHtml, routeToOutputFile, loadPagesManifest, isBodyPrerenderEnabled, prerenderBodies } from '../chunk-F3EIWEZD.js';
|
|
2
|
+
export { buildVitePressSeoHead, createSeoTransformPageData, defaultRelativePathToRoute } from '../chunk-F3EIWEZD.js';
|
|
3
|
+
import fs5 from 'fs';
|
|
4
|
+
import path5 from 'path';
|
|
5
|
+
import yaml4 from 'js-yaml';
|
|
6
|
+
import http from 'http';
|
|
6
7
|
import { defineComponent, h } from 'vue';
|
|
7
8
|
|
|
8
9
|
function dcsSearchPaths(projectRoot, relPath) {
|
|
9
10
|
return [
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
path5.resolve(projectRoot, relPath),
|
|
12
|
+
path5.resolve(projectRoot, "..", relPath),
|
|
13
|
+
path5.resolve(process.cwd(), relPath)
|
|
13
14
|
];
|
|
14
15
|
}
|
|
15
16
|
function resolveDcsFile(projectRoot, relPath) {
|
|
16
|
-
return dcsSearchPaths(projectRoot, relPath).find((p) =>
|
|
17
|
+
return dcsSearchPaths(projectRoot, relPath).find((p) => fs5.existsSync(p));
|
|
17
18
|
}
|
|
18
19
|
function readDcsYamlFresh(projectRoot, relPath, label, debug = false) {
|
|
19
20
|
const found = resolveDcsFile(projectRoot, relPath);
|
|
@@ -22,7 +23,7 @@ function readDcsYamlFresh(projectRoot, relPath, label, debug = false) {
|
|
|
22
23
|
return void 0;
|
|
23
24
|
}
|
|
24
25
|
try {
|
|
25
|
-
return
|
|
26
|
+
return yaml4.load(fs5.readFileSync(found, "utf8"));
|
|
26
27
|
} catch (error) {
|
|
27
28
|
console.warn(`[${label}] serve: failed to parse ${relPath}:`, error);
|
|
28
29
|
return void 0;
|
|
@@ -33,7 +34,84 @@ function buildGlobalAssignScript(globalName, value) {
|
|
|
33
34
|
return `globalThis.${globalName} = ${json};`;
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
// src/plugins/motionTokens.ts
|
|
38
|
+
var DCS_MOTION_TOKENS_CSS = `:root {
|
|
39
|
+
--motion-duration-stagger: 40ms;
|
|
40
|
+
--motion-duration-micro: 80ms;
|
|
41
|
+
--motion-duration-quick: 150ms;
|
|
42
|
+
--motion-duration-fast: 250ms;
|
|
43
|
+
--motion-duration-medium: 350ms;
|
|
44
|
+
--motion-duration-slow: 400ms;
|
|
45
|
+
--motion-duration-very-slow: 500ms;
|
|
46
|
+
--motion-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
|
|
47
|
+
--motion-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
|
48
|
+
--motion-ease-linear: linear;
|
|
49
|
+
--motion-ease-bounce: cubic-bezier(0.34, 1.36, 0.64, 1);
|
|
50
|
+
--motion-ease-bounce-strong: cubic-bezier(0.34, 3.85, 0.64, 1);
|
|
51
|
+
--motion-distance-xs: 4px;
|
|
52
|
+
--motion-distance-sm: 8px;
|
|
53
|
+
--motion-distance-md: 12px;
|
|
54
|
+
--motion-distance-lg: 24px;
|
|
55
|
+
--motion-scale-lg: 0.96;
|
|
56
|
+
--motion-scale-md: 0.97;
|
|
57
|
+
--motion-scale-sm: 0.98;
|
|
58
|
+
--motion-scale-xs: 0.99;
|
|
59
|
+
--motion-blur-sm: 2px;
|
|
60
|
+
--motion-blur-md: 3px;
|
|
61
|
+
--motion-blur-lg: 8px;
|
|
62
|
+
}`;
|
|
63
|
+
function dcsMotionTokensStyleTag() {
|
|
64
|
+
return {
|
|
65
|
+
tag: "style",
|
|
66
|
+
attrs: { "data-dcs-motion-tokens": "" },
|
|
67
|
+
children: DCS_MOTION_TOKENS_CSS,
|
|
68
|
+
injectTo: "head-prepend"
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
var DEFAULT_AGENT_API_BASE_URL = "https://portal.duffcloudservices.com";
|
|
72
|
+
var DEFAULT_AGENT_WIDGET_SCRIPT_URL = "https://files.duffcloudservices.com/agent-widget/v1/dcs-agent-widget.js";
|
|
73
|
+
var trimTrailingSlash = (value) => value.replace(/\/+$/, "");
|
|
74
|
+
var encodeForInlineScript = (value) => JSON.stringify(value).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
75
|
+
function buildAgentWidgetLoaderScript(options) {
|
|
76
|
+
const slug = encodeForInlineScript(options.siteSlug);
|
|
77
|
+
const api = encodeForInlineScript(trimTrailingSlash(options.apiBaseUrl || DEFAULT_AGENT_API_BASE_URL));
|
|
78
|
+
const cdn = encodeForInlineScript(options.cdnScriptUrl || DEFAULT_AGENT_WIDGET_SCRIPT_URL);
|
|
79
|
+
return "(function(){try{if(window.__DCS_AGENT_LOADER__)return;window.__DCS_AGENT_LOADER__=1;try{if(window.self!==window.top)return;}catch(e){return;}if(/[?&]dcs-hide-widget(?:[=&]|$)/.test(location.search))return;var S=" + slug + ",A=" + api + ",C=" + cdn + ';var go=function(){try{fetch(A+"/api/v1/sites/"+encodeURIComponent(S)+"/agent/config",{headers:{Accept:"application/json"}}).then(function(r){return r&&r.ok?r.json():null;}).then(function(c){if(!c||!c.enabled)return;window.__DCS_AGENT_BOOTSTRAP__={siteSlug:S,apiBaseUrl:A,config:c};var s=document.createElement("script");s.src=C;s.async=true;s.setAttribute("data-dcs-agent-slug",S);(document.head||document.documentElement).appendChild(s);}).catch(function(){});}catch(e){}};if("requestIdleCallback"in window){requestIdleCallback(go,{timeout:4000});}else{setTimeout(go,1200);}}catch(e){}})();';
|
|
80
|
+
}
|
|
81
|
+
var SITE_YAML_CANDIDATES = [".dcs/site.yaml", "../.dcs/site.yaml"];
|
|
82
|
+
function readSiteSlug(projectRoot) {
|
|
83
|
+
const candidates = [
|
|
84
|
+
...SITE_YAML_CANDIDATES.map((rel) => path5.resolve(projectRoot, rel)),
|
|
85
|
+
path5.resolve(process.cwd(), ".dcs/site.yaml")
|
|
86
|
+
];
|
|
87
|
+
for (const candidate of candidates) {
|
|
88
|
+
try {
|
|
89
|
+
if (!fs5.existsSync(candidate)) continue;
|
|
90
|
+
const parsed = yaml4.load(fs5.readFileSync(candidate, "utf8"));
|
|
91
|
+
const slug = parsed && typeof parsed.site_slug === "string" ? parsed.site_slug.trim() : "";
|
|
92
|
+
if (slug) return slug;
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
function dcsAgentWidgetLoaderTag(options) {
|
|
99
|
+
const siteSlug = readSiteSlug(options.projectRoot);
|
|
100
|
+
if (!siteSlug) return null;
|
|
101
|
+
return {
|
|
102
|
+
tag: "script",
|
|
103
|
+
attrs: { "data-dcs-agent-loader": "" },
|
|
104
|
+
children: buildAgentWidgetLoaderScript({
|
|
105
|
+
siteSlug,
|
|
106
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
107
|
+
cdnScriptUrl: options.cdnScriptUrl
|
|
108
|
+
}),
|
|
109
|
+
injectTo: "head"
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
36
113
|
// src/plugins/dcsContentPlugin.ts
|
|
114
|
+
var DCS_SSR_NO_EXTERNAL = ["@duffcloudservices/cms"];
|
|
37
115
|
function dcsContentPlugin(options = {}) {
|
|
38
116
|
const { contentPath = ".dcs/content.yaml", debug = false } = options;
|
|
39
117
|
let resolvedConfig;
|
|
@@ -49,18 +127,19 @@ function dcsContentPlugin(options = {}) {
|
|
|
49
127
|
return {
|
|
50
128
|
define: {
|
|
51
129
|
__DCS_CONTENT__: "globalThis.__DCS_CONTENT__"
|
|
52
|
-
}
|
|
130
|
+
},
|
|
131
|
+
ssr: { noExternal: DCS_SSR_NO_EXTERNAL }
|
|
53
132
|
};
|
|
54
133
|
}
|
|
55
134
|
const projectRoot = config.root || process.cwd();
|
|
56
135
|
const possiblePaths = [
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
136
|
+
path5.resolve(projectRoot, contentPath),
|
|
137
|
+
path5.resolve(projectRoot, "..", contentPath),
|
|
138
|
+
path5.resolve(process.cwd(), contentPath)
|
|
60
139
|
];
|
|
61
140
|
let foundPath;
|
|
62
141
|
for (const testPath of possiblePaths) {
|
|
63
|
-
if (
|
|
142
|
+
if (fs5.existsSync(testPath)) {
|
|
64
143
|
foundPath = testPath;
|
|
65
144
|
break;
|
|
66
145
|
}
|
|
@@ -74,12 +153,13 @@ function dcsContentPlugin(options = {}) {
|
|
|
74
153
|
return {
|
|
75
154
|
define: {
|
|
76
155
|
__DCS_CONTENT__: "undefined"
|
|
77
|
-
}
|
|
156
|
+
},
|
|
157
|
+
ssr: { noExternal: DCS_SSR_NO_EXTERNAL }
|
|
78
158
|
};
|
|
79
159
|
}
|
|
80
160
|
try {
|
|
81
|
-
const fileContent =
|
|
82
|
-
const content =
|
|
161
|
+
const fileContent = fs5.readFileSync(foundPath, "utf8");
|
|
162
|
+
const content = yaml4.load(fileContent);
|
|
83
163
|
if (debug) {
|
|
84
164
|
console.log(`[dcs-content] Loaded ${foundPath}`);
|
|
85
165
|
console.log(`[dcs-content] Version: ${content.version}`);
|
|
@@ -89,50 +169,68 @@ function dcsContentPlugin(options = {}) {
|
|
|
89
169
|
return {
|
|
90
170
|
define: {
|
|
91
171
|
__DCS_CONTENT__: JSON.stringify(content)
|
|
92
|
-
}
|
|
172
|
+
},
|
|
173
|
+
ssr: { noExternal: DCS_SSR_NO_EXTERNAL }
|
|
93
174
|
};
|
|
94
175
|
} catch (error) {
|
|
95
176
|
console.warn("[dcs-content] Failed to parse content.yaml:", error);
|
|
96
177
|
return {
|
|
97
178
|
define: {
|
|
98
179
|
__DCS_CONTENT__: "undefined"
|
|
99
|
-
}
|
|
180
|
+
},
|
|
181
|
+
ssr: { noExternal: DCS_SSR_NO_EXTERNAL }
|
|
100
182
|
};
|
|
101
183
|
}
|
|
102
184
|
},
|
|
103
185
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
186
|
+
* Inject into `<head>` on every HTML request. Two concerns:
|
|
187
|
+
*
|
|
188
|
+
* 1. The constant DCS motion-token `:root` block (`DCS_MOTION_TOKENS_CSS`)
|
|
189
|
+
* — the fleet-wide seam that gives every DCS site the shared `--motion-*`
|
|
190
|
+
* vocabulary. It carries no per-site data, so (unlike the content inject)
|
|
191
|
+
* it is NOT gated on `isDev`: it runs in both `serve` and `build`.
|
|
192
|
+
* `head-prepend` keeps it ABOVE the bundled site CSS, so a site's own
|
|
193
|
+
* `:root` (theme `tailwind.css` / `style.css`) can still override a token.
|
|
106
194
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
195
|
+
* 2. Dev-only: the FRESH on-disk `content.yaml` as an inline
|
|
196
|
+
* `globalThis.__DCS_CONTENT__ = {…}` classic script. Runs on every dev
|
|
197
|
+
* HTML request, so the portal's `?_hc` hard reload re-reads the YAML with
|
|
198
|
+
* no restart. A classic `<script>` in `<head>` executes before the
|
|
199
|
+
* deferred module app entry, so the global is set before the consumer's
|
|
200
|
+
* `useTextContent` setup reads it. Gated on `isDev` so it never runs in
|
|
201
|
+
* `vite`/`vitepress build` (the build path keeps the baked `define`).
|
|
113
202
|
*/
|
|
114
203
|
transformIndexHtml: {
|
|
115
204
|
order: "pre",
|
|
116
205
|
handler(html) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (content === void 0) return html;
|
|
126
|
-
if (debug) {
|
|
127
|
-
console.log("[dcs-content] serve: injecting fresh __DCS_CONTENT__ into <head>");
|
|
206
|
+
const tags = [dcsMotionTokensStyleTag()];
|
|
207
|
+
if (!isDev) {
|
|
208
|
+
const projectRoot = resolvedConfig?.root || process.cwd();
|
|
209
|
+
const agentTag = dcsAgentWidgetLoaderTag({
|
|
210
|
+
projectRoot,
|
|
211
|
+
apiBaseUrl: process.env.VITE_API_BASE_URL
|
|
212
|
+
});
|
|
213
|
+
if (agentTag) tags.push(agentTag);
|
|
128
214
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
215
|
+
if (isDev) {
|
|
216
|
+
const projectRoot = resolvedConfig?.root || process.cwd();
|
|
217
|
+
const content = readDcsYamlFresh(
|
|
218
|
+
projectRoot,
|
|
219
|
+
contentPath,
|
|
220
|
+
"dcs-content",
|
|
221
|
+
debug
|
|
222
|
+
);
|
|
223
|
+
if (content !== void 0) {
|
|
224
|
+
if (debug) {
|
|
225
|
+
console.log("[dcs-content] serve: injecting fresh __DCS_CONTENT__ into <head>");
|
|
226
|
+
}
|
|
227
|
+
tags.push({
|
|
228
|
+
tag: "script",
|
|
229
|
+
children: buildGlobalAssignScript("__DCS_CONTENT__", content),
|
|
230
|
+
injectTo: "head-prepend"
|
|
231
|
+
});
|
|
134
232
|
}
|
|
135
|
-
|
|
233
|
+
}
|
|
136
234
|
return { html, tags };
|
|
137
235
|
}
|
|
138
236
|
},
|
|
@@ -147,17 +245,17 @@ function dcsContentPlugin(options = {}) {
|
|
|
147
245
|
configureServer(server) {
|
|
148
246
|
const projectRoot = resolvedConfig?.root || process.cwd();
|
|
149
247
|
const watchPaths = [
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
].map((p) =>
|
|
248
|
+
path5.resolve(projectRoot, contentPath),
|
|
249
|
+
path5.resolve(projectRoot, "..", contentPath)
|
|
250
|
+
].map((p) => path5.normalize(p));
|
|
153
251
|
watchPaths.forEach((watchPath) => {
|
|
154
|
-
if (
|
|
252
|
+
if (fs5.existsSync(watchPath)) {
|
|
155
253
|
server.watcher.add(watchPath);
|
|
156
254
|
}
|
|
157
255
|
});
|
|
158
256
|
let reloadTimer;
|
|
159
257
|
server.watcher.on("change", (changedPath) => {
|
|
160
|
-
if (!watchPaths.includes(
|
|
258
|
+
if (!watchPaths.includes(path5.normalize(changedPath))) return;
|
|
161
259
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
162
260
|
reloadTimer = setTimeout(() => {
|
|
163
261
|
if (debug) {
|
|
@@ -169,19 +267,191 @@ function dcsContentPlugin(options = {}) {
|
|
|
169
267
|
}
|
|
170
268
|
};
|
|
171
269
|
}
|
|
270
|
+
var CONTENT_TYPES = {
|
|
271
|
+
".html": "text/html; charset=utf-8",
|
|
272
|
+
".js": "text/javascript; charset=utf-8",
|
|
273
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
274
|
+
".css": "text/css; charset=utf-8",
|
|
275
|
+
".json": "application/json; charset=utf-8",
|
|
276
|
+
".svg": "image/svg+xml",
|
|
277
|
+
".png": "image/png",
|
|
278
|
+
".jpg": "image/jpeg",
|
|
279
|
+
".jpeg": "image/jpeg",
|
|
280
|
+
".webp": "image/webp",
|
|
281
|
+
".gif": "image/gif",
|
|
282
|
+
".ico": "image/x-icon",
|
|
283
|
+
".woff": "font/woff",
|
|
284
|
+
".woff2": "font/woff2",
|
|
285
|
+
".ttf": "font/ttf",
|
|
286
|
+
".txt": "text/plain; charset=utf-8",
|
|
287
|
+
".xml": "application/xml; charset=utf-8",
|
|
288
|
+
".map": "application/json; charset=utf-8"
|
|
289
|
+
};
|
|
290
|
+
async function startStaticServer(outDir) {
|
|
291
|
+
const server = http.createServer((req, res) => {
|
|
292
|
+
let pathname = "/";
|
|
293
|
+
try {
|
|
294
|
+
pathname = decodeURIComponent(new URL(req.url ?? "/", "http://127.0.0.1").pathname);
|
|
295
|
+
} catch {
|
|
296
|
+
pathname = "/";
|
|
297
|
+
}
|
|
298
|
+
const resolved = path5.resolve(outDir, "." + pathname);
|
|
299
|
+
if (resolved !== outDir && !resolved.startsWith(outDir + path5.sep)) {
|
|
300
|
+
res.writeHead(403);
|
|
301
|
+
res.end();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
let filePath = resolved;
|
|
305
|
+
try {
|
|
306
|
+
const stat = fs5.statSync(filePath);
|
|
307
|
+
if (stat.isDirectory()) filePath = path5.join(filePath, "index.html");
|
|
308
|
+
} catch {
|
|
309
|
+
if (path5.extname(pathname)) {
|
|
310
|
+
res.writeHead(404);
|
|
311
|
+
res.end();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
filePath = path5.join(outDir, "index.html");
|
|
315
|
+
}
|
|
316
|
+
fs5.readFile(filePath, (err, buf) => {
|
|
317
|
+
if (err) {
|
|
318
|
+
res.writeHead(404);
|
|
319
|
+
res.end();
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
res.writeHead(200, {
|
|
323
|
+
"Content-Type": CONTENT_TYPES[path5.extname(filePath).toLowerCase()] ?? "application/octet-stream"
|
|
324
|
+
});
|
|
325
|
+
res.end(buf);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
329
|
+
const addr = server.address();
|
|
330
|
+
const origin = `http://127.0.0.1:${addr.port}`;
|
|
331
|
+
return {
|
|
332
|
+
origin,
|
|
333
|
+
close: () => new Promise((resolve) => {
|
|
334
|
+
server.close(() => resolve());
|
|
335
|
+
})
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
async function createPlaywrightRenderer(options) {
|
|
339
|
+
const {
|
|
340
|
+
outDir,
|
|
341
|
+
navTimeoutMs = 3e4,
|
|
342
|
+
mountTimeoutMs = 15e3,
|
|
343
|
+
settleMs = 250,
|
|
344
|
+
debug = false
|
|
345
|
+
} = options;
|
|
346
|
+
let chromium;
|
|
347
|
+
try {
|
|
348
|
+
const specifier = "playwright";
|
|
349
|
+
const pw = await import(
|
|
350
|
+
/* @vite-ignore */
|
|
351
|
+
specifier
|
|
352
|
+
);
|
|
353
|
+
chromium = pw.chromium;
|
|
354
|
+
} catch {
|
|
355
|
+
console.warn(
|
|
356
|
+
"[dcs-seo] body-prerender: `playwright` is not installed; skipping body prerender (head + JSON-LD still emitted). `pnpm add -D playwright` to enable."
|
|
357
|
+
);
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
if (!chromium) {
|
|
361
|
+
console.warn("[dcs-seo] body-prerender: playwright has no chromium export; skipping.");
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
let browser;
|
|
365
|
+
try {
|
|
366
|
+
browser = await chromium.launch({ headless: true });
|
|
367
|
+
} catch (err) {
|
|
368
|
+
console.warn(
|
|
369
|
+
"[dcs-seo] body-prerender: failed to launch Chromium (run `npx playwright install chromium`); skipping body prerender:",
|
|
370
|
+
err instanceof Error ? err.message : err
|
|
371
|
+
);
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
const staticServer = await startStaticServer(outDir);
|
|
375
|
+
const context = await browser.newContext({ reducedMotion: "reduce" });
|
|
376
|
+
const renderer = {
|
|
377
|
+
async renderRoute(routePath) {
|
|
378
|
+
const page = await context.newPage();
|
|
379
|
+
const errors = [];
|
|
380
|
+
page.on("pageerror", (err) => errors.push(`pageerror: ${err.message}`));
|
|
381
|
+
if (debug) {
|
|
382
|
+
page.on("console", (msg) => {
|
|
383
|
+
if (msg.type() === "error") console.log(`[dcs-seo] (console) ${msg.text()}`);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
await page.route("**/*", (route) => {
|
|
387
|
+
let sameOrigin = false;
|
|
388
|
+
try {
|
|
389
|
+
sameOrigin = new URL(route.request().url()).origin === staticServer.origin;
|
|
390
|
+
} catch {
|
|
391
|
+
sameOrigin = false;
|
|
392
|
+
}
|
|
393
|
+
if (sameOrigin) {
|
|
394
|
+
route.continue().catch(() => {
|
|
395
|
+
});
|
|
396
|
+
} else {
|
|
397
|
+
route.abort().catch(() => {
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
try {
|
|
402
|
+
await page.goto(staticServer.origin + routePath, {
|
|
403
|
+
waitUntil: "load",
|
|
404
|
+
timeout: navTimeoutMs
|
|
405
|
+
});
|
|
406
|
+
await page.waitForFunction(
|
|
407
|
+
() => {
|
|
408
|
+
const el = document.querySelector("#app");
|
|
409
|
+
return !!el && el.children.length > 0;
|
|
410
|
+
},
|
|
411
|
+
void 0,
|
|
412
|
+
{ timeout: mountTimeoutMs }
|
|
413
|
+
);
|
|
414
|
+
if (settleMs > 0) await page.waitForTimeout(settleMs);
|
|
415
|
+
const bodyHtml = await page.$eval("#app", (el) => el.innerHTML);
|
|
416
|
+
return { bodyHtml: bodyHtml ?? "", errors };
|
|
417
|
+
} catch (err) {
|
|
418
|
+
errors.push(err instanceof Error ? err.message : String(err));
|
|
419
|
+
return { bodyHtml: "", errors };
|
|
420
|
+
} finally {
|
|
421
|
+
await page.close();
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
return {
|
|
426
|
+
renderer,
|
|
427
|
+
async close() {
|
|
428
|
+
try {
|
|
429
|
+
await context.close();
|
|
430
|
+
} catch {
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
await browser.close();
|
|
434
|
+
} catch {
|
|
435
|
+
}
|
|
436
|
+
await staticServer.close();
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// src/plugins/dcsSeoPlugin.ts
|
|
172
442
|
function resolveOutDir(config) {
|
|
173
443
|
const out = config.build?.outDir || "dist";
|
|
174
|
-
return
|
|
444
|
+
return path5.isAbsolute(out) ? out : path5.resolve(config.root || process.cwd(), out);
|
|
175
445
|
}
|
|
176
446
|
function loadSeoConfig(projectRoot, seoPath, debug) {
|
|
177
447
|
const possiblePaths = [
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
448
|
+
path5.resolve(projectRoot, seoPath),
|
|
449
|
+
path5.resolve(projectRoot, "..", seoPath),
|
|
450
|
+
path5.resolve(process.cwd(), seoPath)
|
|
181
451
|
];
|
|
182
452
|
let foundPath;
|
|
183
453
|
for (const testPath of possiblePaths) {
|
|
184
|
-
if (
|
|
454
|
+
if (fs5.existsSync(testPath)) {
|
|
185
455
|
foundPath = testPath;
|
|
186
456
|
break;
|
|
187
457
|
}
|
|
@@ -195,8 +465,8 @@ function loadSeoConfig(projectRoot, seoPath, debug) {
|
|
|
195
465
|
return null;
|
|
196
466
|
}
|
|
197
467
|
try {
|
|
198
|
-
const fileContent =
|
|
199
|
-
const config =
|
|
468
|
+
const fileContent = fs5.readFileSync(foundPath, "utf8");
|
|
469
|
+
const config = yaml4.load(fileContent);
|
|
200
470
|
return { config, foundPath };
|
|
201
471
|
} catch (error) {
|
|
202
472
|
console.warn("[dcs-seo] Failed to parse seo.yaml:", error);
|
|
@@ -205,17 +475,17 @@ function loadSeoConfig(projectRoot, seoPath, debug) {
|
|
|
205
475
|
}
|
|
206
476
|
function loadContentConfig(projectRoot, contentRelPath, debug) {
|
|
207
477
|
const possiblePaths = [
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
478
|
+
path5.resolve(projectRoot, contentRelPath),
|
|
479
|
+
path5.resolve(projectRoot, "..", contentRelPath),
|
|
480
|
+
path5.resolve(process.cwd(), contentRelPath)
|
|
211
481
|
];
|
|
212
|
-
const foundPath = possiblePaths.find((p) =>
|
|
482
|
+
const foundPath = possiblePaths.find((p) => fs5.existsSync(p));
|
|
213
483
|
if (!foundPath) {
|
|
214
484
|
if (debug) console.log(`[dcs-seo] No content.yaml found (reviews disabled)`);
|
|
215
485
|
return void 0;
|
|
216
486
|
}
|
|
217
487
|
try {
|
|
218
|
-
const parsed =
|
|
488
|
+
const parsed = yaml4.load(fs5.readFileSync(foundPath, "utf8"));
|
|
219
489
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
220
490
|
return parsed;
|
|
221
491
|
} catch (error) {
|
|
@@ -223,21 +493,16 @@ function loadContentConfig(projectRoot, contentRelPath, debug) {
|
|
|
223
493
|
return void 0;
|
|
224
494
|
}
|
|
225
495
|
}
|
|
226
|
-
function routeToOutputFile(outDir, routePath) {
|
|
227
|
-
const trimmed = routePath.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
228
|
-
if (trimmed === "") return path3.join(outDir, "index.html");
|
|
229
|
-
return path3.join(outDir, ...trimmed.split("/"), "index.html");
|
|
230
|
-
}
|
|
231
496
|
function loadExcludedGlobs(projectRoot, pagesPath) {
|
|
232
497
|
const possiblePaths = [
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
498
|
+
path5.resolve(projectRoot, pagesPath),
|
|
499
|
+
path5.resolve(projectRoot, "..", pagesPath),
|
|
500
|
+
path5.resolve(process.cwd(), pagesPath)
|
|
236
501
|
];
|
|
237
|
-
const found = possiblePaths.find((p) =>
|
|
502
|
+
const found = possiblePaths.find((p) => fs5.existsSync(p));
|
|
238
503
|
if (!found) return [];
|
|
239
504
|
try {
|
|
240
|
-
const raw =
|
|
505
|
+
const raw = yaml4.load(fs5.readFileSync(found, "utf8"));
|
|
241
506
|
const excluded = raw?.excluded;
|
|
242
507
|
if (!Array.isArray(excluded)) return [];
|
|
243
508
|
return excluded.filter((e) => typeof e === "string");
|
|
@@ -249,14 +514,14 @@ function deriveLastmod(seoConfig, projectRoot, pagesPath) {
|
|
|
249
514
|
const fromSeo = seoConfig?.lastUpdated;
|
|
250
515
|
if (typeof fromSeo === "string" && fromSeo.length > 0) return fromSeo;
|
|
251
516
|
const possiblePaths = [
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
517
|
+
path5.resolve(projectRoot, pagesPath),
|
|
518
|
+
path5.resolve(projectRoot, "..", pagesPath),
|
|
519
|
+
path5.resolve(process.cwd(), pagesPath)
|
|
255
520
|
];
|
|
256
|
-
const found = possiblePaths.find((p) =>
|
|
521
|
+
const found = possiblePaths.find((p) => fs5.existsSync(p));
|
|
257
522
|
if (!found) return void 0;
|
|
258
523
|
try {
|
|
259
|
-
const raw =
|
|
524
|
+
const raw = yaml4.load(fs5.readFileSync(found, "utf8"));
|
|
260
525
|
const fromPages = raw?.lastUpdated;
|
|
261
526
|
if (typeof fromPages === "string" && fromPages.length > 0) return fromPages;
|
|
262
527
|
} catch {
|
|
@@ -294,7 +559,7 @@ function emitSiteFiles(params) {
|
|
|
294
559
|
lastmod
|
|
295
560
|
});
|
|
296
561
|
if (xml) {
|
|
297
|
-
|
|
562
|
+
fs5.writeFileSync(path5.join(outDir, "sitemap.xml"), xml, "utf8");
|
|
298
563
|
wroteSitemap = true;
|
|
299
564
|
written.push("sitemap.xml");
|
|
300
565
|
if (debug) console.log("[dcs-seo] wrote sitemap.xml");
|
|
@@ -303,8 +568,8 @@ function emitSiteFiles(params) {
|
|
|
303
568
|
}
|
|
304
569
|
}
|
|
305
570
|
if (robots.enabled ?? true) {
|
|
306
|
-
const robotsPath =
|
|
307
|
-
const existing =
|
|
571
|
+
const robotsPath = path5.join(outDir, "robots.txt");
|
|
572
|
+
const existing = fs5.existsSync(robotsPath) && !robots.force ? fs5.readFileSync(robotsPath, "utf8") : null;
|
|
308
573
|
const keepHandAuthored = existing !== null && isHandAuthoredRobotsAcceptable(existing);
|
|
309
574
|
if (keepHandAuthored) {
|
|
310
575
|
if (debug)
|
|
@@ -316,7 +581,7 @@ function emitSiteFiles(params) {
|
|
|
316
581
|
robots,
|
|
317
582
|
hasSitemap: wroteSitemap
|
|
318
583
|
});
|
|
319
|
-
|
|
584
|
+
fs5.writeFileSync(robotsPath, txt, "utf8");
|
|
320
585
|
written.push("robots.txt");
|
|
321
586
|
if (debug) {
|
|
322
587
|
console.log(
|
|
@@ -335,7 +600,7 @@ function emitSiteFiles(params) {
|
|
|
335
600
|
excludedGlobs
|
|
336
601
|
});
|
|
337
602
|
if (txt) {
|
|
338
|
-
|
|
603
|
+
fs5.writeFileSync(path5.join(outDir, "llms.txt"), txt, "utf8");
|
|
339
604
|
written.push("llms.txt");
|
|
340
605
|
if (debug) console.log("[dcs-seo] wrote llms.txt");
|
|
341
606
|
} else if (debug) {
|
|
@@ -385,6 +650,7 @@ function emitStaticSeoHtml(params) {
|
|
|
385
650
|
const forceNoindex = noindexSet.has(route.path) || route.slug && noindexSet.has(route.slug);
|
|
386
651
|
const breadcrumbTrail = siteUrl ? breadcrumbTrailFromRoute(route.path, siteUrl, routeTitles) : void 0;
|
|
387
652
|
const reviews = contentConfig ? findReviewItemsForPage(contentConfig, route.slug) : void 0;
|
|
653
|
+
const license = contentConfig ? findBusinessLicense(contentConfig, route.slug) : void 0;
|
|
388
654
|
const isBlogPost = /^\/blog\/.+/.test(route.path) && !!route.title;
|
|
389
655
|
const blogMeta = isBlogPost ? { headline: route.title, url: breadcrumbTrail?.[breadcrumbTrail.length - 1]?.item } : void 0;
|
|
390
656
|
const faq = pickPageFaq(contentConfig, route.slug);
|
|
@@ -395,27 +661,50 @@ function emitStaticSeoHtml(params) {
|
|
|
395
661
|
emitGraph: true,
|
|
396
662
|
breadcrumbTrail,
|
|
397
663
|
reviews,
|
|
664
|
+
license,
|
|
398
665
|
blogMeta,
|
|
399
666
|
faq
|
|
400
667
|
});
|
|
401
668
|
const html = spliceHeadHtml(shellHtml, tags);
|
|
402
669
|
const outFile = routeToOutputFile(outDir, route.path);
|
|
403
|
-
|
|
404
|
-
|
|
670
|
+
fs5.mkdirSync(path5.dirname(outFile), { recursive: true });
|
|
671
|
+
fs5.writeFileSync(outFile, html, "utf8");
|
|
405
672
|
written++;
|
|
406
673
|
if (debug) {
|
|
407
674
|
console.log(
|
|
408
|
-
`[dcs-seo] wrote ${
|
|
675
|
+
`[dcs-seo] wrote ${path5.relative(outDir, outFile)} (title="${tags.title}"${forceNoindex ? ", noindex" : ""})`
|
|
409
676
|
);
|
|
410
677
|
}
|
|
411
678
|
}
|
|
412
679
|
return written;
|
|
413
680
|
}
|
|
681
|
+
async function runBodyPrerender(ctx, opts) {
|
|
682
|
+
const handle = await createPlaywrightRenderer({ outDir: ctx.outDir, debug: opts.debug });
|
|
683
|
+
if (!handle) return;
|
|
684
|
+
console.log("[dcs-seo] body-prerender: rendering routes via headless Chromium\u2026");
|
|
685
|
+
try {
|
|
686
|
+
const result = await prerenderBodies({
|
|
687
|
+
outDir: ctx.outDir,
|
|
688
|
+
routes: ctx.routes,
|
|
689
|
+
renderer: handle.renderer,
|
|
690
|
+
exclude: opts.exclude,
|
|
691
|
+
noindex: opts.noindex,
|
|
692
|
+
excludedGlobs: ctx.excludedGlobs,
|
|
693
|
+
debug: opts.debug
|
|
694
|
+
});
|
|
695
|
+
console.log(
|
|
696
|
+
`[dcs-seo] body-prerender: ${result.prerendered} route(s) now have crawler-visible body content (${result.skipped} skipped)`
|
|
697
|
+
);
|
|
698
|
+
} finally {
|
|
699
|
+
await handle.close();
|
|
700
|
+
}
|
|
701
|
+
}
|
|
414
702
|
function dcsSeoPlugin(options = {}) {
|
|
415
703
|
const {
|
|
416
704
|
seoPath = ".dcs/seo.yaml",
|
|
417
705
|
debug = false,
|
|
418
706
|
emitStaticHtml = false,
|
|
707
|
+
prerenderBody,
|
|
419
708
|
pagesPath = ".dcs/pages.yaml",
|
|
420
709
|
contentPath = ".dcs/content.yaml",
|
|
421
710
|
exclude = [],
|
|
@@ -425,7 +714,9 @@ function dcsSeoPlugin(options = {}) {
|
|
|
425
714
|
emitSiteFiles: emitSiteFilesOpt = emitStaticHtml,
|
|
426
715
|
siteUrl,
|
|
427
716
|
robots = {},
|
|
428
|
-
preview
|
|
717
|
+
// Self-detect preview builds from DCS_PREVIEW (mirrors dcsEditorPlugin) so a
|
|
718
|
+
// release/** SWA preview build never body-prerenders; an explicit option wins.
|
|
719
|
+
preview = process.env.DCS_PREVIEW === "true",
|
|
429
720
|
llms = true
|
|
430
721
|
} = options;
|
|
431
722
|
let resolvedConfig;
|
|
@@ -477,7 +768,7 @@ function dcsSeoPlugin(options = {}) {
|
|
|
477
768
|
* Fully defensive: any missing/unparseable input logs a warning and
|
|
478
769
|
* no-ops. Never throws (so it can never break a production build).
|
|
479
770
|
*/
|
|
480
|
-
writeBundle() {
|
|
771
|
+
async writeBundle() {
|
|
481
772
|
if (!emitStaticHtml) {
|
|
482
773
|
if (options.emitSiteFiles === true) {
|
|
483
774
|
console.warn(
|
|
@@ -486,15 +777,16 @@ function dcsSeoPlugin(options = {}) {
|
|
|
486
777
|
}
|
|
487
778
|
return;
|
|
488
779
|
}
|
|
780
|
+
let bodyPrerenderCtx = null;
|
|
489
781
|
try {
|
|
490
782
|
const projectRoot = resolvedConfig?.root || process.cwd();
|
|
491
783
|
const outDir = resolveOutDir(resolvedConfig);
|
|
492
|
-
if (!
|
|
784
|
+
if (!fs5.existsSync(outDir)) {
|
|
493
785
|
console.warn(`[dcs-seo] emitStaticHtml: outDir not found (${outDir}); skipping`);
|
|
494
786
|
return;
|
|
495
787
|
}
|
|
496
|
-
const shellPath =
|
|
497
|
-
if (!
|
|
788
|
+
const shellPath = path5.join(outDir, "index.html");
|
|
789
|
+
if (!fs5.existsSync(shellPath)) {
|
|
498
790
|
console.warn(
|
|
499
791
|
`[dcs-seo] emitStaticHtml: no index.html in ${outDir}; nothing to emit`
|
|
500
792
|
);
|
|
@@ -513,7 +805,7 @@ function dcsSeoPlugin(options = {}) {
|
|
|
513
805
|
`[dcs-seo] emitStaticHtml: ${seoPath} missing or unparseable; emitting with defaults only`
|
|
514
806
|
);
|
|
515
807
|
}
|
|
516
|
-
const shellHtml =
|
|
808
|
+
const shellHtml = fs5.readFileSync(shellPath, "utf8");
|
|
517
809
|
const excludedGlobs = loadExcludedGlobs(projectRoot, pagesPath);
|
|
518
810
|
const contentConfig = loadContentConfig(projectRoot, contentPath, debug);
|
|
519
811
|
const written = emitStaticSeoHtml({
|
|
@@ -551,9 +843,28 @@ function dcsSeoPlugin(options = {}) {
|
|
|
551
843
|
);
|
|
552
844
|
}
|
|
553
845
|
}
|
|
846
|
+
const buildBase = resolvedConfig?.base ?? "/";
|
|
847
|
+
const baseIsRoot = buildBase === "/" || buildBase === "./" || buildBase === "";
|
|
848
|
+
if (isBodyPrerenderEnabled({
|
|
849
|
+
emitStaticHtml,
|
|
850
|
+
prerenderBodyOption: prerenderBody,
|
|
851
|
+
preview,
|
|
852
|
+
seoPrerenderBody: loaded?.config?.prerenderBody
|
|
853
|
+
})) {
|
|
854
|
+
if (baseIsRoot) {
|
|
855
|
+
bodyPrerenderCtx = { outDir, routes, excludedGlobs };
|
|
856
|
+
} else {
|
|
857
|
+
console.warn(
|
|
858
|
+
`[dcs-seo] body prerender skipped: non-root base "${buildBase}" (assets would not resolve through the prerender server; head + JSON-LD still emitted)`
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
554
862
|
} catch (error) {
|
|
555
863
|
console.warn("[dcs-seo] emitStaticHtml failed; build output left unchanged:", error);
|
|
556
864
|
}
|
|
865
|
+
if (bodyPrerenderCtx) {
|
|
866
|
+
await runBodyPrerender(bodyPrerenderCtx, { exclude, noindex, debug });
|
|
867
|
+
}
|
|
557
868
|
},
|
|
558
869
|
/**
|
|
559
870
|
* Dev-only: inject the FRESH on-disk `seo.yaml` as an inline
|
|
@@ -594,17 +905,17 @@ function dcsSeoPlugin(options = {}) {
|
|
|
594
905
|
configureServer(server) {
|
|
595
906
|
const projectRoot = resolvedConfig?.root || process.cwd();
|
|
596
907
|
const watchPaths = [
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
].map((p) =>
|
|
908
|
+
path5.resolve(projectRoot, seoPath),
|
|
909
|
+
path5.resolve(projectRoot, "..", seoPath)
|
|
910
|
+
].map((p) => path5.normalize(p));
|
|
600
911
|
watchPaths.forEach((watchPath) => {
|
|
601
|
-
if (
|
|
912
|
+
if (fs5.existsSync(watchPath)) {
|
|
602
913
|
server.watcher.add(watchPath);
|
|
603
914
|
}
|
|
604
915
|
});
|
|
605
916
|
let reloadTimer;
|
|
606
917
|
server.watcher.on("change", (changedPath) => {
|
|
607
|
-
if (!watchPaths.includes(
|
|
918
|
+
if (!watchPaths.includes(path5.normalize(changedPath))) return;
|
|
608
919
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
609
920
|
reloadTimer = setTimeout(() => {
|
|
610
921
|
if (debug) {
|
|
@@ -761,14 +1072,14 @@ function buildPictureElement(entry, alt, extraAttrs, sizes) {
|
|
|
761
1072
|
}
|
|
762
1073
|
function loadCdnImageMap(projectRoot, relativeMapPath, debug) {
|
|
763
1074
|
const possiblePaths = [
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
1075
|
+
path5.resolve(projectRoot, relativeMapPath),
|
|
1076
|
+
path5.resolve(projectRoot, "..", relativeMapPath),
|
|
1077
|
+
path5.resolve(process.cwd(), relativeMapPath)
|
|
767
1078
|
];
|
|
768
1079
|
for (const testPath of possiblePaths) {
|
|
769
|
-
if (
|
|
1080
|
+
if (fs5.existsSync(testPath)) {
|
|
770
1081
|
try {
|
|
771
|
-
const raw =
|
|
1082
|
+
const raw = fs5.readFileSync(testPath, "utf8");
|
|
772
1083
|
const data = JSON.parse(raw);
|
|
773
1084
|
const map = /* @__PURE__ */ new Map();
|
|
774
1085
|
for (const entry of data.images) {
|
|
@@ -929,13 +1240,13 @@ function dcsCdnBuildEnd(options = {}) {
|
|
|
929
1240
|
return;
|
|
930
1241
|
}
|
|
931
1242
|
const outDir = siteConfig.outDir;
|
|
932
|
-
if (!
|
|
1243
|
+
if (!fs5.existsSync(outDir)) return;
|
|
933
1244
|
let filesProcessed = 0;
|
|
934
1245
|
let refsReplaced = 0;
|
|
935
1246
|
function walkDir(dir) {
|
|
936
|
-
const entries =
|
|
1247
|
+
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
937
1248
|
for (const entry of entries) {
|
|
938
|
-
const fullPath =
|
|
1249
|
+
const fullPath = path5.join(dir, entry.name);
|
|
939
1250
|
if (entry.isDirectory()) {
|
|
940
1251
|
walkDir(fullPath);
|
|
941
1252
|
} else if (extensions.some((ext) => entry.name.endsWith(ext))) {
|
|
@@ -944,7 +1255,7 @@ function dcsCdnBuildEnd(options = {}) {
|
|
|
944
1255
|
}
|
|
945
1256
|
}
|
|
946
1257
|
function processFile(filePath) {
|
|
947
|
-
let content =
|
|
1258
|
+
let content = fs5.readFileSync(filePath, "utf8");
|
|
948
1259
|
if (!pathPrefixes.some((p) => content.includes(p))) return;
|
|
949
1260
|
let changed = false;
|
|
950
1261
|
if (filePath.endsWith(".html")) {
|
|
@@ -979,7 +1290,7 @@ function dcsCdnBuildEnd(options = {}) {
|
|
|
979
1290
|
}
|
|
980
1291
|
}
|
|
981
1292
|
if (changed) {
|
|
982
|
-
|
|
1293
|
+
fs5.writeFileSync(filePath, content, "utf8");
|
|
983
1294
|
filesProcessed++;
|
|
984
1295
|
}
|
|
985
1296
|
}
|
|
@@ -1028,6 +1339,6 @@ function responsiveImagePlugin(md) {
|
|
|
1028
1339
|
};
|
|
1029
1340
|
}
|
|
1030
1341
|
|
|
1031
|
-
export { dcsCdnBuildEnd, dcsCdnImagePlugin, dcsContentPlugin, dcsEditorPlugin, dcsPreviewPlugin, dcsSeoPlugin, emitSiteFiles, emitStaticSeoHtml, responsiveImagePlugin };
|
|
1342
|
+
export { DCS_MOTION_TOKENS_CSS, DEFAULT_AGENT_API_BASE_URL, DEFAULT_AGENT_WIDGET_SCRIPT_URL, buildAgentWidgetLoaderScript, dcsAgentWidgetLoaderTag, dcsCdnBuildEnd, dcsCdnImagePlugin, dcsContentPlugin, dcsEditorPlugin, dcsMotionTokensStyleTag, dcsPreviewPlugin, dcsSeoPlugin, emitSiteFiles, emitStaticSeoHtml, readSiteSlug, responsiveImagePlugin };
|
|
1032
1343
|
//# sourceMappingURL=index.js.map
|
|
1033
1344
|
//# sourceMappingURL=index.js.map
|