| 1 | import * as NodeFSP from "node:fs/promises"; |
| 2 | import * as NodePath from "node:path"; |
| 3 | import * as NodeURL from "node:url"; |
| 4 | import { build } from "vite-plus"; |
| 5 | |
| 6 | const mobileRoot = NodePath.resolve(NodePath.dirname(NodeURL.fileURLToPath(import.meta.url)), ".."); |
| 7 | |
| 8 | /** Metro embeds each shared browser transport as a small script in a native WebView. */ |
| 9 | async function generateWebViewScript(feature: string, name: string) { |
| 10 | const stem = `${name.toLowerCase()}-stream`; |
| 11 | const result = await build({ |
| 12 | configFile: false, |
| 13 | logLevel: "silent", |
| 14 | build: { |
| 15 | write: false, |
| 16 | target: "es2022", |
| 17 | minify: true, |
| 18 | lib: { |
| 19 | entry: NodePath.join(mobileRoot, "src/features", feature, `${stem}.browser.ts`), |
| 20 | name: `T3${name}Stream`, |
| 21 | formats: ["iife"], |
| 22 | }, |
| 23 | }, |
| 24 | }); |
| 25 | const bundles = Array.isArray(result) ? result : [result]; |
| 26 | const chunk = bundles |
| 27 | .flatMap((bundle) => ("output" in bundle ? bundle.output : [])) |
| 28 | .find((output) => output.type === "chunk"); |
| 29 | if (!chunk) throw new Error(`${name} build did not emit a script.`); |
| 30 | const root = NodePath.join(mobileRoot, ".generated", stem); |
| 31 | await NodeFSP.mkdir(root, { recursive: true }); |
| 32 | for (const [file, contents] of [ |
| 33 | ["index.js", `module.exports = ${JSON.stringify(chunk.code)};\n`], |
| 34 | ["package.json", '{"main":"index.js"}\n'], |
| 35 | ] as const) { |
| 36 | const destination = NodePath.join(root, file); |
| 37 | const previous = await NodeFSP.readFile(destination, "utf8").catch(() => null); |
| 38 | if (previous !== contents) await NodeFSP.writeFile(destination, contents); |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | export const generateDeviceStreamScript = () => generateWebViewScript("devices", "Device"); |
| 43 | export const generatePreviewStreamScript = () => generateWebViewScript("browser", "Preview"); |