@goodfellow-cms/next 0.3.0 → 0.5.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 +2 -2
- package/bin/goodfellow-next.js +249 -11
- package/dist/admin.d.ts +26 -9
- package/dist/admin.js +89 -18
- package/dist/components.d.ts +21 -0
- package/dist/components.js +27 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.js +84 -10
- package/dist/dev-editor-DiPKrIAS.js +124 -0
- package/dist/editor.d.ts +14 -0
- package/dist/editor.js +32 -0
- package/dist/export.d.ts +102 -3
- package/dist/export.js +218 -12
- package/dist/index.d.ts +12 -4
- package/dist/index.js +86 -41
- package/dist/server.d.ts +57 -0
- package/dist/server.js +45 -0
- package/dist/site-files-BeLnLxCl.js +50 -0
- package/package.json +23 -9
package/dist/config.js
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
|
-
import { CALENDARS_DIR, allPages, loadSiteContent, normalizeBase, redirectFrom, redirectProblems } from "@goodfellow-cms/core";
|
|
2
|
-
import { DEV_API_PREFIX, fileSystemSource, handleDevApi, isLocalOrigin, localFileStore, localRegistryDir } from "@goodfellow-cms/core/node";
|
|
1
|
+
import { CALENDARS_DIR, FEEDS_DIR, allPages, brokerOrigin, configAdmin, configBroker, loadSiteContent, normalizeBase, redirectFrom, redirectProblems, shownContent, vercelAdminHeaders } from "@goodfellow-cms/core";
|
|
2
|
+
import { BUILD_DATES_DIR, BUILD_DATES_ENV, DEV_API_PREFIX, contentRepositoryProblem, fileSystemSource, handleDevApi, isLocalOrigin, localFileStore, localRegistryDir } from "@goodfellow-cms/core/node";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { rm } from "node:fs/promises";
|
|
3
5
|
import { createServer } from "node:http";
|
|
4
|
-
import { resolve } from "node:path";
|
|
6
|
+
import { join, resolve } from "node:path";
|
|
5
7
|
//#region src/config.ts
|
|
8
|
+
const CONFIG_FILES = [
|
|
9
|
+
"goodfellow.config.tsx",
|
|
10
|
+
"goodfellow.config.ts",
|
|
11
|
+
"goodfellow.config.jsx",
|
|
12
|
+
"goodfellow.config.js"
|
|
13
|
+
];
|
|
14
|
+
/** The config's admin address, from its line of its own, since Next.js's config can't load the site's. */
|
|
15
|
+
function siteAdmin(root) {
|
|
16
|
+
const file = CONFIG_FILES.map((name) => join(root, name)).find((path) => existsSync(path));
|
|
17
|
+
return file ? configAdmin(readFileSync(file, "utf8")) : void 0;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The admin address's header rules, for hosts that read them from the build,
|
|
21
|
+
* such as Vercel: every page there sandboxed but the admin panel's own, as
|
|
22
|
+
* `goodfellow build`'s `_headers` does on Cloudflare Pages. Next.js adds the base path itself.
|
|
23
|
+
*/
|
|
24
|
+
function adminHeaders(root) {
|
|
25
|
+
const admin = siteAdmin(root);
|
|
26
|
+
const file = CONFIG_FILES.map((name) => join(root, name)).find((path) => existsSync(path));
|
|
27
|
+
const broker = brokerOrigin(file ? configBroker(readFileSync(file, "utf8")) : void 0);
|
|
28
|
+
return admin ? vercelAdminHeaders(admin, "/", broker) : [];
|
|
29
|
+
}
|
|
6
30
|
/** `PHASE_DEVELOPMENT_SERVER` from `next/constants`, which Node can't import by that name. */
|
|
7
31
|
const PHASE_DEVELOPMENT_SERVER = "phase-development-server";
|
|
32
|
+
const PHASE_PRODUCTION_BUILD = "phase-production-build";
|
|
8
33
|
const SERVER_KEY = Symbol.for("goodfellow.next.devApi");
|
|
9
34
|
/**
|
|
10
35
|
* The admin panel's local backend, which reads and writes the site's files on
|
|
@@ -16,7 +41,12 @@ function startDevApi(root) {
|
|
|
16
41
|
globals[SERVER_KEY] ??= new Promise((resolvePort, reject) => {
|
|
17
42
|
const store = localFileStore(root);
|
|
18
43
|
const registryDir = localRegistryDir(root);
|
|
44
|
+
const editor = import("./dev-editor-DiPKrIAS.js").then(({ startDevEditor }) => startDevEditor(root)).catch((error) => {
|
|
45
|
+
console.error(`The editor's frames can't be served: ${error.message}`);
|
|
46
|
+
return { serve: async () => false };
|
|
47
|
+
});
|
|
19
48
|
const server = createServer(async (req, res) => {
|
|
49
|
+
if (await (await editor).serve(req, res)) return;
|
|
20
50
|
if (!await handleDevApi(store, req, res, {
|
|
21
51
|
trustOrigin: isLocalOrigin,
|
|
22
52
|
registryDir
|
|
@@ -65,7 +95,7 @@ function redirectSource(path) {
|
|
|
65
95
|
* Content with a problem gives none, and the build reports the problem.
|
|
66
96
|
*/
|
|
67
97
|
async function siteRedirects(root) {
|
|
68
|
-
const content = await loadSiteContent(fileSystemSource(root)).
|
|
98
|
+
const content = await loadSiteContent(fileSystemSource(root)).then(shownContent, () => void 0);
|
|
69
99
|
if (!content?.redirects) return [];
|
|
70
100
|
const taken = new Set(allPages(content).map((page) => page.path));
|
|
71
101
|
const problems = redirectProblems(content.redirects);
|
|
@@ -91,6 +121,10 @@ async function siteRedirects(root) {
|
|
|
91
121
|
* - Serves images as they are unless the site sets an image loader, since static files can't be optimized on request.
|
|
92
122
|
* - Adds the site's redirects (Site Settings → Redirects) ahead of the site's own, for hosts that
|
|
93
123
|
* send them, such as Vercel. Others get the pages `goodfellow-next finish` writes at old addresses.
|
|
124
|
+
* - For a site with an admin address, adds header rules that sandbox every page there but the
|
|
125
|
+
* admin panel's own, for hosts that send headers, such as Vercel.
|
|
126
|
+
* - With `{ server: true }`, builds a full-stack site for a server instead of as static
|
|
127
|
+
* files: see `goodfellowApi()` in `@goodfellow-cms/next/server`.
|
|
94
128
|
* - In `next dev`, runs the admin panel's local backend, so publishing saves to
|
|
95
129
|
* the files on disk. It's never part of a build.
|
|
96
130
|
* - In `next dev`, turns off React's debug channel (`experimental.reactDebugChannel`)
|
|
@@ -101,6 +135,8 @@ function withGoodfellow(nextConfig = {}, options = {}) {
|
|
|
101
135
|
const root = resolve(options.root ?? process.cwd());
|
|
102
136
|
const basePath = nextBasePath(nextConfig.basePath ?? process.env.GOODFELLOW_BASE);
|
|
103
137
|
return async (phase) => {
|
|
138
|
+
const problem = contentRepositoryProblem(root);
|
|
139
|
+
if (problem) throw new Error(problem);
|
|
104
140
|
const config = {
|
|
105
141
|
trailingSlash: true,
|
|
106
142
|
...nextConfig,
|
|
@@ -111,27 +147,65 @@ function withGoodfellow(nextConfig = {}, options = {}) {
|
|
|
111
147
|
GOODFELLOW_BASE_PATH: basePath
|
|
112
148
|
}
|
|
113
149
|
};
|
|
150
|
+
if (phase === PHASE_PRODUCTION_BUILD) {
|
|
151
|
+
const dates = join(root, nextConfig.distDir ?? ".next", BUILD_DATES_DIR);
|
|
152
|
+
await rm(dates, {
|
|
153
|
+
recursive: true,
|
|
154
|
+
force: true
|
|
155
|
+
});
|
|
156
|
+
process.env[BUILD_DATES_ENV] = dates;
|
|
157
|
+
}
|
|
158
|
+
if (phase !== PHASE_DEVELOPMENT_SERVER && options.server) {
|
|
159
|
+
if (siteAdmin(root)) throw new Error("A full-stack site can't have an admin address: its admin panel signs in with the site's own sign-in.");
|
|
160
|
+
return {
|
|
161
|
+
...config,
|
|
162
|
+
images: nextConfig.images,
|
|
163
|
+
outputFileTracingIncludes: {
|
|
164
|
+
...nextConfig.outputFileTracingIncludes,
|
|
165
|
+
"/**": [
|
|
166
|
+
...nextConfig.outputFileTracingIncludes?.["/**"] ?? [],
|
|
167
|
+
"./content/**/*",
|
|
168
|
+
"./public/media/**/*"
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
redirects: async () => [...await siteRedirects(root), ...await nextConfig.redirects?.() ?? []]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
114
174
|
if (phase !== PHASE_DEVELOPMENT_SERVER) return {
|
|
115
175
|
output: "export",
|
|
116
176
|
...config,
|
|
117
|
-
redirects: async () => [...await siteRedirects(root), ...await nextConfig.redirects?.() ?? []]
|
|
177
|
+
redirects: async () => [...await siteRedirects(root), ...await nextConfig.redirects?.() ?? []],
|
|
178
|
+
...siteAdmin(root) && { headers: async () => [...adminHeaders(root), ...await nextConfig.headers?.() ?? []] }
|
|
118
179
|
};
|
|
119
180
|
const port = await startDevApi(root);
|
|
120
181
|
const rewrite = {
|
|
121
182
|
source: `${DEV_API_PREFIX}/:path*`,
|
|
122
183
|
destination: `http://127.0.0.1:${port}${DEV_API_PREFIX}/:path*`
|
|
123
184
|
};
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
185
|
+
const buildFiles = [{
|
|
186
|
+
dir: CALENDARS_DIR,
|
|
187
|
+
file: ":file(.+\\.ics)"
|
|
188
|
+
}, {
|
|
189
|
+
dir: FEEDS_DIR,
|
|
190
|
+
file: ":file(.+\\.rss|.+\\.atom)"
|
|
191
|
+
}].flatMap(({ dir, file }) => [{
|
|
192
|
+
source: `/${dir}/${file}`,
|
|
193
|
+
destination: `http://127.0.0.1:${port}${DEV_API_PREFIX}/${dir}/:file`
|
|
194
|
+
}, {
|
|
195
|
+
source: `/:language([a-z0-9-]+)/${dir}/${file}`,
|
|
196
|
+
destination: `http://127.0.0.1:${port}${DEV_API_PREFIX}/:language/${dir}/:file`
|
|
197
|
+
}]);
|
|
128
198
|
return {
|
|
129
199
|
...config,
|
|
130
200
|
experimental: {
|
|
131
201
|
reactDebugChannel: false,
|
|
132
202
|
...nextConfig.experimental
|
|
133
203
|
},
|
|
134
|
-
rewrites: async () =>
|
|
204
|
+
rewrites: async () => {
|
|
205
|
+
let rewrites = await nextConfig.rewrites?.();
|
|
206
|
+
for (const next of [...buildFiles, rewrite]) rewrites = withRewrite(rewrites, next);
|
|
207
|
+
return rewrites ?? [];
|
|
208
|
+
}
|
|
135
209
|
};
|
|
136
210
|
};
|
|
137
211
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { DEV_EDITOR_PREFIX, EDITOR_PRELUDE, editorPage } from "@goodfellow-cms/core";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { join, resolve, sep } from "node:path";
|
|
5
|
+
//#region src/dev-editor.ts
|
|
6
|
+
const CONFIG_FILES = [
|
|
7
|
+
"goodfellow.config.tsx",
|
|
8
|
+
"goodfellow.config.ts",
|
|
9
|
+
"goodfellow.config.jsx",
|
|
10
|
+
"goodfellow.config.js"
|
|
11
|
+
];
|
|
12
|
+
const ENTRY = "\0goodfellow:next-editor";
|
|
13
|
+
const TAILWIND_BROWSER = "tailwind-browser.js";
|
|
14
|
+
/** How long the editor's frames stay as built before the admin panel reloads them. */
|
|
15
|
+
const REBUILT_DELAY = 300;
|
|
16
|
+
const TYPES = {
|
|
17
|
+
html: "text/html; charset=utf-8",
|
|
18
|
+
js: "text/javascript; charset=utf-8",
|
|
19
|
+
css: "text/css; charset=utf-8",
|
|
20
|
+
map: "application/json",
|
|
21
|
+
json: "application/json"
|
|
22
|
+
};
|
|
23
|
+
async function startDevEditor(root) {
|
|
24
|
+
const configFile = CONFIG_FILES.map((name) => join(root, name)).find((file) => existsSync(file));
|
|
25
|
+
if (!configFile) throw new Error(`No goodfellow.config.tsx in ${root}.`);
|
|
26
|
+
const outDir = join(root, "node_modules/.goodfellow/next-editor");
|
|
27
|
+
await mkdir(outDir, { recursive: true });
|
|
28
|
+
const [{ watch }, { default: tailwindBrowser }] = await Promise.all([import("rolldown"), import("./tailwind-browser-Ds-ZH7sO.js")]);
|
|
29
|
+
await writeFile(join(outDir, TAILWIND_BROWSER), tailwindBrowser);
|
|
30
|
+
const stylesheets = /* @__PURE__ */ new Set();
|
|
31
|
+
let version = 0;
|
|
32
|
+
let built = () => {};
|
|
33
|
+
const ready = new Promise((resolveReady) => {
|
|
34
|
+
built = resolveReady;
|
|
35
|
+
});
|
|
36
|
+
let counting;
|
|
37
|
+
const writePage = async () => {
|
|
38
|
+
const css = await Promise.all([...stylesheets].map((file) => readFile(file, "utf8")));
|
|
39
|
+
await writeFile(join(outDir, "editor.css"), css.join("\n"));
|
|
40
|
+
await writeFile(join(outDir, "index.html"), editorPage({
|
|
41
|
+
scripts: ["editor.js"],
|
|
42
|
+
stylesheets: ["editor.css"]
|
|
43
|
+
}));
|
|
44
|
+
counting = setTimeout(() => {
|
|
45
|
+
version += 1;
|
|
46
|
+
writeFile(join(outDir, "version.json"), JSON.stringify({ version }));
|
|
47
|
+
}, version === 0 ? 0 : REBUILT_DELAY);
|
|
48
|
+
};
|
|
49
|
+
watch({
|
|
50
|
+
input: { editor: ENTRY },
|
|
51
|
+
cwd: root,
|
|
52
|
+
platform: "browser",
|
|
53
|
+
tsconfig: existsSync(join(root, "tsconfig.json")) ? join(root, "tsconfig.json") : false,
|
|
54
|
+
transform: {
|
|
55
|
+
jsx: { runtime: "automatic" },
|
|
56
|
+
define: { "process.env.NODE_ENV": JSON.stringify("development") }
|
|
57
|
+
},
|
|
58
|
+
plugins: [{
|
|
59
|
+
name: "goodfellow:next-editor",
|
|
60
|
+
resolveId: (id) => id === ENTRY ? id : void 0,
|
|
61
|
+
load(id) {
|
|
62
|
+
if (id === ENTRY) return [
|
|
63
|
+
`import config from ${JSON.stringify(configFile)};`,
|
|
64
|
+
`import { mountEditorFrame } from "@goodfellow-cms/admin/editor";`,
|
|
65
|
+
`import "@puckeditor/core/puck.css";`,
|
|
66
|
+
`import "@goodfellow-cms/admin/styles.css";`,
|
|
67
|
+
`mountEditorFrame(config, undefined, { tailwindBrowserUrl: ${JSON.stringify(TAILWIND_BROWSER)} });`
|
|
68
|
+
].join("\n");
|
|
69
|
+
if (id.endsWith(".css")) {
|
|
70
|
+
stylesheets.add(id);
|
|
71
|
+
return {
|
|
72
|
+
code: "",
|
|
73
|
+
moduleType: "js"
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}],
|
|
78
|
+
onLog(level, log, handler) {
|
|
79
|
+
if (log.code === "MODULE_LEVEL_DIRECTIVE") return;
|
|
80
|
+
handler(level, log);
|
|
81
|
+
},
|
|
82
|
+
output: {
|
|
83
|
+
dir: outDir,
|
|
84
|
+
format: "iife",
|
|
85
|
+
codeSplitting: false,
|
|
86
|
+
entryFileNames: "editor.js",
|
|
87
|
+
banner: EDITOR_PRELUDE,
|
|
88
|
+
sourcemap: true
|
|
89
|
+
}
|
|
90
|
+
}).on("event", (event) => {
|
|
91
|
+
if (event.code === "BUNDLE_START") clearTimeout(counting);
|
|
92
|
+
else if (event.code === "BUNDLE_END") {
|
|
93
|
+
event.result.close();
|
|
94
|
+
writePage().then(built, (error) => {
|
|
95
|
+
console.error(`The editor's frames couldn't be written: ${error.message}`);
|
|
96
|
+
built();
|
|
97
|
+
});
|
|
98
|
+
} else if (event.code === "ERROR") {
|
|
99
|
+
event.result?.close();
|
|
100
|
+
console.error(`The editor's frames couldn't be built: ${event.error.message}`);
|
|
101
|
+
built();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return { async serve(req, res) {
|
|
105
|
+
const pathname = new URL(req.url ?? "/", "http://localhost").pathname;
|
|
106
|
+
const page = pathname === DEV_EDITOR_PREFIX.slice(0, -1);
|
|
107
|
+
if (!(page || pathname.startsWith(DEV_EDITOR_PREFIX)) || req.method !== "GET" && req.method !== "HEAD") return false;
|
|
108
|
+
await ready;
|
|
109
|
+
const name = page ? "index.html" : pathname.slice(DEV_EDITOR_PREFIX.length) || "index.html";
|
|
110
|
+
const file = resolve(outDir, name);
|
|
111
|
+
if (!file.startsWith(`${outDir}${sep}`)) return false;
|
|
112
|
+
try {
|
|
113
|
+
const data = await readFile(file);
|
|
114
|
+
res.setHeader("Content-Type", TYPES[file.slice(file.lastIndexOf(".") + 1)] ?? "application/octet-stream");
|
|
115
|
+
res.setHeader("Cache-Control", "no-store");
|
|
116
|
+
res.end(req.method === "HEAD" ? void 0 : data);
|
|
117
|
+
} catch {
|
|
118
|
+
res.writeHead(404).end();
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
} };
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
export { startDevEditor };
|
package/dist/editor.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { GoodfellowConfig } from "@goodfellow-cms/core";
|
|
2
|
+
import "@goodfellow-cms/admin/styles.css";
|
|
3
|
+
import "@puckeditor/core/puck.css";
|
|
4
|
+
//#region src/editor.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The editor's frames, for a Next.js site's `app/admin/editor/page.tsx`,
|
|
7
|
+
* which must be a Client Component (`"use client"`) that imports the site's
|
|
8
|
+
* config: Puck, the config and every block, sandboxed away from the admin
|
|
9
|
+
* panel's page, which signs in and publishes.
|
|
10
|
+
*/
|
|
11
|
+
export declare function GoodfellowEditor({ config }: {
|
|
12
|
+
config: GoodfellowConfig;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
//#endregion
|
package/dist/editor.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import "@goodfellow-cms/admin/styles.css";
|
|
5
|
+
import "@puckeditor/core/puck.css";
|
|
6
|
+
//#region src/editor.tsx
|
|
7
|
+
/** Started once a page: React runs effects twice in development, and a second start would connect again. */
|
|
8
|
+
let started = false;
|
|
9
|
+
/**
|
|
10
|
+
* The editor's frames, for a Next.js site's `app/admin/editor/page.tsx`,
|
|
11
|
+
* which must be a Client Component (`"use client"`) that imports the site's
|
|
12
|
+
* config: Puck, the config and every block, sandboxed away from the admin
|
|
13
|
+
* panel's page, which signs in and publishes.
|
|
14
|
+
*/
|
|
15
|
+
function GoodfellowEditor({ config }) {
|
|
16
|
+
const element = useRef(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const container = element.current;
|
|
19
|
+
if (!container || started) return;
|
|
20
|
+
started = true;
|
|
21
|
+
Promise.all([import("@goodfellow-cms/admin/editor"), import("./tailwind-browser-Ds-ZH7sO.js").then((module) => module.default)]).then(([{ mountEditorFrame }, tailwindBrowser]) => {
|
|
22
|
+
const tailwindBrowserUrl = URL.createObjectURL(new Blob([tailwindBrowser], { type: "text/javascript" }));
|
|
23
|
+
mountEditorFrame(config, container, { tailwindBrowserUrl });
|
|
24
|
+
});
|
|
25
|
+
}, [config]);
|
|
26
|
+
return /* @__PURE__ */ jsx("div", {
|
|
27
|
+
ref: element,
|
|
28
|
+
id: "goodfellow-frame"
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { GoodfellowEditor };
|
package/dist/export.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import { SelfHostedResult, SiteProblem } from "@goodfellow-cms/core";
|
|
2
|
+
import { SiteFile } from "@goodfellow-cms/core/node";
|
|
3
|
+
//#region src/site-files.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The Next.js starter's files that `goodfellow-next update` keeps up to date
|
|
6
|
+
* where nobody has changed them, as the starter now has them. A test checks
|
|
7
|
+
* they match `templates/next`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const NEXT_SITE_FILES: readonly SiteFile[];
|
|
10
|
+
//#endregion
|
|
1
11
|
//#region src/export.d.ts
|
|
2
12
|
/**
|
|
3
13
|
* Writes the calendar files of the site's collections of events into the
|
|
@@ -5,12 +15,59 @@
|
|
|
5
15
|
* how many it wrote.
|
|
6
16
|
*/
|
|
7
17
|
export declare function writeCalendarFiles(outDir: string, root?: string): Promise<number>;
|
|
18
|
+
/**
|
|
19
|
+
* Writes the feeds of the site's collections into the export, as `goodfellow
|
|
20
|
+
* build` does. Returns how many it wrote: none without the site's address.
|
|
21
|
+
*/
|
|
22
|
+
export declare function writeFeedFiles(outDir: string, root?: string): Promise<number>;
|
|
23
|
+
/**
|
|
24
|
+
* The folders the calendar files and feeds go in: `calendars/` and `feeds/`,
|
|
25
|
+
* and on a site in several languages, the same under each other language's
|
|
26
|
+
* code, such as `es/feeds/`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildFileFolders(root?: string): Promise<string[]>;
|
|
29
|
+
/** What `writeFontFiles()` did, for `buildNotes()`. */
|
|
30
|
+
export interface FontsWritten {
|
|
31
|
+
fonts?: SelfHostedResult;
|
|
32
|
+
robotsElsewhere?: string;
|
|
33
|
+
sitemap?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Copies the site's Google Fonts into the export and points its pages at
|
|
37
|
+
* them, as `goodfellow build` does (`selfHostFonts()`), with the export's base
|
|
38
|
+
* path, and says where search engines read `robots.txt` for a site in a
|
|
39
|
+
* subfolder (`rootRobotsUrl()`).
|
|
40
|
+
*/
|
|
41
|
+
export declare function writeFontFiles(outDir: string, root?: string): Promise<FontsWritten>;
|
|
42
|
+
/**
|
|
43
|
+
* Writes the build record (`goodfellow-build.json`) into the export, as
|
|
44
|
+
* `goodfellow build` does, from the dates the processes that rendered its
|
|
45
|
+
* pages wrote into `.next/` (see `withGoodfellow()`). Returns when the site
|
|
46
|
+
* stops being current, if it does.
|
|
47
|
+
*/
|
|
48
|
+
export declare function writeBuildRecordFile(outDir: string, root?: string): Promise<string | undefined>;
|
|
49
|
+
/** What `writeRedirectFiles()` wrote. */
|
|
50
|
+
export interface RedirectsWritten {
|
|
51
|
+
/** How many pages at old addresses. */
|
|
52
|
+
pages: number;
|
|
53
|
+
/** How many redirects didn't fit in Cloudflare Pages' `_redirects`, and are left to their pages. */
|
|
54
|
+
cloudflareLeft: number;
|
|
55
|
+
}
|
|
8
56
|
/**
|
|
9
57
|
* Writes a page at each of the site's old addresses that sends visitors on, as
|
|
10
|
-
* `goodfellow build` does
|
|
11
|
-
*
|
|
58
|
+
* `goodfellow build` does, and the same redirects in `_redirects` for
|
|
59
|
+
* Cloudflare Pages, which sends them itself. Pages win: an address the export
|
|
60
|
+
* has a page at keeps it.
|
|
61
|
+
*/
|
|
62
|
+
export declare function writeRedirectFiles(outDir: string, root?: string): Promise<RedirectsWritten>;
|
|
63
|
+
/**
|
|
64
|
+
* For a site with an admin address (its config's `admin`, which the exported
|
|
65
|
+
* `goodfellow-site.json` carries), puts the guard first in every page of the
|
|
66
|
+
* export and adds Cloudflare Pages' header rules, as `goodfellow build` does.
|
|
67
|
+
* Run it last, once every page is written. Returns how many pages it guarded,
|
|
68
|
+
* or `undefined` for a site without an admin address.
|
|
12
69
|
*/
|
|
13
|
-
export declare function
|
|
70
|
+
export declare function guardExport(outDir: string, root?: string): Promise<number | undefined>;
|
|
14
71
|
/**
|
|
15
72
|
* Puts a static export's prefetch files where the browser asks for them.
|
|
16
73
|
* Next.js names each after its segment path with `/` turned into `.`
|
|
@@ -19,4 +76,46 @@ export declare function writeRedirectFiles(outDir: string, root?: string): Promi
|
|
|
19
76
|
* prefetch is "not found". Returns how many files it moved; none elsewhere.
|
|
20
77
|
*/
|
|
21
78
|
export declare function fixSegmentFiles(outDir: string): Promise<number>;
|
|
79
|
+
/** Where the editor's frames' page is in an export, and in a full-stack site's build. */
|
|
80
|
+
export declare const EDITOR_PAGES: string[];
|
|
81
|
+
/**
|
|
82
|
+
* Gives the editor's frames' page (`app/admin/editor/`) its Content Security
|
|
83
|
+
* Policy and first script, which removes WebRTC, as the first things in its
|
|
84
|
+
* head, so they apply before anything Next.js put there. The policy runs only
|
|
85
|
+
* the site's own scripts, Next.js's inline ones by their hashes, and fetches
|
|
86
|
+
* nothing (`editorPolicy()`). Returns whether it found the page.
|
|
87
|
+
*/
|
|
88
|
+
export declare function writeEditorPolicy(dir: string): Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* On a site in several languages, puts each page's language on its `<html>`,
|
|
91
|
+
* which Next.js's root layout, shared by every page, says is the main one:
|
|
92
|
+
* in a static export's pages (`outDir`), or, without one, in the pages a
|
|
93
|
+
* full-stack site's `next build` rendered ahead. Returns how many it changed.
|
|
94
|
+
*/
|
|
95
|
+
export declare function writePageLanguages(outDir: string | undefined, root?: string): Promise<number>;
|
|
96
|
+
/** A page `next build` rendered ahead: its address on the site, and its HTML. */
|
|
97
|
+
export interface BuiltPage {
|
|
98
|
+
url: string;
|
|
99
|
+
html: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The pages `next build` rendered ahead for a full-stack site (`withGoodfellow(config,
|
|
103
|
+
* { server: true })`), at their addresses on the site, without its base path, as the
|
|
104
|
+
* Search block looks them up. Next.js lists them in `.next/prerender-manifest.json`
|
|
105
|
+
* and keeps their HTML in `.next/server/app/`. The admin panel and Next.js's own pages are left out.
|
|
106
|
+
*/
|
|
107
|
+
export declare function builtPages(root?: string): Promise<BuiltPage[]>;
|
|
108
|
+
/**
|
|
109
|
+
* The pages a static export has, at their addresses on the site, without its
|
|
110
|
+
* base path: `about.html` and `about/index.html` are `/about`. The admin panel
|
|
111
|
+
* and Next.js's own files are left out.
|
|
112
|
+
*/
|
|
113
|
+
export declare function exportedPages(outDir: string): Promise<BuiltPage[]>;
|
|
114
|
+
/**
|
|
115
|
+
* What automated checks find on the pages Next.js built, as `goodfellow build`
|
|
116
|
+
* reports them: images without alt text, headings that skip a level, links
|
|
117
|
+
* that don't say where they go, and axe-core's checks (`checkBuiltPages()`).
|
|
118
|
+
* Pages that aren't the site's, such as Next.js's own, are left out.
|
|
119
|
+
*/
|
|
120
|
+
export declare function checkPages(pages: readonly BuiltPage[], root?: string): Promise<SiteProblem[]>;
|
|
22
121
|
//#endregion
|