niucloud/uni-app/scripts/generate-diy-dynamic-bridge-mp.cjs
wangchen14709853322 5ed9a0ba81 v2.0-beta-20260626
v2框架公测版测试流程请看v2.0-beta.md
2026-07-01 12:25:30 +08:00

244 lines
7.5 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.

/**
* 生成小程序用 DIY bridge静态 v-if禁止 <component :is>
*
* target:
* app -> diy-dynamic-bridge-app框架 app 微页面)
* addon -> diy-dynamic-bridge-{key}(单插件微页面,供 zip 合并)
* router-> diy-dynamic-bridge.router开发期 vue routermp-core 用原生模板)
*/
const fs = require('fs')
const path = require('path')
const { ROOT, BUILD_DIR } = require('./addon-utils.cjs')
const { scanAllDiyComponents } = require('./diy-component-scan.cjs')
const REGISTRY_JSON = path.join(BUILD_DIR, 'diy-component-registry.json')
function importPath(entry) {
if (entry.scope === 'app') {
return `@/app/components/diy/${entry.folder}/index.vue`
}
return `@/addon/${entry.addonKey}/components/diy/${entry.folder}/index.vue`
}
function resolveOutputPath(options = {}) {
if (options.target === 'app' || options.appOnly) {
return path.join(ROOT, 'src/components/diy-dynamic-bridge-app/diy-dynamic-bridge-app.mp.vue')
}
if (options.target === 'addon' && options.addonKey) {
const key = options.addonKey
return path.join(ROOT, `src/components/diy-dynamic-bridge-${key}/diy-dynamic-bridge-${key}.mp.vue`)
}
if (options.target === 'router') {
return path.join(ROOT, 'src/components/diy-dynamic-bridge/diy-dynamic-bridge.router.mp.vue')
}
return path.join(ROOT, 'src/components/diy-dynamic-bridge/diy-dynamic-bridge.mp.vue')
}
function loadComponents(options = {}) {
if (options.target === 'app' || options.appOnly) {
return scanAllDiyComponents(options).app
}
if (options.target === 'addon' && options.addonKey) {
return scanAllDiyComponents({ addonKeys: [options.addonKey] }).addon
}
if (options.target === 'router') {
return []
}
if (options.addonKeys && options.addonKeys.length) {
const { app, addon } = scanAllDiyComponents({ addonKeys: options.addonKeys })
return [...app, ...addon].sort((a, b) => a.vueComponentName.localeCompare(b.vueComponentName))
}
if (fs.existsSync(REGISTRY_JSON)) {
const data = JSON.parse(fs.readFileSync(REGISTRY_JSON, 'utf-8'))
if (Array.isArray(data.components) && data.components.length) {
return data.components
}
}
return scanAllDiyComponents(options).all
}
function buildBridgeVue(components) {
const imports = components
.map((entry) => `import ${entry.vueComponentName} from '${importPath(entry)}'`)
.join('\n')
const blocks = components
.map(
(entry) => ` <${entry.vueComponentName}
v-if="componentName === '${entry.vueComponentName}'"
:ref="setInnerRef"
:component="component"
:global="global"
:index="index"
:scrollBool="scrollBool"
@update:componentIsShow="emit('update:componentIsShow', $event)"
@loadingFn="emit('loadingFn', $event)"
/>`
)
.join('\n')
return `<!-- AUTO-GENERATED by generate-diy-dynamic-bridge-mp.cjs — do not edit -->
<template>
<view v-if="componentName">
${blocks}
</view>
</template>
<script setup lang="ts">
import { shallowRef, watch } from 'vue'
import { resolveDiyMeta } from '@/utils/diy-component-registry'
${imports}
const emit = defineEmits<{
'update:componentIsShow': [value: boolean]
loadingFn: [value: unknown]
}>()
const props = defineProps<{
componentName?: string
component?: object
global?: object
index?: number
scrollBool?: number
}>()
const innerRef = shallowRef<any>(null)
function setInnerRef(el: any) {
innerRef.value = el
}
function warnIfUnknown() {
const name = props.componentName || ''
if (!name) return
if (!resolveDiyMeta(name)) {
console.warn('[diy-dynamic-bridge] unknown componentName:', name)
}
}
watch(() => props.componentName, warnIfUnknown, { immediate: true })
defineExpose({
getInnerRef: () => innerRef.value
})
</script>
`
}
function buildRouterVue() {
return `<!-- AUTO-GENERATED router by generate-diy-dynamic-bridge-mp.cjs -->
<template>
<view v-if="componentName">
<diy-dynamic-bridge-app
v-if="routeBridge === 'app'"
:ref="setInnerRef"
:componentName="componentName"
:component="component"
:global="global"
:index="index"
:scrollBool="scrollBool"
@update:componentIsShow="emit('update:componentIsShow', $event)"
@loadingFn="emit('loadingFn', $event)"
/>
<!-- MP_MERGE_ADDON_BRIDGE_VUE -->
</view>
</template>
<script setup lang="ts">
import { computed, shallowRef } from 'vue'
import { resolveDiyMeta } from '@/utils/diy-component-registry'
const emit = defineEmits<{
'update:componentIsShow': [value: boolean]
loadingFn: [value: unknown]
}>()
const props = defineProps<{
componentName?: string
component?: object
global?: object
index?: number
scrollBool?: number
}>()
const innerRef = shallowRef<any>(null)
function setInnerRef(el: any) {
innerRef.value = el
}
const routeBridge = computed(() => {
const meta = resolveDiyMeta(props.componentName || '')
return meta?.addonKey || 'app'
})
defineExpose({
getInnerRef: () => innerRef.value
})
</script>
`
}
function ensureBridgeShells(options = {}) {
const appVue = path.join(ROOT, 'src/components/diy-dynamic-bridge-app/diy-dynamic-bridge-app.vue')
fs.mkdirSync(path.dirname(appVue), { recursive: true })
if (!fs.existsSync(appVue)) {
fs.writeFileSync(
appVue,
`<!-- MP: injected from diy-dynamic-bridge-app.mp.vue -->\n<template><view /></template>\n<script setup lang="ts"></script>\n`,
'utf-8'
)
}
if (options.addonKey) {
const key = options.addonKey
const addonVue = path.join(ROOT, `src/components/diy-dynamic-bridge-${key}/diy-dynamic-bridge-${key}.vue`)
fs.mkdirSync(path.dirname(addonVue), { recursive: true })
fs.writeFileSync(
addonVue,
`<!-- AUTO-GENERATED stub for addon bridge ${key} -->\n<template><view v-if="componentName" /></template>\n<script setup lang="ts"></script>\n`,
'utf-8'
)
}
}
function describeScope(options, count) {
if (options.target === 'app' || options.appOnly) return `app-only (${count})`
if (options.target === 'addon' && options.addonKey) return `addon/${options.addonKey} (${count})`
if (options.target === 'router') return 'router'
if (options.addonKeys?.length) return `app + ${options.addonKeys.join(', ')} (${count})`
return `full registry (${count})`
}
function generateDiyDynamicBridgeMp(options = {}) {
ensureBridgeShells(options)
const outPath = resolveOutputPath(options)
const vue =
options.target === 'router'
? buildRouterVue()
: buildBridgeVue(loadComponents(options))
fs.mkdirSync(path.dirname(outPath), { recursive: true })
fs.writeFileSync(outPath, vue, 'utf-8')
const count = options.target === 'router' ? 0 : loadComponents(options).length
console.log(
`[generate-diy-dynamic-bridge-mp] ${describeScope(options, count)} -> ${path.relative(ROOT, outPath)}`
)
return outPath
}
module.exports = {
generateDiyDynamicBridgeMp,
resolveOutputPath,
ensureBridgeShells,
OUT_VUE: path.join(ROOT, 'src/components/diy-dynamic-bridge/diy-dynamic-bridge.mp.vue')
}
if (require.main === module) {
const { generateDiyRegistry } = require('./generate-diy-registry.cjs')
generateDiyRegistry()
generateDiyDynamicBridgeMp()
}