Introducing Surface: A new component-based (...) - Marlus Saraiva | ElixirConf EU Virtual 2020

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
i'm here today to talk about surface and surface is a server-side random rendering component library built on top of phoenix live view and before we get deeper into how the components work and how you can define components i'd like to talk shortly about the motivation and the context uh behind the whole thing i mean behind the whole project what motivated me to start this project so about a year ago i started working on a dashboard for broadway so i could present at the lexiconfus and i took up a few lessons from that experience like designing the this dashboard because it was the first uh project that i had the opportunity to use live view so it was like a learning experience and at the same time i took a few lessons from there and a few uh disappointments with regards to to how we could build applications uh especially because my background i mean the last uh projects that i i worked was using react so we have all these components everywhere and i i kind of felt there was something was missing when i was developing the dashboard so the thing is i i needed a better way to express in use components in phoenix and the reasons are especially because phoenix templates are flexible but they're really hard to maintain especially when you're working on a large project i mean the dashboard wasn't even a large project but i felt that many cases i i was lost among the templates and the lack of structure and specification of those templates so there's no standard api to define components right i mean and back then component api was just an idea as far as i i know so this was really hard for me coming from i mean all the technologies i used in the past was object oriented and they usually have this uh especially when you're doing some some something in the front end you know you also can separate things in components and i really miss that so let's talk about finite phoenix templates i mean what's wrong about phoenix templates actually there's nothing wrong about it it's probably the best template engine out there as far as i'm i'm concerned because it's really fast it's fantastic but the problem is that html which is the main language you use to create uh front-end applications html it's a structured language i mean it has a and they have it had defines nodes and those nodes are well def has well-defined attributes and children which are also structured so the problem is that e for ex everything is text so it's really complicated that you you want to produce something that is structured but then you have a template engine that just ignores everything that is already there i mean every information about parents and child nodes attributes is just ignored for ex so i think we we miss a lot that and we also have uh a couple of months later we had uh phoenix live component api which is awesome it's definitely a great foundation to define components and that's actually the foundation that we needed back then to create surface so i remember back then i was already starting working with surface and then i just took a couple of months break and wait until the the component api was ready so i can build surface uh using that api so it does all the heavy lifting the state managing event handling diff tracking i mean i couldn't even imagine myself doing all that stuff i would probably would have given up the project if i had to do all that so but still it's it's a good foundation but it does not define a standard way to create component specifications so we need a higher level thing that say how these components should be specified and how they interact with each other so that's basically the what surface tries to achieve so we introduce a new higher level html like language similar to react or vue.js does and we also uh propose a standard api to define components and we're gonna see the benefits of that so that's that that's the goal so the goal is templates should be parsed into an internet data structure so we can keep the information that was in the original language like the html in this case is surface templates so we we need to keep that information so instead of just using ex to uh to process that template we're gonna parse the template and create uh keeping all the important information we want to use later the second thing is that we also going to need to define components will have to be specified using a standard api so this api will impose a few rules and the good thing is that every component that we use this api they're going to share those those specifications so uh this is important for for what we want to achieve and finally we want to use both i mean we want to use the ast generated by the templates right we want to use these specifications from the components and you want to confront them right you want to to to do things that is not possible using phoenix templates so we want to improve development experience so here's how how it looks like here's the definition of a component it's pretty similar to what you already have in in live view this is a component as you can see it defines a single property we're going to see that but it has an api so if you want to define a way to pass information to the component you need to specify using the api the template is a little bit different from what you're used to so the interpolation use the mustache syntax and as you can see you can inject components inside the template directly just like you react so you don't have to interpolate to to include a component to inject the component in the template so this is how it looks like so let's start with properties so properties are the mechanism the basic mechanism to pass information from a parent component to a child component so again if you are used to work if you're used to work with react or vue.js any of those technologies this is pretty straightforward so let's see here in action so here's basically the the the example that we have in the in the slide so you can see it defines a property called name and then you just print hello and whatever value is in the in this profit so if you take a look here not a big deal if you change here basically the same thing you do when you're using live component passing the assigns um it's important to notice that as i i talked about specification here's what i have in mind you can see that we define this property as required so if for any reason you forgot to pass this information so the compiler can warn you about it so that's a missing property so you can do this at compile time which is great so this is only possible because of those two goals that we had so we need to have the specification we need to have a structure and then you need to confront that structure with the specification so if the if we ignore that hello it's a component and this is not an attribute if you treat everything as text we are not able to do this so i think compile time checking is something really important for large projects and this is one of the things that i miss the most when i'm working with templates with phoenix templates so another cool thing is that since you have that information and that information is available so editors and other tools can also make use of that information so you can have everything that the component those are directives you can talk about them later but you can see that the name property is available here so if i if i try to to add a property that doesn't exist so the compiler was warning so there is no property called phone right so you can define new property here and and there it goes and it was it will be via it will be available for for the editor so to show the documentation to see if it's required or not so i think i i missed this a lot maybe i was spoiled by the the previous uh tools i used to to have before using reactant and so and but this is this is a key point for me i mean the the whole introspection the ability to introspect the information have it's it's it's awesome so data is quite simple i mean we have this already on live view and it's similar to the concept that we have in view js so it just defines the state of the component this is not necessary if you want i mean if you think about live view you can define those assign anywhere you can define an amount usually but one thing that i think it's important to define them not only because you get all of those benefits tooling compile time validation is that you you have a place where you can look at when you look at a component you you can take a look at the top of the component and see what defines the component i mean you can see how it behaves what you use what is the state of the component instead of just a bunch of assigns that you you take a look at where this come from so i think the funny data it's it's it's nice even though we do we don't have uh we don't do as much uh static checking that we can do with properties so here's data in action you can define in this case this is like the hello world of phoenix live view it's a counter so you just have a couple of buttons and then you increment the value decrement the value and one interesting thing here that also comes as a benefit from the specification is that if you define the data as a default value for the data you don't have to implement amount just initialize that value so any value if you can take a look here this is the counter pretty basic stuff so you can just say that can start at value 10 so i think it's really nice to take a look at one place and say okay that's the state and that's the initial state and the same thing as uh properties so since this data is specified it's declared you can the the the editor can make use of that information and list to the user so you have more stuff here you just be available here and also if you use the update or assign will also be available here that helps me a lot if i just jump into a component that is not mine i mean it's someone else's component i have no idea what's going on so it's nice to have the the editor help you to be more productive excuse me so have seen properties we have seen data we also have slots so it's lots a little bit different from what you're used to in live view because in live view you have inner content when you can kind of pass the content of the of the from the parent component you can pass uh you can pass it's similar to properties it's a way to pass information to a component but instead of that information coming from attributes which is which are properties on components you you pass this information as the body of the component so here's how it looks like we have a button here which defines a single slot which is the default slot and the slot is like a placeholder so whenever you have a slot inside a component this is going to become a public interface so you can pass that information you can pass that content to the component so it can be replaced so in this case we define a default slot and the default slot is placed here so if we use that button and we just say change my style as the content so you're gonna have a button with the label change my style so again it's not very sophisticated but that's the way uh you can use default slot you usually using default slot to just pass a string is not the something usual uh because you can pass a string just as a property but since the html button receives the label as in the body so it's interesting to keep that same uh that the same api for for that but the thing is that you can actually create more than one slot you can create multiple slots for instance if you have a card component you can create like the default slot to be like the main content you can have the footer you can have a header header you can have multiple slots and then you have to name them so a slot without any name it's just the default slot so other slots you put the name say the footer and we work exactly the same way so when you're using the component using the card component whatever you pass here is going to be placed in the default slot and whatever you pass here using template slot footer it's going to be placed inside all that and if the slot is not required you can also place uh fallback content for for that slot so this is pretty similar to for what you have in other other technologies this is basically a template and slot are specified in the html specification we don't have a strong uh we are not forced to follow that so we have a few things that are different but since other technologies already use it and people are already familiar with it we decided to use that approach uh on slots so another thing again about the specification is that if since this uh slot is required if for some reason like here like we have the default slot all the buttons are so since we have the default slot and the default slot is defined as required in case you don't pass it we're going to have a warning so we always the compiler tries to to inform you of anything that it's not quite right and he knows that because of the specification slots can also be very interesting in a way that sometimes you want to define a component but uh you don't there's a common logic in the component even a common uh component be a common behavior but there are some pieces of the component that should be injected so you can use slots to do that and you can pass information to the parent so you can use that as well to customize that that content so this is for instance a component called rating it's pretty basic it's similar to the other one but the difference here is that uh we have value that you can increment and decrement but i don't want to when i design the component i don't want i don't know how to render the that information so the component will be responsible to hold the value of the counter it's going to hold the buttons that we're going to uh increment and decrement the value and we're going to handle all the events but we're just gonna let the users say how he's going to render that information so if you take a look at this example you're gonna see that i'm using this component twice here in this view so the first one we are using we are passing the content of this the default slot right and you just pre we just rendering the value directly so that's what you can see here the second one a little bit more sophisticated you just have some logic to render stars instead of the value so you can see it receives the values so otherwise i'm not i i don't know what's the status of the counter i mean all the implementation all the details are inside the component but doing this you can actually pass the information back to the parent so the parent can customize the rendering so here you can have the same component uh rendering things differently customized so they are really powerful i really like uh to develop components based on slots there are also other other things that you can do with slots i mean you you can create renders less components that will act like just as data sometimes you have for instance if you're trying to print the table like a grid and one way people do this it's like they pass the date information and then they pass the columns as parameters so you have like this you create a data structure to and and and fill your properties with that data structure so instead you can use the the the template itself to use the nodes to use to create custom components to do that that will act as data so you can have the grid you can create the component and you can create another component called column that will just hold the information you want to pass so it's a more declarative way to do this which matches perfect what we have in html so this you can this is you have the documentation you everything it's you you want to do if you want to use this it's using the same principle you can also use generators so it's you want to extend that example and now the columns you actually want to pass snippets of code for each column so you can actually use the the property and define a generator so defining variable and that variable will be available might be available in the column so here you have like you have a list of uh items in the parent you pass that to the parent the parrot handle all that stuff it interacts with the the list and then calls each column using slots so it's really powerful you can create really beautiful code using that approach and the one the last thing i want to talk about the api is context and it's it's uh it's something that you have to be careful if you want to use it because contacts allow allows you to pass information to children without using properties so you can define a something in the context and then down deep in the tree any child can ask for that information so this is something that i say well don't you don't abuse uh of this i mean use i usually use for only localized things like forms so i think it's one thing but don't use context like in the top of your page and define a bunch of stuff i mean you're gonna lose a lot of things uh you're gonna lose information because it's gonna be everything implicit and i don't think it's a good thing but i think it matches perfect with forms as you can see here if uh you already work with forms in using phoenix templates you need to define the form and then pass the variable to each field and each input and sometimes it's just too much information i mean you don't need to pollute the code that much if you so you can use this context in in in form so your component can define that that form instance in the beginning in any child can access that form internally so in that case i think it's pretty obvious that this is happening unlike if you just put the context at the beginning of the page so contacts are useful i think it's great to create a very clean code but it comes with a price don't abuse so i would say that the first rules of using context is to not use context at all unless for something very similar there is another kind of component that we cannot find as well in phoenix which is the macro components uh and they are really handy i mean this one is the marketable component you can actually create a component that you say look uh surface don't parse the content i will parse the content myself so you can actually you create a way to extend the language so the website of the surface website use this a lot because it's really handy so if you can take a look here this is the code from the website so you can just mix html you have the components here and then you have markdown you can just start using it to have syntax highlight and so it's i think it's really really handy i mean the whole website was was basically using the markup uh the markdown component including all the the other fancy stuff that that you can see you can mix uh you can mix uh mark down with html and whatever so it's really powerful this is also a macro component so this is really cool because i can have this content here this source code and i say surface don't evaluate this code right now because i want to show it highlighted and then i say now you can do it so i don't have to duplicate this code here to actually render this and then adds this code again to for syntax highlighting it's just one code and he can render this and we can use it directly here so again macro components also follow the same rules of macros in elixir so don't use it unless you really need it and documentation and examples you can find on this temporary webpage as soon as we have the first table release we gonna move this to a proper uh domain but i want you to show this which is the documentation that we have which is all generated uh from the component specification so if you generate a component if you create a component you can use those same components here to expose the api so it's really nice that you can just take a look at the component and see everything that the components has as a public api you can see all these properties you can see the type you can see which values it accepts if there is a default value you can see if it defines any slot so and what is the meaning of that slot if you had some advance so everything is introspected so it's really nice to i i i felt that when i was in dashboard i was looking for components and i said how does this component work i don't know because everyone will document that component differently some people will not even document it at all so you just have to go into the into the code to find out how it works so it's really nice go take a look at the website and if you have questions if you want to help just open an issue so to wrap up uh the benefits of such approaches compile time validation as we've seen it the structure is validated against the specification this is crucial this is important and this improves a lot uh the experience so we can have custom code generation like directives similar to vue.js events we can customize the way events work and surface it's it's uh for instance if you work if you define a component and you want the component to handle the the events you need to use the phoenix target and set it to myself in surface you don't need to do that by default when you define uh the the event you're gonna if you pass an event to a element you can handle that event locally without doing this because you know who's the parent you know who's the children and introspection tooling agitors as you can see i just started to do this plugging for elixir science so will be soon available for elixir language server and any other editors that use elixir science so the current current status of the project is that i just released the first uh release candidate and it it should be a stable release the it will turn into a stable release as soon as live view the next version of live view is out because it depends on something that was recently added to live view so at least from the api perspective there is no plan to change it until the first stable v release so feel free to use it create components and what's next so basically since now we have the foundation ready and you have the api stable we are just starting to create components so i started to create a few components using bulma uh lloyd which is another core member is using taiwan so there are people trying different things and it would be great if you have something if you want to share it would be great uh scoped css style is something that we're working on so if you know what it is some people love it some people hate it so i'm in the middle right now i'm not sure if you're going to implement this directly into surface but it seems you can come up with some some middle ground to have maybe parts of it and that can be extended by other libraries maybe a couple of mix tests more tooling and what else i mean you're the ones that are going to say what else i mean now that you have a release candidate people can actually start using it let's see how it goes so that's what i have for you today there's a a lot more in on surface take a look at the website if you want there's a lot of documentation it took me a long time to get all the documentation but i think it's it's it's worth it if you if you interest take a look there you have questions open issues and i just want to very shortly thank two people which is uh jose that was very patient uh i find myself i find myself a few times on a dead end and he was there to rescue me so i'm really grateful for that and to lloyd remy which is uh did a great job in a compiler so without these two people uh surface wouldn't be ready so thank you very much oh that's really nice you can see the uh the round of applause there thanks everybody uh and thank you marcus um i really enjoyed the demo especially um yeah so let's let's move on to questions uh we have uh we have some time for questions fortunately um and you can upload them so that order changes while we're asking um maybe you could do that as soon as possible um and so let's just uh let's see who's who's at the top um that would be damian um i think you should be able to unmute yourself and go ahead and ask that question so uh is it possible to use files for templates instead of the hcgill yeah sure uh you can create s face files and just call up uh just in the same folder and we'll pick up this file if you just put the same name just like phoenix yeah just like phoenix live view great uh and then the other one toward the top is uh let's see who is that um heiko uh maybe you're able to unmute yeah yes can you hear me yeah um yeah um at first i'm really um yeah really really happy to hear your talks great stuff really great stuff thank you um my question is i don't know how to handle state um universal so universal state uh i'm used a little bit to view and swift ui and they have something like redux or so do you have some kind of pattern there too uh i mean i i had many discussions about something similar with redux especially with jose and the thing is redux is the way it is because they don't have otp right so we have otp and state managing in erlang in general is so much easier to do than in in javascript and phoenix already comes with pub sub which i mean if you use pub sub you basically along with components it's probably everything you need there are some some things that i want to explore later it's uh basic to make a little bit more uh a little bit less bureaucracy so especially using pub sub but those are just experiments and [Music] let's see how it goes but basically in general you don't need redux when everything is on the server the status or the live view is on the server you have otp you have pub sub you have events so it's it's quite different you
Info
Channel: Code Sync
Views: 2,737
Rating: 5 out of 5
Keywords:
Id: 6x-Xavz1o9M
Channel Id: undefined
Length: 37min 11sec (2231 seconds)
Published: Fri Dec 18 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.