提交 1784df6f 编写于 作者: fxy060608's avatar fxy060608

feat: renderjs

上级 c45940ca
......@@ -9,12 +9,13 @@ export function initAppConfig(appConfig: AppConfig) {
const globalProperties = appConfig.globalProperties
extend(globalProperties, instance)
if (__UNI_FEATURE_WXS__) {
globalProperties.getComponentDescriptor = getComponentDescriptor
Object.defineProperty(globalProperties, '$ownerInstance', {
get() {
return this.$getComponentDescriptor(this)
},
})
//$getComponentDescriptor
globalProperties.$gcd = getComponentDescriptor
// Object.defineProperty(globalProperties, '$ownerInstance', {
// get() {
// return getComponentDescriptor(this)
// },
// })
// globalProperties.$handleWxsEvent = handleWxsEvent
}
}
import { ComponentPublicInstance } from 'vue'
import { isFunction, isPlainObject } from '@vue/shared'
import { hyphenate, isFunction, isPlainObject } from '@vue/shared'
import { isBuiltInComponent } from '@dcloudio/uni-shared'
// import { normalizeEvent, findUniTarget } from './componentEvents'
interface WxsElement extends HTMLElement {
......@@ -192,7 +193,7 @@ function createComponentDescriptor(
isOwnerInstance &&
vm &&
vm.$options.name &&
vm.$options.name.indexOf('VUni') === 0
isBuiltInComponent(hyphenate(vm.$options.name))
) {
// ownerInstance 内置组件需要使用父 vm
vm = vm.$parent!
......@@ -206,11 +207,10 @@ function createComponentDescriptor(
}
export function getComponentDescriptor(
this: ComponentPublicInstance,
instance: ComponentPublicInstance,
isOwnerInstance: boolean
) {
return createComponentDescriptor(instance || this, isOwnerInstance)
return createComponentDescriptor(instance, isOwnerInstance)
}
// export function handleWxsEvent(this: ComponentPublicInstance, $event: Event) {
......
......@@ -8424,9 +8424,32 @@ function patchStopImmediatePropagation(e, value) {
}
}
function patchWxs(el, rawName, nextValue, instance = null) {
if (!el.__wxsWatches) {
el.__wxsWatches = {};
}
if (!nextValue) {
return el.__wxsWatches[rawName] && el.__wxsWatches[rawName]();
}
if (!el.__wxsWatches[rawName] && instance && instance.proxy) {
const proxy = instance.proxy;
const name = rawName.split(':')[1];
el.__wxsWatches[rawName] = proxy.$watch(() => instance.attrs[name], (value, oldValue) => {
// TODO ownerInstance,instance
nextValue(value, oldValue, proxy.$gcd(proxy, true), proxy.$gcd(proxy, true));
}, {
deep: true
});
}
}
const nativeOnRE = /^on[a-z]/;
const forcePatchProp = (_, key) => key === 'value';
const patchProp = (el, key, prevValue, nextValue, isSVG = false, prevChildren, parentComponent, parentSuspense, unmountChildren) => {
// @ts-expect-error fixed by xxxxxx
if (__UNI_FEATURE_WXS__ && key.indexOf('change:') === 0) {
patchWxs(el, key, nextValue, parentComponent);
}
switch (key) {
// special
case 'class':
......
......@@ -8424,9 +8424,32 @@ function patchStopImmediatePropagation(e, value) {
}
}
function patchWxs(el, rawName, nextValue, instance = null) {
if (!el.__wxsWatches) {
el.__wxsWatches = {};
}
if (!nextValue) {
return el.__wxsWatches[rawName] && el.__wxsWatches[rawName]();
}
if (!el.__wxsWatches[rawName] && instance && instance.proxy) {
const proxy = instance.proxy;
const name = rawName.split(':')[1];
el.__wxsWatches[rawName] = proxy.$watch(() => instance.attrs[name], (value, oldValue) => {
// TODO ownerInstance,instance
nextValue(value, oldValue, proxy.$gcd(proxy, true), proxy.$gcd(proxy, true));
}, {
deep: true
});
}
}
const nativeOnRE = /^on[a-z]/;
const forcePatchProp = (_, key) => key === 'value';
const patchProp = (el, key, prevValue, nextValue, isSVG = false, prevChildren, parentComponent, parentSuspense, unmountChildren) => {
// @ts-expect-error fixed by xxxxxx
if (__UNI_FEATURE_WXS__ && key.indexOf('change:') === 0) {
patchWxs(el, key, nextValue, parentComponent);
}
switch (key) {
// special
case 'class':
......
import {isFunction, extend, isPlainObject, isString, isArray, hasOwn as hasOwn$1, isObject as isObject$1, capitalize, toRawType, makeMap as makeMap$1, isPromise, invokeArrayFns as invokeArrayFns$1, hyphenate} from "@vue/shared";
import {isFunction, extend, hyphenate, isPlainObject, isString, isArray, hasOwn as hasOwn$1, isObject as isObject$1, capitalize, toRawType, makeMap as makeMap$1, isPromise, invokeArrayFns as invokeArrayFns$1} from "@vue/shared";
import {injectHook, withModifiers, createVNode, inject, provide, reactive, computed, nextTick, getCurrentInstance, onBeforeMount, onMounted, onBeforeActivate, onBeforeDeactivate, openBlock, createBlock, mergeProps, toDisplayString, ref, defineComponent, resolveComponent, toHandlers, renderSlot, watch, onUnmounted, onBeforeUnmount, onActivated, withDirectives, vShow, createTextVNode, createCommentVNode, renderList, onDeactivated, createApp, watchEffect, Transition, withCtx, KeepAlive, resolveDynamicComponent, Fragment} from "vue";
import {once, passive, normalizeTarget, invokeArrayFns, NAVBAR_HEIGHT, parseQuery, PRIMARY_COLOR, removeLeadingSlash, getLen, ON_REACH_BOTTOM_DISTANCE, decodedQuery, debounce, updateElementStyle, addFont, scrollTo} from "@dcloudio/uni-shared";
import {once, passive, normalizeTarget, isBuiltInComponent, invokeArrayFns, NAVBAR_HEIGHT, parseQuery, PRIMARY_COLOR, removeLeadingSlash, getLen, ON_REACH_BOTTOM_DISTANCE, decodedQuery, debounce, updateElementStyle, addFont, scrollTo} from "@dcloudio/uni-shared";
import {useRoute, createRouter, createWebHistory, createWebHashHistory, useRouter, isNavigationFailure, RouterView} from "vue-router";
function applyOptions(options, instance2, publicThis) {
Object.keys(options).forEach((name) => {
......@@ -1087,7 +1087,7 @@ class ComponentDescriptor {
}
}
function createComponentDescriptor(vm, isOwnerInstance = true) {
if (isOwnerInstance && vm && vm.$options.name && vm.$options.name.indexOf("VUni") === 0) {
if (isOwnerInstance && vm && vm.$options.name && isBuiltInComponent(hyphenate(vm.$options.name))) {
vm = vm.$parent;
}
if (vm && vm.$el) {
......@@ -1098,18 +1098,13 @@ function createComponentDescriptor(vm, isOwnerInstance = true) {
}
}
function getComponentDescriptor(instance2, isOwnerInstance) {
return createComponentDescriptor(instance2 || this, isOwnerInstance);
return createComponentDescriptor(instance2, isOwnerInstance);
}
function initAppConfig$1(appConfig) {
const globalProperties = appConfig.globalProperties;
extend(globalProperties, instance);
if (__UNI_FEATURE_WXS__) {
globalProperties.getComponentDescriptor = getComponentDescriptor;
Object.defineProperty(globalProperties, "$ownerInstance", {
get() {
return this.$getComponentDescriptor(this);
}
});
globalProperties.$gcd = getComponentDescriptor;
}
}
function initView(app) {
......@@ -13144,7 +13139,7 @@ function useToastIcon(props2) {
let showToastState;
let showType = "";
let timeoutId;
const onHidePopupOnce = once(() => {
const onHidePopupOnce = /* @__PURE__ */ once(() => {
UniServiceJSBridge.on("onHidePopup", () => hidePopup("onHidePopup"));
});
function createToast(args) {
......
......@@ -30,7 +30,7 @@ import { once } from '@dcloudio/uni-shared'
let showToastState: ToastProps
let showType: 'onShowToast' | 'onShowLoading' | '' = ''
let timeoutId: number
const onHidePopupOnce = once(() => {
const onHidePopupOnce = /*#__PURE__*/ once(() => {
UniServiceJSBridge.on('onHidePopup', () => hidePopup('onHidePopup'))
})
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`wxs normalizeWxsCode 1`] = `
Array [
Array [],
"<template><view></view><view></view></template>
<script>
export default {}
</script>
<renderjs name=\\"echarts\\">
export default{
mounted(){
console.log('mounted')
}
}
</renderjs>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
",
]
`;
exports[`wxs normalizeWxsCode 2`] = `
Array [
Array [],
"<template><view></view><view></view></template>
<script>
export default {}
</script>
<wxs name=\\"echarts\\">
export default{
mounted(){
console.log('mounted')
}
}
</wxs>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
",
]
`;
import { normalizeWxsCode } from '../src/configResolved/plugins/preVue'
describe('wxs', () => {
test('normalizeWxsCode', () => {
expect(
normalizeWxsCode(`<template><view></view><view></view></template>
<script>
export default {}
</script>
<script lang="renderjs" module="echarts">
export default{
mounted(){
console.log('mounted')
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
`)
).toMatchSnapshot()
expect(
normalizeWxsCode(`<template><view></view><view></view></template>
<script>
export default {}
</script>
<script lang="wxs" module="echarts">
export default{
mounted(){
console.log('mounted')
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
`)
).toMatchSnapshot()
})
})
......@@ -68,7 +68,10 @@ export function uniEasycomPlugin(options: UniPluginFilterOptions): Plugin {
return
}
const { filename, query } = parseVueRequest(id)
if (query.vue || !EXTNAME_VUE.includes(path.extname(filename))) {
if (
query.type !== 'template' &&
(query.vue || !EXTNAME_VUE.includes(path.extname(filename)))
) {
return
}
debugEasycom(id)
......
......@@ -15,6 +15,8 @@ import { uniPageVuePlugin } from './pageVue'
import { uniCopyPlugin } from './copy'
import { uniStaticPlugin } from './static'
import { uniCssScopedPlugin } from './cssScoped'
import { uniRenderjsPlugin } from './renderjs'
import { uniPreVuePlugin } from './preVue'
const debugPlugin = debug('uni:plugin')
......@@ -28,14 +30,13 @@ const UNI_H5_RE = /@dcloudio\/uni-h5/
const COMMON_EXCLUDE = [
/pages\.json\.js$/,
/manifest\.json\.js$/,
/vue&type=/,
/vite\//,
/\/@vue\//,
/\/vue-router\//,
/\/vuex\//,
/@dcloudio\/uni-h5-vue/,
/@dcloudio\/uni-shared/,
/\.html$/,
/@dcloudio\/uni-components\/style/,
]
const APP_VUE_RE = /App.vue$/
......@@ -112,6 +113,9 @@ export function initPlugins(
uniPreCssPlugin(Object.assign(uniPreCssPluginOptions, options)),
'vite:css'
)
addPlugin(plugins, uniPreVuePlugin(), 'vite:vue', 'pre')
addPlugin(plugins, uniRenderjsPlugin(), 'vite:vue')
if (command === 'build') {
addPlugin(
plugins,
......
......@@ -26,11 +26,12 @@ export function uniPrePlugin(options: UniPluginFilterOptions): Plugin {
return code
}
const { filename, query } = parseVueRequest(id)
if (query.vue) {
if (query.vue && query.type !== 'template') {
return code
}
const extname = path.extname(filename)
const isHtml = PRE_HTML_EXTNAME.includes(extname)
const isHtml =
query.type === 'template' || PRE_HTML_EXTNAME.includes(extname)
const isJs = PRE_JS_EXTNAME.includes(extname)
const isPre = isHtml || isJs
if (isPre) {
......@@ -49,8 +50,8 @@ export function uniPrePlugin(options: UniPluginFilterOptions): Plugin {
// 读取sourcemap时,需要移除?mpType=page等参数,否则读取不到提示文件不存在
const map = this.getCombinedSourcemap()
if (map) {
map.sources = map.sources.map((source) =>
source.replace('?mpType=page', '')
map.sources = map.sources.map(
(source) => parseVueRequest(source).filename
)
}
return {
......
import path from 'path'
import debug from 'debug'
import { Plugin } from 'vite'
import {
TextModes,
NodeTypes,
ElementNode,
AttributeNode,
} from '@vue/compiler-core'
import { parse } from '@vue/compiler-dom'
import { MagicString } from '@vue/compiler-sfc'
import { EXTNAME_VUE, parseVueRequest } from '@dcloudio/uni-cli-shared'
const debugPreVue = debug('uni:pre-vue')
const WXS_LANG_RE = /lang=["|'](renderjs|wxs)["|']/
const WXS_ATTRS = ['wxs', 'renderjs']
const sourceToSFC = new Map<string, string>()
export function uniPreVuePlugin(): Plugin {
return {
name: 'vite:uni-pre-vue',
transform(code, id) {
const { filename, query } = parseVueRequest(id)
if (query.vue) {
return
}
if (!EXTNAME_VUE.includes(path.extname(filename))) {
return
}
if (!WXS_LANG_RE.test(code)) {
return
}
const sourceKey = code + filename
const cache = sourceToSFC.get(sourceKey)
if (cache) {
debugPreVue('cache', id)
return cache
}
debugPreVue(id)
const [errors, wxsCode] = normalizeWxsCode(code)
if (errors.length) {
this.error(errors.join('\n'))
}
sourceToSFC.set(sourceKey, wxsCode)
return wxsCode
},
}
}
export function normalizeWxsCode(code: string): [SyntaxError[], string] {
const errors: SyntaxError[] = []
const ast = parse(code, {
isNativeTag: () => true,
isPreTag: () => true,
getTextMode: () => TextModes.DATA,
onError: (e) => {
errors.push(e)
},
})
const wxsNode = ast.children.find(
(node) =>
node.type === NodeTypes.ELEMENT &&
node.tag === 'script' &&
node.props.find(
(prop) =>
prop.name === 'lang' &&
prop.type === NodeTypes.ATTRIBUTE &&
prop.value &&
WXS_ATTRS.includes(prop.value.content)
)
)
if (wxsNode) {
code = normalizeWxsNode(code, wxsNode as ElementNode)
}
return [errors, code]
}
const SCRIPT_END_LEN = '</script>'.length
const SCRIPT_START_LEN = '<script'.length
function normalizeWxsNode(code: string, { loc, props }: ElementNode) {
const magicString = new MagicString(code)
const langAttr = props.find((prop) => prop.name === 'lang') as AttributeNode
const moduleAttr = props.find(
(prop) => prop.name === 'module'
) as AttributeNode
const startOffset = loc.start.offset
const endOffset = loc.end.offset
const lang = langAttr.value!.content
const langStartOffset = langAttr.loc.start.offset
magicString.overwrite(startOffset, startOffset + SCRIPT_START_LEN, '<' + lang) // <renderjs or <wxs
magicString.overwrite(
langStartOffset,
langStartOffset + ('lang="' + lang + '"').length,
''
) // remove lang="renderjs" or lang="wxs"
magicString.overwrite(
endOffset - SCRIPT_END_LEN,
endOffset,
'</' + lang + '>'
) //</renderjs> or </wxs>
if (moduleAttr) {
const moduleStartOffset = moduleAttr.loc.start.offset
magicString.overwrite(
moduleStartOffset,
moduleStartOffset + 'module'.length,
'name'
) // module="echarts" => name="echarts"
}
return magicString.toString()
}
import debug from 'debug'
import { Plugin } from 'vite'
import { rewriteDefault } from '@vue/compiler-sfc'
import { parseVueRequest } from '@dcloudio/uni-cli-shared'
const debugRenderjs = debug('uni:renderjs')
export function uniRenderjsPlugin(): Plugin {
return {
name: 'vite:uni-renderjs',
transform(code, id) {
const isWxs = /vue&type=wxs/.test(id)
const isRenderjs = /vue&type=renderjs/.test(id)
if (!isWxs && !isRenderjs) {
return
}
const type = isWxs ? 'wxs' : 'renderjs'
const { query } = parseVueRequest(id)
debugRenderjs(id)
if (!(query as any).name) {
this.error(
`<script module="missing module name" lang="${type}">
${code}
</script>`
)
}
return `${rewriteDefault(code, '_sfc_' + type)}
export default Comp => {
if(!Comp.mixins){Comp.mixins = []}
Comp.mixins.push({beforeCreate(){ this['${(query as any).name}'] = this }})
Comp.mixins.push(_sfc_${type})
}`
},
}
}
import { ElementNode, NodeTransform } from '@vue/compiler-core'
import { CompilerOptions, SFCTemplateCompileOptions } from '@vue/compiler-sfc'
import { isNativeTag } from '@dcloudio/uni-shared'
const transform: NodeTransform = (node, ctx) => {
if (
process.env.UNI_PLATFORM !== 'mp-weixin' &&
(node as ElementNode).tag === 'match-media'
) {
;(node as ElementNode).tag = 'uni-match-media'
}
}
import { matchMedia } from './transforms/matchMedia'
export const uniVueCompilerOptions: CompilerOptions = {
isNativeTag,
nodeTransforms: [transform],
nodeTransforms: [matchMedia],
}
export const uniVueTransformAssetUrls: SFCTemplateCompileOptions['transformAssetUrls'] = {
......
import { ElementNode, NodeTransform } from '@vue/compiler-core'
export const matchMedia: NodeTransform = (node) => {
if (
process.env.UNI_PLATFORM !== 'mp-weixin' &&
(node as ElementNode).tag === 'match-media'
) {
;(node as ElementNode).tag = 'uni-match-media'
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册