Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: materials new protocol #940

Merged
merged 27 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0e38294
feat: 物料资产包协议修改
yy-wow Dec 16, 2024
c0ee9b3
fix:容错处理packages不存在的情况
yy-wow Dec 16, 2024
7b910c5
fix:新建或修改npm类型工具类都要触发画布重新渲染
yy-wow Dec 16, 2024
6c49614
fix:动态导入组件库模块失败
yy-wow Dec 18, 2024
c971b2b
fix:动态导入组件库模块失败
yy-wow Dec 18, 2024
b277596
fix:画布物料依赖优化
yy-wow Dec 18, 2024
27cb75e
Merge branch 'refactor/develop' into feat/materials-new-protocol
yy-wow Jan 9, 2025
9ec89fb
fix: 新增或修改npm类型的utils更新画布
yy-wow Jan 9, 2025
50ef894
fix: 字段修改
yy-wow Jan 9, 2025
775f6c9
fix: 修复报错
yy-wow Jan 9, 2025
49caefe
fix: 修复工具类更新问题
yy-wow Jan 11, 2025
1942594
fix: 修复预览依赖字段问题
yy-wow Jan 11, 2025
8c36268
fix: 删除无用代码
yy-wow Jan 13, 2025
d8dd7eb
fix: 工具类依赖不添加到importmap,改为直接import cdn地址
yy-wow Jan 13, 2025
90917fa
fix: 预览页面工具类依赖处理
yy-wow Jan 13, 2025
b26bbf4
fix: 更新注释
yy-wow Jan 13, 2025
330c3a1
fix: review
yy-wow Jan 13, 2025
6de0c1f
fix: utils添加importmap字段修复
yy-wow Jan 13, 2025
861a6fc
fix: review
yy-wow Jan 13, 2025
12f43b0
Merge branch 'refactor/develop' into feat/materials-new-protocol
yy-wow Jan 14, 2025
58a3376
Merge branch 'refactor/develop' into feat/materials-new-protocol
yy-wow Jan 15, 2025
6d22724
fix: 动态加载npm类型工具类
yy-wow Jan 15, 2025
16e762a
fix: 卸载时停止订阅通知
yy-wow Jan 15, 2025
29fa9de
fix: 修复类型问题
yy-wow Jan 15, 2025
20d054c
fix: 卸载时停止订阅通知
yy-wow Jan 15, 2025
e2a5eb4
fix: 优化注释
yy-wow Jan 15, 2025
0df006e
fix: 兼容旧的物料协议
yy-wow Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
661 changes: 144 additions & 517 deletions designer-demo/public/mock/bundle.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion mockServer/src/mock/get/app-center/v1/apps/schema/918.json
Original file line number Diff line number Diff line change
Expand Up @@ -2092,7 +2092,8 @@
"value": "",
"package": "axios",
"destructuring": false,
"exportName": "axios"
"exportName": "axios",
"cdnLink": "https://unpkg.com/browse/[email protected]/dist/esm/axios.min.js"
}
},
{
Expand Down
19 changes: 14 additions & 5 deletions packages/canvas/DesignCanvas/src/DesignCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
useMaterial,
useHistory,
useModal,
useMessage,
getMergeRegistry,
getMergeMeta,
getOptions,
Expand Down Expand Up @@ -57,12 +58,20 @@ export default {
const canvasRef = ref(null)
let showModal = false // 弹窗标识
const { canvasSrc = '' } = getOptions(meta.id) || {}
let canvasSrcDoc = ''
const canvasSrcDoc = ref('')

if (!canvasSrc) {
const { importMap, importStyles } = getImportMapData(getMergeMeta('engine.config')?.importMapVersion)
canvasSrcDoc = initCanvas(importMap, importStyles).html
}
useMessage().subscribe({
topic: 'init_canvas_deps',
callback: (deps) => {
if (canvasSrc) {
return
}

const { importMap, importStyles } = getImportMapData(getMergeMeta('engine.config')?.importMapVersion, deps)

canvasSrcDoc.value = initCanvas(importMap, importStyles).html
}
})
yy-wow marked this conversation as resolved.
Show resolved Hide resolved

const removeNode = (node) => {
const { pageState } = useCanvas()
Expand Down
13 changes: 10 additions & 3 deletions packages/canvas/DesignCanvas/src/importMap.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { VITE_CDN_DOMAIN } from '@opentiny/tiny-engine-common/js/environments'

export function getImportMapData(overrideVersions = {}) {
export function getImportMapData(overrideVersions = {}, canvasDeps = { scripts: [], styles: [] }) {
const importMapVersions = Object.assign(
{
vue: '3.4.23',
Expand All @@ -27,16 +27,23 @@ export function getImportMapData(overrideVersions = {}) {
}
}

const materialRequire = canvasDeps.scripts.reduce((imports, { package: pkg, script }) => {
imports[pkg] = script

return imports
}, {})

const importMap = {
imports: {
vue: `${VITE_CDN_DOMAIN}/vue@${importMapVersions.vue}/dist/vue.runtime.esm-browser.prod.js`,
'vue-i18n': `${VITE_CDN_DOMAIN}/vue-i18n@${importMapVersions.vueI18n}/dist/vue-i18n.esm-browser.js`,
...blockRequire.imports,
...tinyVueRequire.imports
...tinyVueRequire.imports,
...materialRequire
}
}

const importStyles = [...blockRequire.importStyles]
const importStyles = [...blockRequire.importStyles, ...canvasDeps.styles]
yy-wow marked this conversation as resolved.
Show resolved Hide resolved

return {
importMap,
Expand Down
59 changes: 48 additions & 11 deletions packages/canvas/common/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,60 @@ export const copyObject = (node) => {
}

/**
* 动态导入组件,缓存组件对象
* @param {object} param0 组件的依赖: { package: 包名,script:js文件cdn, components:组件id和导出组件名的映射关系}
* 从页面importmap中获取模块的名称
* @returns importmap中模块的名称集合
*/
const getImportMapKeys = () => {
try {
const importMaps = document.querySelector('script[type="importmap"]').textContent
const importMapObject = JSON.parse(importMaps)

return Object.keys(importMapObject.import)
} catch (error) {
return []
}
}
yy-wow marked this conversation as resolved.
Show resolved Hide resolved

/**
* 动态导入获取组件模块
* @param {*} pkg 模块名称
* @param {*} script 模块的cdn地址
* @returns
*/
export const dynamicImportComponents = async ({ package: pkg, script, components }) => {
if (!script) return
const scriptUrl = script.startsWith('.') ? new URL(script, location.href).href : script
const dynamicImportComponents = async (pkg, script) => {
if (window.TinyComponentLibs[pkg]) {
return window.TinyComponentLibs[pkg]
}

if (!window.TinyComponentLibs[pkg]) {
const modules = await import(/* @vite-ignore */ scriptUrl)
let modules = {}

window.TinyComponentLibs[pkg] = modules
try {
// 优先从importmap导入,兼容npm.script字段定义的cdn地址
if (getImportMapKeys().includes(pkg)) {
yy-wow marked this conversation as resolved.
Show resolved Hide resolved
modules = await import(/* @vite-ignore */ pkg)
} else if (script) {
modules = await import(/* @vite-ignore */ script)
}
} catch (error) {
modules = {}
}

Object.entries(components).forEach(([componentId, exportName]) => {
const modules = window.TinyComponentLibs[pkg]
window.TinyComponentLibs[pkg] = modules

return modules
}

/**
* 获取组件对象并缓存,组件渲染时使用
* @param {object} param0 组件的依赖: { package: 包名,script:js文件cdn, components:组件id和导出组件名的映射关系}
* @returns
*/
export const setComponents = async ({ package: pkg, script, components }) => {
if (!pkg) return

const modules = await dynamicImportComponents(pkg, script)

Object.entries(components).forEach(([componentId, exportName]) => {
if (!window.TinyLowcodeComponent[componentId]) {
window.TinyLowcodeComponent[componentId] = modules[exportName]
}
Expand All @@ -85,7 +122,7 @@ export const dynamicImportComponents = async ({ package: pkg, script, components
*/
export const updateDependencies = ({ detail }) => {
const { scripts = [], styles = [] } = detail || {}
const { styles: canvasStyles } = window.thirdPartyDeps
const { styles: canvasStyles } = window.componentsDepsMap
const newStyles = [...styles].filter((item) => !canvasStyles.has(item))

newStyles.forEach((item) => canvasStyles.add(item))
Expand Down
2 changes: 1 addition & 1 deletion packages/canvas/container/src/CanvasContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export default {
const beforeCanvasReady = () => {
if (iframe.value) {
const win = iframe.value.contentWindow
win.thirdPartyDeps = useMaterial().materialState.thirdPartyDeps
win.componentsDepsMap = useMaterial().materialState.componentsDepsMap
yy-wow marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/canvas/container/src/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,6 @@ export const initCanvas = ({ renderer, iframe, emit, controller }) => {
setUtils(useResource().resState.utils)
setSchema(schema)
setConfigure(useMaterial().getConfigureMap())
canvasDispatch('updateDependencies', { detail: useMaterial().materialState.thirdPartyDeps })
canvasDispatch('updateDependencies', { detail: useMaterial().materialState.componentsDepsMap })
canvasState.loading = false
}
37 changes: 20 additions & 17 deletions packages/canvas/render/src/RenderMain.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@

import { h, provide, inject, nextTick, shallowReactive, reactive, ref, watch, watchEffect } from 'vue'
import { I18nInjectionKey } from 'vue-i18n'
import TinyVue from '@opentiny/vue'
import * as TinyVueIcon from '@opentiny/vue-icon'
import { useBroadcastChannel } from '@vueuse/core'
import { constants, utils as commonUtils } from '@opentiny/tiny-engine-utils'
import renderer, { parseData, setConfigure, setController, globalNotify, isStateAccessor } from './render'
Expand Down Expand Up @@ -69,30 +67,35 @@ watchEffect(() => {

const getUtils = () => utils

const setUtils = (data, clear, isForceRefresh) => {
const setUtils = async (data, clear, isForceRefresh) => {
if (clear) {
reset(utils)
}
const utilsCollection = {}
// 目前画布还不具备远程加载utils工具类的功能,目前只能加载TinyVue组件库中的组件工具
data?.forEach((item) => {
const util = TinyVue[item.content.exportName]
if (util) {
utilsCollection[item.name] = util
}

// 此处需要把工具类中的icon图标也加入utils上下文环境
const utilIcon = TinyVueIcon[item.content.exportName]
if (utilIcon) {
utilsCollection[item.name] = utilIcon
}
const utilsCollection = {}

// 解析函数式的工具类
if (item.type === 'function') {
data
.filter((item) => item.type === 'function')
.forEach((item) => {
const defaultFn = () => {}
utilsCollection[item.name] = generateFunction(item.content.value, context) || defaultFn
})

const npmUtils = data.filter((item) => item.type === 'npm' && item.content.cdnLink)
const results = await Promise.allSettled(npmUtils.map((item) => import(/* @vite-ignore */ item.content.package)))
yy-wow marked this conversation as resolved.
Show resolved Hide resolved

results.forEach((res, index) => {
if (res.status !== 'fulfilled') {
return
}

const module = res.value
const { name, content } = npmUtils[index]
const { exportName, destructuring } = content

utilsCollection[name] = destructuring ? module[exportName] : module.default
})
yy-wow marked this conversation as resolved.
Show resolved Hide resolved

yy-wow marked this conversation as resolved.
Show resolved Hide resolved
Object.assign(utils, utilsCollection)

// 因为工具类并不具有响应式行为,所以需要通过修改key来强制刷新画布
yy-wow marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
8 changes: 4 additions & 4 deletions packages/canvas/render/src/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

import { createApp } from 'vue'
import { addScript, addStyle, dynamicImportComponents, updateDependencies } from '../../common'
import { addScript, addStyle, setComponents, updateDependencies } from '../../common'
import TinyI18nHost, { I18nInjectionKey } from '@opentiny/tiny-engine-common/js/i18n'
import Main, { api } from './RenderMain'
import lowcode from './lowcode'
Expand Down Expand Up @@ -82,10 +82,10 @@ export const createRender = (config) => {
initRenderContext()

const { styles = [], scripts = [] } = config.canvasDependencies
const { styles: thirdStyles = [], scripts: thirdScripts = [] } = window.thirdPartyDeps || {}
const { scripts: componentsScriptsDeps = [], styles: componentsStylesDeps = [] } = window.componentsDepsMap || {}

Promise.all([
...thirdScripts.map(dynamicImportComponents),
...scripts.map((src) => addScript(src)).concat([...thirdStyles, ...styles].map((src) => addStyle(src)))
...componentsScriptsDeps.map(setComponents),
...scripts.map((src) => addScript(src)).concat([...componentsStylesDeps, ...styles].map((src) => addStyle(src)))
yy-wow marked this conversation as resolved.
Show resolved Hide resolved
yy-wow marked this conversation as resolved.
Show resolved Hide resolved
]).finally(() => create(config))
}
2 changes: 1 addition & 1 deletion packages/common/js/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const open = (params = {}) => {
params.app = paramsMap.get('id')
params.tenant = paramsMap.get('tenant')

const { scripts, styles } = useMaterial().materialState.thirdPartyDeps
const { scripts, styles } = useMaterial().materialState.componentsDepsMap
params.scripts = {}
scripts
.filter((item) => item.script)
Expand Down
13 changes: 1 addition & 12 deletions packages/design-core/src/preview/src/preview/Preview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,6 @@ export default {
store['initTsConfig']() // 触发获取组件d.ts方便调试
}

const addUtilsImportMap = (importMap, utils = []) => {
const utilsImportMaps = {}
utils.forEach(({ type, content: { package: packageName, cdnLink } }) => {
if (type === 'npm' && cdnLink) {
utilsImportMaps[packageName] = cdnLink
}
})
const newImportMap = { imports: { ...importMap.imports, ...utilsImportMaps } }
store.setImportMap(newImportMap)
}

const queryParams = getSearchParams()
const getImportMap = async () => {
if (import.meta.env.VITE_LOCAL_BUNDLE_DEPS === 'true') {
Expand All @@ -91,7 +80,7 @@ export default {
getImportMap()
]
Promise.all(promiseList).then(async ([appData, metaData, _void, importMapData]) => {
addUtilsImportMap(importMapData, metaData.utils || [])
store.setImportMap(importMapData)

const { getAllNestedBlocksSchema, generatePageCode } = getMetaApi('engine.service.generateCode')

Expand Down
77 changes: 44 additions & 33 deletions packages/plugins/bridge/src/js/resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@
*/

import { reactive } from 'vue'
import { useResource, useNotify, useCanvas, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
import {
useResource,
useNotify,
useCanvas,
getMetaApi,
META_SERVICE,
useMaterial
} from '@opentiny/tiny-engine-meta-register'
import { isVsCodeEnv } from '@opentiny/tiny-engine-common/js/environments'
import {
fetchResourceList,
Expand Down Expand Up @@ -175,48 +182,52 @@ const generateBridgeUtil = (...args) => {
}
}

export const saveResource = (data, callback, emit) => {
const { updateUtils } = useCanvas().canvasApi.value
export const saveResource = async (data, callback, emit) => {
let result = {}

yy-wow marked this conversation as resolved.
Show resolved Hide resolved
try {
if (getActionType() === ACTION_TYPE.Edit) {
data.id = state.resource.id
const result = await requestUpdateReSource(data)

if (getActionType() === ACTION_TYPE.Edit) {
data.id = state.resource.id
requestUpdateReSource(data).then((result) => {
if (result) {
const index = useResource().resState[data.category].findIndex((item) => item.name === result.name)
useResource().resState[data.category][index] = result

// 更新画布工具函数环境,保证渲染最新工具类返回值, 并触发画布的强制刷新
updateUtils([result])
generateBridgeUtil(getAppId())

useNotify({
type: 'success',
message: '修改成功'
})

emit('refresh', state.type)
state.refresh = true
callback()
}
})
} else {
requestAddReSource(data).then((result) => {
} else {
const result = await requestAddReSource(data)

if (result) {
useResource().resState[data.category].push(result)

// 更新画布工具函数环境,保证渲染最新工具类返回值, 并触发画布的强制刷新
updateUtils([result])
generateBridgeUtil(getAppId())
useNotify({
type: 'success',
message: '创建成功'
})
emit('refresh', state.type)
state.refresh = true
callback()
}
}
} catch (error) {
useNotify({
type: 'error',
message: `${getActionType() === ACTION_TYPE.Edit ? '更新' : '创建'}失败:${error}`
})

return
}

if (data.type === 'npm') {
// 更新画布import并刷新画布
useMaterial().setCanvasDeps()
} else {
const { updateUtils } = useCanvas().canvasApi.value

// 更新画布工具函数环境,保证渲染最新工具类返回值, 并触发画布的强制刷新
updateUtils([result])
}

generateBridgeUtil(getAppId())
useNotify({
type: 'success',
message: `${getActionType() === ACTION_TYPE.Edit ? '更新' : '创建'}成功`
})
emit('refresh', state.type)
state.refresh = true
callback()
}

export const deleteData = (name, callback, emit) => {
Expand Down
Loading
Loading