-
Notifications
You must be signed in to change notification settings - Fork 392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add support for locators #701
Conversation
*/ | ||
var locatorDetail = e.detail; | ||
var target = locatorDetail.target; | ||
var host = locatorDetail.host; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this?
} | ||
*/ | ||
var locatorDetail = e.detail; | ||
var target = locatorDetail.target; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this? how is this different from e.target
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not supportive of this! I think we need to get back to the whiteboard here. There are many things that I don't like, it feels to me that this is the wrong abstraction.
const host: Element = component[ViewModelReflection].elm as Element; | ||
const locatorEvent = new CustomEvent('LWCLocator', { | ||
bubbles: false, | ||
detail: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
detail
should contain only strings. extract that information from the vm
that owns the currentTarget.
|
||
return function(event: Event) { | ||
try { | ||
const target: Element = event.currentTarget as Element; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this currentTarget should be extracted using a getter, can't use the dot notation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I get the VNode for the target element here ?
@@ -39,8 +39,8 @@ describe('fixtures', () => { | |||
const src = readFixtureFile('actual.html'); | |||
|
|||
const configOverride = JSON.parse(readFixtureFile('config.json')); | |||
const expectedCode = readFixtureFile(expectedJsFile); | |||
const expectedMetaData = JSON.parse(readFixtureFile(expectedMetaFile)); | |||
let expectedCode = readFixtureFile(expectedJsFile); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are mutated in the case where the expected js and metadata files don't exists. May as well let the test run properly and use the same value for these thats being written to file
} | ||
|
||
if (expectedMetaData === null) { | ||
// write metadata file if doesn't exist (ie new fixture) | ||
const metadata = { | ||
warnings: actual.warnings, | ||
...actualMeta, | ||
metadata: {...actualMeta}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was actually busted. the file would not be correctly written out
Benchmark resultsBase commit: lwc-engine-benchmark
|
docs/proposals/locators.md
Outdated
@@ -0,0 +1,349 @@ | |||
# RFC: Locators |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still need to update the RFC. Please focus on changes to the compiler and engine and test cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tariq-sfdc if you don't have time to finish this today/tomorrow, then remove it from the PR, and make another PR just for the RFC, no rush.
@@ -17,6 +18,8 @@ export interface RenderAPI { | |||
p(text: string): VComment; | |||
d(value: any): VNode | null; | |||
b(fn: EventListener): EventListener; | |||
fb(fn: () => any): () => any; | |||
ll(fn: EventListener): EventListener; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
signature does not correspond to the implementation.
@@ -438,6 +441,53 @@ export function b(fn: EventListener): EventListener { | |||
}; | |||
} | |||
|
|||
// [f]unction_[b]ind | |||
export function fb(fn: () => any): () => any { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is what we need. What we need is just a regular binding mechanism where you pass the obj and the fn to be bound, and this method does the trick. Imagine something like this: <button locator:context={foo.bar}>
, in that case, bar
method must be called with the this
value set to $cmp.foo
. Keep in mind that invokeComponentCallback
is for callbacks, e.g.: connectedCallback, etc, it is not for common functions like locator:context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so looking at what the click event handler does is api_bind
and cmp
is set as the context. Is that intended behavior ?
if todoItem
is the iteration index and todoItem.handleClick
was the event handler attached to a todo item, then when the click handler executes (no locators), the this
context is set to the component. You don't get access to the this which is the todo items
So we're saying that for locator:provider it's going to be different ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a context provider is not an event handler. api.b is equivalent to elm.addEventListener('click', foo.bar)
, in which case the context is still the element. In your case, it is not an event handler, it is just a function call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it.
So if we have {x.y.z}
, then we first find to $cmp
if we need to or if it's inside an iteration then that remains unchanged.
Then from the resulting expression, the this
context should be everything just before .z
?
Is there anything that already in codegen that can help extract this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, that's it.
no, I don't know.
locator.resolved = { | ||
target: id, | ||
host: locator.id, | ||
targetProvider: isFunction(provider) && invokeComponentCallback(vm, provider), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here is should just call provider()
. when is provider supposed to be a non-function? in the method signature, it says it must be a function, why the test?
target: id, | ||
host: locator.id, | ||
targetProvider: isFunction(provider) && invokeComponentCallback(vm, provider), | ||
hostProvider: isFunction(locator.provider) && locator.provider() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
locator.provider.call()
otherwise you might be leaking information as a this
value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when locator.provider will not be a function? if locator
exists, how is the provider not provided?
const interaction = { | ||
target: target, | ||
scope: host, | ||
context: Object.assign(targetProvider || {}, hostProvider) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this work could be done in the layer above inside ll
scope: host, | ||
context: Object.assign(targetProvider || {}, hostProvider) | ||
}; | ||
console.log("interaction", interaction); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
???
($ctx._m1 = locator_listener_bind( | ||
$cmp.handleClick, | ||
"button-in-slot", | ||
$cmp.locatorProvider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remember that this one should also be bounded via function_bind
, something like function_bind($cmp, $cmp.locatorProvider)
locator: { | ||
id: "button-in-slot", | ||
provider: | ||
_m0 || ($ctx._m0 = function_bind($cmp.locatorProvider)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function_bind($cmp, $cmp.locatorProvider)
should be the proper process to bind the method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sure that it also work for deep obj as a provider, e.g: function_bind($cmp.foo, $cmp.foo.bar)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
few things to be adjusted
Benchmark resultsBase commit: lwc-engine-benchmark
|
@@ -9,19 +9,21 @@ import { VM } from "./vm"; | |||
type ServiceCallback = (component: object, data: VNodeData, def: ComponentDef, context: Context) => void; | |||
interface ServiceDef { | |||
wiring?: ServiceCallback; | |||
located?: ServiceCallback; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably rename this to locator
as well
locator.resolved = { | ||
target : id, | ||
host : locator.id, | ||
targetProvider: provider && provider(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isFunction(provider) ? provider() : {}
maybe?
same for the following line.
Benchmark resultsBase commit: lwc-engine-benchmark
|
@@ -438,6 +441,54 @@ export function b(fn: EventListener): EventListener { | |||
}; | |||
} | |||
|
|||
// [f]unction_[b]ind | |||
export function fb(scope: any, fn: (...args: any[]) => any): () => any { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@caridy I'll remove this completely and instead use invokeComponentCallback ?
context: { | ||
locator: { | ||
id: "todo-item", | ||
provider: function_bind(todo, todo.locatorProviderTodo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will just become
provider:api_bind(todo.locatorProviderTodo) // memorized
click: locator_listener_bind( | ||
todo.clickHandler, | ||
"todo-item", | ||
function_bind(todo, todo.locatorProviderTodo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here. it just becomes
todo.locatorProviderTodo
Benchmark resultsBase commit: lwc-engine-benchmark
|
Benchmark resultsBase commit: lwc-engine-benchmark
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nips, and notes... but I'm good with this.
Benchmark resultsBase commit: lwc-engine-benchmark
|
Test needs to run in IE11. Use ES5 function definition style
Benchmark resultsBase commit: lwc-engine-benchmark
|
@tariq-sfdc thanks a lot of all the work. Let's get this merge today. |
Add support to the compiler and engine for locators.
Details
See the locators.md proposal in the file list for this PR.
Does this PR introduce a breaking change?