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

231 lines
9.0 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/build/mp-core/
*/
const fs = require('fs')
const path = require('path')
const {
ROOT,
PAGES_JSON,
BUILD_DIR,
MP_OUT_BUILD,
MP_CORE_DIR,
MP_FRAMEWORK_DIR,
MP_LOCK_PATH,
makeBuildId,
runUniMpBuild,
snapshotMpBuild,
collectCommonManifest,
readJson,
writeJson,
stripOrphanAddonSubpackages,
installMergeScriptToFramework,
applyFrameworkAppJsonSubPackages,
loadFrameworkNonAddonSubPackages,
rmDir
} = require('./mp-utils.cjs')
const { patchDiyGroupInlineComponents } = require('./mp-diy-group-inline.cjs')
const {
installNativeDiyBridgeRouter,
buildAppDiyRegistryMap
} = require('./mp-diy-bridge-merge.cjs')
const { scanAllDiyComponents } = require('./diy-component-scan.cjs')
const PAGES_BACKUP = path.join(BUILD_DIR, 'pages.full.backup.json')
const PAGES_FRAMEWORK = path.join(BUILD_DIR, 'pages.framework.json')
function swapPagesJson(useFramework, rawBackup) {
if (useFramework) {
// 保存原始内容到内存(保留注释),不依赖磁盘备份文件
rawBackup = fs.readFileSync(PAGES_JSON, 'utf-8')
fs.copyFileSync(PAGES_FRAMEWORK, PAGES_JSON)
console.log('[build-mp-framework] swapped pages.json -> pages.framework.json')
return rawBackup
} else if (rawBackup) {
fs.writeFileSync(PAGES_JSON, rawBackup, 'utf-8')
console.log('[build-mp-framework] restored pages.json (with comments)')
}
}
const UV_BARREL_PAGE_PATH = 'app/pages/_uv_barrel/index'
/**
* 构建期专用:在主包插入一个临时页面,模板里用上全部 uview-plus 组件,
* 强制 uni 把组件文件(node-modules/uview-plus/components/*)与各自 props(NN)
* 全部打进框架 common/vendor.js构建完成后该页面会从 app.json 与产物中移除。
* 这样框架自带完整 uview-plus插件合并时无需再处理 uview-plus 组件。
*/
// 判断某个 pages 条目是否为本脚本注入的临时 barrel 页面(兼容历史遗留的不同路径/格式)
function isBarrelPageEntry(p) {
const entryPath = typeof p === 'string' ? p : p && p.path
return typeof entryPath === 'string' && entryPath.includes('_uv_barrel')
}
function injectUviewBarrelPage() {
if (process.env.SKIP_UV_BARREL) {
console.log('[build-mp-framework] SKIP_UV_BARREL set, skip barrel page')
return false
}
const compRoot = path.join(ROOT, 'node_modules', 'uview-plus', 'components')
if (!fs.existsSync(compRoot)) {
console.warn('[build-mp-framework] uview-plus not found, skip barrel page')
return false
}
const names = fs
.readdirSync(compRoot)
.filter((n) => {
const d = path.join(compRoot, n)
if (!fs.statSync(d).isDirectory()) return false
if (n.includes('--')) return false // u--xxx 为内部别名标签,双连字符在模板中无法解析
return fs.existsSync(path.join(d, `${n}.vue`))
})
.sort()
if (!names.length) return false
const tags = names.map((n) => ` <${n} />`).join('\n')
const pageVue =
`<template>\n` +
` <view class="uv-barrel">\n` +
`${tags}\n` +
` </view>\n` +
`</template>\n\n` +
`<script setup>\n` +
`// 构建期专用:强制打包全部 uview-plus 组件,产物中会被移除\n` +
`</script>\n`
const srcDir = path.join(ROOT, 'src', 'app', 'pages', '_uv_barrel')
fs.mkdirSync(srcDir, { recursive: true })
fs.writeFileSync(path.join(srcDir, 'index.vue'), pageVue, 'utf-8')
const fw = readJson(PAGES_FRAMEWORK)
if (!Array.isArray(fw.pages)) fw.pages = []
// 先清除任何历史残留的 barrel 条目(可能格式/路径不同),避免重复或非法 page
fw.pages = fw.pages.filter((p) => !isBarrelPageEntry(p))
fw.pages.push({ path: UV_BARREL_PAGE_PATH, style: {} })
writeJson(PAGES_FRAMEWORK, fw)
console.log(`[build-mp-framework] injected uview barrel page (${names.length} components)`)
return true
}
/** 从 mp-core/app.json 移除临时页面入口并删除其编译产物文件 */
function stripUviewBarrelFromCore() {
const appPath = path.join(MP_CORE_DIR, 'app.json')
if (fs.existsSync(appPath)) {
const appJson = readJson(appPath)
if (Array.isArray(appJson.pages)) {
const len = appJson.pages.length
appJson.pages = appJson.pages.filter((p) => !isBarrelPageEntry(p))
if (appJson.pages.length !== len) {
writeJson(appPath, appJson)
console.log('[build-mp-framework] removed barrel page entry from app.json')
}
}
}
const outDirs = [
path.join(MP_CORE_DIR, 'app', 'pages', '_uv_barrel'),
path.join(MP_CORE_DIR, 'pages', '_uv_barrel'),
path.join(MP_OUT_BUILD, 'app', 'pages', '_uv_barrel'),
path.join(MP_OUT_BUILD, 'pages', '_uv_barrel')
]
outDirs.forEach((outDir) => {
if (fs.existsSync(outDir)) {
rmDir(outDir)
console.log('[build-mp-framework] removed barrel page files from mp-core:', outDir)
}
})
}
/** 清理构建期临时文件src 临时页面 + pages.framework.json 中的注入项 */
function removeUviewBarrelTemp() {
const srcDirs = [
path.join(ROOT, 'src', 'app', 'pages', '_uv_barrel'),
path.join(ROOT, 'src', 'pages', '_uv_barrel')
]
srcDirs.forEach((srcDir) => {
if (fs.existsSync(srcDir)) rmDir(srcDir)
})
if (fs.existsSync(PAGES_FRAMEWORK)) {
const fw = readJson(PAGES_FRAMEWORK)
if (Array.isArray(fw.pages)) {
const len = fw.pages.length
fw.pages = fw.pages.filter((p) => !isBarrelPageEntry(p))
if (fw.pages.length !== len) writeJson(PAGES_FRAMEWORK, fw)
}
}
}
function main() {
const buildId = makeBuildId('mp-framework')
require('./generate-mp-framework-pages.cjs')
require('./generate-diy-registry.cjs').generateDiyRegistry()
const { generateDiyDynamicBridgeMp } = require('./generate-diy-dynamic-bridge-mp.cjs')
generateDiyDynamicBridgeMp({ target: 'app' })
generateDiyDynamicBridgeMp({ target: 'router' })
injectUviewBarrelPage()
const pagesBackup = swapPagesJson(true)
let code = 0
let buildOk = false
try {
console.log('[build-mp-framework] uni build -p mp-weixin ...')
code = runUniMpBuild()
if (code !== 0) {
console.error('[build-mp-framework] FAILED')
process.exit(code)
}
if (!fs.existsSync(MP_OUT_BUILD)) {
console.error('[build-mp-framework] missing output:', MP_OUT_BUILD)
process.exit(1)
}
const stripped = stripOrphanAddonSubpackages(MP_OUT_BUILD)
if (stripped) {
console.log(`[build-mp-framework] removed ${stripped} orphan addon plugin dir(s)`)
}
snapshotMpBuild(MP_OUT_BUILD, MP_CORE_DIR, {
kind: 'framework',
buildId,
commonManifest: collectCommonManifest(MP_OUT_BUILD)
})
applyFrameworkAppJsonSubPackages(MP_CORE_DIR)
stripUviewBarrelFromCore()
writeJson(
path.join(MP_CORE_DIR, 'mp-framework-subpackages.json'),
loadFrameworkNonAddonSubPackages()
)
installNativeDiyBridgeRouter(MP_CORE_DIR, buildAppDiyRegistryMap(scanAllDiyComponents))
console.log('[build-mp-framework] installed native diy-dynamic-bridge router (merge-patchable)')
const appRegistry = buildAppDiyRegistryMap(scanAllDiyComponents)
const inlineResult = patchDiyGroupInlineComponents(MP_CORE_DIR, appRegistry)
console.log(
`[build-mp-framework] diy-group inlined ${inlineResult.count} app diy component(s) (no bridge hop)`
)
const { applyMpWeixinPost } = require('./mp-weixin-post.cjs')
applyMpWeixinPost(MP_CORE_DIR)
const meta = readJson(path.join(MP_CORE_DIR, 'mp-build-meta.json'))
const lock = fs.existsSync(MP_LOCK_PATH) ? readJson(MP_LOCK_PATH) : {}
lock.framework = {
buildId,
gitCommit: meta.gitCommit,
time: new Date().toISOString(),
dir: 'dist/build/mp-core'
}
writeJson(MP_LOCK_PATH, lock)
installMergeScriptToFramework(MP_CORE_DIR)
console.log(`[build-mp-framework] OK -> ${path.relative(ROOT, MP_CORE_DIR)}/ (${buildId})`)
console.log('[build-mp-framework] 框架包可直接导入开发者工具(仅主包,无插件分包)')
console.log('[build-mp-framework] 添加插件后合并:')
console.log(' 1. 将插件包放入 dist/build/mp-core/mp-addons/{key}/')
console.log(' 或 npm run build:mp-weixin:addon shop (自动输出到 mp-addons/shop/')
console.log(' 2. cd dist/build/mp-core && node merge-mp-addon.cjs')
buildOk = true
} finally {
swapPagesJson(false, pagesBackup)
removeUviewBarrelTemp()
if (buildOk) {
require('./cleanup-diy-dynamic-bridge-src.cjs').cleanupAddonDiyBridgeSrc()
}
}
}
main()