one
Version:
One is a new React Framework that makes Vite serve both native and web.
118 lines (117 loc) • 5.55 kB
JavaScript
import { dirname, join, resolve } from "node:path";
import generator from "@babel/generator";
import parser from "@babel/parser";
import traverse from "@babel/traverse";
import t from "@babel/types";
import { resolvePath } from "@vxrn/resolve";
import FSExtra from "fs-extra";
import fs from "fs-extra";
import { serverlessVercelNodeJsConfig } from "../config/vc-config-base";
import { serverlessVercelPackageJson } from "../config/vc-package-base";
import { getPathFromRoute } from "../getPathFromRoute";
async function createApiServerlessFunction(route, code, oneOptionsRoot, postBuildLogs) {
try {
const path = getPathFromRoute(route, { includeIndex: !0 });
postBuildLogs.push(`[one.build][vercel.createSsrServerlessFunction] pageName: ${path}`);
const funcFolder = join(oneOptionsRoot, `.vercel/output/functions/${path}.func`);
if (await fs.ensureDir(funcFolder), code.includes("react")) {
postBuildLogs.push(
`[one.build][vercel.createSsrServerlessFunction] detected react in depenency tree for ${path}`
);
const reactPath = dirname(resolvePath("react/package.json", oneOptionsRoot));
await fs.copy(resolve(reactPath), resolve(join(funcFolder, "node_modules", "react")));
}
const distAssetsFolder = resolve(join(funcFolder, "assets"));
postBuildLogs.push(
`[one.build][vercel.createSsrServerlessFunction] copy shared assets to ${distAssetsFolder}`
);
const sourceAssetsFolder = resolve(join(oneOptionsRoot, "dist", "api", "assets"));
await FSExtra.pathExists(sourceAssetsFolder) && await fs.copy(sourceAssetsFolder, distAssetsFolder), await fs.ensureDir(resolve(join(funcFolder, "entrypoint")));
const entrypointFilePath = resolve(join(funcFolder, "entrypoint", "index.js"));
postBuildLogs.push(
`[one.build][vercel.createSsrServerlessFunction] writing entrypoint to ${entrypointFilePath}`
), await fs.writeFile(entrypointFilePath, wrapHandlerFunctions(code));
const packageJsonFilePath = resolve(join(funcFolder, "package.json"));
return postBuildLogs.push(
`[one.build][vercel.createSsrServerlessFunction] writing package.json to ${packageJsonFilePath}`
), await fs.writeJSON(packageJsonFilePath, serverlessVercelPackageJson), postBuildLogs.push(
`[one.build][vercel.createSsrServerlessFunction] writing .vc-config.json to ${join(funcFolder, ".vc-config.json")}`
), fs.writeJson(join(funcFolder, ".vc-config.json"), {
...serverlessVercelNodeJsConfig,
handler: "entrypoint/index.js"
});
} catch (e) {
console.error(
`[one.build][vercel.createSsrServerlessFunction] failed to generate func for ${route.file}`,
e
);
}
}
function wrapHandlerFunctions(code) {
const ast = parser.parse(code, {
sourceType: "module"
});
return traverse.default(ast, {
FunctionDeclaration(path) {
const { node } = path, functionNamesToHandle = [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"HEAD",
"OPTIONS"
// TODO: more possibilities?
];
if (!node.id || !functionNamesToHandle.includes(node.id.name) || node.extra && node.extra.isWrapper || node.extra && node.extra.isWrapped) return;
const originalName = `orig_${node.id.name}`, originalFunction = t.functionDeclaration(
t.identifier(originalName),
node.params,
node.body,
node.generator,
node.async
), requestIdentifier = t.identifier("request"), wrapperParams = [requestIdentifier], urlIdentifier = t.identifier("url"), paramsIdentifier = t.identifier("params"), urlDecl = t.variableDeclaration("const", [
t.variableDeclarator(
urlIdentifier,
t.newExpression(t.identifier("URL"), [
t.memberExpression(requestIdentifier, t.identifier("url"))
])
)
]), paramsDecl = t.variableDeclaration("const", [
t.variableDeclarator(
paramsIdentifier,
t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("fromEntries")),
[
t.callExpression(
t.memberExpression(
t.memberExpression(
urlIdentifier,
t.identifier("searchParams")
),
t.identifier("entries")
),
[]
)
]
)
)
]), callOrigFnStatement = t.callExpression(t.identifier(originalName), [
requestIdentifier,
t.objectExpression([t.objectProperty(t.identifier("params"), paramsIdentifier)])
]), wrapperFunction = t.functionDeclaration(
t.identifier(node.id.name + ""),
wrapperParams,
t.blockStatement([urlDecl, paramsDecl, t.returnStatement(callOrigFnStatement)])
// No need to care if the wrapper function should be async,
// since we didn't use any await in the wrapper function, and we'll
// just return what the original function returns.
);
node.extra = node.extra || {}, node.extra.isWrapped = !0, wrapperFunction.extra = wrapperFunction.extra || {}, wrapperFunction.extra.isWrapper = !0, path.parentPath.isExportNamedDeclaration() ? path.replaceWithMultiple([originalFunction, t.exportNamedDeclaration(wrapperFunction, [])]) : path.replaceWithMultiple([originalFunction, wrapperFunction]);
}
}), generator.default(ast, {}).code;
}
export {
createApiServerlessFunction
};
//# sourceMappingURL=createApiServerlessFunction.js.map