diff --git a/core/framework/src/dsls/xvm/page/interface.js b/core/framework/src/dsls/xvm/page/interface.js index b5032ba2..647fb6b3 100644 --- a/core/framework/src/dsls/xvm/page/interface.js +++ b/core/framework/src/dsls/xvm/page/interface.js @@ -61,6 +61,10 @@ function initPage(page, code, query, globals) { const instEvaluate = context.quickapp.dock.makeEvaluateBuildScript(globals) + const jsonRequire = (jsonModuleName, options) => { + return context.quickapp.platform.requireJson(jsonModuleName, options) + } + // 处理代码 let functionBody if (typeof code === 'function') { @@ -84,7 +88,8 @@ function initPage(page, code, query, globals) { $app_bootstrap$: instBootstrap, $app_require$: instRequireModule, $app_define_wrap$: instDefineWrap, - $app_evaluate$: instEvaluate + $app_evaluate$: instEvaluate, + $json_require$: jsonRequire }, globals ) @@ -99,6 +104,7 @@ function initPage(page, code, query, globals) { global.$app_require$ = instRequireModule global.$app_define_wrap$ = instDefineWrap global.$app_evaluate$ = instEvaluate + global.$json_require$ = jsonRequire global.setTimeout = globals.setTimeout global.setInterval = globals.setInterval diff --git a/core/framework/src/dsls/xvm/plugin-i18n/index.js b/core/framework/src/dsls/xvm/plugin-i18n/index.js index 2ef9a3b6..42249324 100644 --- a/core/framework/src/dsls/xvm/plugin-i18n/index.js +++ b/core/framework/src/dsls/xvm/plugin-i18n/index.js @@ -106,7 +106,24 @@ class PluginI18n { return null } for (let i = 0, len = resources.length; i < len; i++) { - const ret = this._interpolate(locale, resources[i], key, host, interpolateMode, params, [key]) + let ret + if (global.isRpkCardMinPlatformVersionGEQ(2000, host)) { + console.log( + `### App Framework ### i18n:读取卡片多语言资源,key: ${key}, locale: ${locale}, resources: ${JSON.stringify( + resources[i] + )}` + ) + ret = this._interpolateFlatten(locale, resources[i], key, host, interpolateMode, params, [ + key + ]) + } else { + console.log( + `### App Framework ### i18n:读取多语言资源,key: ${key}, locale: ${locale}, resources: ${JSON.stringify( + resources[i] + )}` + ) + ret = this._interpolate(locale, resources[i], key, host, interpolateMode, params, [key]) + } if (!isNull(ret)) { return ret } @@ -114,12 +131,41 @@ class PluginI18n { return null } + _interpolateFlatten(locale, jsonObject, key, host, interpolateMode, params, visitedLinkStack) { + if (!jsonObject) { + return null + } + + const keyRet = jsonObject[key] + return this._interpolateCore( + locale, + key, + host, + interpolateMode, + params, + visitedLinkStack, + keyRet + ) + } + _interpolate(locale, jsonObject, key, host, interpolateMode, params, visitedLinkStack) { if (!jsonObject) { return null } const keyRet = this._path.getPathValue(jsonObject, key) + return this._interpolateCore( + locale, + key, + host, + interpolateMode, + params, + visitedLinkStack, + keyRet + ) + } + + _interpolateCore(locale, key, host, interpolateMode, params, visitedLinkStack, keyRet) { if (isPlainObject(keyRet) || Array.isArray(keyRet)) { return keyRet } diff --git a/core/framework/src/dsls/xvm/plugin-i18n/mixin.js b/core/framework/src/dsls/xvm/plugin-i18n/mixin.js index ddb1a62f..c3f692b2 100644 --- a/core/framework/src/dsls/xvm/plugin-i18n/mixin.js +++ b/core/framework/src/dsls/xvm/plugin-i18n/mixin.js @@ -38,9 +38,9 @@ export default { onConfigurationChanged(evt) { // 页面级Vm if (evt.type === 'locale') { - if (this.$root() === this && this._i18n && this.$app) { + if (this.$root() === this && this._i18n && this._page && this._page.app) { const i18n = this._i18n - const ret = this.$app.getLocaleConfig() + const ret = this._page.app.getLocaleConfig() const retNew = JSON.parse(JSON.stringify(ret)) i18n.locale = retNew.locale i18n.resources = retNew.resources diff --git a/core/framework/src/dsls/xvm/vm/compiler.js b/core/framework/src/dsls/xvm/vm/compiler.js index 5c202699..cc85d461 100644 --- a/core/framework/src/dsls/xvm/vm/compiler.js +++ b/core/framework/src/dsls/xvm/vm/compiler.js @@ -507,6 +507,13 @@ function compileFor(vm, target, dest) { const repeat = target.repeat // 获取数据源函数 let getter = repeat.exp || repeat + if (typeof getter === 'number') { + const num = getter + getter = function() { + return num + } + } + // 确保getter是函数,则添加空函数 if (typeof getter !== 'function') { getter = function() { diff --git a/core/framework/src/dsls/xvm/vm/index.js b/core/framework/src/dsls/xvm/vm/index.js index 41079143..7b6c1927 100644 --- a/core/framework/src/dsls/xvm/vm/index.js +++ b/core/framework/src/dsls/xvm/vm/index.js @@ -405,6 +405,13 @@ export default class XVm { } options = options || {} + // 打包结果包含extracted字段,说明是新的js卡打包格式 + // template和style的前处理后,js卡option.template和option.style的格式和之前的快应用就保持一致了 + if (options.style && options.style.extracted) { + preHandleTemplate(options.template) + preHandleStyle(options) + } + // 页面级Vm:i18n配置合并 if (this._isPageVm() && this._page.app) { const ret = this._page.app.getLocaleConfig() @@ -1193,3 +1200,64 @@ XVm.mixin = function(options) { } } } + +function inReservedKeys(key) { + const RESERVED_ATTRS = ['$listeners', '$attrs'] + return RESERVED_ATTRS.includes(key) +} + +function isFunctionStr(str) { + const pattern = /^\s*function\s*\([\w\s,$]*\)\s*\{[\s\S]*\}\s*$/ + return pattern.test(str.trim()) +} + +/** + * 如果携带了新打包格式的参数,则先进行template和style的预处理 + * 主要是将key的$符号去除 + * 以及将字符串的"function"转成真正的function + * */ + +function preHandleTemplate(target) { + if (!target || Object.prototype.toString.call(target) !== '[object Object]') return + + Object.keys(target).forEach(key => { + if (Object.prototype.toString.call(target[key]) === '[object Object]') { + preHandleTemplate(target[key]) + } else if (Object.prototype.toString.call(target[key]) === '[object Array]') { + target[key].forEach(item => { + preHandleTemplate(item) + }) + } else if (typeof target[key] === 'string') { + if (!isFunctionStr(target[key])) { + // value非function字符串 + if (key.startsWith('$') && !inReservedKeys(key)) { + // example: "$value": "name",代表name为变量 + const trimKey = key.substring(1) + const func = `function () { return this.${target[key]} }` + target[trimKey] = new Function(`return ${func}`)() + delete target[key] + } + } else { + // value为function字符串 + if (key.startsWith('$')) { + // example: "$value": "function() {return this.a + '-' + this.b}",代表name为变量 + const trimKey = key.substring(1) + target[trimKey] = new Function(`return ${target[key]}`)() + delete target[key] + } else { + // 理论上不存在该情况,防止打包处理遗漏,在这里兜底 + target[key] = new Function(`return ${target[key]}`)() + } + } + } + }) +} + +function preHandleStyle(options) { + if (!options.style) return + + const styleObjectId = options.style['@info'].styleObjectId + const jsonPath = options.style.jsonPath + + options.style = context.quickapp.platform.requireJson(jsonPath, { styleObjectId }) || {} +} diff --git a/core/framework/src/infras/dock/page/index.js b/core/framework/src/infras/dock/page/index.js index 2e0c650d..7f57adad 100644 --- a/core/framework/src/infras/dock/page/index.js +++ b/core/framework/src/infras/dock/page/index.js @@ -38,6 +38,7 @@ class XPage extends ModuleHost { this._visible = false this._meta = Object.assign({ query }, intent, meta) this._orientation = intent.orientation + this._currentPageName = intent.currentPageName this.nextTickCallbacks = [] // nextTick的回调函数数组 } @@ -53,6 +54,10 @@ class XPage extends ModuleHost { return this._orientation } + get currentPageName() { + return this._currentPageName + } + get pageName() { return this._meta.name } diff --git a/core/framework/src/infras/platform/chunk.js b/core/framework/src/infras/platform/chunk.js index 71581170..9e1e1c3a 100644 --- a/core/framework/src/infras/platform/chunk.js +++ b/core/framework/src/infras/platform/chunk.js @@ -37,4 +37,68 @@ function requireBundleChunk(filePath) { return cont } -export { registerBundleChunks, requireBundleChunk } +const templateJsonMap = new Map() +const styleJsonMap = new Map() +function registerComponentJson(templateJson, cssJson) { + if (typeof templateJson === 'string') { + templateJson = JSON.parse(templateJson) + } + for (const compPath in templateJson) { + if (templateJson.hasOwnProperty(compPath)) { + let pathKey = compPath + if (pathKey.startsWith('/')) { + pathKey = pathKey.replace(/^\/+/, '') + } + const templateObj = templateJson[compPath] + templateJsonMap.set(pathKey, templateObj) + } + } + + if (typeof cssJson === 'string') { + cssJson = JSON.parse(cssJson) + } + for (const compPath in cssJson) { + if (cssJson.hasOwnProperty(compPath)) { + let pathKey = compPath + if (pathKey.startsWith('/')) { + pathKey = pathKey.replace(/^\/+/, '') + } + const styleObj = cssJson[compPath] + styleJsonMap.set(pathKey, styleObj) + } + } +} + +function requireJson(compPath, options) { + try { + if (options && options.styleObjectId) { + const styleObj = JSON.parse(styleJsonMap.get(compPath)) + if (!styleObj) { + console.warn( + `### App Framework ### requireJson not exist ${compPath} -- options: ${JSON.stringify( + options + )}` + ) + return {} + } + const style = styleObj[options.styleObjectId] + return style + } else if (options && options.componentPath) { + const templateObj = JSON.parse(templateJsonMap.get(compPath)) + if (!templateObj) { + console.warn( + `### App Framework ### requireJson not exist ${compPath} -- options: ${JSON.stringify( + options + )}` + ) + return {} + } + const template = templateObj[options.componentPath].template + return template + } + } catch (e) { + console.error(`### App Framework ### requireJson error: ${JSON.stringify(e)}`) + } +} + +export { registerBundleChunks, requireBundleChunk, registerComponentJson, requireJson } diff --git a/core/framework/src/infras/platform/interface.js b/core/framework/src/infras/platform/interface.js index 83435eda..95ce515d 100644 --- a/core/framework/src/infras/platform/interface.js +++ b/core/framework/src/infras/platform/interface.js @@ -10,11 +10,17 @@ import { invokeScript } from 'src/shared/function' import ModuleHost from './module/index' import { registerModules, execInvokeCallback, requireModule } from './module/interface' import Session from './session' -import { registerBundleChunks, requireBundleChunk } from './chunk' +import { + registerBundleChunks, + requireBundleChunk, + registerComponentJson, + requireJson +} from './chunk' import { registerManifest, isRpkMinPlatformVersionGEQ, + isRpkCardMinPlatformVersionGEQ, getManifestField, isRpkDebugMode } from './manifest' @@ -140,14 +146,17 @@ export default { ModuleHost, requireModule, requireScriptFile, + requireJson, initInterface, exposure: { registerModules, registerBundleChunks, + registerComponentJson, execInvokeCallback, registerManifest, getManifestField, isRpkMinPlatformVersionGEQ, + isRpkCardMinPlatformVersionGEQ, isRpkDebugMode } } diff --git a/core/framework/src/infras/platform/manifest.js b/core/framework/src/infras/platform/manifest.js index 71cf4a3f..86248924 100644 --- a/core/framework/src/infras/platform/manifest.js +++ b/core/framework/src/infras/platform/manifest.js @@ -55,6 +55,14 @@ function isRpkMinPlatformVersionGEQ(val) { return manifestJSON.minPlatformVersion >= val } +function isRpkCardMinPlatformVersionGEQ(val, vm) { + const widgetKey = vm._page.currentPageName + const widgetsOption = (manifestJSON.router && manifestJSON.router.widgets) || {} + const widgetManiest = widgetsOption[widgetKey] || {} + + return widgetManiest.minCardPlatformVersion >= val +} + let mode = null function isRpkDebugMode() { @@ -66,4 +74,10 @@ function isRpkDebugMode() { return mode } -export { registerManifest, isRpkMinPlatformVersionGEQ, getManifestField, isRpkDebugMode } +export { + registerManifest, + isRpkMinPlatformVersionGEQ, + isRpkCardMinPlatformVersionGEQ, + getManifestField, + isRpkDebugMode +}