// Isolated local visual harness: compiles the real AppIcon/BottomNav components. // No login, production API, remote assets, or user data is used. import { createServer } from 'node:http'; import { readFileSync } from 'node:fs'; import { createRequire } from 'node:module'; import { parse, compileScript } from 'vue/compiler-sfc'; import ts from 'typescript'; const require = createRequire(import.meta.url); const root = new URL('../', import.meta.url); const read = (path) => readFileSync(new URL(path, root), 'utf8'); const transpile = (content) => ts.transpileModule(content, { compilerOptions: { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.ES2020 }, }).outputText; const descriptors = new Map(['AppIcon', 'BottomNav'].map((name) => [ name, parse(read(`src/components/${name}.vue`), { filename: `${name}.vue` }).descriptor, ])); const componentModule = (name) => transpile(compileScript(descriptors.get(name), { id: `preview-${name}`, inlineTemplate: true, templateOptions: { compilerOptions: { isCustomElement: (tag) => ['view', 'text'].includes(tag) } }, }).content).replace(/from ['"]vue['"]/g, 'from "/vue.js"') .replace(/from ['"]\.\.\/utils\/icon-mask['"]/g, 'from "/icon-mask.js"') .replace(/from ['"]\.\/AppIcon.vue['"]/g, 'from "/AppIcon.js"') .replace(/from ['"]\.\.\/utils\/app-state['"]/g, 'from "/state.js"'); const css = [...descriptors.values()].flatMap((item) => item.styles.map((style) => style.content)).join('\n') .replace(/(-?\d+(?:\.\d+)?)rpx/g, 'calc(var(--preview-rpx) * $1)'); // Include the actual App-vue button defaults: auto margins/overflow:hidden are // essential to reproduce badge clipping (plain HTML buttons hide this bug). const nativeCSS = read('node_modules/@dcloudio/uni-app-plus/dist/style.css'); const nativeButtonRule = [...nativeCSS.matchAll(/uni-button\{([^{}]+)\}/g)] .find((match) => match[1].includes('margin-left:auto'))?.[1]; if (!nativeButtonRule) throw new Error('Native button defaults not found'); const html = `