@modern-js/server-core
Version:
A Progressive React Framework for modern web development.
160 lines (159 loc) • 6.07 kB
JavaScript
import path from "path";
import { fileReader } from "@modern-js/runtime-utils/fileReader";
import { fs, LOADABLE_STATS_FILE, MAIN_ENTRY_NAME, NESTED_ROUTE_SPEC_FILE, ROUTE_MANIFEST_FILE, SERVER_BUNDLE_DIRECTORY, compatibleRequire, isProd } from "@modern-js/utils";
import { uniqueKeyByRoute } from "../../../utils";
async function getHtmlTemplates(pwd, routes) {
const htmlRoutes = routes.filter((route) => route.entryName);
const htmls = await Promise.all(htmlRoutes.map(async (route) => {
let html;
try {
var _this;
const htmlPath = path.join(pwd, route.entryPath);
html = (_this = await fileReader.readFile(htmlPath, "utf-8")) === null || _this === void 0 ? void 0 : _this.toString();
} catch (e) {
}
return [
uniqueKeyByRoute(route),
html
];
}) || []);
const templates = Object.fromEntries(htmls);
return templates;
}
function injectTemplates(pwd, routes, htmlTemplatePromise) {
return async (c, next) => {
if (routes && !c.get("templates")) {
const templates = await (htmlTemplatePromise || getHtmlTemplates(pwd, routes));
c.set("templates", templates);
}
await next();
};
}
const loadBundle = async (filepath, logger) => {
if (!await fs.pathExists(filepath)) {
return void 0;
}
try {
const module = await compatibleRequire(filepath, false);
return module;
} catch (e) {
logger.error(`Load ${filepath} bundle failed, error = %s`, e instanceof Error ? e.stack || e.message : e);
return void 0;
}
};
async function getServerManifest(pwd, routes, logger) {
const loaderBundles = {};
const renderBundles = {};
await Promise.all(routes.filter((route) => Boolean(route.bundle)).map(async (route) => {
const entryName = route.entryName || MAIN_ENTRY_NAME;
const renderBundlePath = path.join(pwd, route.bundle || "");
const loaderBundlePath = path.join(pwd, SERVER_BUNDLE_DIRECTORY, `${entryName}-server-loaders.js`);
const renderBundle = await loadBundle(renderBundlePath, logger);
const loaderBundle = await loadBundle(loaderBundlePath, logger);
renderBundle && (renderBundles[entryName] = renderBundle);
loaderBundle && (loaderBundles[entryName] = (loaderBundle === null || loaderBundle === void 0 ? void 0 : loaderBundle.loadModules) ? await (loaderBundle === null || loaderBundle === void 0 ? void 0 : loaderBundle.loadModules()) : loaderBundle);
}));
const loadableUri = path.join(pwd, LOADABLE_STATS_FILE);
const loadableStats = await compatibleRequire(loadableUri).catch((_) => ({}));
const routesManifestUri = path.join(pwd, ROUTE_MANIFEST_FILE);
const routeManifest = await compatibleRequire(routesManifestUri).catch((_) => ({}));
const nestedRoutesJsonPath = path.join(pwd, NESTED_ROUTE_SPEC_FILE);
const nestedRoutesJson = await compatibleRequire(nestedRoutesJsonPath).catch((_) => ({}));
return {
loaderBundles,
renderBundles,
loadableStats,
routeManifest,
nestedRoutesJson
};
}
function injectServerManifest(pwd, routes, manifestPromise) {
return async (c, next) => {
if (routes && !c.get("serverManifest")) {
const logger = c.get("logger");
const serverManifest = await (manifestPromise || getServerManifest(pwd, routes, logger));
c.set("serverManifest", serverManifest);
}
await next();
};
}
async function getRscServerManifest(pwd) {
const rscServerManifest = await compatibleRequire(path.join(pwd, "bundles", "react-server-manifest.json")).catch((_) => void 0);
return rscServerManifest;
}
async function getClientManifest(pwd) {
const rscClientManifest = await compatibleRequire(path.join(pwd, "react-client-manifest.json")).catch((_) => void 0);
return rscClientManifest;
}
async function getRscSSRManifest(pwd) {
const rscSSRManifest = await compatibleRequire(path.join(pwd, "react-ssr-manifest.json")).catch((_) => void 0);
return rscSSRManifest;
}
const injectRscManifestPlugin = () => ({
name: "@modern-js/plugin-inject-rsc-manifest",
setup(api) {
return {
async prepare() {
var _config_server;
const { middlewares, distDirectory: pwd } = api.useAppContext();
const config = api.useConfigContext();
if (!((_config_server = config.server) === null || _config_server === void 0 ? void 0 : _config_server.rsc)) {
return;
}
middlewares.push({
name: "inject-rsc-manifest",
handler: async (c, next) => {
if (!c.get("rscServerManifest")) {
const rscServerManifest = await getRscServerManifest(pwd);
c.set("rscServerManifest", rscServerManifest);
}
if (!c.get("rscClientManifest")) {
const rscClientManifest = await getClientManifest(pwd);
c.set("rscClientManifest", rscClientManifest);
}
if (!c.get("rscSSRManifest")) {
const rscSSRManifest = await getRscSSRManifest(pwd);
c.set("rscSSRManifest", rscSSRManifest);
}
await next();
}
});
}
};
}
});
const injectResourcePlugin = () => ({
name: "@modern-js/plugin-inject-resource",
setup(api) {
return {
async prepare() {
const { middlewares, routes, distDirectory: pwd } = api.useAppContext();
let htmlTemplatePromise;
let manifestPromise;
if (isProd()) {
manifestPromise = getServerManifest(pwd, routes || [], console);
htmlTemplatePromise = getHtmlTemplates(pwd, routes || []);
}
middlewares.push({
name: "inject-server-manifest",
handler: injectServerManifest(pwd, routes, manifestPromise)
});
middlewares.push({
name: "inject-html",
handler: injectTemplates(pwd, routes, htmlTemplatePromise)
});
}
};
}
});
export {
getClientManifest,
getHtmlTemplates,
getRscSSRManifest,
getRscServerManifest,
getServerManifest,
injectResourcePlugin,
injectRscManifestPlugin,
injectServerManifest,
injectTemplates
};