forked from opentiny/tiny-engine
Compare commits
1 Commits
develop
...
merge-deve
Author | SHA1 | Date |
---|---|---|
wenmine | ce27050d1c |
|
@ -55,7 +55,8 @@
|
|||
"vite": "^4.3.7",
|
||||
"vite-plugin-monaco-editor": "^1.0.10",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue-eslint-parser": "^8.0.1"
|
||||
"vue-eslint-parser": "^8.0.1",
|
||||
"vue-i18n": "^9.9.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
import { transform } from './src/transform.js'
|
||||
import { transformSFC } from './src/transform-sfc.js'
|
||||
|
||||
export default function () {
|
||||
return {
|
||||
name: 'vite-plugin-generate-comments',
|
||||
enforce: 'pre',
|
||||
transform(code, id) {
|
||||
if (id.endsWith('.vue')) {
|
||||
const result = transformSFC(code, id)
|
||||
return result
|
||||
}
|
||||
|
||||
if (id.endsWith('.js') || id.endsWith('.jsx') || id.endsWith('.ts')) {
|
||||
const result = transform(code, id)
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "@opentiny/vite-plugin-generate-comments",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"module": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "node ./src/test/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"vite": "^5.2.7",
|
||||
"@babel/parser": "^7.18.13",
|
||||
"@babel/traverse": "^7.18.13",
|
||||
"@babel/generator": "^7.18.13",
|
||||
"@babel/template": "^7.18.13",
|
||||
"@vue/compiler-sfc": "^3.4.21"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/* metaService */
|
||||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { reactive, onMounted, onBeforeMount as beforeMount } from 'vue'
|
||||
import { deepCopy } from 'loash-es'
|
||||
export const useRenderless = ({ props }) => {
|
||||
const state = reactive({
|
||||
tableData: props.data || props.op.data || []
|
||||
})
|
||||
|
||||
onMounted(() => {})
|
||||
onMounted(() => {})
|
||||
onMounted(() => {})
|
||||
|
||||
beforeMount(() => {})
|
||||
|
||||
const logMessage = () => {
|
||||
console.log('我是纯函数我不需要闭包参数')
|
||||
}
|
||||
|
||||
const aaa = 'aaa',
|
||||
bbb = 'bbb'
|
||||
|
||||
const handleClick = (e) => {
|
||||
console.log(e.target, aaa)
|
||||
state.tableData.push({
|
||||
key: 'TinyEngine',
|
||||
zhCN: '低代码引擎',
|
||||
enUS: 'TinyEngine'
|
||||
})
|
||||
}
|
||||
|
||||
const ccc = 111
|
||||
|
||||
const sendMessage = () => {
|
||||
logMessage('自定义是的范德萨')
|
||||
}
|
||||
|
||||
function last() {}
|
||||
|
||||
return {
|
||||
state,
|
||||
aa,
|
||||
handleClick,
|
||||
sendMessage
|
||||
}
|
||||
}
|
|
@ -0,0 +1,575 @@
|
|||
import { callEntry as _callEntry, beforeCallEntry as _beforeCallEntry, afterCallEntry as _afterCallEntry, useCompile as _useCompile } from '@opentiny/tiny-engine-entry';
|
||||
import _metaData from '../meta.js';
|
||||
/* metaService */
|
||||
import { reactive, onMounted, onBeforeMount as beforeMount } from 'vue';
|
||||
import { deepCopy } from 'loash-es';
|
||||
export const useRenderless = _callEntry(({
|
||||
props
|
||||
}) => {
|
||||
const state = reactive({
|
||||
tableData: props.data || props.op.data || []
|
||||
});
|
||||
onMounted(_callEntry(() => {}, {
|
||||
metaData: {
|
||||
id: `${_metaData.id}.onMounted[0]`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
}));
|
||||
onMounted(_callEntry(() => {}, {
|
||||
metaData: {
|
||||
id: `${_metaData.id}.onMounted[1]`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
}));
|
||||
onMounted(_callEntry(() => {}, {
|
||||
metaData: {
|
||||
id: `${_metaData.id}.onMounted[2]`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
}));
|
||||
beforeMount(_callEntry(() => {}, {
|
||||
metaData: {
|
||||
id: `${_metaData.id}.onBeforeMount[0]`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
}));
|
||||
_beforeCallEntry({
|
||||
metaData: {
|
||||
id: `${_metaData.id}.logMessage`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
const logMessage = _callEntry(() => {
|
||||
console.log('我是纯函数我不需要闭包参数');
|
||||
}, {
|
||||
metaData: {
|
||||
id: `${_metaData.id}.logMessage`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
_afterCallEntry({
|
||||
metaData: {
|
||||
id: `${_metaData.id}.logMessage`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
const aaa = 'aaa',
|
||||
bbb = 'bbb';
|
||||
_beforeCallEntry({
|
||||
metaData: {
|
||||
id: `${_metaData.id}.handleClick`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
e,
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
const handleClick = _callEntry(e => {
|
||||
console.log(e.target, aaa);
|
||||
state.tableData.push({
|
||||
key: 'TinyEngine',
|
||||
zhCN: '低代码引擎',
|
||||
enUS: 'TinyEngine'
|
||||
});
|
||||
}, {
|
||||
metaData: {
|
||||
id: `${_metaData.id}.handleClick`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
e,
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
_afterCallEntry({
|
||||
metaData: {
|
||||
id: `${_metaData.id}.handleClick`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
e,
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
const ccc = 111;
|
||||
_beforeCallEntry({
|
||||
metaData: {
|
||||
id: `${_metaData.id}.sendMessage`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
const sendMessage = _callEntry(() => {
|
||||
logMessage('自定义是的范德萨');
|
||||
}, {
|
||||
metaData: {
|
||||
id: `${_metaData.id}.sendMessage`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
_afterCallEntry({
|
||||
metaData: {
|
||||
id: `${_metaData.id}.sendMessage`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
||||
function last() {}
|
||||
return {
|
||||
state,
|
||||
aa,
|
||||
handleClick,
|
||||
sendMessage
|
||||
};
|
||||
}, {
|
||||
metaData: {
|
||||
id: `${_metaData.id}.useRenderless`
|
||||
},
|
||||
ctx: () => {
|
||||
let asyncVars = {};
|
||||
try {
|
||||
asyncVars = {
|
||||
props,
|
||||
state,
|
||||
logMessage,
|
||||
aaa,
|
||||
bbb,
|
||||
handleClick,
|
||||
ccc,
|
||||
sendMessage,
|
||||
last,
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy,
|
||||
useRenderless
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
reactive,
|
||||
onMounted,
|
||||
beforeMount,
|
||||
deepCopy
|
||||
};
|
||||
}
|
||||
return asyncVars;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import { transform } from '../transform.js'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import * as path from 'path'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
const code = fs.readFileSync(path.join(__dirname, './code/entry.js'), 'utf8')
|
||||
|
||||
const id = path.resolve(__dirname, './code/entry.js')
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, './code/output.js'), transform(code, id) || '', 'utf8')
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
import { parse } from '@vue/compiler-sfc' //vue 处理sfc 的专用库
|
||||
import { transform } from './transform.js'
|
||||
import { isCallEntryFile } from './utils.js'
|
||||
|
||||
const getAttrsString = (attrs) => {
|
||||
let attrStr = ''
|
||||
if (!attrs) {
|
||||
return attrStr
|
||||
}
|
||||
|
||||
Object.keys(attrs).forEach((key) => {
|
||||
const val = attrs[key]
|
||||
if (val === true) {
|
||||
attrStr += ` ${key}`
|
||||
} else {
|
||||
attrStr += ` ${key}="${val}"`
|
||||
}
|
||||
})
|
||||
return attrStr
|
||||
}
|
||||
const generateTagContent = (tagDescriptor) => {
|
||||
if (!tagDescriptor) {
|
||||
return ''
|
||||
}
|
||||
const { attrs, content, type } = tagDescriptor
|
||||
return `<${type}${getAttrsString(attrs)}>${content}</${type}>`
|
||||
}
|
||||
|
||||
export const generateSFC = (descriptor) => {
|
||||
const { script, scriptSetup, styles = [], template } = descriptor
|
||||
return `${generateTagContent(template)}
|
||||
${generateTagContent(script)}
|
||||
${generateTagContent(scriptSetup)}
|
||||
${styles.map(generateTagContent).join('\n')}
|
||||
`
|
||||
}
|
||||
|
||||
export const transformSFC = (code, id) => {
|
||||
const { descriptor } = parse(code)
|
||||
const { script, scriptSetup } = descriptor
|
||||
if (!isCallEntryFile(code) || (!script && !scriptSetup)) {
|
||||
return
|
||||
}
|
||||
if (script) {
|
||||
script.content = transform(script.content, id) || script.content
|
||||
}
|
||||
if (scriptSetup) {
|
||||
scriptSetup.content = transform(scriptSetup.content, id) || scriptSetup.content
|
||||
}
|
||||
return generateSFC(descriptor)
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { parse } from '@babel/parser'
|
||||
import generate from '@babel/generator'
|
||||
import traverse from '@babel/traverse'
|
||||
import template from '@babel/template'
|
||||
import {
|
||||
wrapEntryFuncNode,
|
||||
COMMON_PACKAGE_NAME,
|
||||
CALLENTRY,
|
||||
BEFORE_CALLENTRY,
|
||||
AFTER_CALLENTRY,
|
||||
USE_COMPILE,
|
||||
METADATANAME,
|
||||
isCallEntryFile,
|
||||
isCompileFile,
|
||||
getMeataPath,
|
||||
wrapExportComp,
|
||||
vueLifeHook,
|
||||
wrapHookCall,
|
||||
getModuleId
|
||||
} from './utils.js'
|
||||
|
||||
const generateTraverse = traverse.default
|
||||
|
||||
export const transform = (code, id) => {
|
||||
// 如果不包含metaService或者metaComponent的文件直接退出
|
||||
const isCallEntry = isCallEntryFile(code)
|
||||
const isCompile = isCompileFile(code)
|
||||
if (!isCallEntry && !isCompile) {
|
||||
return
|
||||
}
|
||||
|
||||
// 本次转换保存的状态
|
||||
const state = {
|
||||
varName: {}, // 变量名对应的映射表
|
||||
hooksName: {},
|
||||
hooksIndex: {},
|
||||
varDeclartion: new Map(),
|
||||
moduleId: '', // 自定义的模块ID,用于区分元服务中不同文件,
|
||||
noUseVars: []
|
||||
}
|
||||
|
||||
// 找不到meta.js告警并返回
|
||||
const metaPath = getMeataPath(id)
|
||||
if (!metaPath) {
|
||||
console.log('找不到对应的meta.js')
|
||||
return
|
||||
}
|
||||
|
||||
// 将源码解析为ast语法数
|
||||
const resultAst = parse(code, {
|
||||
sourceType: 'module',
|
||||
plugins: ['typescript', 'jsx']
|
||||
})
|
||||
|
||||
generateTraverse(resultAst, {
|
||||
// 使用特定的类型回调处理、函数表达式、箭头函数、带导出的函数
|
||||
'ArrowFunctionExpression|FunctionExpression'(path) {
|
||||
const parentNode = path.parentPath || {}
|
||||
const functionName = parentNode.node?.id?.name
|
||||
|
||||
// 只有拿到函数的名称才可以被复写
|
||||
if (functionName) {
|
||||
wrapEntryFuncNode({
|
||||
path,
|
||||
functionName,
|
||||
varName: state.varName,
|
||||
state
|
||||
})
|
||||
}
|
||||
},
|
||||
ImportDeclaration(path) {
|
||||
// 解析vue的引入
|
||||
const depName = path.node?.source?.value
|
||||
if (depName === 'vue') {
|
||||
const specifiers = path.node.specifiers
|
||||
specifiers?.forEach((importSpecifier) => {
|
||||
const { imported, local } = importSpecifier
|
||||
const hookName = vueLifeHook.find((name) => imported.name === name)
|
||||
if (hookName) {
|
||||
state.hooksName[local.name] = hookName
|
||||
}
|
||||
state.noUseVars.push(local.name)
|
||||
})
|
||||
} else if (depName === '@opentiny/vue') {
|
||||
const specifiers = path.node.specifiers
|
||||
specifiers?.forEach((importSpecifier) => {
|
||||
const { local } = importSpecifier
|
||||
state.noUseVars.push(local.name)
|
||||
})
|
||||
}
|
||||
},
|
||||
VariableDeclaration(path) {
|
||||
path.node.declarations?.forEach((val) => {
|
||||
const name = val.id.name
|
||||
const block = path.scope.block
|
||||
if (!state.varDeclartion.has(block)) {
|
||||
const arr = [name]
|
||||
state.varDeclartion.set(block, arr)
|
||||
} else {
|
||||
const arr = state.varDeclartion.get(block)
|
||||
arr.push(name)
|
||||
}
|
||||
})
|
||||
},
|
||||
ExpressionStatement(path) {
|
||||
const { hooksName, varName, hooksIndex } = state
|
||||
const callName = path.node.expression?.callee?.name
|
||||
const hookName = hooksName[callName]
|
||||
if (hookName) {
|
||||
let hookIndex
|
||||
if (hooksIndex[hookName]) {
|
||||
hookIndex = hooksIndex[hookName]
|
||||
hooksIndex[hookName] = hookIndex + 1
|
||||
} else {
|
||||
hooksIndex[hookName] = 1
|
||||
hookIndex = 0
|
||||
}
|
||||
const functionName = `${hookName}[${hookIndex}]`
|
||||
wrapHookCall({
|
||||
path,
|
||||
varName,
|
||||
hooksName,
|
||||
functionName,
|
||||
callName,
|
||||
state
|
||||
})
|
||||
}
|
||||
},
|
||||
Program(path) {
|
||||
const code = path.toString()
|
||||
state.moduleId = getModuleId(code)
|
||||
const metaData = path.scope.generateUid(METADATANAME)
|
||||
state.varName[METADATANAME] = metaData
|
||||
path.node.body.unshift(template.statement(`import ${metaData} from '${metaPath}'`)())
|
||||
|
||||
const callEntry = path.scope.generateUid(CALLENTRY)
|
||||
const beforeCallEntry = path.scope.generateUid(BEFORE_CALLENTRY)
|
||||
const afterCallEntry = path.scope.generateUid(AFTER_CALLENTRY)
|
||||
const useCompile = path.scope.generateUid(USE_COMPILE)
|
||||
state.varName[CALLENTRY] = callEntry
|
||||
state.varName[BEFORE_CALLENTRY] = beforeCallEntry
|
||||
state.varName[AFTER_CALLENTRY] = afterCallEntry
|
||||
state.varName[USE_COMPILE] = useCompile
|
||||
path.node.body.unshift(
|
||||
template.statement(
|
||||
`import {
|
||||
${CALLENTRY} as ${callEntry},
|
||||
${BEFORE_CALLENTRY} as ${beforeCallEntry},
|
||||
${AFTER_CALLENTRY} as ${afterCallEntry},
|
||||
${USE_COMPILE} as ${useCompile}
|
||||
} from '${COMMON_PACKAGE_NAME}'`
|
||||
)()
|
||||
)
|
||||
},
|
||||
ExportDefaultDeclaration(path) {
|
||||
const comment = path.node.leadingComments
|
||||
const lastComment = comment && comment[comment.length - 1].value
|
||||
// 只判断最接近export default的注释节点
|
||||
if (comment && lastComment.includes('metaComponent')) {
|
||||
wrapExportComp({ path, varName: state.varName })
|
||||
path.skip()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return generate.default(resultAst).code || ''
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import template from '@babel/template'
|
||||
import path from 'node:path'
|
||||
import fs from 'node:fs'
|
||||
|
||||
export const CALLENTRY = 'callEntry'
|
||||
export const BEFORE_CALLENTRY = 'beforeCallEntry'
|
||||
export const AFTER_CALLENTRY = 'afterCallEntry'
|
||||
export const USE_COMPILE = 'useCompile'
|
||||
export const METADATANAME = 'metaData'
|
||||
export const COMMON_PACKAGE_NAME = '@opentiny/tiny-engine-entry'
|
||||
export const vueLifeHook = [
|
||||
'onMounted',
|
||||
'onUpdated',
|
||||
'onUnmounted',
|
||||
'onBeforeMount',
|
||||
'onBeforeUpdate',
|
||||
'onBeforeUnmount',
|
||||
'onActivated',
|
||||
'onDeactivated'
|
||||
]
|
||||
const callEntryExp = /\/\*\s*metaService/
|
||||
const compileExp = /\/\*\s*metaComponent/
|
||||
|
||||
export const isCallEntryFile = (code) => {
|
||||
return callEntryExp.test(code)
|
||||
}
|
||||
|
||||
export const isCompileFile = (code) => {
|
||||
return compileExp.test(code)
|
||||
}
|
||||
|
||||
export const getModuleId = (str) => {
|
||||
const [, moduleId = ''] = str.match(/\/\*\s*metaService: \s*(.+?)\s*\*\//) || []
|
||||
return moduleId
|
||||
}
|
||||
|
||||
// 将注释中的参数提取出来,并组合成目前参数格式
|
||||
export const getEntryParam = ({ functionName = '', syncVars, asyncVars, state }) => {
|
||||
const { varName, moduleId, noUseVars } = state
|
||||
const metaData = varName[METADATANAME]
|
||||
const id = moduleId ? `'${moduleId}.${functionName}'` : `\`\${${metaData}.id}.${functionName}\``
|
||||
const syncVarsKey = Object.keys(syncVars).filter((key) => !noUseVars.includes(key))
|
||||
const asyncVarsKey = Object.keys(asyncVars).filter((key) => !noUseVars.includes(key) && !syncVarsKey.includes(key))
|
||||
const ctx = ` () => {
|
||||
let asyncVars = {}
|
||||
const syncVars = {${syncVarsKey.join(',')}}
|
||||
try {
|
||||
asyncVars = { ${asyncVarsKey.join(',')} }
|
||||
} catch {
|
||||
return syncVars
|
||||
}
|
||||
return { ...syncVars, ...asyncVars }
|
||||
}`
|
||||
if (functionName) {
|
||||
return `{ ${METADATANAME}: { id: ${id} }, ctx: ${ctx}}`
|
||||
}
|
||||
|
||||
return `{ ${METADATANAME}: ${metaData} }`
|
||||
}
|
||||
|
||||
const getParentVariableDeclaration = (path) => {
|
||||
if (!path) {
|
||||
return
|
||||
}
|
||||
|
||||
if (path.type === 'VariableDeclaration' && path.parentPath.type !== 'ExportNamedDeclaration') {
|
||||
return path
|
||||
} else {
|
||||
return getParentVariableDeclaration(path?.parentPath)
|
||||
}
|
||||
}
|
||||
|
||||
const generateBeforeAfterEntry = ({ path, beforeEntryAst, afterEntryAst }) => {
|
||||
const parent = getParentVariableDeclaration(path)
|
||||
if (parent) {
|
||||
parent.insertBefore(beforeEntryAst)
|
||||
parent.insertAfter(afterEntryAst)
|
||||
}
|
||||
}
|
||||
|
||||
export const getOuterBingdings = (path) => {
|
||||
const outerBindings = {}
|
||||
const allBindings = path.scope.getAllBindings()
|
||||
const selfBindings = path.scope.bindings
|
||||
Object.keys(allBindings).forEach((key) => {
|
||||
if (allBindings[key] && !selfBindings[key]) {
|
||||
outerBindings[key] = allBindings[key]
|
||||
}
|
||||
})
|
||||
return outerBindings
|
||||
}
|
||||
|
||||
// 获取当前上下文已经可以使用的scope变量
|
||||
export const getValidBingdinngs = ({ path, state, functionName }) => {
|
||||
const validBindings = {}
|
||||
const { varDeclartion } = state
|
||||
let varArr = []
|
||||
let parentPath = path.parentPath
|
||||
let block
|
||||
while (parentPath) {
|
||||
const newBlock = parentPath.scope.block
|
||||
parentPath = parentPath.parentPath
|
||||
if (newBlock === block) {
|
||||
continue
|
||||
}
|
||||
block = newBlock
|
||||
varArr = varArr.concat(varDeclartion.get(block))
|
||||
}
|
||||
|
||||
const allBindings = path.scope.getAllBindings()
|
||||
const selfBindings = path.scope.bindings
|
||||
Object.keys(allBindings).forEach((key) => {
|
||||
if (selfBindings[key]) {
|
||||
return
|
||||
}
|
||||
const value = allBindings[key]
|
||||
// 如果是变量定义,并且此时还没有初始化,则过滤掉
|
||||
if ((['var', 'const', 'let'].includes(value.kind) && !varArr.includes(key)) || key === functionName) {
|
||||
return
|
||||
}
|
||||
validBindings[key] = value
|
||||
})
|
||||
return validBindings
|
||||
}
|
||||
|
||||
export const getModuleBindings = (path) => {
|
||||
const moduleBindings = {}
|
||||
const allBindings = path.scope.getAllBindings()
|
||||
Object.keys(allBindings).forEach((key) => {
|
||||
if (allBindings[key].kind === 'module') {
|
||||
moduleBindings[key] = allBindings[key]
|
||||
}
|
||||
})
|
||||
return moduleBindings
|
||||
}
|
||||
|
||||
// 生成callEntry表达式并包裹当前函数,如果有参与还需要处理参数
|
||||
export const wrapEntryFuncNode = ({ path, functionName = '', varName, state }) => {
|
||||
const syncVars = getValidBingdinngs({ path, state, functionName })
|
||||
const asyncVars = getOuterBingdings(path)
|
||||
const entryParam = getEntryParam({
|
||||
functionName,
|
||||
syncVars,
|
||||
asyncVars,
|
||||
varName,
|
||||
state
|
||||
})
|
||||
const callEntry = varName[CALLENTRY]
|
||||
const beforeCallEntry = varName[BEFORE_CALLENTRY]
|
||||
const afterCallEntry = varName[AFTER_CALLENTRY]
|
||||
const entryAst = template.statement(`${callEntry}(${entryParam})`)()
|
||||
const beforeEntryAst = template.statement(`${beforeCallEntry}(${entryParam})`)()
|
||||
const afterEntryAst = template.statement(`${afterCallEntry}(${entryParam})`)()
|
||||
|
||||
const resultNode = path.node
|
||||
generateBeforeAfterEntry({ path, beforeEntryAst, afterEntryAst })
|
||||
|
||||
entryAst.expression.arguments.unshift(JSON.parse(JSON.stringify(resultNode)))
|
||||
// 替换整个节点
|
||||
path.replaceWith(entryAst)
|
||||
}
|
||||
|
||||
// 获取两个文件路径的相对路径,入参为两个文件绝对路径
|
||||
export const getRelFilePath = (path1, path2) => {
|
||||
const dir1 = path.join(path1, '..')
|
||||
const dir2 = path.join(path2, '..')
|
||||
const relPath = path.relative(dir1, dir2) || '.'
|
||||
return `${relPath}/${path.basename(path2)}`.replaceAll('\\', '/')
|
||||
}
|
||||
|
||||
// 向上获取meta.js的相对路径
|
||||
export const getMeataPath = (id) => {
|
||||
let tempPath = path.join(id, '../meta.js')
|
||||
|
||||
const endCondition = () => {
|
||||
// 找到了meta.js
|
||||
const findMeta = fs.existsSync(tempPath)
|
||||
// 发现了package.json说明到达子包根目录
|
||||
const isSubRoot = fs.existsSync(path.join(tempPath, '../package.json'))
|
||||
// 到达系统根节点,防止死循环
|
||||
const isRoot = tempPath === path.join(tempPath, '../../meta.js')
|
||||
return findMeta || isSubRoot || isRoot
|
||||
}
|
||||
|
||||
while (!endCondition()) {
|
||||
tempPath = path.join(tempPath, '../../meta.js')
|
||||
}
|
||||
if (fs.existsSync(tempPath)) {
|
||||
return getRelFilePath(id, tempPath)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export const wrapExportComp = ({ path, varName }) => {
|
||||
const properties = path.node.declaration?.properties || []
|
||||
const metaData = varName[METADATANAME]
|
||||
const useCompile = varName[USE_COMPILE]
|
||||
|
||||
// 对键值为component属性包一层useCompile
|
||||
properties.forEach((prop) => {
|
||||
if (prop.key?.name === 'component') {
|
||||
const val = prop.value
|
||||
const compileAst = template.statement(`${useCompile}({ component: null, ${METADATANAME}: ${metaData} });`)()
|
||||
compileAst.expression.arguments[0].properties[0].value = val
|
||||
path.traverse({
|
||||
enter(subPath) {
|
||||
if (subPath.node === val) {
|
||||
subPath.replaceWith(compileAst)
|
||||
subPath.skip()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const wrapHookCall = ({ path, varName, functionName, callName, state }) => {
|
||||
// vue的生命周期hook只有一个参数
|
||||
const argument = path.node.expression.arguments[0]
|
||||
const callEntry = varName[CALLENTRY]
|
||||
const syncVars = getValidBingdinngs({ path, state, functionName })
|
||||
const asyncVars = path.scope.getAllBindings()
|
||||
const entryParam = getEntryParam({
|
||||
functionName,
|
||||
syncVars,
|
||||
asyncVars,
|
||||
varName,
|
||||
state
|
||||
})
|
||||
const wrapAst = template.statement(`${callName}(${callEntry}(${entryParam}))`)()
|
||||
wrapAst.expression.arguments[0].arguments.unshift(argument)
|
||||
path.replaceWith(wrapAst)
|
||||
path.skip()
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { defineEntry } from '@opentiny/tiny-engine-entry'
|
||||
import { createApp } from 'vue'
|
||||
import EngineApp from './src/index.js'
|
||||
import defaultResigry from './registry.js'
|
||||
import { merge } from 'lodash-es'
|
||||
import initSvgs from '@opentiny/tiny-engine-svgs'
|
||||
import { setGlobalConfig } from '@opentiny/tiny-engine-controller'
|
||||
import i18n from '@opentiny/tiny-engine-controller/js/i18n'
|
||||
import globalConfig from './config/lowcode.config'
|
||||
import { initMonitor } from '@opentiny/tiny-engine-controller/js/monitor'
|
||||
import { injectGlobalComponents } from '@opentiny/tiny-engine-common'
|
||||
import { initHttp } from '@opentiny/tiny-engine-http'
|
||||
import 'virtual:svg-icons-register'
|
||||
|
||||
import TinyThemeTool from '@opentiny/vue-theme/theme-tool'
|
||||
import { tinySmbTheme } from '@opentiny/vue-theme/theme' // SMB 主题
|
||||
|
||||
const type = (obj) => {
|
||||
return Object.prototype.toString.call(obj).match(/\[object (.*)\]/)[1]
|
||||
}
|
||||
|
||||
const mergeRegistry = (registry) => {
|
||||
Object.entries(registry).forEach(([key, value]) => {
|
||||
const defaultConfig = defaultResigry[key]
|
||||
if (Array.isArray(value) && defaultConfig) {
|
||||
value.forEach((meta, index) => {
|
||||
const defaultMeta = defaultConfig.find((item) => item.id === meta.id)
|
||||
if (defaultMeta) {
|
||||
value[index] = merge(defaultMeta, meta)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (type(value) === 'Object' && defaultConfig) {
|
||||
registry[key] = merge(defaultConfig, registry[key])
|
||||
}
|
||||
})
|
||||
|
||||
return registry
|
||||
}
|
||||
|
||||
const init = (selector, registry) => {
|
||||
// 合并用户自定义注册表
|
||||
const newRegistry = mergeRegistry(registry)
|
||||
|
||||
// 在common层注入合并后的注册表
|
||||
defineEntry(newRegistry)
|
||||
const app = createApp(EngineApp)
|
||||
initHttp({ env: import.meta.env })
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new TinyThemeTool(tinySmbTheme, 'smbtheme') // 初始化主题
|
||||
|
||||
if (import.meta.env.VITE_ERROR_MONITOR === 'true' && import.meta.env.VITE_ERROR_MONITOR_URL) {
|
||||
initMonitor(import.meta.env.VITE_ERROR_MONITOR_URL)
|
||||
}
|
||||
|
||||
window.TinyGlobalConfig = globalConfig
|
||||
setGlobalConfig(globalConfig)
|
||||
|
||||
initSvgs(app)
|
||||
window.lowcodeI18n = i18n
|
||||
app.use(i18n).use(injectGlobalComponents).mount('#app')
|
||||
app.mount(selector)
|
||||
}
|
||||
export { init }
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"name": "@opentiny/tiny-engine",
|
||||
"version": "1.0.0-beta.4",
|
||||
"type": "module",
|
||||
"description": "TinyEngine enables developers to customize low-code platforms, build low-bit platforms online in real time, and support secondary development or integration of low-bit platform capabilities.",
|
||||
"homepage": "https://opentiny.design/tiny-engine",
|
||||
"keywords": [
|
||||
|
@ -11,6 +12,14 @@
|
|||
"lowcode",
|
||||
"tiny-engine"
|
||||
],
|
||||
"module": "index.js",
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
".": "index.js",
|
||||
"./vite.config.js": "./vite.config.js",
|
||||
"./config/lowcode.config": "./config/lowcode.config.js",
|
||||
"./scripts/externalDeps": "./scripts/externalDeps.js"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "cross-env NODE_OPTIONS=--max-old-space-size=10240 VITE_API_MOCK=mock vite",
|
||||
"serve": "cross-env NODE_OPTIONS=--max-old-space-size=10240 vite",
|
||||
|
@ -34,6 +43,8 @@
|
|||
"@babel/generator": "~7.23.2",
|
||||
"@babel/parser": "~7.23.2",
|
||||
"@babel/traverse": "~7.23.2",
|
||||
"@opentiny/vite-plugin-generate-comments": "workspace:*",
|
||||
"@opentiny/tiny-engine-entry": "workspace:*",
|
||||
"@opentiny/tiny-engine-canvas": "workspace:*",
|
||||
"@opentiny/tiny-engine-common": "workspace:*",
|
||||
"@opentiny/tiny-engine-controller": "workspace:*",
|
||||
|
@ -126,7 +137,8 @@
|
|||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"vite-plugin-static-copy": "^0.16.0",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue-eslint-parser": "^8.0.1"
|
||||
"vue-eslint-parser": "^8.0.1",
|
||||
"lodash-es": "^4.17.21"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import i18nMeta from '@opentiny/tiny-engine-plugin-i18n'
|
||||
|
||||
export default {
|
||||
plugins: [i18nMeta]
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import component from './App.vue'
|
||||
|
||||
export default component
|
|
@ -2,18 +2,29 @@ import { defineConfig, loadEnv } from 'vite'
|
|||
|
||||
import path from 'path'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import monacoEditorPlugin from 'vite-plugin-monaco-editor'
|
||||
import monacoEditorPluginCjs from 'vite-plugin-monaco-editor'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import nodeGlobalsPolyfillPlugin from '@esbuild-plugins/node-globals-polyfill'
|
||||
import nodeModulesPolyfillPlugin from '@esbuild-plugins/node-modules-polyfill'
|
||||
import nodeGlobalsPolyfillPluginCjs from '@esbuild-plugins/node-globals-polyfill'
|
||||
import nodeModulesPolyfillPluginCjs from '@esbuild-plugins/node-modules-polyfill'
|
||||
import nodePolyfill from 'rollup-plugin-polyfill-node'
|
||||
import esbuildCopy from 'esbuild-plugin-copy'
|
||||
import lowcodeConfig from './config/lowcode.config'
|
||||
import lowcodeConfig from './config/lowcode.config.js'
|
||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||
import { importmapPlugin } from './scripts/externalDeps'
|
||||
import visualizer from 'rollup-plugin-visualizer'
|
||||
import { importmapPlugin } from './scripts/externalDeps.js'
|
||||
import visualizerCjs from 'rollup-plugin-visualizer'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import generateComment from '@opentiny/vite-plugin-generate-comments'
|
||||
import { getBaseUrlFromCli, copyBundleDeps, copyPreviewImportMap, copyLocalImportMap } from './scripts/localCdnFile'
|
||||
|
||||
const monacoEditorPlugin = monacoEditorPluginCjs.default
|
||||
const nodeGlobalsPolyfillPlugin = nodeGlobalsPolyfillPluginCjs.default
|
||||
const nodeModulesPolyfillPlugin = nodeModulesPolyfillPluginCjs.default
|
||||
const visualizer = visualizerCjs.default
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
const origin = 'http://localhost:9090/'
|
||||
|
||||
const config = {
|
||||
|
@ -52,6 +63,7 @@ const config = {
|
|||
open: false
|
||||
},
|
||||
plugins: [
|
||||
generateComment(),
|
||||
visualizer({
|
||||
filename: 'tmp/report.html',
|
||||
title: 'Bundle Analyzer'
|
||||
|
@ -183,7 +195,8 @@ const devAlias = {
|
|||
'@opentiny/tiny-engine-utils': path.resolve(__dirname, '../utils/src/index.js'),
|
||||
'@opentiny/tiny-engine-webcomponent-core': path.resolve(__dirname, '../webcomponent/src/lib.js'),
|
||||
'@opentiny/tiny-engine-i18n-host': path.resolve(__dirname, '../i18n/src/lib.js'),
|
||||
'@opentiny/tiny-engine-builtin-component': path.resolve(__dirname, '../builtinComponent/index.js')
|
||||
'@opentiny/tiny-engine-builtin-component': path.resolve(__dirname, '../builtinComponent/index.js'),
|
||||
'@opentiny/tiny-engine-entry': path.resolve(__dirname, '../entry/index.js')
|
||||
}
|
||||
|
||||
const prodAlias = {
|
||||
|
@ -197,8 +210,12 @@ const commonAlias = {
|
|||
'@opentiny/tiny-engine-app-addons': path.resolve(__dirname, './config/addons.js')
|
||||
}
|
||||
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
const { VITE_CDN_DOMAIN, VITE_LOCAL_IMPORT_MAPS, VITE_LOCAL_BUNDLE_DEPS } = loadEnv(mode, process.cwd(), '')
|
||||
export default defineConfig(({ command = 'serve', mode = 'serve' }) => {
|
||||
const {
|
||||
VITE_CDN_DOMAIN = 'https://npm.onmicrosoft.cn',
|
||||
VITE_LOCAL_IMPORT_MAPS,
|
||||
VITE_LOCAL_BUNDLE_DEPS
|
||||
} = loadEnv(mode, process.cwd(), '')
|
||||
const isLocalImportMap = VITE_LOCAL_IMPORT_MAPS === 'true' // true公共依赖库使用本地打包文件,false公共依赖库使用公共CDN
|
||||
const isCopyBundleDeps = VITE_LOCAL_BUNDLE_DEPS === 'true' // true bundle里的cdn依赖处理成本地依赖, false 不处理
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env node
|
||||
import '../src/index.js'
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "@opentiny/tiny-engine-cli",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"bin": {
|
||||
"engine-cli": "./bin/cli.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.0.0",
|
||||
"execa": "^8.0.1",
|
||||
"fs-extra": "^11.2.0",
|
||||
"globby": "^14.0.1",
|
||||
"handlebars": "^4.7.8",
|
||||
"inquirer": "^9.2.17",
|
||||
"ora": "^8.0.1",
|
||||
"vite": "^5.1.6"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { build } from 'vite'
|
||||
import { resolveViteConfig } from '../common.js'
|
||||
|
||||
export default async function () {
|
||||
const viteConfig = await resolveViteConfig()
|
||||
await build({
|
||||
configFile: false,
|
||||
...viteConfig,
|
||||
// root: __dirname,
|
||||
server: {
|
||||
port: 8000
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { cwd } from 'node:process'
|
||||
import path from 'node:path'
|
||||
import fs from 'fs-extra'
|
||||
import chalk from 'chalk'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
export default function (name) {
|
||||
const sourcePath = path.join(__dirname, '../../template')
|
||||
const destPath = path.join(cwd(), name)
|
||||
fs.copySync(sourcePath, destPath)
|
||||
console.log(
|
||||
chalk.green(`create finish, run the follow command to start project: \ncd ${name} && npm install && npm run dev`)
|
||||
)
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { createServer } from 'vite'
|
||||
import { resolveViteConfig } from '../common.js'
|
||||
|
||||
export default async function () {
|
||||
const viteConfig = await resolveViteConfig()
|
||||
const server = await createServer({
|
||||
configFile: false,
|
||||
...viteConfig,
|
||||
// root: __dirname,
|
||||
server: {
|
||||
...{
|
||||
port: 8000
|
||||
},
|
||||
...viteConfig.server
|
||||
}
|
||||
})
|
||||
await server.listen()
|
||||
|
||||
server.printUrls()
|
||||
server.bindCLIShortcuts({ print: true })
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { cwd } from 'node:process'
|
||||
import path from 'node:path'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
const resolveViteConfig = async () => {
|
||||
const configPath = path.join(cwd(), 'engine.config.js')
|
||||
let config = {}
|
||||
try {
|
||||
const allConfig = (await import(`file://${configPath}`)).default
|
||||
config = allConfig?.viteConfig || {}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
return defineConfig(config)
|
||||
}
|
||||
|
||||
export { resolveViteConfig }
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import fs from 'fs-extra'
|
||||
import * as globby from 'globby'
|
||||
import { Command } from 'commander'
|
||||
import * as path from 'path'
|
||||
import chalk from 'chalk'
|
||||
import create from './commands/create.js'
|
||||
import serve from './commands/serve.js'
|
||||
import build from './commands/build.js'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
|
||||
const __dirname = path.dirname(__filename)
|
||||
const program = new Command()
|
||||
|
||||
let commandsPath = []
|
||||
let pkgVersion = ''
|
||||
let pkgName = ''
|
||||
|
||||
// 获取当前包的信息
|
||||
const getPkgInfo = () => {
|
||||
const jsonPath = path.join(__dirname, '../package.json')
|
||||
const jsonResult = fs.readJSONSync(jsonPath)
|
||||
pkgVersion = jsonResult.version
|
||||
return pkgVersion
|
||||
}
|
||||
|
||||
program
|
||||
.command('create <name>')
|
||||
.description('创建一个新工程')
|
||||
.action((name) => {
|
||||
create(name)
|
||||
})
|
||||
|
||||
program
|
||||
.command('serve')
|
||||
.description('开启服务')
|
||||
.action(() => {
|
||||
serve()
|
||||
})
|
||||
|
||||
program
|
||||
.command('build')
|
||||
.description('构建')
|
||||
.action(() => {
|
||||
build()
|
||||
})
|
||||
|
||||
program.parse(process.argv)
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
// TODO: 考虑是否把各项配置合并到一个配置文件当中
|
||||
export default {
|
||||
registry: {},
|
||||
viteConfig: {
|
||||
plugins: [vue()]
|
||||
}, // 将vite.config.js配置到此处
|
||||
otherConfig: {}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "engine-cli-demo",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "engine-cli serve",
|
||||
"build": "engine-cli build"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.21",
|
||||
"@opentiny/tiny-engine": "workspace:^",
|
||||
"@opentiny/tiny-engine-entry": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"vite": "^5.2.7",
|
||||
"@opentiny/tiny-engine-cli": "workspace:^"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
export default {
|
||||
layout: { id: 'engine.layout' },
|
||||
toolbars: [
|
||||
{
|
||||
id: 'engine.toolbars.download'
|
||||
},
|
||||
{
|
||||
id: 'engine.toolbars.refresh'
|
||||
}
|
||||
],
|
||||
plugins: [{ id: 'engine.plugins.i18n' }, { id: 'engine.plugins.status' }],
|
||||
dsls: [{ id: 'engine.dsls.dslvue' }],
|
||||
settings: [],
|
||||
canvas: {},
|
||||
utils: { id: 'engine.utils' }
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { init } from '@opentiny/tiny-engine'
|
||||
import registry from '../registry.js'
|
||||
|
||||
onMounted(() => {
|
||||
init('#engine-app', registry)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="engine-app"></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import registry from '../registry.js'
|
||||
import { defineEntry } from '@opentiny/tiny-engine-entry'
|
||||
defineEntry(registry)
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import './defineEntry.js'
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { getMergeMeta } from './src/common'
|
||||
import { useCompile } from './src/templateHash'
|
||||
import { defineEntry, callEntry, beforeCallEntry, afterCallEntry, getMergeRegistry } from './src/entryHash'
|
||||
|
||||
import { getLayoutComponent } from './src/layoutHash'
|
||||
|
||||
export {
|
||||
getMergeMeta,
|
||||
useCompile,
|
||||
defineEntry,
|
||||
callEntry,
|
||||
beforeCallEntry,
|
||||
afterCallEntry,
|
||||
getLayoutComponent,
|
||||
getMergeRegistry
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "@opentiny/tiny-engine-entry",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.21"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
const vueLifeHook = [
|
||||
'onMounted',
|
||||
'onUpdated',
|
||||
'onUnmounted',
|
||||
'onBeforeMount',
|
||||
'onBeforeUpdate',
|
||||
'onBeforeUnmount',
|
||||
'onActivated',
|
||||
'onDeactivated'
|
||||
]
|
||||
|
||||
/**
|
||||
* 自定义方法注册哈希表,形式如下:
|
||||
* {
|
||||
* 'engine.plugins.i18n.handleClick': () => { // do something }
|
||||
* }
|
||||
*/
|
||||
export const entryHashMap = {}
|
||||
/**
|
||||
* 自定义模板注册哈希表,形式如下:
|
||||
* {
|
||||
* 'engine.plugins.status.metas.app': <template></template>
|
||||
* }
|
||||
*/
|
||||
export const templateHashMap = {}
|
||||
|
||||
/**
|
||||
* 自定布局hash,形式如下:
|
||||
* {
|
||||
* 'engine.plugins.status': customLayout
|
||||
* }
|
||||
*/
|
||||
export const layoutHashMap = {}
|
||||
|
||||
export const metasHashMap = {}
|
||||
|
||||
const handleMethods = (id, methods) => {
|
||||
Object.entries(methods).forEach(([fileId, idMethods]) => {
|
||||
if (typeof idMethods === 'object') {
|
||||
Object.entries(idMethods).forEach(([name, method]) => {
|
||||
const prefix = fileId ? `.${fileId}` : ''
|
||||
const methodId = `${id}${prefix}.${name}`
|
||||
entryHashMap[methodId] = method
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleVueLifeCycle = (id, value) => {
|
||||
vueLifeHook.forEach((hookName) => {
|
||||
const hookConfig = value[hookName]
|
||||
if (!hookConfig) {
|
||||
return
|
||||
}
|
||||
if (typeof hookConfig === 'function') {
|
||||
const hookId = `${id}.${hookName}[0]`
|
||||
entryHashMap[hookId] = hookConfig
|
||||
}
|
||||
if (hookConfig instanceof Array) {
|
||||
hookConfig.forEach((hookFn, index) => {
|
||||
if (typeof hookFn === 'function') {
|
||||
const hookId = `${id}.${hookName}[${index}]`
|
||||
entryHashMap[hookId] = hookFn
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleLifeCycles = (id, lifeCycles) => {
|
||||
Object.entries(lifeCycles).forEach(([fileId, idLifeCycles]) => {
|
||||
const prefix = fileId ? `.${fileId}` : ''
|
||||
const lifeCycleId = `${id}${prefix}`
|
||||
handleVueLifeCycle(lifeCycleId, idLifeCycles)
|
||||
})
|
||||
}
|
||||
|
||||
const handleRegistryProp = (id, value) => {
|
||||
const { template, layout, methods, lifeCycles } = value
|
||||
// 处理生命周期
|
||||
if (lifeCycles) {
|
||||
handleLifeCycles(id, lifeCycles)
|
||||
}
|
||||
// 如果id和模板配置同时存在则放到模板hash表中
|
||||
if (template) {
|
||||
templateHashMap[id] = template
|
||||
}
|
||||
if (layout) {
|
||||
layoutHashMap[id] = layout
|
||||
}
|
||||
if (methods) {
|
||||
handleMethods(id, methods)
|
||||
}
|
||||
}
|
||||
|
||||
export const generateRegistry = (registry) => {
|
||||
Object.entries(registry).forEach(([key, value]) => {
|
||||
if (typeof value === 'object' && value) {
|
||||
const { id } = value
|
||||
// 如果匹配到了id,说明是元服务配置,对元服务配置做读取和写入
|
||||
if (id && key !== 'metaData') {
|
||||
handleRegistryProp(id, value)
|
||||
metasHashMap[id] = value
|
||||
} else {
|
||||
// TODO: 其他类型配置处理
|
||||
}
|
||||
|
||||
generateRegistry(value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const getMergeMeta = (meta) => {
|
||||
return metasHashMap[meta?.id]
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { generateRegistry, entryHashMap } from './common'
|
||||
|
||||
const lowcodeRegistry = { registry: null }
|
||||
|
||||
export const getMergeRegistry = () => lowcodeRegistry.registry
|
||||
|
||||
export const defineEntry = (registry) => {
|
||||
if (!registry) {
|
||||
throw new Error('请传递正确的注册表')
|
||||
}
|
||||
lowcodeRegistry.registry = registry
|
||||
generateRegistry(registry)
|
||||
}
|
||||
|
||||
export const callEntry = (fn, params) => {
|
||||
const { metaData, ctx } = params
|
||||
const customMethod = entryHashMap[metaData?.id]
|
||||
if (customMethod) {
|
||||
const customFn = customMethod.entry ? customMethod.entry : customMethod
|
||||
if (typeof customFn === 'function') {
|
||||
return customFn(ctx, fn)
|
||||
}
|
||||
}
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
export const beforeCallEntry = ({ metaData, ctx }) => {
|
||||
const id = metaData?.id
|
||||
|
||||
const customMethod = entryHashMap[id]?.before
|
||||
if (customMethod) {
|
||||
customMethod(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
export const afterCallEntry = ({ metaData, ctx }) => {
|
||||
const id = metaData?.id
|
||||
const customMethod = entryHashMap[id]?.after
|
||||
if (customMethod) {
|
||||
customMethod(ctx)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { layoutHashMap } from './common'
|
||||
|
||||
export const getLayoutComponent = (metaData) => {
|
||||
const customLayout = layoutHashMap[metaData.id]
|
||||
return customLayout
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Copyright (c) 2024 - present TinyEngine Authors.
|
||||
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { compile } from 'vue/dist/vue.esm-bundler.js'
|
||||
import { templateHashMap } from './common'
|
||||
|
||||
const generateTemplate = (template) => {
|
||||
const templateString = template.trim()
|
||||
if (templateString.startsWith('<template>') && templateString.endsWith('</template>')) {
|
||||
return templateString.slice(10, -11)
|
||||
}
|
||||
return templateString
|
||||
}
|
||||
|
||||
export const useCompile = ({ component, metaData }) => {
|
||||
// 此处compile会缓存template对应的render函数,并且render函数一个纯函数(用到的所有变量都来自参数)
|
||||
const customTem = templateHashMap[metaData.id]
|
||||
if (customTem) {
|
||||
const template = generateTemplate(customTem)
|
||||
component.render = compile(template)
|
||||
}
|
||||
|
||||
return component
|
||||
}
|
|
@ -1,21 +1,18 @@
|
|||
/**
|
||||
* Copyright (c) 2023 - present TinyEngine Authors.
|
||||
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
* Copyright (c) 2023 - present TinyEngine Authors.
|
||||
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
import component from './src/Main.vue'
|
||||
import metaData from './meta.js'
|
||||
|
||||
export default {
|
||||
id: 'I18n',
|
||||
title: '国际化',
|
||||
icon: 'plugin-icon-language',
|
||||
align: 'top',
|
||||
...metaData,
|
||||
component
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import { iconLanguage } from '@opentiny/vue-icon'
|
||||
export default {
|
||||
id: 'engine.plugins.i18n',
|
||||
title: '国际化',
|
||||
type: 'plugins',
|
||||
align: 'top',
|
||||
icon: iconLanguage()
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
"license": "MIT",
|
||||
"homepage": "https://opentiny.design/tiny-engine",
|
||||
"dependencies": {
|
||||
"@opentiny/tiny-engine-entry": "workspace:*",
|
||||
"@opentiny/tiny-engine-common": "workspace:*",
|
||||
"@opentiny/tiny-engine-controller": "workspace:*",
|
||||
"@opentiny/tiny-engine-http": "workspace:*",
|
||||
|
@ -40,4 +41,4 @@
|
|||
"@opentiny/vue-icon": "^3.14.0",
|
||||
"vue": "^3.4.15"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -119,6 +119,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="jsx">
|
||||
/* metaService */
|
||||
import { computed, ref, watchEffect, reactive, onMounted, nextTick, resolveComponent } from 'vue'
|
||||
import useClipboard from 'vue-clipboard3'
|
||||
import { Grid, GridColumn, Input, Popover, Button, FileUpload, Loading, Tooltip, Select } from '@opentiny/vue'
|
||||
|
@ -127,7 +128,7 @@ import { PluginPanel, LinkButton, SearchEmpty } from '@opentiny/tiny-engine-comm
|
|||
import { useTranslate, useApp, useModal, getGlobalConfig, useHelp } from '@opentiny/tiny-engine-controller'
|
||||
import { utils } from '@opentiny/tiny-engine-utils'
|
||||
import { useHttp } from '@opentiny/tiny-engine-http'
|
||||
import { BASE_URL } from '@opentiny/tiny-engine-controller/js/environments'
|
||||
// import { BASE_URL } from '@opentiny/tiny-engine-controller/js/environments'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -288,7 +289,7 @@ export default {
|
|||
}
|
||||
|
||||
const downloadFile = () => {
|
||||
window.open(`${BASE_URL}src/app/public/i18n-mock/i18n-template-for-batch-import.zip`)
|
||||
// window.open(`${BASE_URL}src/app/public/i18n-mock/i18n-template-for-batch-import.zip`)
|
||||
}
|
||||
|
||||
const openDeletePopover = (row) => {
|
||||
|
|
Loading…
Reference in New Issue