-
Notifications
You must be signed in to change notification settings - Fork 535
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
Exposed package "path" on IComponentContext. #1220
Exposed package "path" on IComponentContext. #1220
Conversation
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.
@@ -67,6 +67,12 @@ export abstract class ComponentContext extends EventEmitter implements IComponen | |||
return this._hostRuntime.id; | |||
} | |||
|
|||
public get packagePath(): string[] | never { |
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.
can we make this readonly string[], that way consumers will know it shouldn't be modified
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.
/** | ||
* The package path of the component as per the package factory. | ||
*/ | ||
readonly packagePath: string[] | never; |
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 is separate from this review but why is the path an array? It seems like it should just be a string. And ideally to fit in with the rest of the system a URL.
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.
It is a string array and not just a string because we allowed special character in our types. If we made it a string we would have to not allow / which would have broken backwards compatibility.
@@ -67,6 +67,12 @@ export abstract class ComponentContext extends EventEmitter implements IComponen | |||
return this._hostRuntime.id; | |||
} | |||
|
|||
public get packagePath(): string[] | never { |
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.
At some level what's the point of knowing this...? Doesn't the component already know what it is?
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.
See the other comment - but if we don't want to restructure that way - it would be nice to just have this have a string return type rather than even showing the never. The runtime should just assert and guarantee no client of the API could even call this property prior to use.
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.
The runtime knows this but the component itself doesn't. Since we don't expose it to the Component it doesn't know the context it was in when it was created originally.
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.
It should not be possible for a component to be able to access the context to get the packagePath before it is fully loaded and realized. I added an assert in the packagePath method to make sure no one does this. Since it can assert and not return a value, a return type of never should be fine here right?
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.
For use in subsequent loads I think I see the need to know - I do wonder if we can pass a component handle (or component) that is the factory that loaded you. And so we never actually expose the path directly. Only via a component.
Never might work - but I always find composite types a bit confusing. Especially since if we expose this on the IComponentContext interface I think its best to have the return type be a string[].
The fact that it does existing undefined is more due to how we structure the load. But we should be able to protect against this invariant and so should be able to guarantee that once a client gets access to this it's always a string[].
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 agree with you that by exposing string[]
we are exposing a design implementation but without a change to our attach message I'm not convinced that this will work.
We've done the work to hide subComponent from component creation which is a great step towards hiding how component registry works. I see exposing this as a way to give developers power for advanced scenarios. The embeddedComponentLoader for example, knows how to dynamically load components at it's included registry. The ECL doesn't know the registry path to itself but it needs to attach based off its registry. It currently assumes that it's just at the root which is not always true.
Without a huge refactor Handles don't really make sense. This is because we are not getting a handle to a Component Instance but to the registry. The registry doesn't necessarily have a resolution path.
@@ -426,7 +437,7 @@ export class RemotedComponentContext extends ComponentContext { | |||
runtime: ContainerRuntime, | |||
storage: IDocumentStorageService, | |||
scope: IComponent, | |||
private readonly pkg?: string[], | |||
pkg?: string[], |
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 being sometimes optional makes me think we can restructure things to make it always required. I imagine it's because we include the type of component in its summary folder. But use the existence of a path in the tree to know it exists. I'd think the load flow could be updated so that we defer create the actual 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.
Yea, I had the same concern. The reason it's not always defined is because of the loading from snapshot scenario. When we load from snapshot we generate a RemoteComponentContext for each component in the snapshot. But the component snapshot body can be a Snapshot blob or a string which is a pointer to a previous snapshot. If it's a string we don't have the pkg type and to get it we would need to resolve the snapshot id. Since we don't know if this component will be used we don't want to make and resolve needless things.
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.
It is optional here but it should not be possible for a component to have access to the context before it is realized at which point the pkg should be available.
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.
To be clear Kurt, I think you're right that we can delay context creation till we try to resolve the componentRuntime. I'm just not sure it's even worth it. I also think it's a bigger change than this. The componentContext is designed to be a proxy object given to the componentRuntime. So the runtime should really be the only thing interacting with the 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.
Yeah - the fix to make this non-optional might not be worth the cost - since you'd have to restructure how we have the local vs. remote contexts.
But I think as far as a client of the runtime goes - they'll never see a context where this isn't defined - and we can probably put in asserts to guard against this.
@@ -384,6 +391,10 @@ export abstract class ComponentContext extends EventEmitter implements IComponen | |||
this.loaded = true; | |||
this.componentRuntime = componentRuntime; | |||
|
|||
// Freeze the package path to ensure that someone doesn't modify it when it is | |||
// returned in packagePath(). | |||
Object.freeze(this.pkg); |
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.
If pkg can be a string it avoids needing to freeze as well.
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.
If you're concerned you could also just clone the array rather than requiring the freeze which we don't use very often in the rest of the code.
I can't tell what the goal of this is... is this effectively replacing a component registry? i.e. are you intending to use this pkg list so that components can invoke createComponent with this list? |
@SamBroner , the goal of this PR is simply to expose the components package path to the component itself. This will originally be used just for telemetry. |
@SamBroner @skylerjokiel It could also be used to create sub components relative to the current path of a container that is created via dynamic registry (similar to how the ExternalComponentLoader is doing it now). Without the packagePath, can such a component create a sub component with a specific path? |
Fixes #1123 and #1208 .