Skip to content

Commit 0e20469

Browse files
authored
Merge pull request #261 from wechat-miniprogram/fix-some-issue
Fix some issue
2 parents eb07793 + e1fe8e2 commit 0e20469

File tree

11 files changed

+335
-37
lines changed

11 files changed

+335
-37
lines changed

glass-easel-miniprogram-adapter/src/space.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ export class CodeSpace {
320320
dataDeepCopy: options?.dataDeepCopy,
321321
propertyPassingDeepCopy: options?.propertyPassingDeepCopy,
322322
propertyEarlyInit: options?.propertyEarlyInit,
323+
propertyComparer: options?.propertyComparer,
323324
}
324325
return [ret, styleIsolation]
325326
}

glass-easel-miniprogram-adapter/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export type ComponentDefinitionOptions = {
3535
dataDeepCopy?: DeepCopyKind
3636
propertyPassingDeepCopy?: DeepCopyKind
3737
propertyEarlyInit?: boolean
38+
propertyComparer?: (a: any, b: any) => boolean
3839
}
3940

4041
type ComponentMethod = utils.ComponentMethod

glass-easel-miniprogram-adapter/tests/space.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,62 @@ describe('define', () => {
662662
expect(callOrder).toStrictEqual([1])
663663
})
664664

665+
test('options propertyComparer', () => {
666+
const env = new MiniProgramEnv()
667+
const codeSpace = env.createCodeSpace('', true)
668+
let execArr: string[] = []
669+
670+
codeSpace.addCompiledTemplate(
671+
'child/comp',
672+
tmpl(`
673+
<div>{{a}}</div>
674+
`),
675+
)
676+
677+
codeSpace.componentEnv('child/comp', ({ Component }) =>
678+
Component()
679+
.property('a', { type: Number, value: 123 })
680+
.observer('a', () => {
681+
execArr.push('a')
682+
})
683+
.register(),
684+
)
685+
686+
codeSpace.addCompiledTemplate(
687+
'path/to/comp',
688+
tmpl(`
689+
<child a="{{a}}" />
690+
`),
691+
)
692+
693+
codeSpace.addComponentStaticConfig('path/to/comp', {
694+
usingComponents: {
695+
child: '/child/comp',
696+
},
697+
})
698+
699+
codeSpace.componentEnv('path/to/comp', ({ Component }) =>
700+
Component()
701+
.options({
702+
propertyComparer: (a: unknown, b: unknown) => a !== b,
703+
})
704+
.property('a', { type: Number, value: 123 })
705+
.register(),
706+
)
707+
708+
const ab = env.associateBackend()
709+
const root = ab.createRoot('body', codeSpace, 'path/to/comp')
710+
const rootComp = root.getComponent()
711+
712+
expect(execArr).toEqual(['a'])
713+
execArr = []
714+
rootComp.setData({ a: 233 })
715+
expect(execArr).toEqual(['a'])
716+
execArr = []
717+
rootComp.setData({ a: 233 })
718+
expect(execArr).toEqual([])
719+
})
720+
665721
test('definition filter', () => {
666722
const env = new MiniProgramEnv()
667723
const codeSpace = env.createCodeSpace('', true)

glass-easel-shadow-sync/src/backend.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -802,14 +802,13 @@ export class ShadowSyncBackendContext implements GlassEaselBackend.Context {
802802
}
803803

804804
export const hookBuilderToSyncData = <TBuilder extends GeneralBehaviorBuilder>(
805-
glassEasel: typeof import('glass-easel'),
806805
builder: TBuilder,
806+
getComponentFromMethodCaller?: (methodCaller: GeneralComponent) => GeneralComponent | undefined
807807
): TBuilder => {
808808
const properties: string[] = []
809-
const methodCallerMap = new WeakMap<any, GeneralComponent>()
810809

811810
const getContextFromMethodCaller = (methodCaller: GeneralComponent) => {
812-
const component: GeneralComponent = methodCallerMap.get(methodCaller) || methodCaller
811+
const component: GeneralComponent = getComponentFromMethodCaller?.(methodCaller) || methodCaller
813812
const context = component.getBackendContext() as ShadowSyncBackendContext
814813
const backendElement = component.getBackendElement() as ShadowSyncElement
815814
if (!(context instanceof ShadowSyncBackendContext)) {
@@ -867,30 +866,16 @@ export const hookBuilderToSyncData = <TBuilder extends GeneralBehaviorBuilder>(
867866
return this
868867
},
869868
},
870-
methodCallerInit: {
871-
value(func: (this: GeneralComponent) => any) {
872-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
873-
builderPrototype.methodCaller.call(this, function (this: GeneralComponent) {
874-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
875-
const methodCaller = func.call(this)
876-
methodCallerMap.set(methodCaller, this)
877-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
878-
return methodCaller
879-
})
880-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
881-
return this
882-
},
883-
},
884869
}),
885870
)
886871

887872
return builder.init(({ self, lifetime }) => {
888873
lifetime('created', () => {
889-
const { context, backendElement } = getContextFromMethodCaller(self)
874+
const { component, context, backendElement } = getContextFromMethodCaller(self)
890875
context.channel.initValues(
891876
backendElement._id,
892877
properties.reduce((initValues, property) => {
893-
initValues[property] = self.data[property]
878+
initValues[property] = component.data[property]
894879
return initValues
895880
}, {} as Record<string, unknown>),
896881
)

glass-easel-shadow-sync/tests/spec/backend.test.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ describe('backend', () => {
108108
expect(ops).toEqual([{ foo: 'foo' }])
109109
})
110110
test('hook to sync behavior builder', async () => {
111-
const beh = hookBuilderToSyncData(glassEasel, componentSpace.define())
111+
const beh = hookBuilderToSyncData(componentSpace.define())
112112
.property('name', String)
113113
.property('value', String)
114114
.registerBehavior()
@@ -135,6 +135,48 @@ describe('backend', () => {
135135
expect(viewRoot.data.name).toEqual('a')
136136
expect(viewRoot.data.value).toEqual('b')
137137
})
138+
test('hook to sync behavior builder with method caller', async () => {
139+
const methodCallerMap = new WeakMap<any, glassEasel.GeneralComponent>()
140+
141+
const beh = hookBuilderToSyncData(componentSpace.define(), (methodCaller) =>
142+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
143+
methodCallerMap.get(methodCaller),
144+
)
145+
.property('name', String)
146+
.property('value', String)
147+
.registerBehavior()
148+
149+
const compDef = componentSpace
150+
.define()
151+
.behavior(beh)
152+
.template(
153+
tmpl(`
154+
<view>{{name}}-{{value}}</view>
155+
`),
156+
)
157+
.methodCallerInit(function () {
158+
const methodCaller = {}
159+
methodCallerMap.set(methodCaller, this)
160+
return methodCaller
161+
})
162+
.registerComponent()
163+
164+
const root = glassEasel.Component.createWithContext('root', compDef, shadowSyncBackend)
165+
166+
root.destroyBackendElementOnDetach()
167+
168+
const viewRoot = getViewNode(root) as glassEasel.GeneralComponent
169+
170+
expect(domHtml(root)).toEqual('<view>-</view>')
171+
expect(viewRoot.data.name).toEqual('')
172+
expect(viewRoot.data.value).toEqual('')
173+
174+
root.setData({ name: 'a', value: 'b' })
175+
await Promise.resolve()
176+
expect(domHtml(root)).toEqual('<view>a-b</view>')
177+
expect(viewRoot.data.name).toEqual('a')
178+
expect(viewRoot.data.value).toEqual('b')
179+
})
138180
test('hook template engine to sync', () => {
139181
viewComponentSpace.setGlobalUsingComponent(
140182
'wx-textarea',

glass-easel/src/component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@ export class Component<
878878
propertyPassingDeepCopy,
879879
options.reflectToAttributes,
880880
comp._$dataGroupObserverTree,
881+
options.propertyComparer,
881882
)
882883
comp._$dataGroup = dataGroup
883884

glass-easel/src/component_space.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ export const normalizeUrl = (
8181
absPath,
8282
}
8383
}
84+
// Hack for invalid relPath like `wx://the-comp`, privide some compatibility
85+
const relProtoSep = relPath.indexOf('://')
86+
if (relProtoSep > 0) {
87+
const domain = relPath.slice(0, relProtoSep + 3)
88+
const absPath = normalizePath(path, relPath.slice(relProtoSep + 3))
89+
return {
90+
domain,
91+
absPath,
92+
}
93+
}
8494
return {
8595
domain: null,
8696
absPath: normalizePath(path, relPath),

glass-easel/src/data_proxy.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,7 @@ export type DataObserver = (...values: unknown[]) => void
305305

306306
export type DataChange = DataReplace | DataSplice
307307
// for replace
308-
export type DataReplace = [DataPath, DataValue, RequireComparer, undefined]
309-
export type RequireComparer = true | undefined
308+
export type DataReplace = [DataPath, DataValue, undefined, undefined]
310309
// for splice, numbers are index, removal count
311310
export type DataSplice = [DataPath, DataValue[], number, number]
312311

@@ -525,6 +524,8 @@ export class DataGroup<
525524
} | null = null
526525
/* @internal */
527526
private _$recUpdateLevel = 0
527+
/* @internal */
528+
private _$propertyComparer: ((a: DataValue, b: DataValue) => boolean) | null
528529

529530
/* @internal */
530531
private _$generateInnerData(data: { [key: string]: DataValue }) {
@@ -558,6 +559,7 @@ export class DataGroup<
558559
propertyPassingDeepCopy: DeepCopyStrategy,
559560
reflectToAttributes: boolean,
560561
observerTree: DataGroupObserverTree,
562+
propertyComparer: ((a: DataValue, b: DataValue) => boolean) | null,
561563
) {
562564
this._$comp = associatedComponent
563565
this.data = data
@@ -568,6 +570,7 @@ export class DataGroup<
568570
this._$propFields = observerTree.propFields
569571
this._$observerTree = observerTree
570572
this._$observerStatus = new Array(observerTree.observers.length) as boolean[]
573+
this._$propertyComparer = propertyComparer
571574
this.innerData = this._$generateInnerData(data)
572575
}
573576

@@ -581,6 +584,7 @@ export class DataGroup<
581584
DeepCopyStrategy.None,
582585
false,
583586
new DataGroupObserverTree({}),
587+
null,
584588
)
585589
}
586590

@@ -637,7 +641,7 @@ export class DataGroup<
637641
data = simpleDeepCopy(newData)
638642
}
639643
}
640-
this._$pendingChanges.push([[propName], data, true, undefined])
644+
this._$pendingChanges.push([[propName], data, undefined, undefined])
641645
return true
642646
}
643647

@@ -794,19 +798,14 @@ export class DataGroup<
794798

795799
// run comparer for properties
796800
let comparerResult: boolean
797-
if (!isSplice && maybeSpliceIndex === true) {
798-
if (prop.comparer) {
799-
change[2] = undefined
800-
comparerResult = !!safeCallback(
801-
'Property Comparer',
802-
prop.comparer,
803-
comp!,
804-
[newData, oldData],
805-
comp?.general(),
806-
)
807-
} else {
808-
comparerResult = oldData !== filteredData
809-
}
801+
if (!isSplice && (prop.comparer || this._$propertyComparer)) {
802+
comparerResult = !!safeCallback(
803+
'Property Comparer',
804+
prop.comparer || this._$propertyComparer!,
805+
comp!,
806+
[newData, oldData],
807+
comp?.general(),
808+
)
810809
changed = comparerResult
811810
} else {
812811
comparerResult = oldData !== filteredData

glass-easel/src/global_options.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ export type ComponentOptions = {
8181
virtualHost?: boolean
8282
/** Init component with property values or not */
8383
propertyEarlyInit?: boolean
84+
/** Property comparer function, return false if properties are equal */
85+
propertyComparer?: ((a: any, b: any) => boolean) | null
8486
}
8587

8688
export type NormalizedComponentOptions = {
@@ -102,6 +104,7 @@ export type NormalizedComponentOptions = {
102104
listenerChangeLifetimes: boolean
103105
virtualHost: boolean
104106
propertyEarlyInit: boolean
107+
propertyComparer: ((a: any, b: any) => boolean) | null
105108
}
106109

107110
/**
@@ -143,6 +146,7 @@ export const globalOptions: NormalizedComponentOptions & EnvironmentOptions = {
143146
listenerChangeLifetimes: false,
144147
virtualHost: false,
145148
propertyEarlyInit: false,
149+
propertyComparer: null,
146150
throwGlobalError: false,
147151
writeExtraInfoToAttr: false,
148152
backendContext: null,
@@ -191,5 +195,6 @@ export const normalizeComponentOptions = (
191195
virtualHost: p.virtualHost !== undefined ? p.virtualHost : b.virtualHost,
192196
propertyEarlyInit:
193197
p.propertyEarlyInit !== undefined ? p.propertyEarlyInit : b.propertyEarlyInit,
198+
propertyComparer: p.propertyComparer !== undefined ? p.propertyComparer : b.propertyComparer,
194199
}
195200
}

glass-easel/tests/core/component_space.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,20 @@ describe('Component Space', () => {
292292
expect((b.$$ as unknown as HTMLElement).tagName).toBe('SPAN')
293293
})
294294

295+
test('normalizeUrl with prefixed `is` compatibility', () => {
296+
const cs = new glassEasel.ComponentSpace()
297+
const behavior = cs.define('beh').registerBehavior()
298+
cs.exportBehavior('beh', 'beh')
299+
cs.importSpace('wx://', cs, false)
300+
const component = cs.defineComponent({
301+
is: 'wx://comp',
302+
behaviors: ['beh'],
303+
})
304+
const comp = glassEasel.Component.createWithContext('root', component, domBackend)
305+
expect(comp.asInstanceOf(component)).toEqual(comp)
306+
expect(comp.hasBehavior(behavior)).toBe(true)
307+
})
308+
295309
describe('Hooks', () => {
296310
test('`createTextNode` hook', () => {
297311
const cs = new glassEasel.ComponentSpace()

0 commit comments

Comments
 (0)