UNPKG

hermesx

Version:

Run TypeScript files with Hermes JS engine

154 lines (153 loc) 7.13 kB
import { resolve, join, dirname, basename } from "node:path"; import { existsSync } from "fs"; import { tmpdir } from "os"; import { randomBytes } from "crypto"; import { fileURLToPath } from "node:url"; import { createRequire } from "node:module"; import { rspack } from "@rspack/core"; import { HermesXError } from "./hermes-binary.js"; export class Bundler { async bundleTypeScript(filePath, scriptArgs = []) { const require = createRequire(import.meta.url); const absolutePath = resolve(filePath); if (!existsSync(absolutePath)) { throw new HermesXError(`TypeScript file not found: ${filePath}`, "FILE_NOT_FOUND"); } // Create temporary output file const tempDir = tmpdir(); const randomSuffix = randomBytes(8).toString("hex"); const outputPath = join(tempDir, `hermesx-bundle-${randomSuffix}.js`); try { console.log(`Bundling ${basename(filePath)} with rspack...`); // Use rspack for TypeScript compilation and bundling const hermesSrcDir = dirname(fileURLToPath(import.meta.url)); console.log("hermesSrcDir", hermesSrcDir); const npxDir = hermesSrcDir.split("/node_modules/")[0]; const nodeModulesDir = npxDir + "/node_modules"; const hermesPackageRoot = join(hermesSrcDir, ".."); const rspackConfig = { context: hermesPackageRoot, entry: { main: absolutePath, }, output: { path: dirname(outputPath), filename: basename(outputPath), chunkFormat: "commonjs", }, mode: "development", target: ["es5"], resolve: { extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"], modules: [ npxDir, nodeModulesDir, join(hermesPackageRoot, "node_modules"), "node_modules", ], }, resolveLoader: { modules: [ npxDir, nodeModulesDir, join(hermesPackageRoot, "node_modules"), "node_modules", ], }, module: { rules: [ { test: /\.(ts|tsx|js|jsx|mjs|cjs)$/, // Don't exclude node_modules - we need to transform external libraries too use: [ { loader: "babel-loader", options: { configFile: join(hermesPackageRoot, "babel.config.cjs"), babelrc: false, root: hermesPackageRoot, cwd: hermesPackageRoot, // Force transformation of all files including node_modules ignore: [], }, }, ], type: "javascript/auto", }, ], }, optimization: { minimize: false, splitChunks: false, }, devtool: false, }; console.log("outputPath", outputPath); // Create a promise-based wrapper for rspack compilation const result = await new Promise((resolve, reject) => { const compiler = rspack(rspackConfig); compiler.run((err, stats) => { compiler.close((closeErr) => { if (closeErr) { reject(new HermesXError(`Rspack close error: ${closeErr.message}`, "COMPILATION_FAILED")); return; } if (err) { reject(new HermesXError(`Rspack compilation error: ${err.message}`, "COMPILATION_FAILED")); return; } if (!stats) { reject(new HermesXError("No stats returned from rspack compilation", "COMPILATION_FAILED")); return; } const hasErrors = stats.hasErrors(); if (hasErrors) { const info = stats.toJson(); resolve({ hasErrors: true, errors: info.errors }); } else { resolve({ hasErrors: false }); } }); }); }); if (result.hasErrors && result.errors) { const errorMessages = result.errors .map((err) => `${err.message || err}`) .join("\n"); throw new HermesXError(`Rspack compilation failed:\n${errorMessages}`, "COMPILATION_FAILED"); } // Prepend globals to the bundled file try { const fs = await import("fs/promises"); // Get the path to hermes-globals.js relative to the built lib directory const currentFile = fileURLToPath(import.meta.url); const currentDir = dirname(currentFile); const globalsPath = join(currentDir, "..", "hermes-globals.js"); const globalsContent = await fs.readFile(globalsPath, "utf8"); const bundledContent = await fs.readFile(outputPath, "utf8"); // Inject command line arguments const argsInjection = ` // Inject command line arguments if (globalThis.process && globalThis.process.argv) { globalThis.process.argv = ['hermes', '${basename(filePath)}'].concat(${JSON.stringify(scriptArgs)}); } `; // Combine globals, args injection, and bundled code const combinedContent = globalsContent + "\n" + argsInjection + "\n" + bundledContent; await fs.writeFile(outputPath, combinedContent, "utf8"); console.log(`Bundled to: ${outputPath}`); return outputPath; } catch (error) { throw new HermesXError(`Failed to combine globals: ${error instanceof Error ? error.message : "Unknown error"}`, "GLOBALS_COMBINE_FAILED"); } } catch (error) { if (error instanceof HermesXError) { throw error; } throw new HermesXError(`Bundling failed: ${error instanceof Error ? error.message : "Unknown error"}`, "COMPILATION_FAILED"); } } }