1 | var __rest = (this && this.__rest) || function (s, e) {
|
2 | var t = {};
|
3 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
4 | t[p] = s[p];
|
5 | if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
6 | for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
7 | if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
8 | t[p[i]] = s[p[i]];
|
9 | }
|
10 | return t;
|
11 | };
|
12 | import crypto from "crypto";
|
13 | import { resolve, join } from "path";
|
14 | import { writeFile, copyFile, fileExists } from "./fs.js";
|
15 | import module from "module";
|
16 | const { createRequire } = module;
|
17 | const require = createRequire(import.meta.url);
|
18 | import { Document as InternalDocument, __HeadContext, __InternalDocContext, } from "../document.js";
|
19 | import { h } from "preact";
|
20 | import { renderToString } from "preact-render-to-string";
|
21 | import { generateStaticPropsContext } from "./router.js";
|
22 | import fetch from "node-fetch";
|
23 | export const CACHE_DIR = ".microsite/cache";
|
24 | export const STAGING_DIR = ".microsite/staging";
|
25 | export const SSR_DIR = ".microsite/ssr";
|
26 | export const OUT_DIR_NO_BASE = "./dist";
|
27 | export let OUT_DIR = "./dist";
|
28 | export const setBasePath = (p) => (OUT_DIR =
|
29 | p === "/"
|
30 | ? OUT_DIR
|
31 | : join(OUT_DIR, ...p.replace(/^\//, "").replace(/\/$/, "").split("/")));
|
32 | export const getFileNameFromPath = (path) => {
|
33 | return path
|
34 | .split(STAGING_DIR)[1]
|
35 | .replace(/^\/src\//, "")
|
36 | .replace(/([\[\]])/gi, "_")
|
37 | .replace(/\..*$/, "");
|
38 | };
|
39 | const PROXY_IMPORT_REGEX = /^.*\.(\w+)\.proxy\.js$/g;
|
40 | export const proxyImportTransformer = {
|
41 | filter: (source) => PROXY_IMPORT_REGEX.test(source),
|
42 | transform: (source) => source.replace(PROXY_IMPORT_REGEX, (fullMatch, originalExt) => {
|
43 | if (originalExt === "json") {
|
44 | return fullMatch;
|
45 | }
|
46 | return fullMatch.replace(".proxy.js", "");
|
47 | }),
|
48 | };
|
49 | const PREACT_IMPORT_REGEX = /^.*_snowpack\/pkg\/preact([\/\w]+)?\.js$/gm;
|
50 | export const preactImportTransformer = {
|
51 | filter: (source) => PREACT_IMPORT_REGEX.test(source),
|
52 | transform: (source) => source.replace(PREACT_IMPORT_REGEX, (_match, subpath) => {
|
53 | return subpath ? `preact${subpath}` : `preact`;
|
54 | }),
|
55 | };
|
56 | const PREACT_PKG = require("preact/package.json");
|
57 | const PREACT_VERSION = PREACT_PKG.version;
|
58 | const PREACT_CDN_LOOKUP = Object.keys(PREACT_PKG.exports).reduce((acc, key) => {
|
59 | if (key !== "./package.json" && key !== "./") {
|
60 | const sub = key.replace(/^\./, "");
|
61 | return Object.assign(Object.assign({}, acc), { [`preact${sub}`]: `https://cdn.skypack.dev/preact@${PREACT_VERSION}${sub}` });
|
62 | }
|
63 | return acc;
|
64 | }, {});
|
65 | let PREACT_CDN_SOURCES = null;
|
66 | const resolvePreactCdnSources = async () => {
|
67 | if (PREACT_CDN_SOURCES)
|
68 | return;
|
69 | const mdls = Object.keys(PREACT_CDN_LOOKUP);
|
70 | const pinnedUrls = await Promise.all(mdls.map((mdl) => {
|
71 | const lookupUrl = PREACT_CDN_LOOKUP[mdl];
|
72 | return fetch(lookupUrl).then((res) => `https://cdn.skypack.dev${res.headers.get("x-pinned-url")}`);
|
73 | }));
|
74 | PREACT_CDN_SOURCES = mdls.reduce((acc, curr, i) => {
|
75 | return Object.assign(Object.assign({}, acc), { [curr]: pinnedUrls[i] });
|
76 | }, {});
|
77 | return;
|
78 | };
|
79 | const PREACT_REGEX = /['"]preact([\/\w]+)?['"]/gm;
|
80 | export const preactToCDN = async (code) => {
|
81 | if (!/preact/gm.test(code)) {
|
82 | return code;
|
83 | }
|
84 | await resolvePreactCdnSources();
|
85 | return code.replace(PREACT_REGEX, (fullMatch, subpath) => {
|
86 | if (subpath === "/hooks") {
|
87 | return fullMatch.replace("preact/hooks", PREACT_CDN_SOURCES["preact/hooks"]);
|
88 | }
|
89 | return fullMatch.replace("preact", PREACT_CDN_SOURCES["preact"]);
|
90 | });
|
91 | };
|
92 | const WITH_HYDRATE_REGEX = /import\s+\{\s*withHydrate\s*(?:as (\w+))?\}\s+from\s+['"]microsite\/hydrate(?:\.js)?['"];?/gim;
|
93 | export const withHydrateTransformer = {
|
94 | filter: (source) => WITH_HYDRATE_REGEX.test(source),
|
95 | transform: (source) => source.replace(WITH_HYDRATE_REGEX, (_match, name = "withHydrate") => {
|
96 | return `const ${name} = i=>i;`;
|
97 | }),
|
98 | };
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 | export const stripWithHydrate = (source) => {
|
105 | if (!withHydrateTransformer.filter(source))
|
106 | return source;
|
107 | return withHydrateTransformer.transform(source);
|
108 | };
|
109 | export const hashContentSync = (content, len) => {
|
110 | const hash = crypto.createHash("sha256");
|
111 | hash.update(Buffer.from(content));
|
112 | let res = hash.digest("hex");
|
113 | if (typeof len === "number")
|
114 | res = res.slice(0, len);
|
115 | return res;
|
116 | };
|
117 | export const emitFile = (filename, content) => writeFile(resolve(process.cwd(), join(SSR_DIR, filename)), content.toString());
|
118 | export const emitFinalAsset = (filename, content) => writeFile(resolve(process.cwd(), join(OUT_DIR, filename)), content.toString());
|
119 | export const copyAssetToFinal = async (path, transform) => copyFile(path, resolve(process.cwd(), join(OUT_DIR, path.slice(resolve(SSR_DIR).length))), { transform });
|
120 | const importPage = (filename) => import(resolve(process.cwd(), join(SSR_DIR, filename))).then((mod) => mod.default);
|
121 | let UserDocument = null;
|
122 | const getDocument = async () => {
|
123 | if (UserDocument)
|
124 | return UserDocument;
|
125 | else if (UserDocument === false)
|
126 | return InternalDocument;
|
127 | else if (await fileExists(resolve(process.cwd(), join(SSR_DIR, "pages", "_document.js")))) {
|
128 | UserDocument = await importPage(join("pages", "_document.js"));
|
129 | return UserDocument;
|
130 | }
|
131 | UserDocument = false;
|
132 | return InternalDocument;
|
133 | };
|
134 | export const renderPage = async (data, manifest, { basePath = "/", debug = false, hasGlobalScript = false } = {}) => {
|
135 | let [Document, Page] = await Promise.all([
|
136 | getDocument(),
|
137 | importPage(manifest.name),
|
138 | resolvePreactCdnSources(),
|
139 | ]);
|
140 | Page = unwrapPage(Page);
|
141 | const pageProps = data.props;
|
142 | const headContext = {
|
143 | head: {
|
144 | current: [],
|
145 | },
|
146 | };
|
147 | const HeadProvider = ({ children }) => {
|
148 | return (h(__HeadContext.Provider, { value: headContext }, children));
|
149 | };
|
150 | const _a = await Document.prepare({
|
151 | renderPage: async () => ({
|
152 | __renderPageResult: renderToString(h(HeadProvider, null,
|
153 | h(Page, Object.assign({}, pageProps)))),
|
154 | }),
|
155 | }), { __renderPageResult } = _a, docProps = __rest(_a, ["__renderPageResult"]);
|
156 | const docContext = {
|
157 | dev: false,
|
158 | manifest,
|
159 | styles: manifest.hydrateStyleBindings,
|
160 | scripts: manifest.hydrateBindings,
|
161 | preload: manifest.hydrateBindings ? Object.values(PREACT_CDN_SOURCES) : [],
|
162 | preconnect: [],
|
163 | debug,
|
164 | hasGlobalScript,
|
165 | basePath,
|
166 | __renderPageResult,
|
167 | __renderPageHead: headContext.head.current,
|
168 | };
|
169 | let contents = renderToString(h(__InternalDocContext.Provider, { value: docContext },
|
170 | h(Document, Object.assign({}, docProps))));
|
171 | contents = contents.replace(/<hydrate-marker>(\?h[\s\S]*?\?)<\/hydrate-marker>/g, "<$1>\n");
|
172 | contents = "<!DOCTYPE html>\n<!-- Generated by microsite -->\n" + contents;
|
173 | return {
|
174 | name: `${data.route.replace(/\.js$/, "")}.html`,
|
175 | contents,
|
176 | };
|
177 | };
|
178 | export const unwrapPage = (Page) => {
|
179 | return Page.Component ? Page.Component : Page;
|
180 | };
|
181 | let noop = () => Promise.resolve();
|
182 | export const importDataMethods = (path) => import(path).then((mod) => {
|
183 | var _a, _b;
|
184 | const Page = mod.default;
|
185 | let getStaticPaths = noop;
|
186 | let getStaticProps = noop;
|
187 | if (Page.Component) {
|
188 | getStaticPaths = (_a = Page.getStaticPaths) !== null && _a !== void 0 ? _a : noop;
|
189 | getStaticProps = (_b = Page.getStaticProps) !== null && _b !== void 0 ? _b : noop;
|
190 | }
|
191 | return { getStaticPaths, getStaticProps };
|
192 | });
|
193 |
|
194 | export async function applyDataMethods(fileName, handlers) {
|
195 | const { getStaticPaths, getStaticProps } = handlers;
|
196 |
|
197 | let staticPaths = [];
|
198 | staticPaths = await getStaticPaths({}).then((res) => { var _a; return (_a = res === null || res === void 0 ? void 0 : res.paths) !== null && _a !== void 0 ? _a : []; });
|
199 | if (staticPaths.length === 0) {
|
200 | const ctx = generateStaticPropsContext(fileName, fileName);
|
201 | const staticProps = await getStaticProps(ctx).then((res) => { var _a; return (_a = res === null || res === void 0 ? void 0 : res.props) !== null && _a !== void 0 ? _a : {}; });
|
202 | return [{ name: fileName, route: ctx.path, props: staticProps }];
|
203 | }
|
204 | return Promise.all(staticPaths.map((pathOrParams) => {
|
205 | const ctx = generateStaticPropsContext(fileName, pathOrParams);
|
206 | return getStaticProps(ctx).then((res) => {
|
207 | var _a;
|
208 | let staticProps = (_a = res === null || res === void 0 ? void 0 : res.props) !== null && _a !== void 0 ? _a : {};
|
209 | return { name: fileName, route: ctx.path, props: staticProps };
|
210 | });
|
211 | }));
|
212 | }
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|