/**
* 组装 H5 分构建最终产物 → dist/build/h5/
*/
const fs = require('fs')
const path = require('path')
const { spawnSync } = require('child_process')
const { ROOT, listAddonKeys } = require('./addon-utils.cjs')
const { IMPORT_MAP, SHARED_BUILD_ORDER } = require('./shared-external.cjs')
const { fixDir } = require('./wap-locale-import-utils.cjs')
const { applyRouterBase } = require('./apply-router-base.cjs')
const { patchAddonDir } = require('./patch-addon-uni-h5.cjs')
const { patchVueJsFile } = require('./uni-feature-defines.cjs')
const { stripAddonStyleImport } = require('./inject-addon-style-import.cjs')
const { injectChunkScopedCss } = require('./inject-addon-chunk-scoped-css.cjs')
const { injectChunkWindiCss } = require('./inject-addon-chunk-windi.cjs')
const { patchAddonDir: patchAddonLocaleLeak } = require('./patch-addon-locale-leak.cjs')
const { patchAddonDir: patchAddonDiyLeak } = require('./patch-addon-diy-leak.cjs')
const { patchCoreH5Dir: patchCoreLocaleExternal } = require('./patch-core-locale-external.cjs')
const { mergeIntoWapLocale } = require('./merge-addon-locales-into-wap-locale.cjs')
const CORE_DIR = path.join(ROOT, 'dist', '.core', 'h5')
const ADDONS_STAGING = path.join(ROOT, 'dist', '.addons')
const SHARED_DIR = path.join(ROOT, 'dist', '.shared')
const OUT_DIR = path.join(ROOT, 'dist', 'build', 'h5')
const REPORT_PATH = path.join(ROOT, 'build-report.json')
function rmDir(dir) {
if (!fs.existsSync(dir)) return
fs.rmSync(dir, { recursive: true, force: true, maxRetries: 8, retryDelay: 300 })
}
function copyDir(src, dest) {
fs.mkdirSync(dest, { recursive: true })
for (const name of fs.readdirSync(src)) {
const s = path.join(src, name)
const d = path.join(dest, name)
if (fs.statSync(s).isDirectory()) copyDir(s, d)
else fs.copyFileSync(s, d)
}
}
function copyTree(src, dest) {
fs.mkdirSync(path.dirname(dest), { recursive: true })
fs.cpSync(src, dest, { recursive: true, force: true })
}
function cleanCoreAssetsOutput() {
const outAssets = path.join(OUT_DIR, 'assets')
if (!fs.existsSync(outAssets)) {
fs.mkdirSync(outAssets, { recursive: true })
return null
}
const addonsSrc = path.join(outAssets, 'addons')
const addonsTmp = path.join(OUT_DIR, '.addons_staging')
if (fs.existsSync(addonsTmp)) rmDir(addonsTmp)
if (fs.existsSync(addonsSrc)) {
fs.renameSync(addonsSrc, addonsTmp)
}
const staleAssets = path.join(OUT_DIR, `.assets_stale_${Date.now()}`)
try {
fs.renameSync(outAssets, staleAssets)
} catch {
rmDir(outAssets)
return null
}
fs.mkdirSync(outAssets, { recursive: true })
if (fs.existsSync(addonsTmp)) {
fs.renameSync(addonsTmp, path.join(outAssets, 'addons'))
}
return staleAssets
}
function cleanupAssembleArtifacts(staleAssets) {
if (staleAssets) rmDir(staleAssets)
if (!fs.existsSync(OUT_DIR)) return
for (const name of fs.readdirSync(OUT_DIR)) {
if (name.startsWith('.assets_stale_')) {
rmDir(path.join(OUT_DIR, name))
}
}
const addonsStaging = path.join(OUT_DIR, '.addons_staging')
if (fs.existsSync(addonsStaging)) rmDir(addonsStaging)
}
function mergeCoreOutput() {
fs.mkdirSync(OUT_DIR, { recursive: true })
for (const name of fs.readdirSync(CORE_DIR)) {
if (name === 'assets') continue
const src = path.join(CORE_DIR, name)
const dest = path.join(OUT_DIR, name)
if (fs.statSync(src).isDirectory()) copyTree(src, dest)
else fs.copyFileSync(src, dest)
console.log(`[assemble-wap] core ${name}`)
}
const coreAssets = path.join(CORE_DIR, 'assets')
const outAssets = path.join(OUT_DIR, 'assets')
if (!fs.existsSync(coreAssets)) return
fs.mkdirSync(outAssets, { recursive: true })
for (const name of fs.readdirSync(coreAssets)) {
if (name === 'addons') continue
const src = path.join(coreAssets, name)
const dest = path.join(outAssets, name)
if (fs.statSync(src).isDirectory()) copyDir(src, dest)
else fs.copyFileSync(src, dest)
}
}
function copyLocale(key, destAddonDir) {
const localeSrc = path.join(ROOT, 'src', 'addon', key, 'locale')
if (!fs.existsSync(localeSrc)) return
copyDir(localeSrc, path.join(destAddonDir, 'locale'))
}
function copyAppLocale() {
const localeSrc = path.join(ROOT, 'src', 'app', 'locale')
if (!fs.existsSync(localeSrc)) return
copyDir(localeSrc, path.join(OUT_DIR, 'assets', 'locale', 'app'))
}
function writeAddonManifest(key, destAddonDir) {
const manifest = {
key,
version: '1.0.0',
sharedVersion: 'wap-core-1.0.0',
entry: './index.js',
localeBase: './locale/'
}
fs.writeFileSync(path.join(destAddonDir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf-8')
}
function fixIndexHtml() {
const fn = path.join(OUT_DIR, 'index.html')
if (!fs.existsSync(fn)) return
let text = fs.readFileSync(fn, 'utf-8')
text = text.replaceAll('./assets/', '/wap/assets/')
fs.writeFileSync(fn, text, 'utf-8')
}
function injectImportMap() {
const fn = path.join(OUT_DIR, 'index.html')
if (!fs.existsSync(fn)) return
let text = fs.readFileSync(fn, 'utf-8')
const script = ``
if (text.includes('type="importmap"')) {
text = text.replace(/