Files
niucloud-saas/uni-app/scripts/build-mp-addon.cjs
niuzhiyun e4f780a152 v2.0.1
2026-08-04 14:27:05 +08:00

250 lines
8.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 打包单个插件小程序源码 → dist/mp-addons/{key}/
* 含 addon/{key}/...、common/、manifest.jsonsubPackages 等合并信息)
*/
const fs = require('fs')
const path = require('path')
const {
ROOT,
PAGES_JSON,
BUILD_DIR,
MP_OUT_BUILD,
MP_CORE_DIR,
MP_ADDONS_DIR,
MP_LOCK_PATH,
makeBuildId,
runUniMpBuild,
readJson,
writeJson,
readAppJson,
rmDir,
copyDir,
getSubPackageRootsForKey,
parsePagesJson,
collectCommonManifest,
stripAddonSubpackagesExcept,
getAppSubPackages,
getAddonPackageDir,
installMergeScriptToFramework,
copyMpRelativeFiles,
readMpSharedBridgeMeta,
installMpSharedBridgePage,
removeMpSharedBridgePage,
packageSharedAddonComponents,
collectMainComponentDirs,
packageMainComponents,
packageAddonDiyBridge
} = require('./mp-utils.cjs')
const { buildAddonDiyRegistryMap } = require('./mp-diy-bridge-merge.cjs')
const { scanAllDiyComponents } = require('./diy-component-scan.cjs')
const { scanSubPackageRequires } = require('./scan-mp-requires.cjs')
const PAGES_BACKUP = path.join(BUILD_DIR, 'pages.full.backup.json')
function swapPagesJson(key, enable, rawBackup) {
const pagesAddon = path.join(BUILD_DIR, `pages.addon.${key}.json`)
if (enable) {
if (!fs.existsSync(pagesAddon)) {
console.error(`[build-mp-addon] missing ${path.relative(ROOT, pagesAddon)}`)
process.exit(1)
}
// 保存原始内容(保留注释)
rawBackup = fs.readFileSync(PAGES_JSON, 'utf-8')
fs.copyFileSync(pagesAddon, PAGES_JSON)
console.log(`[build-mp-addon] swapped pages.json -> pages.addon.${key}.json`)
return rawBackup
} else if (rawBackup) {
fs.writeFileSync(PAGES_JSON, rawBackup, 'utf-8')
console.log('[build-mp-addon] restored pages.json (with comments)')
}
}
function packageAddonBuild(key, buildDir, buildId) {
const pagesJson = parsePagesJson()
const roots = getSubPackageRootsForKey(key, pagesJson)
const appJson = readAppJson(buildDir)
const subPackages = getAppSubPackages(appJson).filter((s) => roots.includes(s.root))
const dest = getAddonPackageDir(key)
rmDir(dest)
fs.mkdirSync(dest, { recursive: true })
for (const root of roots) {
const src = path.join(buildDir, root)
if (!fs.existsSync(src)) {
console.error(`[build-mp-addon] missing ${root}`)
process.exit(1)
}
copyDir(src, path.join(dest, root))
}
const commonSrc = path.join(buildDir, 'common')
if (fs.existsSync(commonSrc)) {
copyDir(commonSrc, path.join(dest, 'common'))
}
const nodeModulesSrc = path.join(buildDir, 'node-modules')
if (fs.existsSync(nodeModulesSrc)) {
copyDir(nodeModulesSrc, path.join(dest, 'node-modules'))
}
const scan = scanSubPackageRequires(buildDir, roots, key)
// unionMerge=false: 构建期直接把业务共享模块复制进插件包(含插件专用导出)
// 作为后续合并做「导出并集」的源;其余框架依赖仍跳过。
const depFiles = copyMpRelativeFiles(buildDir, dest, scan.requirePaths, roots, false)
if (depFiles) {
console.log(`[build-mp-addon] packaged ${depFiles} main-package dep file(s)`)
}
const bridgeMeta = readMpSharedBridgeMeta(key)
const sharedCount = packageSharedAddonComponents(buildDir, dest, bridgeMeta.sharedComponents)
if (sharedCount) {
console.log(`[build-mp-addon] packaged ${sharedCount} shared addon/components`)
}
const mainComponentDirs = collectMainComponentDirs(buildDir, roots, bridgeMeta)
const mainComponentCount = packageMainComponents(buildDir, dest, mainComponentDirs)
if (mainComponentCount) {
console.log(`[build-mp-addon] packaged ${mainComponentCount} main component dir(s)`)
}
const diyBridgeCount = packageAddonDiyBridge(key, buildDir, dest)
if (diyBridgeCount) {
console.log(
`[build-mp-addon] packaged diy-dynamic-bridge-${key} (${diyBridgeCount} components)`
)
}
const diyRegistry = buildAddonDiyRegistryMap(scanAllDiyComponents, key)
const manifest = {
key,
kind: 'mp-addon-package',
roots,
buildId,
gitCommit: null,
time: new Date().toISOString(),
subPackages,
sharedComponents: bridgeMeta.sharedComponents,
mainComponents: bridgeMeta.mainComponents,
mainComponentDirs,
deps: scan,
commonManifest: collectCommonManifest(buildDir),
diyBridge: {
key,
componentDir: `components/diy-dynamic-bridge-${key}`,
componentCount: diyBridgeCount || 0,
registry: diyRegistry
}
}
writeJson(path.join(dest, 'manifest.json'), manifest)
console.log(`[build-mp-addon] packaged -> ${path.relative(ROOT, dest)}/`)
return manifest
}
function main() {
const key = process.argv[2]
if (!key) {
console.error('Usage: node build-mp-addon.cjs <addon-key>')
process.exit(1)
}
const buildId = makeBuildId(`mp-addon-${key}`)
// 自动生成 pages.core.json确保所有插件的分包信息最新
const genSplitResult = require('child_process').spawnSync(
'node',
[path.join(__dirname, 'generate-split-pages.cjs')],
{ cwd: ROOT, stdio: 'inherit', shell: process.platform === 'win32' }
)
if (genSplitResult.status !== 0) {
console.error('[build-mp-addon] generate-split-pages failed')
process.exit(genSplitResult.status || 1)
}
spawnSyncGenerate(key)
require('./generate-diy-registry.cjs').generateDiyRegistry({ addonKeys: [key] })
require('./generate-diy-dynamic-bridge-mp.cjs').generateDiyDynamicBridgeMp({
target: 'addon',
addonKey: key
})
const bridgeInstalled = installMpSharedBridgePage(key)
const pagesBackup = swapPagesJson(key, true)
// 额外安全措施:把备份也写入磁盘,即使 finally 未执行也能手动恢复
fs.writeFileSync(path.join(BUILD_DIR, 'pages.last.backup.json'), pagesBackup, 'utf-8')
process.env.MP_ADDON_BRIDGE_KEY = key
let buildOk = false
let exitCode = 1
try {
console.log(`[build-mp-addon] building "${key}" ...`)
const code = runUniMpBuild()
if (code !== 0) {
console.error('[build-mp-addon] FAILED')
exitCode = code
return
}
if (!fs.existsSync(MP_OUT_BUILD)) {
console.error('[build-mp-addon] missing output:', MP_OUT_BUILD)
exitCode = 1
return
}
stripAddonSubpackagesExcept(MP_OUT_BUILD, [key])
const manifest = packageAddonBuild(key, MP_OUT_BUILD, buildId)
manifest.gitCommit = require('./mp-utils.cjs').getGitCommit()
writeJson(path.join(getAddonPackageDir(key), 'manifest.json'), manifest)
const lock = fs.existsSync(MP_LOCK_PATH) ? readJson(MP_LOCK_PATH) : {}
lock.addons = lock.addons || {}
lock.addons[key] = { buildId, dir: path.relative(ROOT, getAddonPackageDir(key)) }
writeJson(MP_LOCK_PATH, lock)
if (fs.existsSync(MP_CORE_DIR)) {
installMergeScriptToFramework(MP_CORE_DIR)
const frameworkAddonDir = path.join(MP_CORE_DIR, 'mp-addons', key)
rmDir(frameworkAddonDir)
copyDir(getAddonPackageDir(key), frameworkAddonDir)
console.log(`[build-mp-addon] synced -> ${path.relative(ROOT, frameworkAddonDir)}/`)
}
console.log(`[build-mp-addon] OK (${buildId})`)
console.log(`[build-mp-addon] 插件包 -> ${path.relative(ROOT, getAddonPackageDir(key))}/`)
console.log('[build-mp-addon] 合并cd dist/build/mp-core && node merge-mp-addon.cjs')
buildOk = true
exitCode = 0
} catch (e) {
console.error('[build-mp-addon] unexpected error:', e.message || e)
exitCode = 1
} finally {
delete process.env.MP_ADDON_BRIDGE_KEY
swapPagesJson(key, false, pagesBackup)
// 恢复成功后删除磁盘备份
try { fs.unlinkSync(path.join(BUILD_DIR, 'pages.last.backup.json')) } catch {}
if (bridgeInstalled) {
removeMpSharedBridgePage()
}
if (buildOk) {
require('./cleanup-diy-dynamic-bridge-src.cjs').cleanupAddonDiyBridgeSrc({ keys: [key] })
}
}
if (exitCode !== 0) {
process.exit(exitCode)
}
}
function spawnSyncGenerate(key) {
const result = require('child_process').spawnSync(
'node',
[path.join(__dirname, 'generate-mp-addon-pages.cjs'), key],
{ cwd: ROOT, stdio: 'inherit', shell: process.platform === 'win32' }
)
if (result.status !== 0) {
process.exit(result.status || 1)
}
}
main()