silverbullet/plugos/compile.ts

149 lines
4.2 KiB
TypeScript
Raw Normal View History

2022-10-04 22:33:29 +08:00
// import { esbuild } from "../../mod.ts";
import * as esbuildWasm from "https://deno.land/x/esbuild@v0.14.54/wasm.js";
import * as esbuildNative from "https://deno.land/x/esbuild@v0.14.54/mod.js";
2022-10-06 17:31:49 +08:00
export const esbuild: typeof esbuildWasm = Deno.run === undefined
? esbuildWasm
: esbuildNative;
2022-10-04 22:33:29 +08:00
2022-10-08 22:36:06 +08:00
import { path } from "../server/deps.ts";
2022-10-04 22:33:29 +08:00
import { denoPlugin } from "../esbuild_deno_loader/mod.ts";
2022-10-08 21:46:56 +08:00
import { patchDenoLibJS } from "../common/hack.ts";
2022-04-26 01:46:08 +08:00
export async function compile(
filePath: string,
2022-05-11 17:49:27 +08:00
functionName: string | undefined = undefined,
2022-10-04 22:33:29 +08:00
debug = false,
2022-04-26 01:46:08 +08:00
excludeModules: string[] = [],
2022-10-06 17:31:49 +08:00
meta = false,
2022-04-26 01:46:08 +08:00
): Promise<string> {
2022-05-11 17:49:27 +08:00
let outFile = path.resolve(path.dirname(filePath), "_out.tmp");
2022-04-26 01:46:08 +08:00
let inFile = filePath;
if (functionName) {
// Generate a new file importing just this one function and exporting it
2022-05-11 17:49:27 +08:00
inFile = path.resolve(path.dirname(filePath), "_in.ts");
2022-10-04 22:33:29 +08:00
await Deno.writeTextFile(
2022-04-26 01:46:08 +08:00
inFile,
2022-10-06 17:31:49 +08:00
`import {${functionName}} from "./${
path.basename(
filePath,
)
}";export default ${functionName};`,
2022-04-26 01:46:08 +08:00
);
}
2022-10-04 22:33:29 +08:00
// console.log("External modules", excludeModules);
2022-07-06 18:17:14 +08:00
try {
// TODO: Figure out how to make source maps work correctly with eval() code
let result = await esbuild.build({
entryPoints: [path.basename(inFile)],
bundle: true,
format: "iife",
globalName: "mod",
platform: "browser",
sourcemap: false, //debug ? "inline" : false,
minify: !debug,
outfile: outFile,
metafile: true,
external: excludeModules,
2022-10-04 22:33:29 +08:00
treeShaking: true,
plugins: [
denoPlugin({
2022-10-08 22:29:43 +08:00
importMapURL: new URL("./../import_map.json", import.meta.url),
2022-10-04 22:33:29 +08:00
}),
],
loader: {
".css": "text",
2022-09-01 16:17:20 +08:00
".md": "text",
".txt": "text",
".html": "text",
".hbs": "text",
".png": "dataurl",
".gif": "dataurl",
".jpg": "dataurl",
},
2022-07-06 18:17:14 +08:00
absWorkingDir: path.resolve(path.dirname(inFile)),
});
2022-04-26 01:46:08 +08:00
2022-07-06 18:17:14 +08:00
if (meta) {
let text = await esbuild.analyzeMetafile(result.metafile);
console.log("Bundle info for", functionName, text);
}
2022-04-26 01:46:08 +08:00
2022-10-04 22:33:29 +08:00
let jsCode = await Deno.readTextFile(outFile);
2022-10-08 21:46:56 +08:00
jsCode = patchDenoLibJS(jsCode);
2022-10-04 22:33:29 +08:00
await Deno.remove(outFile);
2022-07-06 18:17:14 +08:00
return `(() => { ${jsCode} return mod;})()`;
} finally {
if (inFile !== filePath) {
2022-10-04 22:33:29 +08:00
await Deno.remove(inFile);
2022-07-06 18:17:14 +08:00
}
2022-04-26 01:46:08 +08:00
}
2022-05-13 20:36:26 +08:00
}
export async function compileModule(
cwd: string,
2022-10-06 17:31:49 +08:00
moduleName: string,
2022-05-13 20:36:26 +08:00
): Promise<string> {
let inFile = path.resolve(cwd, "_in.ts");
2022-10-04 22:33:29 +08:00
await Deno.writeTextFile(inFile, `export * from "${moduleName}";`);
2022-05-13 20:36:26 +08:00
let code = await compile(inFile);
2022-10-04 22:33:29 +08:00
await Deno.remove(inFile);
2022-05-13 20:36:26 +08:00
return code;
}
2022-10-04 22:33:29 +08:00
// export async function sandboxCompile(
// filename: string,
// code: string,
// functionName?: string,
// debug: boolean = false,
// installModules: string[] = [],
// globalModules: string[] = []
// ): Promise<string> {
// let tmpDir = `${tmpdir()}/plugos-${Math.random()}`;
// await mkdir(tmpDir, { recursive: true });
2022-05-13 20:36:26 +08:00
2022-10-04 22:33:29 +08:00
// const srcNodeModules = `${nodeModulesDir}/node_modules`;
// const targetNodeModules = `${tmpDir}/node_modules`;
2022-05-13 20:36:26 +08:00
2022-10-04 22:33:29 +08:00
// await mkdir(`${targetNodeModules}/@silverbulletmd`, { recursive: true });
// await mkdir(`${targetNodeModules}/@plugos`, { recursive: true });
// for (const exposedModule of exposedModules) {
// await symlink(
// `${srcNodeModules}/${exposedModule}`,
// `${targetNodeModules}/${exposedModule}`,
// "dir"
// );
// }
// for (let moduleName of installModules) {
// await execFilePromise("npm", ["install", moduleName], {
// cwd: tmpDir,
// });
// }
2022-05-13 20:36:26 +08:00
2022-10-04 22:33:29 +08:00
// await writeFile(`${tmpDir}/${filename}`, code);
// let jsCode = await compile(
// `${tmpDir}/${filename}`,
// functionName,
// debug,
// globalModules
// );
// await rm(tmpDir, { recursive: true });
// return jsCode;
// }
2022-05-13 20:36:26 +08:00
export async function sandboxCompileModule(
2022-10-04 22:33:29 +08:00
moduleUrl: string,
2022-10-06 17:31:49 +08:00
globalModules: string[] = [],
2022-05-13 20:36:26 +08:00
): Promise<string> {
2022-10-04 22:33:29 +08:00
await Deno.writeTextFile(
"_mod.ts",
2022-10-06 17:31:49 +08:00
`module.exports = require("${moduleUrl}");`,
2022-05-13 20:36:26 +08:00
);
2022-10-04 22:33:29 +08:00
let code = await compile("_mod.ts", undefined, false, globalModules);
await Deno.remove("_mod.ts");
return code;
2022-04-26 01:46:08 +08:00
}