@gez/rspack
Version:
A high-performance Rspack integration for Gez microfrontend framework, providing module federation and SSR capabilities.
131 lines (128 loc) • 3.59 kB
JavaScript
import fs from "node:fs";
import { pathToFileURL } from "node:url";
import { styleText } from "node:util";
import {
PathType,
RenderContext,
createApp,
mergeMiddlewares
} from "@gez/core";
import { createVmImport } from "@gez/import";
import hotMiddleware from "webpack-hot-middleware";
import { createRspackConfig } from "./config.mjs";
import { pack } from "./pack.mjs";
import { createRsBuild } from "./utils/index.mjs";
export async function createRspackApp(gez, options) {
const app = await createApp(gez, gez.command);
switch (gez.command) {
case gez.COMMAND.dev:
app.middleware = mergeMiddlewares([
...await createMiddleware(gez, options),
app.middleware
]);
app.render = rewriteRender(gez);
break;
case gez.COMMAND.build:
app.build = rewriteBuild(gez, options);
break;
}
return app;
}
async function createMiddleware(gez, options = {}) {
if (gez.command !== gez.COMMAND.dev) {
return [];
}
const rsBuild = createRsBuild([
generateBuildConfig(gez, options, "client"),
generateBuildConfig(gez, options, "server")
]);
rsBuild.watch();
const hot = hotMiddleware(rsBuild.compilers[0], {
path: `${gez.basePath}hot-middleware`
});
return [
(req, res, next) => {
if (req.url?.startsWith(`${gez.basePath}hot-middleware`)) {
return hot(req, res, next);
}
return next();
}
];
}
function generateBuildConfig(gez, options, buildTarget) {
const config = createRspackConfig(gez, buildTarget, options);
options.config?.({ gez, options, buildTarget, config });
return config;
}
function rewriteRender(gez) {
return async (options) => {
const baseURL = pathToFileURL(gez.root);
const importMap = await gez.getImportMap("server");
const vmImport = createVmImport(baseURL, importMap);
const rc = new RenderContext(gez, options);
const module = await vmImport(
`${gez.name}/src/entry.server`,
import.meta.url,
{
console,
setTimeout,
clearTimeout,
process,
URL,
global
}
);
const serverRender = module[rc.entryName];
if (typeof serverRender === "function") {
await serverRender(rc);
}
return rc;
};
}
function rewriteBuild(gez, options = {}) {
return async () => {
for (const item of gez.moduleConfig.exports) {
if (item.type === PathType.root) {
const text = fs.readFileSync(
gez.resolvePath("./", item.exportPath),
"utf-8"
);
if (/\bexport\s+\*\s+from\b/.test(text)) {
console.log(
styleText(
"red",
`The export * syntax is used in the file '${item.exportPath}', which will cause the packaging to fail.`
)
);
console.log(
styleText(
"red",
`Please use specific export syntax, such as export { a, b } from './a';`
)
);
return false;
}
}
}
await createRsBuild([
generateBuildConfig(gez, options, "client"),
generateBuildConfig(gez, options, "server"),
generateBuildConfig(gez, options, "node")
]).build();
gez.writeSync(
gez.resolvePath("dist/index.js"),
`
async function start() {
const options = await import('./node/src/entry.node.js').then(
(mod) => mod.default
);
const { Gez } = await import('@gez/core');
const gez = new Gez(options);
await gez.init(gez.COMMAND.start);
}
start();
`.trim()
);
return pack(gez);
};
}