diff --git a/packages/uni-cli-shared/lib/nvue.css b/packages/uni-cli-shared/lib/nvue.css index b0e67664d45a85f785ad4849a8b7668195626fef..b6107c7411f08a9e83e7e81559faf55c9334e91a 100644 --- a/packages/uni-cli-shared/lib/nvue.css +++ b/packages/uni-cli-shared/lib/nvue.css @@ -1 +1,34 @@ -label,scroll-view,swiper-item,view{display:flex;flex-direction:column;flex-shrink:0;flex-grow:0;flex-basis:auto;align-items:stretch;align-content:flex-start}image,input,scroll-view,swiper,swiper-item,text,textarea,video,view{position:relative;border:0 solid #000;box-sizing:border-box}swiper-item{position:absolute}button{margin:0} \ No newline at end of file +label, +scroll-view, +swiper-item, +view { + display: flex; + flex-direction: column; + flex-shrink: 0; + flex-grow: 0; + flex-basis: auto; + align-items: stretch; + align-content: flex-start; +} + +image, +input, +scroll-view, +swiper, +swiper-item, +text, +textarea, +video, +view { + position: relative; + border: 0 solid #000; + box-sizing: border-box; +} + +swiper-item { + position: absolute; +} + +button { + margin: 0; +} diff --git a/packages/uni-cli-shared/src/constants.ts b/packages/uni-cli-shared/src/constants.ts index d4cfd9d8c8e5a4d6d9ed1435dbfad867d08befad..75135cc6e37f1201d1f74ba8d6df4b586f2eecc7 100644 --- a/packages/uni-cli-shared/src/constants.ts +++ b/packages/uni-cli-shared/src/constants.ts @@ -4,6 +4,8 @@ export const EXTNAME_VUE = ['.vue', '.nvue'] export const EXTNAME_VUE_RE = /\.(vue|nvue)$/ export const EXTNAME_JS_RE = /\.[jt]sx?$/ +export const ASSETS_INLINE_LIMIT = 40 * 1024 + export const BINDING_COMPONENTS = '__BINDING_COMPONENTS__' // APP 平台解析页面后缀的优先级 export const PAGE_EXTNAME_APP = ['.nvue', '.vue', '.tsx', '.jsx', '.js'] diff --git a/packages/uni-cli-shared/src/hbx/log.ts b/packages/uni-cli-shared/src/hbx/log.ts index 943a4c525733a62b5e824cee4464ff61cc4fce98..daec2b5c1d361c0519de7b9d08e7c6acc36ddd6e 100644 --- a/packages/uni-cli-shared/src/hbx/log.ts +++ b/packages/uni-cli-shared/src/hbx/log.ts @@ -42,7 +42,7 @@ export const removeInfoFormatter: Formatter = { return '' }, } -const REMOVED_WARN_MSGS = ['warnings when minifying css:'] +const REMOVED_WARN_MSGS: string[] = [] export const removeWarnFormatter: Formatter = { test(msg) { return !!REMOVED_WARN_MSGS.find((m) => msg.includes(m)) diff --git a/packages/uni-cli-shared/src/preprocess/context.ts b/packages/uni-cli-shared/src/preprocess/context.ts index ddccafd854e70a71dfaed4348bdae0e3937f92c7..4988248643875bf5076409d5092e001386679c8a 100644 --- a/packages/uni-cli-shared/src/preprocess/context.ts +++ b/packages/uni-cli-shared/src/preprocess/context.ts @@ -11,6 +11,7 @@ const DEFAULT_KEYS = [ 'MP_ALIPAY', 'MP_BAIDU', 'MP_QQ', + 'MP_LARK', 'MP_TOUTIAO', 'MP_WEIXIN', 'MP_KUAISHOU', diff --git a/packages/uni-mp-baidu/dist/uni.mp.esm.js b/packages/uni-mp-baidu/dist/uni.mp.esm.js index 0f6455f7dc9ba4a61a10ce82f8696509cb19792e..69f3a8dba36f0b861638da36a162ea7a395db23c 100644 --- a/packages/uni-mp-baidu/dist/uni.mp.esm.js +++ b/packages/uni-mp-baidu/dist/uni.mp.esm.js @@ -438,8 +438,16 @@ function handleEvent(event) { const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; function createObserver(name) { return function observer(newVal) { - if (this.$vm) { - this.$vm.$.props[name] = newVal; // 为了触发其他非 render watcher + const { $vm } = this; + if ($vm) { + // 为了触发其他非 render watcher + const instance = $vm.$; + // 飞书小程序初始化太慢,导致 observer 触发时,vue 组件的 created 可能还没触发,此时开发者可能已经定义了 watch + // 但因为 created 还没触发,导致部分组件出错,如 uni-collapse,在 created 中初始化了 this.children + // 自定义 watch 中使用了 this.children + { + instance.props[name] = newVal; + } } }; } diff --git a/packages/uni-mp-core/src/runtime/componentHooks.ts b/packages/uni-mp-core/src/runtime/componentHooks.ts index 6dd7f7f45586fd1eaeb032d3ff6b61083b7b8131..b662ea89c3ebe1baa20a28c258fd625940820e5c 100644 --- a/packages/uni-mp-core/src/runtime/componentHooks.ts +++ b/packages/uni-mp-core/src/runtime/componentHooks.ts @@ -67,7 +67,10 @@ function initHook( this: CustomAppInstanceProperty | CustomComponentInstanceProperty, args: unknown ) { - if (__PLATFORM__ === 'mp-toutiao' && hook === 'onError') { + if ( + (__PLATFORM__ === 'mp-toutiao' || __PLATFORM__ === 'mp-lark') && + hook === 'onError' + ) { return getApp().$vm.$callHook(hook, args) } return this.$vm && this.$vm.$callHook(hook, args) diff --git a/packages/uni-mp-core/src/runtime/componentProps.ts b/packages/uni-mp-core/src/runtime/componentProps.ts index 3bbd379ee184943c2eb468610fa3a3cf79b74c32..f423f4e5afb2945ca6b244647e9923a7ee33ed4d 100644 --- a/packages/uni-mp-core/src/runtime/componentProps.ts +++ b/packages/uni-mp-core/src/runtime/componentProps.ts @@ -1,4 +1,4 @@ -import { ComponentPropsOptions } from 'vue' +import { onBeforeMount, ComponentPropsOptions } from 'vue' import { isArray, isPlainObject, isFunction } from '@vue/shared' import { MPComponentOptions, MPComponentInstance } from './component' @@ -8,8 +8,22 @@ const PROP_TYPES = [String, Number, Boolean, Object, Array, null] function createObserver(name: string) { return function observer(this: MPComponentInstance, newVal: unknown) { - if (this.$vm) { - this.$vm.$.props[name] = newVal // 为了触发其他非 render watcher + const { $vm } = this + if ($vm) { + // 为了触发其他非 render watcher + const instance = $vm.$ + // 飞书小程序初始化太慢,导致 observer 触发时,vue 组件的 created 可能还没触发,此时开发者可能已经定义了 watch + // 但因为 created 还没触发,导致部分组件出错,如 uni-collapse,在 created 中初始化了 this.children + // 自定义 watch 中使用了 this.children + if (__PLATFORM__ === 'mp-lark') { + if (instance.isMounted) { + instance.props[name] = newVal + } else { + onBeforeMount(() => (instance.props[name] = newVal), instance) + } + } else { + instance.props[name] = newVal + } } } } diff --git a/packages/uni-mp-core/src/runtime/polyfill.ts b/packages/uni-mp-core/src/runtime/polyfill.ts index 3071101793fed55f8126818e2d26011c1f71f81e..3503ef5dd4f1b4147e116f312699b706c034517b 100644 --- a/packages/uni-mp-core/src/runtime/polyfill.ts +++ b/packages/uni-mp-core/src/runtime/polyfill.ts @@ -23,7 +23,10 @@ function initHook( options: Record, isComponent?: boolean ) { - if (__PLATFORM__ === 'mp-toutiao' && isComponent) { + if ( + (__PLATFORM__ === 'mp-toutiao' || __PLATFORM__ === 'mp-lark') && + isComponent + ) { // fix by Lxh 字节自定义组件Component构造器文档上写有created,但是实测只触发了lifetimes上的created options = options.lifetimes } diff --git a/packages/uni-mp-kuaishou/dist/uni.compiler.js b/packages/uni-mp-kuaishou/dist/uni.compiler.js index c4c621ef313c7d62c9259b79af19ee1426e2d034..6fa4bf016a00acd255a12b635f2384b229306a55 100644 --- a/packages/uni-mp-kuaishou/dist/uni.compiler.js +++ b/packages/uni-mp-kuaishou/dist/uni.compiler.js @@ -1,9 +1,9 @@ 'use strict'; +var uniCliShared = require('@dcloudio/uni-cli-shared'); var initMiniProgramPlugin = require('@dcloudio/uni-mp-vite'); var path = require('path'); var uniShared = require('@dcloudio/uni-shared'); -var uniCliShared = require('@dcloudio/uni-cli-shared'); var uniMpCompiler = require('@dcloudio/uni-mp-compiler'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } @@ -190,7 +190,7 @@ const uniMiniProgramKuaishouPlugin = { }, build: { // css 中不支持引用本地资源 - assetsInlineLimit: 40 * 1024, // 40kb + assetsInlineLimit: uniCliShared.ASSETS_INLINE_LIMIT, }, }; }, diff --git a/packages/uni-mp-kuaishou/dist/uni.mp.esm.js b/packages/uni-mp-kuaishou/dist/uni.mp.esm.js index 84d888fcfe14985505a93dd17327e2f89f91d55c..e1d366055bd879faffeb669dcb596d62be16b634 100644 --- a/packages/uni-mp-kuaishou/dist/uni.mp.esm.js +++ b/packages/uni-mp-kuaishou/dist/uni.mp.esm.js @@ -438,8 +438,16 @@ function handleEvent(event) { const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; function createObserver(name) { return function observer(newVal) { - if (this.$vm) { - this.$vm.$.props[name] = newVal; // 为了触发其他非 render watcher + const { $vm } = this; + if ($vm) { + // 为了触发其他非 render watcher + const instance = $vm.$; + // 飞书小程序初始化太慢,导致 observer 触发时,vue 组件的 created 可能还没触发,此时开发者可能已经定义了 watch + // 但因为 created 还没触发,导致部分组件出错,如 uni-collapse,在 created 中初始化了 this.children + // 自定义 watch 中使用了 this.children + { + instance.props[name] = newVal; + } } }; } diff --git a/packages/uni-mp-kuaishou/src/compiler/index.ts b/packages/uni-mp-kuaishou/src/compiler/index.ts index 0204187cfd418badca2fadc526a8bec28dd6a8ca..e7ed437dad2e0f0bc02b921894b28187eff84987 100644 --- a/packages/uni-mp-kuaishou/src/compiler/index.ts +++ b/packages/uni-mp-kuaishou/src/compiler/index.ts @@ -1,5 +1,5 @@ import { Plugin } from 'vite' - +import { ASSETS_INLINE_LIMIT } from '@dcloudio/uni-cli-shared' import initMiniProgramPlugin from '@dcloudio/uni-mp-vite' import { options } from './options' @@ -12,7 +12,7 @@ const uniMiniProgramKuaishouPlugin: Plugin = { }, build: { // css 中不支持引用本地资源 - assetsInlineLimit: 40 * 1024, // 40kb + assetsInlineLimit: ASSETS_INLINE_LIMIT, }, } }, diff --git a/packages/uni-mp-lark/LICENSE b/packages/uni-mp-lark/LICENSE new file mode 100755 index 0000000000000000000000000000000000000000..7a4a3ea2424c09fbe48d455aed1eaa94d9124835 --- /dev/null +++ b/packages/uni-mp-lark/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/uni-mp-lark/build.json b/packages/uni-mp-lark/build.json new file mode 100644 index 0000000000000000000000000000000000000000..ec89593e4db025abb1401c0fe38ce47ece3bfae6 --- /dev/null +++ b/packages/uni-mp-lark/build.json @@ -0,0 +1,41 @@ +[ + { + "input": { + "src/compiler/index.ts": "dist/uni.compiler.js" + }, + "output": { + "format": "cjs" + }, + "external": [ + "@vue/compiler-core", + "@dcloudio/uni-shared", + "@dcloudio/uni-cli-shared", + "@dcloudio/uni-mp-vite", + "@dcloudio/uni-mp-compiler" + ] + }, + { + "input": { + "src/runtime/index.ts": "dist/uni.mp.esm.js", + "src/api/index.ts": "dist/uni.api.esm.js" + }, + "alias": { + "entries": [ + { + "find": "@dcloudio/uni-platform", + "replacement": "packages/uni-mp-lark/src/platform/index.ts" + }, + { + "find": "@dcloudio/uni-mp-platform", + "replacement": "packages/uni-mp-core/src/platform/index.ts" + } + ] + }, + "replacements": { + "__GLOBAL__": "tt", + "__PLATFORM__": "\"mp-lark\"", + "__PLATFORM_TITLE__": "飞书小程序" + }, + "external": ["@dcloudio/uni-i18n", "@vue/shared", "vue"] + } +] diff --git a/packages/uni-mp-lark/dist/uni.api.esm.js b/packages/uni-mp-lark/dist/uni.api.esm.js new file mode 100644 index 0000000000000000000000000000000000000000..ad9e2d6e5832b884dd7478067b97ff50e239d7f9 --- /dev/null +++ b/packages/uni-mp-lark/dist/uni.api.esm.js @@ -0,0 +1,960 @@ +import { isArray, hasOwn, isString, isPlainObject, isObject, capitalize, toRawType, makeMap, isPromise, isFunction, extend } from '@vue/shared'; +import { injectHook } from 'vue'; + +//App +const ON_LAUNCH = 'onLaunch'; + +const eventChannels = {}; +const eventChannelStack = []; +let id = 0; +function initEventChannel(events, cache = true) { + id++; + const eventChannel = new tt.EventChannel(id, events); + if (cache) { + eventChannels[id] = eventChannel; + eventChannelStack.push(eventChannel); + } + return eventChannel; +} +function getEventChannel(id) { + if (id) { + const eventChannel = eventChannels[id]; + delete eventChannels[id]; + return eventChannel; + } + return eventChannelStack.shift(); +} +const navigateTo = { + args(fromArgs) { + const id = initEventChannel(fromArgs.events).id; + if (fromArgs.url) { + fromArgs.url = + fromArgs.url + + (fromArgs.url.indexOf('?') === -1 ? '?' : '&') + + '__id__=' + + id; + } + }, + returnValue(fromRes) { + fromRes.eventChannel = getEventChannel(); + }, +}; + +tt.appLaunchHooks = []; +function onAppLaunch(hook) { + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return injectHook(ON_LAUNCH, hook, app.$vm.$); + } + tt.appLaunchHooks.push(hook); +} + +function getBaseSystemInfo() { + return tt.getSystemInfoSync() +} + +function validateProtocolFail(name, msg) { + console.warn(`${name}: ${msg}`); +} +function validateProtocol(name, data, protocol, onFail) { + if (!onFail) { + onFail = validateProtocolFail; + } + for (const key in protocol) { + const errMsg = validateProp(key, data[key], protocol[key], !hasOwn(data, key)); + if (isString(errMsg)) { + onFail(name, errMsg); + } + } +} +function validateProtocols(name, args, protocol, onFail) { + if (!protocol) { + return; + } + if (!isArray(protocol)) { + return validateProtocol(name, args[0] || Object.create(null), protocol, onFail); + } + const len = protocol.length; + const argsLen = args.length; + for (let i = 0; i < len; i++) { + const opts = protocol[i]; + const data = Object.create(null); + if (argsLen > i) { + data[opts.name] = args[i]; + } + validateProtocol(name, data, { [opts.name]: opts }, onFail); + } +} +function validateProp(name, value, prop, isAbsent) { + if (!isPlainObject(prop)) { + prop = { type: prop }; + } + const { type, required, validator } = prop; + // required! + if (required && isAbsent) { + return 'Missing required args: "' + name + '"'; + } + // missing but optional + if (value == null && !required) { + return; + } + // type check + if (type != null) { + let isValid = false; + const types = isArray(type) ? type : [type]; + const expectedTypes = []; + // value is valid as long as one of the specified types match + for (let i = 0; i < types.length && !isValid; i++) { + const { valid, expectedType } = assertType(value, types[i]); + expectedTypes.push(expectedType || ''); + isValid = valid; + } + if (!isValid) { + return getInvalidTypeMessage(name, value, expectedTypes); + } + } + // custom validator + if (validator) { + return validator(value); + } +} +const isSimpleType = /*#__PURE__*/ makeMap('String,Number,Boolean,Function,Symbol'); +function assertType(value, type) { + let valid; + const expectedType = getType(type); + if (isSimpleType(expectedType)) { + const t = typeof value; + valid = t === expectedType.toLowerCase(); + // for primitive wrapper objects + if (!valid && t === 'object') { + valid = value instanceof type; + } + } + else if (expectedType === 'Object') { + valid = isObject(value); + } + else if (expectedType === 'Array') { + valid = isArray(value); + } + else { + { + valid = value instanceof type; + } + } + return { + valid, + expectedType, + }; +} +function getInvalidTypeMessage(name, value, expectedTypes) { + let message = `Invalid args: type check failed for args "${name}".` + + ` Expected ${expectedTypes.map(capitalize).join(', ')}`; + const expectedType = expectedTypes[0]; + const receivedType = toRawType(value); + const expectedValue = styleValue(value, expectedType); + const receivedValue = styleValue(value, receivedType); + // check if we need to specify expected value + if (expectedTypes.length === 1 && + isExplicable(expectedType) && + !isBoolean(expectedType, receivedType)) { + message += ` with value ${expectedValue}`; + } + message += `, got ${receivedType} `; + // check if we need to specify received value + if (isExplicable(receivedType)) { + message += `with value ${receivedValue}.`; + } + return message; +} +function getType(ctor) { + const match = ctor && ctor.toString().match(/^\s*function (\w+)/); + return match ? match[1] : ''; +} +function styleValue(value, type) { + if (type === 'String') { + return `"${value}"`; + } + else if (type === 'Number') { + return `${Number(value)}`; + } + else { + return `${value}`; + } +} +function isExplicable(type) { + const explicitTypes = ['string', 'number', 'boolean']; + return explicitTypes.some((elem) => type.toLowerCase() === elem); +} +function isBoolean(...args) { + return args.some((elem) => elem.toLowerCase() === 'boolean'); +} + +const HOOK_SUCCESS = 'success'; +const HOOK_FAIL = 'fail'; +const HOOK_COMPLETE = 'complete'; +const globalInterceptors = {}; +const scopedInterceptors = {}; +function wrapperHook(hook) { + return function (data) { + return hook(data) || data; + }; +} +function queue(hooks, data) { + let promise = false; + for (let i = 0; i < hooks.length; i++) { + const hook = hooks[i]; + if (promise) { + promise = Promise.resolve(wrapperHook(hook)); + } + else { + const res = hook(data); + if (isPromise(res)) { + promise = Promise.resolve(res); + } + if (res === false) { + return { + then() { }, + catch() { }, + }; + } + } + } + return (promise || { + then(callback) { + return callback(data); + }, + catch() { }, + }); +} +function wrapperOptions(interceptors, options = {}) { + [HOOK_SUCCESS, HOOK_FAIL, HOOK_COMPLETE].forEach((name) => { + const hooks = interceptors[name]; + if (!isArray(hooks)) { + return; + } + const oldCallback = options[name]; + options[name] = function callbackInterceptor(res) { + queue(hooks, res).then((res) => { + return (isFunction(oldCallback) && oldCallback(res)) || res; + }); + }; + }); + return options; +} +function wrapperReturnValue(method, returnValue) { + const returnValueHooks = []; + if (isArray(globalInterceptors.returnValue)) { + returnValueHooks.push(...globalInterceptors.returnValue); + } + const interceptor = scopedInterceptors[method]; + if (interceptor && isArray(interceptor.returnValue)) { + returnValueHooks.push(...interceptor.returnValue); + } + returnValueHooks.forEach((hook) => { + returnValue = hook(returnValue) || returnValue; + }); + return returnValue; +} +function getApiInterceptorHooks(method) { + const interceptor = Object.create(null); + Object.keys(globalInterceptors).forEach((hook) => { + if (hook !== 'returnValue') { + interceptor[hook] = globalInterceptors[hook].slice(); + } + }); + const scopedInterceptor = scopedInterceptors[method]; + if (scopedInterceptor) { + Object.keys(scopedInterceptor).forEach((hook) => { + if (hook !== 'returnValue') { + interceptor[hook] = (interceptor[hook] || []).concat(scopedInterceptor[hook]); + } + }); + } + return interceptor; +} +function invokeApi(method, api, options, ...params) { + const interceptor = getApiInterceptorHooks(method); + if (interceptor && Object.keys(interceptor).length) { + if (isArray(interceptor.invoke)) { + const res = queue(interceptor.invoke, options); + return res.then((options) => { + return api(wrapperOptions(interceptor, options), ...params); + }); + } + else { + return api(wrapperOptions(interceptor, options), ...params); + } + } + return api(options, ...params); +} + +function handlePromise(promise) { + // if (__UNI_FEATURE_PROMISE__) { + // return promise + // .then((data) => { + // return [null, data] + // }) + // .catch((err) => [err]) + // } + return promise; +} + +function formatApiArgs(args, options) { + const params = args[0]; + if (!options || + (!isPlainObject(options.formatArgs) && isPlainObject(params))) { + return; + } + const formatArgs = options.formatArgs; + const keys = Object.keys(formatArgs); + for (let i = 0; i < keys.length; i++) { + const name = keys[i]; + const formatterOrDefaultValue = formatArgs[name]; + if (isFunction(formatterOrDefaultValue)) { + const errMsg = formatterOrDefaultValue(args[0][name], params); + if (isString(errMsg)) { + return errMsg; + } + } + else { + // defaultValue + if (!hasOwn(params, name)) { + params[name] = formatterOrDefaultValue; + } + } + } +} +function beforeInvokeApi(name, args, protocol, options) { + if ((process.env.NODE_ENV !== 'production')) { + validateProtocols(name, args, protocol); + } + if (options && options.beforeInvoke) { + const errMsg = options.beforeInvoke(args); + if (isString(errMsg)) { + return errMsg; + } + } + const errMsg = formatApiArgs(args, options); + if (errMsg) { + return errMsg; + } +} +function wrapperSyncApi(name, fn, protocol, options) { + return (...args) => { + const errMsg = beforeInvokeApi(name, args, protocol, options); + if (errMsg) { + throw new Error(errMsg); + } + return fn.apply(null, args); + }; +} +function defineSyncApi(name, fn, protocol, options) { + return wrapperSyncApi(name, fn, (process.env.NODE_ENV !== 'production') ? protocol : undefined, options); +} + +const API_UPX2PX = 'upx2px'; +const Upx2pxProtocol = [ + { + name: 'upx', + type: [Number, String], + required: true, + }, +]; + +const EPS = 1e-4; +const BASE_DEVICE_WIDTH = 750; +let isIOS = false; +let deviceWidth = 0; +let deviceDPR = 0; +function checkDeviceWidth() { + const { platform, pixelRatio, windowWidth } = getBaseSystemInfo(); + deviceWidth = windowWidth; + deviceDPR = pixelRatio; + isIOS = platform === 'ios'; +} +const upx2px = defineSyncApi(API_UPX2PX, (number, newDeviceWidth) => { + if (deviceWidth === 0) { + checkDeviceWidth(); + } + number = Number(number); + if (number === 0) { + return 0; + } + let width = newDeviceWidth || deviceWidth; + let result = (number / BASE_DEVICE_WIDTH) * width; + if (result < 0) { + result = -result; + } + result = Math.floor(result + EPS); + if (result === 0) { + if (deviceDPR === 1 || !isIOS) { + result = 1; + } + else { + result = 0.5; + } + } + return number < 0 ? -result : result; +}, Upx2pxProtocol); + +const API_ADD_INTERCEPTOR = 'addInterceptor'; +const API_REMOVE_INTERCEPTOR = 'removeInterceptor'; +const AddInterceptorProtocol = [ + { + name: 'method', + type: [String, Object], + required: true, + }, +]; +const RemoveInterceptorProtocol = AddInterceptorProtocol; + +function mergeInterceptorHook(interceptors, interceptor) { + Object.keys(interceptor).forEach((hook) => { + if (isFunction(interceptor[hook])) { + interceptors[hook] = mergeHook(interceptors[hook], interceptor[hook]); + } + }); +} +function removeInterceptorHook(interceptors, interceptor) { + if (!interceptors || !interceptor) { + return; + } + Object.keys(interceptor).forEach((hook) => { + if (isFunction(interceptor[hook])) { + removeHook(interceptors[hook], interceptor[hook]); + } + }); +} +function mergeHook(parentVal, childVal) { + const res = childVal + ? parentVal + ? parentVal.concat(childVal) + : isArray(childVal) + ? childVal + : [childVal] + : parentVal; + return res ? dedupeHooks(res) : res; +} +function dedupeHooks(hooks) { + const res = []; + for (let i = 0; i < hooks.length; i++) { + if (res.indexOf(hooks[i]) === -1) { + res.push(hooks[i]); + } + } + return res; +} +function removeHook(hooks, hook) { + if (!hooks) { + return; + } + const index = hooks.indexOf(hook); + if (index !== -1) { + hooks.splice(index, 1); + } +} +const addInterceptor = defineSyncApi(API_ADD_INTERCEPTOR, (method, interceptor) => { + if (typeof method === 'string' && isPlainObject(interceptor)) { + mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), interceptor); + } + else if (isPlainObject(method)) { + mergeInterceptorHook(globalInterceptors, method); + } +}, AddInterceptorProtocol); +const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interceptor) => { + if (typeof method === 'string') { + if (isPlainObject(interceptor)) { + removeInterceptorHook(scopedInterceptors[method], interceptor); + } + else { + delete scopedInterceptors[method]; + } + } + else if (isPlainObject(method)) { + removeInterceptorHook(globalInterceptors, method); + } +}, RemoveInterceptorProtocol); +const interceptors = {}; + +const API_ON = '$on'; +const OnProtocol = [ + { + name: 'event', + type: String, + required: true, + }, + { + name: 'callback', + type: Function, + required: true, + }, +]; +const API_ONCE = '$once'; +const OnceProtocol = OnProtocol; +const API_OFF = '$off'; +const OffProtocol = [ + { + name: 'event', + type: [String, Array], + }, + { + name: 'callback', + type: Function, + }, +]; +const API_EMIT = '$emit'; +const EmitProtocol = [ + { + name: 'event', + type: String, + required: true, + }, +]; + +const E = function () { + // Keep this empty so it's easier to inherit from + // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) +}; +E.prototype = { + on: function (name, callback, ctx) { + var e = this.e || (this.e = {}); + (e[name] || (e[name] = [])).push({ + fn: callback, + ctx: ctx, + }); + return this; + }, + once: function (name, callback, ctx) { + var self = this; + function listener() { + self.off(name, listener); + callback.apply(ctx, arguments); + } + listener._ = callback; + return this.on(name, listener, ctx); + }, + emit: function (name) { + var data = [].slice.call(arguments, 1); + var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); + var i = 0; + var len = evtArr.length; + for (i; i < len; i++) { + evtArr[i].fn.apply(evtArr[i].ctx, data); + } + return this; + }, + off: function (name, callback) { + var e = this.e || (this.e = {}); + var evts = e[name]; + var liveEvents = []; + if (evts && callback) { + for (var i = 0, len = evts.length; i < len; i++) { + if (evts[i].fn !== callback && evts[i].fn._ !== callback) + liveEvents.push(evts[i]); + } + } + // Remove event from queue to prevent memory leak + // Suggested by https://github.com/lazd + // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 + liveEvents.length ? (e[name] = liveEvents) : delete e[name]; + return this; + }, +}; +var Emitter = E; + +const emitter = new Emitter(); +const $on = defineSyncApi(API_ON, (name, callback) => { + emitter.on(name, callback); + return () => emitter.off(name, callback); +}, OnProtocol); +const $once = defineSyncApi(API_ONCE, (name, callback) => { + emitter.once(name, callback); + return () => emitter.off(name, callback); +}, OnceProtocol); +const $off = defineSyncApi(API_OFF, (name, callback) => { + if (!name) { + emitter.e = {}; + return; + } + if (!Array.isArray(name)) + name = [name]; + name.forEach((n) => emitter.off(n, callback)); +}, OffProtocol); +const $emit = defineSyncApi(API_EMIT, (name, ...args) => { + emitter.emit(name, ...args); +}, EmitProtocol); + +const SYNC_API_RE = /^\$|getLocale|setLocale|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const CONTEXT_API_RE = /^create|Manager$/; +// Context例外情况 +const CONTEXT_API_RE_EXC = ['createBLEConnection']; +// 同步例外情况 +const ASYNC_API = ['createBLEConnection']; +const CALLBACK_API_RE = /^on|^off/; +function isContextApi(name) { + return CONTEXT_API_RE.test(name) && CONTEXT_API_RE_EXC.indexOf(name) === -1; +} +function isSyncApi(name) { + return SYNC_API_RE.test(name) && ASYNC_API.indexOf(name) === -1; +} +function isCallbackApi(name) { + return CALLBACK_API_RE.test(name) && name !== 'onPush'; +} +function shouldPromise(name) { + if (isContextApi(name) || isSyncApi(name) || isCallbackApi(name)) { + return false; + } + return true; +} +/* eslint-disable no-extend-native */ +if (!Promise.prototype.finally) { + Promise.prototype.finally = function (onfinally) { + const promise = this.constructor; + return this.then((value) => promise.resolve(onfinally && onfinally()).then(() => value), (reason) => promise.resolve(onfinally && onfinally()).then(() => { + throw reason; + })); + }; +} +function promisify(name, api) { + if (!shouldPromise(name)) { + return api; + } + if (!isFunction(api)) { + return api; + } + return function promiseApi(options = {}) { + if (isFunction(options.success) || + isFunction(options.fail) || + isFunction(options.complete)) { + return wrapperReturnValue(name, invokeApi(name, api, options)); + } + return wrapperReturnValue(name, handlePromise(new Promise((resolve, reject) => { + invokeApi(name, api, extend({}, options, { + success: resolve, + fail: reject, + })); + }))); + }; +} + +const CALLBACKS = ['success', 'fail', 'cancel', 'complete']; +function initWrapper(protocols) { + function processCallback(methodName, method, returnValue) { + return function (res) { + return method(processReturnValue(methodName, res, returnValue)); + }; + } + function processArgs(methodName, fromArgs, argsOption = {}, returnValue = {}, keepFromArgs = false) { + if (isPlainObject(fromArgs)) { + // 一般 api 的参数解析 + const toArgs = (keepFromArgs === true ? fromArgs : {}); // returnValue 为 false 时,说明是格式化返回值,直接在返回值对象上修改赋值 + if (isFunction(argsOption)) { + argsOption = argsOption(fromArgs, toArgs) || {}; + } + for (const key in fromArgs) { + if (hasOwn(argsOption, key)) { + let keyOption = argsOption[key]; + if (isFunction(keyOption)) { + keyOption = keyOption(fromArgs[key], fromArgs, toArgs); + } + if (!keyOption) { + // 不支持的参数 + console.warn(`飞书小程序 ${methodName} 暂不支持 ${key}`); + } + else if (isString(keyOption)) { + // 重写参数 key + toArgs[keyOption] = fromArgs[key]; + } + else if (isPlainObject(keyOption)) { + // {name:newName,value:value}可重新指定参数 key:value + toArgs[keyOption.name ? keyOption.name : key] = keyOption.value; + } + } + else if (CALLBACKS.indexOf(key) !== -1) { + const callback = fromArgs[key]; + if (isFunction(callback)) { + toArgs[key] = processCallback(methodName, callback, returnValue); + } + } + else { + if (!keepFromArgs && !hasOwn(toArgs, key)) { + toArgs[key] = fromArgs[key]; + } + } + } + return toArgs; + } + else if (isFunction(fromArgs)) { + fromArgs = processCallback(methodName, fromArgs, returnValue); + } + return fromArgs; + } + function processReturnValue(methodName, res, returnValue, keepReturnValue = false) { + if (isFunction(protocols.returnValue)) { + // 处理通用 returnValue + res = protocols.returnValue(methodName, res); + } + return processArgs(methodName, res, returnValue, {}, keepReturnValue); + } + return function wrapper(methodName, method) { + if (!hasOwn(protocols, methodName)) { + return method; + } + const protocol = protocols[methodName]; + if (!protocol) { + // 暂不支持的 api + return function () { + console.error(`飞书小程序 暂不支持${methodName}`); + }; + } + return function (arg1, arg2) { + // 目前 api 最多两个参数 + let options = protocol; + if (isFunction(protocol)) { + options = protocol(arg1); + } + arg1 = processArgs(methodName, arg1, options.args, options.returnValue); + const args = [arg1]; + if (typeof arg2 !== 'undefined') { + args.push(arg2); + } + const returnValue = tt[options.name || methodName].apply(tt, args); + if (isSyncApi(methodName)) { + // 同步 api + return processReturnValue(methodName, returnValue, options.returnValue, isContextApi(methodName)); + } + return returnValue; + }; + }; +} + +const getLocale = () => { + // 优先使用 $locale + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return app.$vm.$locale; + } + return tt.getSystemInfoSync().language || 'zh-Hans'; +}; +const setLocale = (locale) => { + const app = getApp(); + if (!app) { + return false; + } + const oldLocale = app.$vm.$locale; + if (oldLocale !== locale) { + app.$vm.$locale = locale; + onLocaleChangeCallbacks.forEach((fn) => fn({ locale })); + return true; + } + return false; +}; +const onLocaleChangeCallbacks = []; +const onLocaleChange = (fn) => { + if (onLocaleChangeCallbacks.indexOf(fn) === -1) { + onLocaleChangeCallbacks.push(fn); + } +}; +if (typeof global !== 'undefined') { + global.getLocale = getLocale; +} + +const baseApis = { + $on, + $off, + $once, + $emit, + upx2px, + interceptors, + addInterceptor, + removeInterceptor, + onAppLaunch, + getLocale, + setLocale, + onLocaleChange, +}; +function initUni(api, protocols) { + const wrapper = initWrapper(protocols); + const UniProxyHandlers = { + get(target, key) { + if (hasOwn(target, key)) { + return target[key]; + } + if (hasOwn(api, key)) { + return promisify(key, api[key]); + } + if (hasOwn(baseApis, key)) { + return promisify(key, baseApis[key]); + } + // event-api + // provider-api? + return promisify(key, wrapper(key, tt[key])); + }, + }; + return new Proxy({}, UniProxyHandlers); +} + +function initGetProvider(providers) { + return function getProvider({ service, success, fail, complete, }) { + let res; + if (providers[service]) { + res = { + errMsg: 'getProvider:ok', + service, + provider: providers[service], + }; + isFunction(success) && success(res); + } + else { + res = { + errMsg: 'getProvider:fail:服务[' + service + ']不存在', + }; + isFunction(fail) && fail(res); + } + isFunction(complete) && complete(res); + }; +} + +const redirectTo = {}; + +const previewImage = { + args(fromArgs, toArgs) { + let currentIndex = parseInt(fromArgs.current); + if (isNaN(currentIndex)) { + return; + } + const urls = fromArgs.urls; + if (!isArray(urls)) { + return; + } + const len = urls.length; + if (!len) { + return; + } + if (currentIndex < 0) { + currentIndex = 0; + } + else if (currentIndex >= len) { + currentIndex = len - 1; + } + if (currentIndex > 0) { + toArgs.current = urls[currentIndex]; + toArgs.urls = urls.filter((item, index) => index < currentIndex ? item !== urls[currentIndex] : true); + } + else { + toArgs.current = urls[0]; + } + return { + indicator: false, + loop: false, + }; + }, +}; + +const getProvider = initGetProvider({ + oauth: ['toutiao'], + share: ['toutiao'], + payment: ['toutiao'], + push: ['toutiao'], +}); + +var shims = /*#__PURE__*/Object.freeze({ + __proto__: null, + getProvider: getProvider +}); + +const chooseImage = { + args: { + sizeType: false, + }, +}; +const connectSocket = { + args: { + method: false, + }, +}; +const chooseVideo = { + args: { + camera: false, + }, +}; +const scanCode = { + args: { + onlyFromCamera: false, + scanType: false, + }, +}; +const startAccelerometer = { + args: { + interval: false, + }, +}; +const showToast = { + args: { + image: false, + mask: false, + }, +}; +const showLoading = { + args: { + mask: false, + }, +}; +const showModal = { + args: { + cancelColor: false, + confirmColor: false, + }, +}; +const showActionSheet = { + args: { + itemColor: false, + }, +}; +const login = { + args: { + scopes: false, + timeout: false, + }, +}; +const getUserInfo = { + args: { + lang: false, + timeout: false, + }, +}; +const requestPayment = { + name: tt.pay ? 'pay' : 'requestPayment', + args: { + orderInfo: tt.pay ? 'orderInfo' : 'data', + }, +}; +const getFileInfo = { + args: { + digestAlgorithm: false, + }, +}; + +var protocols = /*#__PURE__*/Object.freeze({ + __proto__: null, + chooseImage: chooseImage, + connectSocket: connectSocket, + chooseVideo: chooseVideo, + scanCode: scanCode, + startAccelerometer: startAccelerometer, + showToast: showToast, + showLoading: showLoading, + showModal: showModal, + showActionSheet: showActionSheet, + login: login, + getUserInfo: getUserInfo, + requestPayment: requestPayment, + getFileInfo: getFileInfo, + redirectTo: redirectTo, + navigateTo: navigateTo, + previewImage: previewImage +}); + +var uni = initUni(shims, protocols); + +export { uni as default }; diff --git a/packages/uni-mp-lark/dist/uni.compiler.js b/packages/uni-mp-lark/dist/uni.compiler.js new file mode 100644 index 0000000000000000000000000000000000000000..6565e6268c8ee9686764684d5a675b5b6168cd5b --- /dev/null +++ b/packages/uni-mp-lark/dist/uni.compiler.js @@ -0,0 +1,143 @@ +'use strict'; + +var initMiniProgramPlugin = require('@dcloudio/uni-mp-vite'); +var uniCliShared = require('@dcloudio/uni-cli-shared'); +var path = require('path'); +var uniShared = require('@dcloudio/uni-shared'); +var uniMpCompiler = require('@dcloudio/uni-mp-compiler'); +var compilerCore = require('@vue/compiler-core'); + +function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } + +var initMiniProgramPlugin__default = /*#__PURE__*/_interopDefaultLegacy(initMiniProgramPlugin); +var path__default = /*#__PURE__*/_interopDefaultLegacy(path); + +var setting = { + urlCheck: false, + es6: true, + postcss: false, + minified: false, + newFeature: true +}; +var appid = "testAppId"; +var projectname = ""; +var condition = { + miniprogram: { + current: -1 + } +}; +var source = { + setting: setting, + appid: appid, + projectname: projectname, + condition: condition +}; + +function transformSwiper(node) { + if (node.type !== 1 /* ELEMENT */ || node.tag !== 'swiper') { + return; + } + const disableTouchProp = compilerCore.findProp(node, 'disable-touch', false, true); + if (!disableTouchProp) { + return; + } + const { props } = node; + if (disableTouchProp.type === 6 /* ATTRIBUTE */) { + // => + props.splice(props.indexOf(disableTouchProp), 1, uniCliShared.createBindDirectiveNode('touchable', 'false')); + } + else { + if (disableTouchProp.exp) { + // => + let touchable = ''; + if (disableTouchProp.exp.type === 4 /* SIMPLE_EXPRESSION */) { + if (disableTouchProp.exp.content === 'true') { + touchable = 'false'; + } + else if (disableTouchProp.exp.content === 'false') { + touchable = 'true'; + } + } + props.splice(props.indexOf(disableTouchProp), 1, uniCliShared.createBindDirectiveNode('touchable', touchable || `!(${uniMpCompiler.genExpr(disableTouchProp.exp)})`)); + } + } +} + +const projectConfigFilename = 'project.config.json'; +const nodeTransforms = [ + uniCliShared.transformRef, + transformSwiper, + uniCliShared.transformMatchMedia, + uniCliShared.transformComponentLink, +]; +const compilerOptions = { + isNativeTag: uniShared.isNativeTag, + isCustomElement: uniShared.isCustomElement, + nodeTransforms, +}; +const miniProgram = { + class: { + array: false, + }, + slot: { + fallbackContent: true, + dynamicSlotNames: true, + }, + directive: 'tt:', +}; +const options = { + vite: { + inject: { + uni: [path__default["default"].resolve(__dirname, 'uni.api.esm.js'), 'default'], + }, + alias: { + 'uni-mp-runtime': path__default["default"].resolve(__dirname, 'uni.mp.esm.js'), + }, + copyOptions: { + assets: ['ttcomponents'], + }, + }, + global: 'tt', + app: { + darkmode: false, + subpackages: true, + }, + project: { + filename: projectConfigFilename, + source, + }, + template: Object.assign(Object.assign({}, miniProgram), { filter: { + extname: '.sjs', + lang: 'sjs', + generate(filter, filename) { + if (filename) { + return ``; + } + return ` +${filter.code} +`; + }, + }, extname: '.ttml', compilerOptions }), + style: { + extname: '.ttss', + }, +}; + +const uniMiniProgramToutiaoPlugin = { + name: 'vite:uni-mp-lark', + config() { + return { + define: { + __VUE_CREATED_DEFERRED__: true, + }, + build: { + // css 中不支持引用本地资源 + assetsInlineLimit: uniCliShared.ASSETS_INLINE_LIMIT, + }, + }; + }, +}; +options.template.slot.fallbackContent = false; +var index = [uniMiniProgramToutiaoPlugin, ...initMiniProgramPlugin__default["default"](options)]; + +module.exports = index; diff --git a/packages/uni-mp-lark/dist/uni.mp.esm.js b/packages/uni-mp-lark/dist/uni.mp.esm.js new file mode 100644 index 0000000000000000000000000000000000000000..c214ee515bb56b6707bd13128d9c0a42b78670f8 --- /dev/null +++ b/packages/uni-mp-lark/dist/uni.mp.esm.js @@ -0,0 +1,963 @@ +import { isPlainObject, isArray, hasOwn, isFunction, extend, camelize, isObject } from '@vue/shared'; +import { injectHook, ref, onBeforeMount } from 'vue'; + +const encode = encodeURIComponent; +function stringifyQuery(obj, encodeStr = encode) { + const res = obj + ? Object.keys(obj) + .map((key) => { + let val = obj[key]; + if (typeof val === undefined || val === null) { + val = ''; + } + else if (isPlainObject(val)) { + val = JSON.stringify(val); + } + return encodeStr(key) + '=' + encodeStr(val); + }) + .filter((x) => x.length > 0) + .join('&') + : null; + return res ? `?${res}` : ''; +} +const invokeArrayFns = (fns, arg) => { + let ret; + for (let i = 0; i < fns.length; i++) { + ret = fns[i](arg); + } + return ret; +}; +// lifecycle +// App and Page +const ON_SHOW = 'onShow'; +const ON_HIDE = 'onHide'; +//App +const ON_LAUNCH = 'onLaunch'; +const ON_ERROR = 'onError'; +const ON_THEME_CHANGE = 'onThemeChange'; +const ON_PAGE_NOT_FOUND = 'onPageNotFound'; +const ON_UNHANDLE_REJECTION = 'onUnhandledRejection'; +//Page +const ON_LOAD = 'onLoad'; +const ON_READY = 'onReady'; +const ON_UNLOAD = 'onUnload'; +const ON_RESIZE = 'onResize'; +const ON_TAB_ITEM_TAP = 'onTabItemTap'; +const ON_REACH_BOTTOM = 'onReachBottom'; +const ON_PULL_DOWN_REFRESH = 'onPullDownRefresh'; +const ON_ADD_TO_FAVORITES = 'onAddToFavorites'; + +class EventChannel { + constructor(id, events) { + this.id = id; + this.listener = {}; + this.emitCache = {}; + if (events) { + Object.keys(events).forEach((name) => { + this.on(name, events[name]); + }); + } + } + emit(eventName, ...args) { + const fns = this.listener[eventName]; + if (!fns) { + return (this.emitCache[eventName] || (this.emitCache[eventName] = [])).push(args); + } + fns.forEach((opt) => { + opt.fn.apply(opt.fn, args); + }); + this.listener[eventName] = fns.filter((opt) => opt.type !== 'once'); + } + on(eventName, fn) { + this._addListener(eventName, 'on', fn); + this._clearCache(eventName); + } + once(eventName, fn) { + this._addListener(eventName, 'once', fn); + this._clearCache(eventName); + } + off(eventName, fn) { + const fns = this.listener[eventName]; + if (!fns) { + return; + } + if (fn) { + for (let i = 0; i < fns.length;) { + if (fns[i].fn === fn) { + fns.splice(i, 1); + i--; + } + i++; + } + } + else { + delete this.listener[eventName]; + } + } + _clearCache(eventName) { + const cacheArgs = this.emitCache[eventName]; + if (cacheArgs) { + for (; cacheArgs.length > 0;) { + this.emit.apply(this, [eventName, ...cacheArgs.shift()]); + } + } + } + _addListener(eventName, type, fn) { + (this.listener[eventName] || (this.listener[eventName] = [])).push({ + fn, + type, + }); + } +} + +const eventChannels = {}; +const eventChannelStack = []; +function getEventChannel(id) { + if (id) { + const eventChannel = eventChannels[id]; + delete eventChannels[id]; + return eventChannel; + } + return eventChannelStack.shift(); +} + +const MP_METHODS = [ + 'createSelectorQuery', + 'createIntersectionObserver', + 'selectAllComponents', + 'selectComponent', +]; +function createEmitFn(oldEmit, ctx) { + return function emit(event, ...args) { + const scope = ctx.$scope; + if (scope && event) { + const detail = { __args__: args }; + scope.triggerEvent(event, detail); + } + return oldEmit.apply(this, [event, ...args]); + }; +} +function initBaseInstance(instance, options) { + const ctx = instance.ctx; + // mp + ctx.mpType = options.mpType; // @deprecated + ctx.$mpType = options.mpType; + ctx.$scope = options.mpInstance; + // TODO @deprecated + ctx.$mp = {}; + if (__VUE_OPTIONS_API__) { + ctx._self = {}; + } + // $vm + ctx.$scope.$vm = instance.proxy; + // slots + { + instance.slots = {}; + if (isArray(options.slots) && options.slots.length) { + options.slots.forEach((name) => { + instance.slots[name] = true; + }); + } + } + ctx.getOpenerEventChannel = function () { + if (!this.__eventChannel__) { + this.__eventChannel__ = new EventChannel(); + } + return this.__eventChannel__; + }; + ctx.$hasHook = hasHook; + ctx.$callHook = callHook; + // $emit + instance.emit = createEmitFn(instance.emit, ctx); +} +function initComponentInstance(instance, options) { + initBaseInstance(instance, options); + const ctx = instance.ctx; + MP_METHODS.forEach((method) => { + ctx[method] = function (...args) { + const mpInstance = ctx.$scope; + if (mpInstance && mpInstance[method]) { + return mpInstance[method].apply(mpInstance, args); + } + }; + }); +} +function initMocks(instance, mpInstance, mocks) { + const ctx = instance.ctx; + mocks.forEach((mock) => { + if (hasOwn(mpInstance, mock)) { + ctx[mock] = mpInstance[mock]; + } + }); +} +function hasHook(name) { + const hooks = this.$[name]; + if (hooks && hooks.length) { + return true; + } + return false; +} +function callHook(name, args) { + if (name === 'mounted') { + callHook.call(this, 'bm'); // beforeMount + this.$.isMounted = true; + name = 'm'; + } + else if (name === 'onLoad' && args && args.__id__) { + this.__eventChannel__ = getEventChannel(args.__id__); + delete args.__id__; + } + const hooks = this.$[name]; + return hooks && invokeArrayFns(hooks, args); +} + +const PAGE_HOOKS = [ + ON_LOAD, + ON_SHOW, + ON_HIDE, + ON_UNLOAD, + ON_RESIZE, + ON_TAB_ITEM_TAP, + ON_REACH_BOTTOM, + ON_PULL_DOWN_REFRESH, + ON_ADD_TO_FAVORITES, + // 'onReady', // lifetimes.ready + // 'onPageScroll', // 影响性能,开发者手动注册 + // 'onShareTimeline', // 右上角菜单,开发者手动注册 + // 'onShareAppMessage' // 右上角菜单,开发者手动注册 +]; +function findHooks(vueOptions, hooks = new Set()) { + if (vueOptions) { + Object.keys(vueOptions).forEach((name) => { + if (name.indexOf('on') === 0 && isFunction(vueOptions[name])) { + hooks.add(name); + } + }); + if (__VUE_OPTIONS_API__) { + const { extends: extendsOptions, mixins } = vueOptions; + if (mixins) { + mixins.forEach((mixin) => findHooks(mixin, hooks)); + } + if (extendsOptions) { + findHooks(extendsOptions, hooks); + } + } + } + return hooks; +} +function initHook$1(mpOptions, hook, excludes) { + if (excludes.indexOf(hook) === -1 && !hasOwn(mpOptions, hook)) { + mpOptions[hook] = function (args) { + if (hook === 'onError') { + return getApp().$vm.$callHook(hook, args); + } + return this.$vm && this.$vm.$callHook(hook, args); + }; + } +} +const EXCLUDE_HOOKS = [ON_READY]; +function initHooks(mpOptions, hooks, excludes = EXCLUDE_HOOKS) { + hooks.forEach((hook) => initHook$1(mpOptions, hook, excludes)); +} +function initUnknownHooks(mpOptions, vueOptions, excludes = EXCLUDE_HOOKS) { + findHooks(vueOptions).forEach((hook) => initHook$1(mpOptions, hook, excludes)); +} + +tt.appLaunchHooks = []; +function injectAppLaunchHooks(appInstance) { + tt.appLaunchHooks.forEach((hook) => { + injectHook(ON_LAUNCH, hook, appInstance); + }); +} + +const HOOKS = [ + ON_SHOW, + ON_HIDE, + ON_ERROR, + ON_THEME_CHANGE, + ON_PAGE_NOT_FOUND, + ON_UNHANDLE_REJECTION, +]; +function parseApp(instance, parseAppOptions) { + const internalInstance = instance.$; + const appOptions = { + globalData: (instance.$options && instance.$options.globalData) || {}, + $vm: instance, + onLaunch(options) { + const ctx = internalInstance.ctx; + if (this.$vm && ctx.$scope) { + // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前 + return; + } + initBaseInstance(internalInstance, { + mpType: 'app', + mpInstance: this, + slots: [], + }); + injectAppLaunchHooks(internalInstance); + ctx.globalData = this.globalData; + instance.$callHook(ON_LAUNCH, extend({ app: this }, options)); + }, + }; + initLocale(instance); + const vueOptions = instance.$.type; + initHooks(appOptions, HOOKS); + initUnknownHooks(appOptions, vueOptions); + if (__VUE_OPTIONS_API__) { + const methods = vueOptions.methods; + methods && extend(appOptions, methods); + } + if (parseAppOptions) { + parseAppOptions.parse(appOptions); + } + return appOptions; +} +function initCreateApp(parseAppOptions) { + return function createApp(vm) { + return App(parseApp(vm, parseAppOptions)); + }; +} +function initLocale(appVm) { + const locale = ref(tt.getSystemInfoSync().language || 'zh-Hans'); + Object.defineProperty(appVm, '$locale', { + get() { + return locale.value; + }, + set(v) { + locale.value = v; + }, + }); +} + +function initBehavior(options) { + return Behavior(options); +} +function initVueIds(vueIds, mpInstance) { + if (!vueIds) { + return; + } + const ids = vueIds.split(','); + const len = ids.length; + if (len === 1) { + mpInstance._$vueId = ids[0]; + } + else if (len === 2) { + mpInstance._$vueId = ids[0]; + mpInstance._$vuePid = ids[1]; + } +} +const EXTRAS = ['externalClasses']; +function initExtraOptions(miniProgramComponentOptions, vueOptions) { + EXTRAS.forEach((name) => { + if (hasOwn(vueOptions, name)) { + miniProgramComponentOptions[name] = vueOptions[name]; + } + }); +} +function initWxsCallMethods(methods, wxsCallMethods) { + if (!isArray(wxsCallMethods)) { + return; + } + wxsCallMethods.forEach((callMethod) => { + methods[callMethod] = function (args) { + return this.$vm[callMethod](args); + }; + }); +} +function selectAllComponents(mpInstance, selector, $refs) { + const components = mpInstance.selectAllComponents(selector); + components.forEach((component) => { + const ref = component.dataset.r; + $refs[ref] = component.$vm || component; + }); +} +function initRefs(instance, mpInstance) { + Object.defineProperty(instance, 'refs', { + get() { + const $refs = {}; + selectAllComponents(mpInstance, '.r', $refs); + const forComponents = mpInstance.selectAllComponents('.r-i-f'); + forComponents.forEach((component) => { + const ref = component.dataset.r; + if (!$refs[ref]) { + $refs[ref] = []; + } + $refs[ref].push(component.$vm || component); + }); + return $refs; + }, + }); +} +function findVmByVueId(instance, vuePid) { + // 标准 vue3 中 没有 $children,定制了内核 + const $children = instance.$children; + // 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200) + for (let i = $children.length - 1; i >= 0; i--) { + const childVm = $children[i]; + if (childVm.$scope._$vueId === vuePid) { + return childVm; + } + } + // 反向递归查找 + let parentVm; + for (let i = $children.length - 1; i >= 0; i--) { + parentVm = findVmByVueId($children[i], vuePid); + if (parentVm) { + return parentVm; + } + } +} + +const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; +function createObserver(name) { + return function observer(newVal) { + const { $vm } = this; + if ($vm) { + // 为了触发其他非 render watcher + const instance = $vm.$; + // 飞书小程序初始化太慢,导致 observer 触发时,vue 组件的 created 可能还没触发,此时开发者可能已经定义了 watch + // 但因为 created 还没触发,导致部分组件出错,如 uni-collapse,在 created 中初始化了 this.children + // 自定义 watch 中使用了 this.children + { + if (instance.isMounted) { + instance.props[name] = newVal; + } + else { + onBeforeMount(() => (instance.props[name] = newVal), instance); + } + } + } + }; +} +function parsePropType(type, defaultValue) { + // [String]=>String + if (isArray(type) && type.length === 1) { + return type[0]; + } + return type; +} +function normalizePropType(type, defaultValue) { + const res = parsePropType(type); + return PROP_TYPES.indexOf(res) !== -1 ? res : null; +} +function initDefaultProps(isBehavior = false) { + const properties = {}; + if (!isBehavior) { + properties.vI = { + type: null, + value: '', + }; + // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots + properties.vS = { + type: null, + value: [], + observer: function (newVal) { + const $slots = Object.create(null); + newVal.forEach((slotName) => { + $slots[slotName] = true; + }); + this.setData({ + $slots, + }); + }, + }; + } + return properties; +} +function createProperty(key, prop) { + prop.observer = createObserver(key); + return prop; +} +/** + * + * @param mpComponentOptions + * @param rawProps + * @param isBehavior + */ +function initProps(mpComponentOptions, rawProps, isBehavior = false) { + const properties = initDefaultProps(isBehavior); + if (isArray(rawProps)) { + rawProps.forEach((key) => { + properties[key] = createProperty(key, { + type: null, + }); + }); + } + else if (isPlainObject(rawProps)) { + Object.keys(rawProps).forEach((key) => { + const opts = rawProps[key]; + if (isPlainObject(opts)) { + // title:{type:String,default:''} + let value = opts.default; + if (isFunction(value)) { + value = value(); + } + const type = opts.type; + opts.type = normalizePropType(type); + properties[key] = createProperty(key, { + type: opts.type, + value, + }); + } + else { + // content:String + properties[key] = createProperty(key, { + type: normalizePropType(opts), + }); + } + }); + } + mpComponentOptions.properties = properties; +} + +function initData(vueOptions) { + let data = vueOptions.data || {}; + if (typeof data === 'function') { + try { + const appConfig = getApp().$vm.$.appContext.config; + data = data.call(appConfig.globalProperties); + } + catch (e) { + if (process.env.VUE_APP_DEBUG) { + console.warn('根据 Vue 的 data 函数初始化小程序 data 失败,请尽量确保 data 函数中不访问 vm 对象,否则可能影响首次数据渲染速度。', data, e); + } + } + } + else { + try { + // 对 data 格式化 + data = JSON.parse(JSON.stringify(data)); + } + catch (e) { } + } + if (!isPlainObject(data)) { + data = {}; + } + return data; +} +function initBehaviors(vueOptions, initBehavior) { + const vueBehaviors = vueOptions.behaviors; + const vueExtends = vueOptions.extends; + const vueMixins = vueOptions.mixins; + let vueProps = vueOptions.props; + if (!vueProps) { + vueOptions.props = vueProps = []; + } + const behaviors = []; + if (isArray(vueBehaviors)) { + vueBehaviors.forEach((behavior) => { + behaviors.push(behavior.replace('uni://', `${__PLATFORM_PREFIX__}://`)); + if (behavior === 'uni://form-field') { + if (isArray(vueProps)) { + vueProps.push('name'); + vueProps.push('value'); + } + else { + vueProps.name = { + type: String, + default: '', + }; + vueProps.value = { + type: [String, Number, Boolean, Array, Object, Date], + default: '', + }; + } + } + }); + } + if (vueExtends && vueExtends.props) { + const behavior = {}; + initProps(behavior, vueExtends.props, true); + behaviors.push(initBehavior(behavior)); + } + if (isArray(vueMixins)) { + vueMixins.forEach((vueMixin) => { + if (vueMixin.props) { + const behavior = {}; + initProps(behavior, vueMixin.props, true); + behaviors.push(initBehavior(behavior)); + } + }); + } + return behaviors; +} +function applyOptions(componentOptions, vueOptions, initBehavior) { + componentOptions.data = initData(vueOptions); + componentOptions.behaviors = initBehaviors(vueOptions, initBehavior); +} + +function parseComponent(vueOptions, { parse, mocks, isPage, initRelation, handleLink, initLifetimes, }) { + vueOptions = vueOptions.default || vueOptions; + const options = { + multipleSlots: true, + addGlobalClass: true, + }; + if (vueOptions.options) { + extend(options, vueOptions.options); + } + const mpComponentOptions = { + options, + lifetimes: initLifetimes({ mocks, isPage, initRelation, vueOptions }), + pageLifetimes: { + show() { + this.$vm && this.$vm.$callHook('onPageShow'); + }, + hide() { + this.$vm && this.$vm.$callHook('onPageHide'); + }, + resize(size) { + this.$vm && this.$vm.$callHook('onPageResize', size); + }, + }, + methods: { + __l: handleLink, + }, + }; + if (__VUE_OPTIONS_API__) { + applyOptions(mpComponentOptions, vueOptions, initBehavior); + } + initProps(mpComponentOptions, vueOptions.props, false); + initExtraOptions(mpComponentOptions, vueOptions); + initWxsCallMethods(mpComponentOptions.methods, vueOptions.wxsCallMethods); + if (parse) { + parse(mpComponentOptions, { handleLink }); + } + return mpComponentOptions; +} +function initCreateComponent(parseOptions) { + return function createComponent(vueComponentOptions) { + return Component(parseComponent(vueComponentOptions, parseOptions)); + }; +} +let $createComponentFn; +let $destroyComponentFn; +function $createComponent(initialVNode, options) { + if (!$createComponentFn) { + $createComponentFn = getApp().$vm.$createComponent; + } + return $createComponentFn(initialVNode, options); +} +function $destroyComponent(instance) { + if (!$destroyComponentFn) { + $destroyComponentFn = getApp().$vm.$destroyComponent; + } + return $destroyComponentFn(instance); +} + +function parsePage(vueOptions, parseOptions) { + const { parse, mocks, isPage, initRelation, handleLink, initLifetimes } = parseOptions; + const miniProgramPageOptions = parseComponent(vueOptions, { + mocks, + isPage, + initRelation, + handleLink, + initLifetimes, + }); + const methods = miniProgramPageOptions.methods; + methods.onLoad = function (query) { + this.options = query; + this.$page = { + fullPath: '/' + this.route + stringifyQuery(query), + }; + return this.$vm && this.$vm.$callHook(ON_LOAD, query); + }; + initHooks(methods, PAGE_HOOKS); + initUnknownHooks(methods, vueOptions); + parse && parse(miniProgramPageOptions, { handleLink }); + return miniProgramPageOptions; +} +function initCreatePage(parseOptions) { + return function createPage(vuePageOptions) { + return Component(parsePage(vuePageOptions, parseOptions)); + }; +} + +const MPPage = Page; +const MPComponent = Component; +const customizeRE = /:/g; +function customize(str) { + return camelize(str.replace(customizeRE, '-')); +} +function initTriggerEvent(mpInstance) { + const oldTriggerEvent = mpInstance.triggerEvent; + mpInstance.triggerEvent = function (event, ...args) { + return oldTriggerEvent.apply(mpInstance, [customize(event), ...args]); + }; +} +function initHook(name, options, isComponent) { + if (isComponent) { + // fix by Lxh 字节自定义组件Component构造器文档上写有created,但是实测只触发了lifetimes上的created + options = options.lifetimes; + } + const oldHook = options[name]; + if (!oldHook) { + options[name] = function () { + initTriggerEvent(this); + }; + } + else { + options[name] = function (...args) { + initTriggerEvent(this); + return oldHook.apply(this, args); + }; + } +} +Page = function (options) { + initHook(ON_LOAD, options); + return MPPage(options); +}; +Component = function (options) { + initHook('created', options, true); + return MPComponent(options); +}; + +function provide(instance, key, value) { + if (!instance) { + if ((process.env.NODE_ENV !== 'production')) { + console.warn(`provide() can only be used inside setup().`); + } + } + else { + let provides = instance.provides; + // by default an instance inherits its parent's provides object + // but when it needs to provide values of its own, it creates its + // own provides object using parent provides object as prototype. + // this way in `inject` we can simply look up injections from direct + // parent and let the prototype chain do the work. + const parentProvides = instance.parent && instance.parent.provides; + if (parentProvides === provides) { + provides = instance.provides = Object.create(parentProvides); + } + // TS doesn't allow symbol as index type + provides[key] = value; + } +} +function initProvide(instance) { + const provideOptions = instance.$options.provide; + if (!provideOptions) { + return; + } + const provides = isFunction(provideOptions) + ? provideOptions.call(instance) + : provideOptions; + const internalInstance = instance.$; + for (const key in provides) { + provide(internalInstance, key, provides[key]); + } +} +function inject(instance, key, defaultValue, treatDefaultAsFactory = false) { + if (instance) { + // #2400 + // to support `app.use` plugins, + // fallback to appContext's `provides` if the intance is at root + const provides = instance.parent == null + ? instance.vnode.appContext && instance.vnode.appContext.provides + : instance.parent.provides; + if (provides && key in provides) { + // TS doesn't allow symbol as index type + return provides[key]; + } + else if (arguments.length > 1) { + return treatDefaultAsFactory && isFunction(defaultValue) + ? defaultValue() + : defaultValue; + } + else if ((process.env.NODE_ENV !== 'production')) { + console.warn(`injection "${String(key)}" not found.`); + } + } + else if ((process.env.NODE_ENV !== 'production')) { + console.warn(`inject() can only be used inside setup() or functional components.`); + } +} +function initInjections(instance) { + const injectOptions = instance.$options.inject; + if (!injectOptions) { + return; + } + const internalInstance = instance.$; + const ctx = internalInstance.ctx; + if (isArray(injectOptions)) { + for (let i = 0; i < injectOptions.length; i++) { + const key = injectOptions[i]; + ctx[key] = inject(internalInstance, key); + } + } + else { + for (const key in injectOptions) { + const opt = injectOptions[key]; + if (isObject(opt)) { + ctx[key] = inject(internalInstance, opt.from || key, opt.default, true /* treat default function as factory */); + } + else { + ctx[key] = inject(internalInstance, opt); + } + } + } +} + +function initLifetimes$1({ mocks, isPage, initRelation, vueOptions, }) { + function attached() { + const properties = this.properties; + initVueIds(properties.vI, this); + const relationOptions = { + vuePid: this._$vuePid, + }; + // 初始化 vue 实例 + const mpInstance = this; + const mpType = isPage(mpInstance) ? 'page' : 'component'; + if (mpType === 'page' && !mpInstance.route && mpInstance.__route__) { + mpInstance.route = mpInstance.__route__; + } + fixProperties(properties); + this.$vm = $createComponent({ + type: vueOptions, + props: properties, + }, { + mpType, + mpInstance, + slots: properties.vS, + parentComponent: relationOptions.parent && relationOptions.parent.$, + onBeforeSetup(instance, options) { + initRefs(instance, mpInstance); + initMocks(instance, mpInstance, mocks); + initComponentInstance(instance, options); + }, + }); + // 处理父子关系 + initRelation(this, relationOptions); + } + function detached() { + this.$vm && $destroyComponent(this.$vm); + } + { + return { attached, detached }; + } +} +function fixProperties(properties) { + // 字节跳动小程序 properties + // 父组件在 attached 中 setData 设置了子组件的 props,在子组件的 attached 中,并不能立刻拿到 + // 此时子组件的 properties 中获取到的值,除了一部分初始化就有的值,只要在模板上绑定了,动态设置的 prop 的值均会根据类型返回,不会应用 prop 自己的默认值 + // 举例: easyinput 的 styles 属性,类型为 Object,`` 在 attached 中 styles 的值为 null + // 目前 null 值会影响 render 函数执行,临时解决方案,调整 properties 中的 null 值为 undefined,让 Vue 来补充为默认值 + // 已知的其他隐患,当使用默认值时,可能组件行为不正确,比如 countdown 组件,默认值是0,导致直接就触发了 timeup 事件,这个应该是组件自身做处理? + // 难道要等父组件首次 setData 完成后,再去执行子组件的初始化? + Object.keys(properties).forEach((name) => { + if (properties[name] === null) { + properties[name] = undefined; + } + }); +} + +const mocks = [ + '__route__', + '__webviewId__', + '__nodeId__', + '__nodeid__' /* @Deprecated */, +]; +function isPage(mpInstance) { + return (mpInstance.__nodeId__ === 0 || mpInstance.__nodeid__ === 0); +} +const instances = Object.create(null); +function initRelation(mpInstance, detail) { + // 头条 triggerEvent 后,接收事件时机特别晚,已经到了 ready 之后 + const nodeId = hasOwn(mpInstance, '__nodeId__') + ? mpInstance.__nodeId__ + : mpInstance.__nodeid__; + const webviewId = mpInstance.__webviewId__ + ''; + instances[webviewId + '_' + nodeId] = mpInstance.$vm; + mpInstance.triggerEvent('__l', { + vuePid: detail.vuePid, + nodeId, + webviewId, + }); +} +function handleLink({ detail: { vuePid, nodeId, webviewId }, }) { + const vm = instances[webviewId + '_' + nodeId]; + if (!vm) { + return; + } + let parentVm; + if (vuePid) { + parentVm = findVmByVueId(this.$vm, vuePid); + } + if (!parentVm) { + parentVm = this.$vm; + } + vm.$.parent = parentVm.$; + if (__VUE_OPTIONS_API__) { + parentVm.$children.push(vm); + const parent = parentVm.$; + vm.$.provides = parent + ? parent.provides + : Object.create(parent.appContext.provides); + initInjections(vm); + initProvide(vm); + } + vm.$callCreatedHook(); + vm.$callHook('mounted'); + vm.$callHook(ON_READY); +} +function parse(componentOptions, { handleLink }) { + componentOptions.methods.__l = handleLink; +} + +var parseComponentOptions = /*#__PURE__*/Object.freeze({ + __proto__: null, + mocks: mocks, + isPage: isPage, + instances: instances, + initRelation: initRelation, + handleLink: handleLink, + parse: parse, + initLifetimes: initLifetimes$1 +}); + +function initLifetimes(lifetimesOptions) { + return extend(initLifetimes$1(lifetimesOptions), { + ready() { + if (this.$vm && lifetimesOptions.isPage(this)) { + if (this.pageinstance) { + this.__webviewId__ = this.pageinstance.__pageId__; + } + this.$vm.$callCreatedHook(); + this.$vm.$callHook('mounted'); + this.$vm.$callHook(ON_READY); + } + else { + this.is && console.warn(this.is + ' is not ready'); + } + }, + detached() { + this.$vm && $destroyComponent(this.$vm); + // 清理 + const webviewId = this.__webviewId__; + webviewId && + Object.keys(instances).forEach((key) => { + if (key.indexOf(webviewId + '_') === 0) { + delete instances[key]; + } + }); + }, + }); +} + +var parsePageOptions = /*#__PURE__*/Object.freeze({ + __proto__: null, + mocks: mocks, + isPage: isPage, + initRelation: initRelation, + handleLink: handleLink, + parse: parse, + initLifetimes: initLifetimes +}); + +const createApp = initCreateApp(); +const createPage = initCreatePage(parsePageOptions); +const createComponent = initCreateComponent(parseComponentOptions); +tt.EventChannel = EventChannel; +tt.createApp = global.createApp = createApp; +tt.createPage = createPage; +tt.createComponent = createComponent; + +export { createApp, createComponent, createPage }; diff --git a/packages/uni-mp-lark/package.json b/packages/uni-mp-lark/package.json new file mode 100644 index 0000000000000000000000000000000000000000..cf42c3c1c6fd174c96f8e820b4a513462e6420af --- /dev/null +++ b/packages/uni-mp-lark/package.json @@ -0,0 +1,22 @@ +{ + "name": "@dcloudio/uni-mp-lark", + "version": "3.0.0-alpha-3021220211102002", + "description": "uni-app mp-lark", + "main": "dist/index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/dcloudio/uni-app.git", + "directory": "packages/uni-mp-lark" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "license": "Apache-2.0", + "uni-app": { + "name": "mp-lark", + "title": "飞书小程序", + "apply": "mp-lark", + "main": "dist/uni.compiler.js" + }, + "gitHead": "7bcc3303c15141d377645a4995ce186f10ed6b78" +} diff --git a/packages/uni-mp-lark/src/api/index.ts b/packages/uni-mp-lark/src/api/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0c860903822558b06a735ced88a767d95f40899b --- /dev/null +++ b/packages/uni-mp-lark/src/api/index.ts @@ -0,0 +1,2 @@ +import uni from '@dcloudio/uni-mp-toutiao/src/api' +export default uni diff --git a/packages/uni-mp-lark/src/compiler/index.ts b/packages/uni-mp-lark/src/compiler/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..083e8e96d077486b82a6fbf02514c418f937f3b2 --- /dev/null +++ b/packages/uni-mp-lark/src/compiler/index.ts @@ -0,0 +1,24 @@ +import { Plugin } from 'vite' +import initMiniProgramPlugin from '@dcloudio/uni-mp-vite' + +import { ASSETS_INLINE_LIMIT } from '@dcloudio/uni-cli-shared' +import { options } from '@dcloudio/uni-mp-toutiao/src/compiler/options' + +const uniMiniProgramToutiaoPlugin: Plugin = { + name: 'vite:uni-mp-lark', + config() { + return { + define: { + __VUE_CREATED_DEFERRED__: true, + }, + build: { + // css 中不支持引用本地资源 + assetsInlineLimit: ASSETS_INLINE_LIMIT, + }, + } + }, +} + +options.template.slot.fallbackContent = false + +export default [uniMiniProgramToutiaoPlugin, ...initMiniProgramPlugin(options)] diff --git a/packages/uni-mp-lark/src/compiler/project.config.json b/packages/uni-mp-lark/src/compiler/project.config.json new file mode 100644 index 0000000000000000000000000000000000000000..9de113e11acae2715791da8b8776f38a1ea984ea --- /dev/null +++ b/packages/uni-mp-lark/src/compiler/project.config.json @@ -0,0 +1,16 @@ +{ + "setting": { + "urlCheck": false, + "es6": true, + "postcss": false, + "minified": false, + "newFeature": true + }, + "appid": "testAppId", + "projectname": "", + "condition": { + "miniprogram": { + "current": -1 + } + } +} diff --git a/packages/uni-mp-lark/src/platform/index.ts b/packages/uni-mp-lark/src/platform/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..53a55c0accaa45f90ca55dfc7e0857f155665228 --- /dev/null +++ b/packages/uni-mp-lark/src/platform/index.ts @@ -0,0 +1,3 @@ +export function getBaseSystemInfo() { + return tt.getSystemInfoSync() +} diff --git a/packages/uni-mp-lark/src/runtime/index.ts b/packages/uni-mp-lark/src/runtime/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..7669a5f48913e1a643b3c8cbe480b1b339ad44e1 --- /dev/null +++ b/packages/uni-mp-lark/src/runtime/index.ts @@ -0,0 +1,19 @@ +import { EventChannel } from '@dcloudio/uni-shared' +import { + initCreateApp, + initCreatePage, + initCreateComponent, +} from '@dcloudio/uni-mp-core' + +import '@dcloudio/uni-mp-polyfill' + +import * as parsePageOptions from '@dcloudio/uni-mp-toutiao/src/runtime/parsePageOptions' +import * as parseComponentOptions from '@dcloudio/uni-mp-toutiao/src/runtime/parseComponentOptions' + +export const createApp = initCreateApp() +export const createPage = initCreatePage(parsePageOptions) +export const createComponent = initCreateComponent(parseComponentOptions) +;(tt as any).EventChannel = EventChannel +;(tt as any).createApp = (global as any).createApp = createApp +;(tt as any).createPage = createPage +;(tt as any).createComponent = createComponent diff --git a/packages/uni-mp-lark/tsconfig.json b/packages/uni-mp-lark/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..54f50ffda5cc115ded524bddaa70cd4265c7ff6d --- /dev/null +++ b/packages/uni-mp-lark/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "paths": { + "@dcloudio/*": ["packages/*/src"], + "@dcloudio/uni-platform": ["packages/uni-mp-lark/src/platform/index.ts"], + "@dcloudio/uni-mp-polyfill": ["packages/uni-mp-core/src/runtime/polyfill"] + } + } +} diff --git a/packages/uni-mp-qq/dist/uni.compiler.js b/packages/uni-mp-qq/dist/uni.compiler.js index a186661bdcd6a1e4b1833d9a7034ecec4e41fb8d..4c4c5d6d4b527e753d69852577025053f79c3f64 100644 --- a/packages/uni-mp-qq/dist/uni.compiler.js +++ b/packages/uni-mp-qq/dist/uni.compiler.js @@ -1,10 +1,10 @@ 'use strict'; +var uniCliShared = require('@dcloudio/uni-cli-shared'); var initMiniProgramPlugin = require('@dcloudio/uni-mp-vite'); var path = require('path'); var fs = require('fs-extra'); var uniShared = require('@dcloudio/uni-shared'); -var uniCliShared = require('@dcloudio/uni-cli-shared'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } @@ -158,7 +158,7 @@ const uniMiniProgramQQPlugin = { }, build: { // css 中不支持引用本地资源 - assetsInlineLimit: 40 * 1024, // 40kb + assetsInlineLimit: uniCliShared.ASSETS_INLINE_LIMIT, }, }; }, diff --git a/packages/uni-mp-qq/dist/uni.mp.esm.js b/packages/uni-mp-qq/dist/uni.mp.esm.js index 866cda7b0e151416ca1b12193d13e27913978b16..1ca7b2f581f02b8b5ddb93db0ab2cc5d8ad5a69c 100644 --- a/packages/uni-mp-qq/dist/uni.mp.esm.js +++ b/packages/uni-mp-qq/dist/uni.mp.esm.js @@ -408,8 +408,16 @@ function findVmByVueId(instance, vuePid) { const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; function createObserver(name) { return function observer(newVal) { - if (this.$vm) { - this.$vm.$.props[name] = newVal; // 为了触发其他非 render watcher + const { $vm } = this; + if ($vm) { + // 为了触发其他非 render watcher + const instance = $vm.$; + // 飞书小程序初始化太慢,导致 observer 触发时,vue 组件的 created 可能还没触发,此时开发者可能已经定义了 watch + // 但因为 created 还没触发,导致部分组件出错,如 uni-collapse,在 created 中初始化了 this.children + // 自定义 watch 中使用了 this.children + { + instance.props[name] = newVal; + } } }; } diff --git a/packages/uni-mp-qq/src/compiler/index.ts b/packages/uni-mp-qq/src/compiler/index.ts index f4bbd478904ca5fb1884338d189231151ce1f707..ef1b7f32672092676618c6fae2d328986535f34d 100644 --- a/packages/uni-mp-qq/src/compiler/index.ts +++ b/packages/uni-mp-qq/src/compiler/index.ts @@ -1,5 +1,5 @@ import { Plugin } from 'vite' - +import { ASSETS_INLINE_LIMIT } from '@dcloudio/uni-cli-shared' import initMiniProgramPlugin from '@dcloudio/uni-mp-vite' import { fix2648 } from './fix2648' @@ -14,7 +14,7 @@ const uniMiniProgramQQPlugin: Plugin = { }, build: { // css 中不支持引用本地资源 - assetsInlineLimit: 40 * 1024, // 40kb + assetsInlineLimit: ASSETS_INLINE_LIMIT, }, } }, diff --git a/packages/uni-mp-toutiao/dist/uni.mp.esm.js b/packages/uni-mp-toutiao/dist/uni.mp.esm.js index d6cbce9a92c51ad5ac763efe9893ec984c0f040f..093f06c90b644a8c36d29cf221a4af83bd41f40c 100644 --- a/packages/uni-mp-toutiao/dist/uni.mp.esm.js +++ b/packages/uni-mp-toutiao/dist/uni.mp.esm.js @@ -411,8 +411,16 @@ function findVmByVueId(instance, vuePid) { const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; function createObserver(name) { return function observer(newVal) { - if (this.$vm) { - this.$vm.$.props[name] = newVal; // 为了触发其他非 render watcher + const { $vm } = this; + if ($vm) { + // 为了触发其他非 render watcher + const instance = $vm.$; + // 飞书小程序初始化太慢,导致 observer 触发时,vue 组件的 created 可能还没触发,此时开发者可能已经定义了 watch + // 但因为 created 还没触发,导致部分组件出错,如 uni-collapse,在 created 中初始化了 this.children + // 自定义 watch 中使用了 this.children + { + instance.props[name] = newVal; + } } }; } @@ -786,51 +794,47 @@ function initInjections(instance) { // 基础库 2.0 以上 attached 顺序错乱,按照 created 顺序强制纠正 const components = []; function initLifetimes$1({ mocks, isPage, initRelation, vueOptions, }) { + function created() { + components.push(this); + } + function attached() { + const properties = this.properties; + initVueIds(properties.vI, this); + const relationOptions = { + vuePid: this._$vuePid, + }; + // 初始化 vue 实例 + const mpInstance = this; + const mpType = isPage(mpInstance) ? 'page' : 'component'; + if (mpType === 'page' && !mpInstance.route && mpInstance.__route__) { + mpInstance.route = mpInstance.__route__; + } + fixProperties(properties); + this.$vm = $createComponent({ + type: vueOptions, + props: properties, + }, { + mpType, + mpInstance, + slots: properties.vS, + parentComponent: relationOptions.parent && relationOptions.parent.$, + onBeforeSetup(instance, options) { + initRefs(instance, mpInstance); + initMocks(instance, mpInstance, mocks); + initComponentInstance(instance, options); + }, + }); + // 处理父子关系 + initRelation(this, relationOptions); + } + function detached() { + this.$vm && $destroyComponent(this.$vm); + } return { - created() { - components.push(this); - }, + created, attached() { this.__lifetimes_attached = function () { - const properties = this.properties; - initVueIds(properties.vI, this); - const relationOptions = { - vuePid: this._$vuePid, - }; - // 初始化 vue 实例 - const mpInstance = this; - const mpType = isPage(mpInstance) ? 'page' : 'component'; - if (mpType === 'page' && !mpInstance.route && mpInstance.__route__) { - mpInstance.route = mpInstance.__route__; - } - // 字节跳动小程序 properties - // 父组件在 attached 中 setData 设置了子组件的 props,在子组件的 attached 中,并不能立刻拿到 - // 此时子组件的 properties 中获取到的值,除了一部分初始化就有的值,只要在模板上绑定了,动态设置的 prop 的值均会根据类型返回,不会应用 prop 自己的默认值 - // 举例: easyinput 的 styles 属性,类型为 Object,`` 在 attached 中 styles 的值为 null - // 目前 null 值会影响 render 函数执行,临时解决方案,调整 properties 中的 null 值为 undefined,让 Vue 来补充为默认值 - // 已知的其他隐患,当使用默认值时,可能组件行为不正确,比如 countdown 组件,默认值是0,导致直接就触发了 timeup 事件,这个应该是组件自身做处理? - // 难道要等父组件首次 setData 完成后,再去执行子组件的初始化? - Object.keys(properties).forEach((name) => { - if (properties[name] === null) { - properties[name] = undefined; - } - }); - this.$vm = $createComponent({ - type: vueOptions, - props: properties, - }, { - mpType, - mpInstance, - slots: properties.vS, - parentComponent: relationOptions.parent && relationOptions.parent.$, - onBeforeSetup(instance, options) { - initRefs(instance, mpInstance); - initMocks(instance, mpInstance, mocks); - initComponentInstance(instance, options); - }, - }); - // 处理父子关系 - initRelation(this, relationOptions); + attached.call(this); }; let component = this; while (component && @@ -843,10 +847,22 @@ function initLifetimes$1({ mocks, isPage, initRelation, vueOptions, }) { component = components[0]; } }, - detached() { - this.$vm && $destroyComponent(this.$vm); - }, + detached, }; +} +function fixProperties(properties) { + // 字节跳动小程序 properties + // 父组件在 attached 中 setData 设置了子组件的 props,在子组件的 attached 中,并不能立刻拿到 + // 此时子组件的 properties 中获取到的值,除了一部分初始化就有的值,只要在模板上绑定了,动态设置的 prop 的值均会根据类型返回,不会应用 prop 自己的默认值 + // 举例: easyinput 的 styles 属性,类型为 Object,`` 在 attached 中 styles 的值为 null + // 目前 null 值会影响 render 函数执行,临时解决方案,调整 properties 中的 null 值为 undefined,让 Vue 来补充为默认值 + // 已知的其他隐患,当使用默认值时,可能组件行为不正确,比如 countdown 组件,默认值是0,导致直接就触发了 timeup 事件,这个应该是组件自身做处理? + // 难道要等父组件首次 setData 完成后,再去执行子组件的初始化? + Object.keys(properties).forEach((name) => { + if (properties[name] === null) { + properties[name] = undefined; + } + }); } const mocks = [ diff --git a/packages/uni-mp-toutiao/src/runtime/componentLifetimes.ts b/packages/uni-mp-toutiao/src/runtime/componentLifetimes.ts index 23272b2ee376724a4fbe9b2ecf3f7e7aa8606b6c..0f982c3cbb9c8b8046ab2f6b0f87bacbb282b58b 100644 --- a/packages/uni-mp-toutiao/src/runtime/componentLifetimes.ts +++ b/packages/uni-mp-toutiao/src/runtime/componentLifetimes.ts @@ -16,6 +16,8 @@ import { initComponentInstance, } from '@dcloudio/uni-mp-core' +const fixAttached = __PLATFORM__ === 'mp-toutiao' + // 基础库 2.0 以上 attached 顺序错乱,按照 created 顺序强制纠正 const components: MPComponentInstance[] = [] @@ -25,60 +27,60 @@ export function initLifetimes({ initRelation, vueOptions, }: CreateLifetimesOptions) { - return { - created(this: MPComponentInstance) { - components.push(this) - }, - attached(this: MPComponentInstance) { - this.__lifetimes_attached = function () { - const properties = this.properties - initVueIds(properties.vI, this) - const relationOptions: RelationOptions = { - vuePid: this._$vuePid, - } - // 初始化 vue 实例 - const mpInstance = this - const mpType = isPage(mpInstance) ? 'page' : 'component' - if (mpType === 'page' && !mpInstance.route && mpInstance.__route__) { - mpInstance.route = mpInstance.__route__ - } + function created(this: MPComponentInstance) { + components.push(this) + } + function attached(this: MPComponentInstance) { + const properties = this.properties + initVueIds(properties.vI, this) + const relationOptions: RelationOptions = { + vuePid: this._$vuePid, + } + // 初始化 vue 实例 + const mpInstance = this + const mpType = isPage(mpInstance) ? 'page' : 'component' + if (mpType === 'page' && !mpInstance.route && mpInstance.__route__) { + mpInstance.route = mpInstance.__route__ + } + + fixProperties(properties) - // 字节跳动小程序 properties - // 父组件在 attached 中 setData 设置了子组件的 props,在子组件的 attached 中,并不能立刻拿到 - // 此时子组件的 properties 中获取到的值,除了一部分初始化就有的值,只要在模板上绑定了,动态设置的 prop 的值均会根据类型返回,不会应用 prop 自己的默认值 - // 举例: easyinput 的 styles 属性,类型为 Object,`` 在 attached 中 styles 的值为 null - // 目前 null 值会影响 render 函数执行,临时解决方案,调整 properties 中的 null 值为 undefined,让 Vue 来补充为默认值 - // 已知的其他隐患,当使用默认值时,可能组件行为不正确,比如 countdown 组件,默认值是0,导致直接就触发了 timeup 事件,这个应该是组件自身做处理? - // 难道要等父组件首次 setData 完成后,再去执行子组件的初始化? - Object.keys(properties).forEach((name) => { - if (properties[name] === null) { - properties[name] = undefined - } - }) + this.$vm = $createComponent( + { + type: vueOptions, + props: properties, + }, + { + mpType, + mpInstance, + slots: properties.vS, // vueSlots + parentComponent: relationOptions.parent && relationOptions.parent.$, + onBeforeSetup( + instance: ComponentInternalInstance, + options: CreateComponentOptions + ) { + initRefs(instance, mpInstance) + initMocks(instance, mpInstance, mocks) + initComponentInstance(instance, options) + }, + } + ) as ComponentPublicInstance - this.$vm = $createComponent( - { - type: vueOptions, - props: properties, - }, - { - mpType, - mpInstance, - slots: properties.vS, // vueSlots - parentComponent: relationOptions.parent && relationOptions.parent.$, - onBeforeSetup( - instance: ComponentInternalInstance, - options: CreateComponentOptions - ) { - initRefs(instance, mpInstance) - initMocks(instance, mpInstance, mocks) - initComponentInstance(instance, options) - }, - } - ) as ComponentPublicInstance + // 处理父子关系 + initRelation(this, relationOptions) + } - // 处理父子关系 - initRelation(this, relationOptions) + function detached(this: MPComponentInstance) { + this.$vm && $destroyComponent(this.$vm) + } + if (!fixAttached) { + return { attached, detached } + } + return { + created, + attached(this: MPComponentInstance) { + this.__lifetimes_attached = function () { + attached.call(this) } let component = this while ( @@ -93,8 +95,21 @@ export function initLifetimes({ component = components[0] } }, - detached(this: MPComponentInstance) { - this.$vm && $destroyComponent(this.$vm) - }, + detached, } } + +function fixProperties(properties: Record) { + // 字节跳动小程序 properties + // 父组件在 attached 中 setData 设置了子组件的 props,在子组件的 attached 中,并不能立刻拿到 + // 此时子组件的 properties 中获取到的值,除了一部分初始化就有的值,只要在模板上绑定了,动态设置的 prop 的值均会根据类型返回,不会应用 prop 自己的默认值 + // 举例: easyinput 的 styles 属性,类型为 Object,`` 在 attached 中 styles 的值为 null + // 目前 null 值会影响 render 函数执行,临时解决方案,调整 properties 中的 null 值为 undefined,让 Vue 来补充为默认值 + // 已知的其他隐患,当使用默认值时,可能组件行为不正确,比如 countdown 组件,默认值是0,导致直接就触发了 timeup 事件,这个应该是组件自身做处理? + // 难道要等父组件首次 setData 完成后,再去执行子组件的初始化? + Object.keys(properties).forEach((name) => { + if (properties[name] === null) { + properties[name] = undefined + } + }) +} diff --git a/packages/uni-mp-toutiao/src/runtime/parseComponentOptions.ts b/packages/uni-mp-toutiao/src/runtime/parseComponentOptions.ts index 4763a4c584c65d13cf931ce47a2a64375311e97c..bf080c38cdecee58c27a347e8c6e2aef2e487fa5 100644 --- a/packages/uni-mp-toutiao/src/runtime/parseComponentOptions.ts +++ b/packages/uni-mp-toutiao/src/runtime/parseComponentOptions.ts @@ -1,5 +1,5 @@ import { hasOwn } from '@vue/shared' - +import { ComponentPublicInstance } from 'vue' import { MPComponentInstance, MPComponentOptions } from '@dcloudio/uni-mp-core' import { findVmByVueId } from '@dcloudio/uni-mp-core' @@ -29,7 +29,8 @@ interface RelationOptions { webviewId: string } -export const instances = Object.create(null) +export const instances: Record = + Object.create(null) export function initRelation(mpInstance: MPComponentInstance, detail: Object) { // 头条 triggerEvent 后,接收事件时机特别晚,已经到了 ready 之后 @@ -37,7 +38,7 @@ export function initRelation(mpInstance: MPComponentInstance, detail: Object) { ? mpInstance.__nodeId__ : mpInstance.__nodeid__ const webviewId = mpInstance.__webviewId__ + '' - instances[webviewId + '_' + nodeId] = mpInstance.$vm + instances[webviewId + '_' + nodeId] = mpInstance.$vm! mpInstance.triggerEvent('__l', { vuePid: (detail as any).vuePid, nodeId, @@ -70,7 +71,7 @@ export function handleLink( if (__VUE_OPTIONS_API__) { ;(parentVm as any).$children.push(vm) const parent = parentVm.$ as any - vm.$.provides = parent + ;(vm.$ as any).provides = parent ? parent.provides : Object.create(parent.appContext.provides) initInjections(vm) diff --git a/packages/uni-mp-vite/src/plugin/build.ts b/packages/uni-mp-vite/src/plugin/build.ts index 9ae381e048ba6f23cc68729994f0e88a6a3f9c7c..a4de3e292aa20b6f28bf2c4d65992124d6cf5f48 100644 --- a/packages/uni-mp-vite/src/plugin/build.ts +++ b/packages/uni-mp-vite/src/plugin/build.ts @@ -34,8 +34,6 @@ export function buildOptions(): UserConfig['build'] { // sourcemap: 'inline', // TODO // target: ['chrome53'], // 由小程序自己启用 es6 编译 emptyOutDir: false, // 不清空输出目录,否则会影响自定义的一些文件输出,比如wxml - // 由各个小程序控制,目前已知百度支持本地路径,其他不支持 - // assetsInlineLimit: 0, // 40kb lib: { entry: resolveMainPathOnce(inputDir), formats: ['cjs'], diff --git a/packages/uni-mp-weixin/dist/uni.compiler.js b/packages/uni-mp-weixin/dist/uni.compiler.js index 9dd0055929ebef8e18a7a0b92b8093ab2cede073..3205faecb0f989d88eef64433af5fc8129fba0d5 100644 --- a/packages/uni-mp-weixin/dist/uni.compiler.js +++ b/packages/uni-mp-weixin/dist/uni.compiler.js @@ -1,9 +1,9 @@ 'use strict'; +var uniCliShared = require('@dcloudio/uni-cli-shared'); var initMiniProgramPlugin = require('@dcloudio/uni-mp-vite'); var path = require('path'); var uniShared = require('@dcloudio/uni-shared'); -var uniCliShared = require('@dcloudio/uni-cli-shared'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } @@ -143,7 +143,7 @@ const uniMiniProgramWeixinPlugin = { }, build: { // css 中不支持引用本地资源 - assetsInlineLimit: 40 * 1024, // 40kb + assetsInlineLimit: uniCliShared.ASSETS_INLINE_LIMIT, }, }; }, diff --git a/packages/uni-mp-weixin/dist/uni.mp.esm.js b/packages/uni-mp-weixin/dist/uni.mp.esm.js index 6f29b310ff840f24ecdce94086efaa18f89cf28d..ea2b689165a415cf34593ce4622400d429acf555 100644 --- a/packages/uni-mp-weixin/dist/uni.mp.esm.js +++ b/packages/uni-mp-weixin/dist/uni.mp.esm.js @@ -353,8 +353,16 @@ function findVmByVueId(instance, vuePid) { function createObserver(name) { return function observer(newVal) { - if (this.$vm) { - this.$vm.$.props[name] = newVal; // 为了触发其他非 render watcher + const { $vm } = this; + if ($vm) { + // 为了触发其他非 render watcher + const instance = $vm.$; + // 飞书小程序初始化太慢,导致 observer 触发时,vue 组件的 created 可能还没触发,此时开发者可能已经定义了 watch + // 但因为 created 还没触发,导致部分组件出错,如 uni-collapse,在 created 中初始化了 this.children + // 自定义 watch 中使用了 this.children + { + instance.props[name] = newVal; + } } }; } diff --git a/packages/uni-mp-weixin/src/compiler/index.ts b/packages/uni-mp-weixin/src/compiler/index.ts index e1c33d7c7402ec5c0e232fba69e8ad5d4e74a248..8d62f03f95a31fcf40e62d99f39be043ab2b53e4 100644 --- a/packages/uni-mp-weixin/src/compiler/index.ts +++ b/packages/uni-mp-weixin/src/compiler/index.ts @@ -1,5 +1,5 @@ import { Plugin } from 'vite' - +import { ASSETS_INLINE_LIMIT } from '@dcloudio/uni-cli-shared' import initMiniProgramPlugin from '@dcloudio/uni-mp-vite' import { options } from './options' @@ -12,7 +12,7 @@ const uniMiniProgramWeixinPlugin: Plugin = { }, build: { // css 中不支持引用本地资源 - assetsInlineLimit: 40 * 1024, // 40kb + assetsInlineLimit: ASSETS_INLINE_LIMIT, }, } }, diff --git a/packages/uni-quickapp-webview/dist/uni.mp.esm.js b/packages/uni-quickapp-webview/dist/uni.mp.esm.js index 74ccc4904d789d2c25a8d32ad3eab164004523f0..8b3873724803994a51774eb672e77f55fad29cc0 100644 --- a/packages/uni-quickapp-webview/dist/uni.mp.esm.js +++ b/packages/uni-quickapp-webview/dist/uni.mp.esm.js @@ -389,8 +389,16 @@ function initRefs(instance, mpInstance) { const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; function createObserver(name) { return function observer(newVal) { - if (this.$vm) { - this.$vm.$.props[name] = newVal; // 为了触发其他非 render watcher + const { $vm } = this; + if ($vm) { + // 为了触发其他非 render watcher + const instance = $vm.$; + // 飞书小程序初始化太慢,导致 observer 触发时,vue 组件的 created 可能还没触发,此时开发者可能已经定义了 watch + // 但因为 created 还没触发,导致部分组件出错,如 uni-collapse,在 created 中初始化了 this.children + // 自定义 watch 中使用了 this.children + { + instance.props[name] = newVal; + } } }; } @@ -757,70 +765,57 @@ function initInjections(instance) { } } -// 基础库 2.0 以上 attached 顺序错乱,按照 created 顺序强制纠正 -const components = []; function initLifetimes$1({ mocks, isPage, initRelation, vueOptions, }) { - return { - created() { - components.push(this); - }, - attached() { - this.__lifetimes_attached = function () { - const properties = this.properties; - initVueIds(properties.vI, this); - const relationOptions = { - vuePid: this._$vuePid, - }; - // 初始化 vue 实例 - const mpInstance = this; - const mpType = isPage(mpInstance) ? 'page' : 'component'; - if (mpType === 'page' && !mpInstance.route && mpInstance.__route__) { - mpInstance.route = mpInstance.__route__; - } - // 字节跳动小程序 properties - // 父组件在 attached 中 setData 设置了子组件的 props,在子组件的 attached 中,并不能立刻拿到 - // 此时子组件的 properties 中获取到的值,除了一部分初始化就有的值,只要在模板上绑定了,动态设置的 prop 的值均会根据类型返回,不会应用 prop 自己的默认值 - // 举例: easyinput 的 styles 属性,类型为 Object,`` 在 attached 中 styles 的值为 null - // 目前 null 值会影响 render 函数执行,临时解决方案,调整 properties 中的 null 值为 undefined,让 Vue 来补充为默认值 - // 已知的其他隐患,当使用默认值时,可能组件行为不正确,比如 countdown 组件,默认值是0,导致直接就触发了 timeup 事件,这个应该是组件自身做处理? - // 难道要等父组件首次 setData 完成后,再去执行子组件的初始化? - Object.keys(properties).forEach((name) => { - if (properties[name] === null) { - properties[name] = undefined; - } - }); - this.$vm = $createComponent({ - type: vueOptions, - props: properties, - }, { - mpType, - mpInstance, - slots: properties.vS, - parentComponent: relationOptions.parent && relationOptions.parent.$, - onBeforeSetup(instance, options) { - initRefs(instance, mpInstance); - initMocks(instance, mpInstance, mocks); - initComponentInstance(instance, options); - }, - }); - // 处理父子关系 - initRelation(this, relationOptions); - }; - let component = this; - while (component && - component.__lifetimes_attached && - components[0] && - component === components[0]) { - components.shift(); - component.__lifetimes_attached(); - delete component.__lifetimes_attached; - component = components[0]; - } - }, - detached() { - this.$vm && $destroyComponent(this.$vm); - }, - }; + function attached() { + const properties = this.properties; + initVueIds(properties.vI, this); + const relationOptions = { + vuePid: this._$vuePid, + }; + // 初始化 vue 实例 + const mpInstance = this; + const mpType = isPage(mpInstance) ? 'page' : 'component'; + if (mpType === 'page' && !mpInstance.route && mpInstance.__route__) { + mpInstance.route = mpInstance.__route__; + } + fixProperties(properties); + this.$vm = $createComponent({ + type: vueOptions, + props: properties, + }, { + mpType, + mpInstance, + slots: properties.vS, + parentComponent: relationOptions.parent && relationOptions.parent.$, + onBeforeSetup(instance, options) { + initRefs(instance, mpInstance); + initMocks(instance, mpInstance, mocks); + initComponentInstance(instance, options); + }, + }); + // 处理父子关系 + initRelation(this, relationOptions); + } + function detached() { + this.$vm && $destroyComponent(this.$vm); + } + { + return { attached, detached }; + } +} +function fixProperties(properties) { + // 字节跳动小程序 properties + // 父组件在 attached 中 setData 设置了子组件的 props,在子组件的 attached 中,并不能立刻拿到 + // 此时子组件的 properties 中获取到的值,除了一部分初始化就有的值,只要在模板上绑定了,动态设置的 prop 的值均会根据类型返回,不会应用 prop 自己的默认值 + // 举例: easyinput 的 styles 属性,类型为 Object,`` 在 attached 中 styles 的值为 null + // 目前 null 值会影响 render 函数执行,临时解决方案,调整 properties 中的 null 值为 undefined,让 Vue 来补充为默认值 + // 已知的其他隐患,当使用默认值时,可能组件行为不正确,比如 countdown 组件,默认值是0,导致直接就触发了 timeup 事件,这个应该是组件自身做处理? + // 难道要等父组件首次 setData 完成后,再去执行子组件的初始化? + Object.keys(properties).forEach((name) => { + if (properties[name] === null) { + properties[name] = undefined; + } + }); } const instances = Object.create(null); diff --git a/packages/vite-plugin-uni/src/cli/utils.ts b/packages/vite-plugin-uni/src/cli/utils.ts index bb4bf5362f6fd4863436327315012f8609faf9c5..f4ed83dcd418c901de0a2e4f984268749cc6df00 100644 --- a/packages/vite-plugin-uni/src/cli/utils.ts +++ b/packages/vite-plugin-uni/src/cli/utils.ts @@ -14,6 +14,7 @@ export const PLATFORMS = [ 'mp-alipay', 'mp-baidu', 'mp-qq', + 'mp-lark', 'mp-toutiao', 'mp-weixin', 'quickapp-webview-huawei', diff --git a/packages/vite-plugin-uni/src/config/css.ts b/packages/vite-plugin-uni/src/config/css.ts index 7a2343105177e7ca73fd0382280dade01ea62783..e6ca5eefb16d9235314a01c0aefac779af284076 100644 --- a/packages/vite-plugin-uni/src/config/css.ts +++ b/packages/vite-plugin-uni/src/config/css.ts @@ -25,6 +25,7 @@ export function createCss( postcss: resolvePostcssConfig(options.inputDir), preprocessorOptions: { scss: { + charset: false, additionalData: resolveAdditionalData(options.inputDir), }, }, diff --git a/scripts/utils.js b/scripts/utils.js index c0725c681fe56b71531dd498f02d97228e65bdb9..369e9f7740c64bd3c2f2559b129a7fcf0388f68a 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -12,6 +12,7 @@ const priority = { 'uni-mp-baidu': 70, 'uni-mp-kuaishou': 70, 'uni-mp-qq': 70, + 'uni-mp-lark': 70, 'uni-mp-toutiao': 70, 'uni-mp-weixin': 70, 'uni-quickapp-webview': 70,