mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Replace the Expo DOM-backed terminal on iOS and Android with a managed WebView running xterm.js. Web and desktop continue to use the existing DOM implementation. Mobile mounted tabs switch from display:none to opacity:0 for the hidden slot on purpose: terminals stay mounted under the LRU tab cache, and keeping the WebView in the layer tree avoids cold-starting it every time the user returns to a terminal tab. EAS native builds rebuild the WebView bundle post-install so the generated HTML stays in sync with the entry source. This does not fix the WS 1006 / NSPOSIXErrorDomain Code=54 host-disconnect symptom that prompted the investigation. After restoring the baseline, that symptom could not be replicated; do not read this commit as its root cause or fix.
90 lines
2.4 KiB
JavaScript
90 lines
2.4 KiB
JavaScript
import esbuild from "esbuild";
|
|
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const appRoot = path.resolve(__dirname, "..");
|
|
const repoRoot = path.resolve(appRoot, "../..");
|
|
const entry = path.join(appRoot, "src/terminal/webview/terminal-emulator-webview-entry.ts");
|
|
const output = path.join(appRoot, "src/terminal/webview/terminal-emulator-webview-html.ts");
|
|
|
|
async function resolveTsPath(basePath) {
|
|
const candidates = [
|
|
basePath,
|
|
`${basePath}.ts`,
|
|
`${basePath}.tsx`,
|
|
`${basePath}.js`,
|
|
`${basePath}.jsx`,
|
|
path.join(basePath, "index.ts"),
|
|
path.join(basePath, "index.tsx"),
|
|
path.join(basePath, "index.js"),
|
|
path.join(basePath, "index.jsx"),
|
|
];
|
|
for (const candidate of candidates) {
|
|
try {
|
|
const stat = await fs.stat(candidate);
|
|
if (stat.isFile()) return candidate;
|
|
} catch {
|
|
// try next candidate
|
|
}
|
|
}
|
|
return basePath;
|
|
}
|
|
|
|
const aliasPlugin = {
|
|
name: "paseo-alias",
|
|
setup(build) {
|
|
build.onResolve({ filter: /^@\// }, async (args) => ({
|
|
path: await resolveTsPath(path.join(appRoot, "src", args.path.slice(2))),
|
|
}));
|
|
build.onResolve({ filter: /^@server\// }, async (args) => ({
|
|
path: await resolveTsPath(
|
|
path.join(repoRoot, "packages/server/src", args.path.slice("@server/".length)),
|
|
),
|
|
}));
|
|
},
|
|
};
|
|
|
|
const result = await esbuild.build({
|
|
entryPoints: [entry],
|
|
bundle: true,
|
|
write: false,
|
|
format: "iife",
|
|
platform: "browser",
|
|
target: ["ios15", "chrome100"],
|
|
loader: {
|
|
".css": "text",
|
|
},
|
|
plugins: [aliasPlugin],
|
|
logLevel: "info",
|
|
});
|
|
|
|
const js = result.outputFiles[0]?.text;
|
|
if (!js) {
|
|
throw new Error("terminal webview bundle produced no JavaScript");
|
|
}
|
|
|
|
const html = `<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
|
|
/>
|
|
</head>
|
|
<body>
|
|
<script>${js}</script>
|
|
</body>
|
|
</html>`;
|
|
|
|
const contents = `// Generated by packages/app/scripts/build-terminal-webview-html.mjs.
|
|
// Do not edit by hand.
|
|
|
|
export const terminalEmulatorWebViewHtml = ${JSON.stringify(html)};
|
|
`;
|
|
|
|
await fs.writeFile(output, contents);
|
|
console.log(`Wrote ${path.relative(repoRoot, output)} (${html.length} bytes)`);
|