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
[RFC]elements schema: add support for custom schemas #12045
Comments
I'll be around tomorrow. Victor Berchet notifications@github.com schrieb am Mo., 3. Okt. 2016,
|
If we do this right, our current |
Roberto Fischer would be interested in this feature |
I think #12840 is a similar request in terms of the customizable sanitization. |
/ref #16306 |
I accidentally created a duplicate of this, here is my suggestion to resolve it (copy & pasted from the other issue): I'd expand the SchemaMetadata interface like this: export interface SchemaMetadata {
name: string;
tokenValid?: (token: string) => boolean;
} The functions would check if the given token (element or attribute name) is valid, it's optional for full backwards compatibility (though that's probably not even necessary). Alternatively this could be split into two functions (attributeValid & elementValid). Then there could be a class or helper function that generates an object which simply checks if the given token is within a set of previously defined tokens. This would also clean up existing code because you don't have to hardcode the logic of the schema everywhere it's used. If you approve, I can implement this and PR, should be pretty simple. |
@BaerMitUmlaut How do you make the compiler to execute a specific function in metadata, without running other code? The main problem is this isn't happening at runtime. |
I'm not an Angular pro, but these are the two spots where I could find logic associated with angular/packages/core/src/render3/instructions/shared.ts Lines 933 to 934 in b057806
They would have to be changed to call the tokenValid method instead. Unless there is some other magic happening somewhere else which I'm missing, that should be it, right?
|
@BaerMitUmlaut The ivy one is not feature complete and currently WIP at #30301 Also, the schemas must be understood by language-service, thus cannot be runtime-only. |
import { MyComponent } from './my-comp'
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
customElements: [MyCompoent]
})
export class AppModule {}
export interface MyComponent {
customData: [string, number]
onChange: (data: string) => void
}
export const MyComponent = { tag: 'my-comp' } as const
class MyComp extends HTMLElement {
// .......
}
<!-- The exported value ensure angular recognize it's tag name -->
<!-- The exported interface ensure angular compiler check all properties of `my-comp` component -->
<!-- They shared the same name "MyCompoent" so angular compiler can combine them together. -->
<!-- Now customData get the type [string, number], $event in "onChange" is type "string" -->
<my-comp [customData]="data" (onChange)="onChange($event)"></my-comp>
@Component({
templateUrl: "./app.component.html"
})
export class AppComponent {
data = ['a', 0];
onChange(newVal: string) {
this.count[0] = newVal;
};
} |
I don't think this should be considered low priority or frequency. We are probably all starting to see the shifting of design system component libraries being built using web components and this makes it very difficult for devs to work with them inside angular apps. Right now to use custom elements you must essentially turn off all schema validation. An ideal solution (for us anyway) would be to be able to build and import a custom schema that was generated by the Stencil compiler. |
I totally agree with @RobM-ADP. Just recently we had to do quite an ugly workaround to avoid the |
Another thing worth noting is that creating a lot of directives or wrapper components as @DmitryEfimenko describes just to make the compiler happy introduces a lot of extra code in the final bundles that doesn't need to be there. One of the big advantages of building a design system as webcomponents is that code defining the components doesn't need to exist in the Angular app's code. So neither |
is there any reason to not just provide a way to customize the following checks?
if these were pluggable users could already significantly refine which tags to bail out on. if i patch my local compiler with 3 lines i can get immediately it to do what i need! |
This sounds reasonable. If it was to be the choice, default checks must be exposed too so we can do something like: override hasProperty(tagName: string, propName: string, schemaMetas: SchemaMetadata[]): boolean {
return propName.includes('MY_CUSTOM_PREFIX') || DEFAULT_CHECK(tagName, propName, schemaMetas);
} |
Why not even allow plugging in a full hook? override hasProperty(tagName: string, propName: string, schemaMetas: SchemaMetadata[]): boolean {
return config.hasPropertyOverride ? config.hasPropertyOverride(tagName, propName, schemaMetas) : DEFAULT_CHECK(tagName, propName, schemaMetas);
} |
As far as I have looked into, the issue is how to expose it this configuration. |
Ok. Would some sort of pattern or similar for the config work? |
Hi, I cooked up the following proposal: sijakret@a5cc45e?branch=a5cc45e121d5ba0437461cab84b452a04ebcfd82&diff=unified it adds a new angular compiler option {
...
"angularCompilerOptions": {
...
"webComponentPattern": "my-prefix-" // RegEx
}
} if it is not used there should be no change in behavior.
Example (config option set like so: @Component({
selector: 'component-exists',
template: `<div style="padding: 20px">{{prop}}</div>`,
})
export class ComponentExists {
@Input() prop:string = 'default'
}
@NgModule({
declarations: [
// ...
ComponentExists
],
//...
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { } template <!-- A
regular angular component with a prop
=> works
-->
<component-exists [prop]="'prop was set'"></component-exists>
<!-- B
same component, but trying to set prop with wrong type
=> error even though CUSTOM_ELEMENTS_SCHEMA is configured
-->
<component-exists [prop]="1"></component-exists>
<!-- C
same component, but trying to set non-existing prop
=> error even though CUSTOM_ELEMENTS_SCHEMA is configured
-->
<component-exists [propOoops]="'prop was set'"></component-exists>
<!-- D
trying to use an angular component that does not exist
=> error,..
-->
<component-does-not-exist></component-does-not-exist>
<!-- E
matches pattern /my-prefix-/i
=> no checks at all
-->
<my-prefix-component></my-prefix-component> This behavior would be a significant upgrade to the current one since we can have E but still get validation feedback for B, C and D. Works well in a test project with both Looking for feedback from the team here - do you see issues with this approach? To reiterate, the use case: I am aware this is not the most comprehensive or elegant solution but it would be very low-risk/high-impact and get the job done |
Thanks, - this would be a great improvement !! |
@sijakret it wouldn't help with HostBinding, because they belong to the parent view, so you will not be able to guarantee that |
@waterplea can you provide an example? |
If you had some directive that processes value somehow and do this, it would cause an error, even if you add @Directive({ selector: 'clamp' })
export class ClampDirective {
@Input() min = 0;
@Input() max = Infinite;
@Input() value = 0;
@HostBinding('prop')
get prop(): number {
return Math.min(Math.max(this.value, this.min), this.max);
}
} <!-- Web component with 'prop' input -->
<component-exists clamp [value]="value"></component-exists> It's a fairly crazy example, I know, but I just wanted to highlight that there's also |
I cannot get your example to do what i think it is inteded to do regardless of any schema-related issues, here it is alive: https://stackblitz.com/edit/angular-ivy-8mzrpk?file=src%2Fapp%2Fapp.module.ts Funny thing is, it works for the web component (CUSTOM_ELEMENT_SCHEMA and WC are commented out in the stackblitz since the problem with the directiv seem unrelated to me)
Regarding libraries: I am not sure about the way angular handles this, but the compiler probably compiles these things AOT and hence use the compiler settings at compile time of the lib for its code (at least regarding templates). Don't know this though. @alxhub looking forward to your thoughts on my proposal #12045 (comment) |
Having just a prefix won't solve the Schema for NativeScript. |
Instead of a RegExp pattern the config load external schemas, for instance as described here: https://github.com/microsoft/vscode-custom-data (example: https://github.com/microsoft/vscode-custom-data/blob/main/samples/helloworld/html.html-data.json) and check against them. This change would be a bit more involved but in essence a regex vs. a dictionary pretty much won't change much about the way it hooks into the compiler. At this point i am looking for feedback whether i am on the right track in the first place ;) |
I updated the proposal: sijakret@2339fe2 Now you can actually extend the dom schema so it is even less intrusive and reuses the exsting paths there. you can specify specific tags (same way as it is done in dom_element_schema_registry.ts already) {
"angularCompilerOptions": {
"customSchema": [
"my-prefix-custom-element^[HTMLElement]|string-prop,#num-prop",
"my-other-element^[HTMLElement]|myprop"
]
}
} I also did a quick tryout with the the angular language service extension for vs code, that also works. What do you think about this approach? |
It would be a really nice addendum to be able to provide custom schema templates. Those could be pre-compiled so they do not have the runtime and maintenance overhead as the wrappers, and this would provide code completion for 3rd party component libraries provided as HTML5 components. |
This issue has been around since 2016, is not hard to fix and would help EVERY angular project that uses web components. |
Are there any updates regarding this issue? |
I hate to agree that this issue increasingly smells like a lock-in strategy. Angular team; please at least share a reason, roadmap, thoughts, anything. |
Can confirm this is affecting our organization. We're migrating our Web design system components from Angular to https://lit.dev/ in order to support framework-less frontends. It feels like we're being punished for using Custom Elements even though that's a web standard. We wouldn't mind doing a little extra work in order for Angular to understand the specific elements and their attributes/properties. Edit: it's also interesting to note that back in the JIT compiler days there were a few different blog posts out there about overriding Additional note: if we get a proposal in-place it would be great to be able to define attributes and properties for each element separately. Currently in our Lit Custom Elements have defined "camelCase" properties that directly correlate to "barrel-case" attributes. A dev can choose to use either, but they are basically using the same "types" underneath (attributes of course are just strings but Lit has a getter/setter layer that allows us to automatically convert those to Numbers, Dates, other custom objects etc) |
We have used the old way to patch the JIT compiler. Because this isn't functional we have switched to patching the angular core, but that is not straight forward. |
@waterplea Isn't it the case, that you always should add the CUSTOM_ELEMENTS_SCHEMA to the module declaring the component which uses the custom element? And in the case of standalone components, to the component itself? |
I guess, but that means if you distribute reusable components you cannot bundle required config with it and people will have to do it themselves, which would then affect their code, which it really shouldn't. |
Is there any update with this? We currently use these plugins to generate VS Code and JetBrains autocomplete and docs, but it would be nice if we could also support type safety for our components. |
hey @pkozlowski-opensource! would you mind weighing in? it'd be nice to get the team's position on this. |
Sad to see that there is no progress on this. I`d also like to throw in web-types, which could be a way to even validate custom elements. I am used to this from vaadin components, but I have seen that it's already in use be some other component libraries. |
in
@Compoent
, schemas can currently only use the following values:CUSTOM_ELEMENTS_SCHEMA
-> allow anycustom-tag
with any property,NO_ERRORS_SCHEMA
-> allow any tag and any propertyWe need to implement a way to defined custom schemas, ie defining all polymer elements and their properties (and events).
@mprobst when would you be available so that we can discuss how to integrate with the security schema ?
The text was updated successfully, but these errors were encountered: