Providing, Injecting, Testing, and Templating Using Vue with Valeri Karpov - VUE 194
Valeri Karpov, maintainer of the popular Mongoose library for Nodejs, visits the show again to talk about a new Vue 3 feature of provide/inject and how it's much better than props, how he uses Vue templates inside Node, tests template output with the cheerio library, and then how he uses plain js, html, and css files for email templates. As always, they end with picks, including a discussion of the The Hobbit and the Lord of the Rings books, and movies, and as always, Steve tops it off with his amazing dad jokes.
Hosted by:
Steve Edwards
Special Guests:
Val Karpov
Show Notes
Valeri Karpov, maintainer of the popular Mongoose library for Nodejs, visits the show again to talk about a new Vue 3 feature of provide/inject and how it's much better than props, how he uses Vue templates inside Node, tests template output with the cheerio library, and then how he uses plain js, html, and css files for email templates. As always, they end with picks, including a discussion of the The Hobbit and the Lord of the Rings books, and movies, and as always, Steve tops it off with his amazing dad jokes.
Sponsors
Links
- Using Provide and Inject in Vue.js
- Provide / Inject | Vue.js
- Reactivity in Vue 3
- Use HTML Files as Vue Templates with Webpack
- cheerio
- GitHub: vkarpov15
- Twitter: @code_barbarian
Picks
Transcript
Steve_Edwards:
Hello everybody and welcome to yet another exciting episode of Views on View. I am Steve Edwards, the host with the face for radio and the voice for being a mime, but I'm still your host. Today, I'm flying solo and I have with me as a returning guest, Val Karpov. How you doing, Val?
Valeri_Karpov:
I'm doing great, how are you doing Steve?
Steve_Edwards:
Good, doing good enjoying some nice warm sunny weather here without the humidity up here in the Portland area. Probably a little drier than what you're getting down there in Florida.
Valeri_Karpov:
Yeah, it's been a surprisingly dry summer here, but we did get some rain this week, which is good. Don't want to drought in Florida. Yeah, because that means
Steve_Edwards:
Right.
Valeri_Karpov:
one ire is excessive heat and not good things.
Steve_Edwards:
Not good things, yes, of course. So Val is probably most well known, I guess, for being the maintainer of Mongoose. I think that's safe to say, your claim to fame, other than being just a JavaScript guru in general. And Mongoose, for those you don't know, is a Node.js driver for the MongoDB database. What else, where are you working now? What are you doing now?
Valeri_Karpov:
Oh, I do freelance contracting. I
Steve_Edwards:
freelance,
Valeri_Karpov:
work primarily
Steve_Edwards:
okay.
Valeri_Karpov:
on Mongoose. I also do web development for some clients with Mongoose in view.
Steve_Edwards:
Right. And he also maintains the Mastering JS website and newsletter that I am a subscriber to. Good stuff. Good stuff. So check that out. Mastering JS. We'll put that in the show notes for sure. So we talked a couple months ago, I think. I forget when exactly it was. Too lazy to look it up. What did we talk about last time? Now I'm brain farting all of
Valeri_Karpov:
We will
Steve_Edwards:
a sudden.
Valeri_Karpov:
talk
Steve_Edwards:
Oh
Valeri_Karpov:
and
Steve_Edwards:
yes,
Valeri_Karpov:
I
Steve_Edwards:
we talked
Valeri_Karpov:
am a certain
Steve_Edwards:
about his
Valeri_Karpov:
next
Steve_Edwards:
book
Valeri_Karpov:
speaker
Steve_Edwards:
on
Valeri_Karpov:
right.
Steve_Edwards:
promises and... Async await, right, we talked about that. And there was a couple things that we had mentioned during that episode that we thought we would continue to talk on and a few other things we wanna talk about, so sort of a potluck episode today. So the first thing that we're gonna talk about is provide and inject in view three. These are some new features that are, I guess you could say, yeah, it's a way to send props, right? directly to a component without a prop drilling and that's the first line of his article on mastering.js about using provided injects. So can you uh... give us a little description what it is and how it works and most importantly why it's good.
Valeri_Karpov:
Yeah, so provide and inject is kind of like long distance passing of a prop. So if a component provides a particular prop, like you call view.provide or list provides in the component definition, any sub component can, any component underneath that component can then inject that prop. So you don't explicitly have to pass that prop down. So like prop drilling, the problem there is, okay, let's say you need access to, let's say at the top level component, you have like a user object that contains like, okay, username, user email, whatnot. And then you have a component four layers down that needs that user object. So now you need to say, okay, like a top level component needs to pass user down to, component B, B needs to pass it down to C, C needs to pass it down to D. Now that gets really annoying real quick. You'd want to add new features down the stack, it just gets annoying. Now with Provide and Inject, the top level component can provide user, the component D can inject user, and components B, C, D, or A, B, C in between don't have to know about user at all.
Steve_Edwards:
So this has always been the use case, at least with Vue 2, and in the past for bringing in something like Vue X, right? Where that as the size of your app grows and you get more and more components and you don't want to pass from A to B and B to C, then this is where Vue X and state management comes into place. So is it, first clarification question though, is even with Provider and Inject, there has to be a direct hierarchy, right? So in other words, if I have A, B, C, and D. B has to be from A, C has to depend from B, D has to descend from C, right? Sort of a direct line as compared to, you know, A imports B, B imports C, but D is somewhere else outside of A. That won't necessarily work there. Will it or will it?
Valeri_Karpov:
You don't need to explicitly import, but the thing is is that like the component that uses user needs to be a descendant of the of a component that provides user That
Steve_Edwards:
it does need to be
Valeri_Karpov:
makes sense. Yeah
Steve_Edwards:
okay so can be so in other words review action or you had you could have your your variables defined in state and it could be anywhere right
Valeri_Karpov:
Yeah.
Steve_Edwards:
but with provided injected has to be sort of a direct linear descendants were not direct but somewhere in the in the hierarchy below
Valeri_Karpov:
Yeah, but the way that I typically do things is again at the very top level, like the top level component, the app component, that basically provides everything that you can then access down the stack or down the component tree.
Steve_Edwards:
Okay, alright.
Valeri_Karpov:
So I don't really use intermediate providers. Usually it's just like, okay, the top level app provides a bunch of things that individual components can then inject, or sometimes just one thing. So one thing for smaller applications, what I end up doing is top level app just provides my property called state that pretty much every component injects and can either read or write the state.
Steve_Edwards:
Okay, so we've established that you can define a property, you know, at the top of a hierarchy or somewhere above where it's needed and then just inject it somewhere below without having to go through each one. Now going back to Vuex, you know, using things like map getters, map actions, map state, at least in Vue 2. you can make things reactive in the template. So you can do the same thing with provide and inject, correct?
Valeri_Karpov:
Yes, because you can pass down a instance of view.reactive. Have you used the view.reactive function before?
Steve_Edwards:
I personally know I haven't had much opportunity to use it yet, unfortunately, but I mean I've seen and read about it, so,
Valeri_Karpov:
Yeah.
Steve_Edwards:
but
Valeri_Karpov:
I mean,
Steve_Edwards:
haven't had a chance to use it.
Valeri_Karpov:
it's something that's like kind of like an exciting new addition in View 3. The idea behind view.reactive is like that basically you pass in a object to view.reactive and you get out like a fully reactive object that you can modify updates using templates and it kind of just works in the sense that like okay, let's say I have a user object at the top level that I pass through view.reactive. So like let's say I have, I call view.reactive on name is Val, or name is Steve, let's say. And then I provide that user property. And somewhere way down the tree, some component changes user.name from Steve to SteveE. That also will affect the templates in the top level component, or any other component whose template injects user. So you know, you say you have like a navbar component that displays your name, like user.name, and then somewhere down you have like a separate component down the tree that lets you update your name. Um, that component doesn't really need to do anything in terms of like no actions, no commits, nothing, just, you know, state that, uh, user.name equals, um, equals steve. And that affects the navbar that updates the navbar template. So it'll, your navbar template will display steve. as opposed to Steve.
Steve_Edwards:
That almost seems sort of dangerous
Valeri_Karpov:
ya, maksudku
Steve_Edwards:
to the point where anything could update something somewhere and you could run into unexpected changes.
Valeri_Karpov:
Yeah, I
Steve_Edwards:
That's
Valeri_Karpov:
mean,
Steve_Edwards:
safe
Valeri_Karpov:
it was
Steve_Edwards:
to
Valeri_Karpov:
a
Steve_Edwards:
say.
Valeri_Karpov:
little dangerous, and some people would call that playing fast and loose, but on the other hand, that's how I do software development. So, I mean, I tend to kind of want to like, you know, you're speaking with Mishko this week on JavaScript Jabber, right?
Steve_Edwards:
Yeah, we did yesterday.
Valeri_Karpov:
Yeah.
Steve_Edwards:
As of this recording, we recorded yesterday, yes.
Valeri_Karpov:
Despite the fact that I interned under Mishko like 15 years ago, I have like very different, like he and I are kind of on like opposite sides of this where like I try to like remove as much friction in the development process as possible. And for me, like being able to update like, okay, user.name somewhere all the way down the tree is like, I think that's great.
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
Um, I think that's something that like, kind of like. lets you be productive and solve a problem quickly and easily and let you get on to moving on to the next thing, as opposed to kind of dealing with kind of like, you know, dotting your I's and crossing your T's with like a Vue X type thing. And it also isn't that you can't like monitor these updates because again, Vue does have like this, there's like an updated hook. in view, right, where like every time the state changes, you can still, you can like print out where, you can print out the state change and you can
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
throw in new error dot stack to see where it came from, right?
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
So in theory, like that is, let's see, like in theory, it's not that bad in the sense that you're, you know, you have like stuff happening that you can't inspect what's going on.
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
You can still inspect what's going on. it's just more convenient and requires less, well, requires less boilerplate. Like what makes me really excited about this was like, let's go back like five or six years when I was doing a lot of React and Angular 2 work. And I just always found it so frustrating when I'm just like, okay, like in Angular 2, we have like these... would have these pretty complex component files where it was like, okay, you have a navbar component, there's navbar.actions.ts, navbar.reducers.ts, action-creators.ts, some NGRX stuff. So it got to the stage where I'm like, just to wire up one silly little button that just sends one silly little HTTP request, I need to change six different files and change them in exactly the right way, otherwise I get some unreadable error. So that's the kind of thing that I try to avoid, and that's why I like this pattern of creating a reactive object and just kind of passing it around so I can update state wherever.
Steve_Edwards:
Yeah, I can see how that certainly increases your flexibility. I'm just, I guess I lean, you know, in the dichotomy between you and, and Mishko on this, the way you describe it. I would probably be slightly towards Mishko,
Valeri_Karpov:
Hahaha
Steve_Edwards:
you know, from center. Um, you know, there's different use cases, but, uh, I guess, I guess, you know, if there's ways that you can catch and avoid errors and. Quick question, so I'm looking at the view docs on provide and inject and you mentioned that your normal workflow or pattern is to put something at the top level in your top level component of a hierarchy of the given hierarchy and then make it available
Valeri_Karpov:
Yeah,
Steve_Edwards:
via
Valeri_Karpov:
yeah.
Steve_Edwards:
inject from there below. But it looks like you can also do this at the app level. So you can do stuff in a component for everything below, but you can also, if you want to, do it at the app level and make it globally available.
Valeri_Karpov:
Yeah, that
Steve_Edwards:
There's
Valeri_Karpov:
would
Steve_Edwards:
like
Valeri_Karpov:
be
Steve_Edwards:
an
Valeri_Karpov:
a
Steve_Edwards:
app.provide.
Valeri_Karpov:
neat thing to do. I guess what I usually do is provide it out just like the top level component. Like I have
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
like an app component that just stores everything.
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
So that's where I would normally provide an inject, but I guess I can put it on the app too. I don't know,
Steve_Edwards:
Uh huh.
Valeri_Karpov:
I must admit to not being as comfortable working with the return value of view.create app
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
as I could be. So I just try to minimize doing anything there. But maybe.
Steve_Edwards:
Right, right. I was just pointing out that the option exists in the docs for those who would like to do it. As it says, app level provides are available to all components rendered in the app. This is especially useful when writing plugins, as plugins typically wouldn't be able to provide values using components.
Valeri_Karpov:
Yeah.
Steve_Edwards:
It's a little bit behind my comprehension there, but I'll put it out there for listeners to investigate on their own.
Valeri_Karpov:
Yeah, honestly writing a Vue plugin is not something that I've ever really done. So
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
I can't say I'm an expert on that. All I kind of know is like, oh, provide and inject seems to work great in my experience. So
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
I'm going to talk about it. You know, I always, of course, take what I say with a grain of salt. You know, I'm not officially affiliated with Vue. This is just kind of the way I do things. And it seems to
Steve_Edwards:
Sure.
Valeri_Karpov:
work now.
Steve_Edwards:
Sure. And you can do things similar to props. You can do default values. So if something's missing, you can say, OK, if it's not here, give it this value to make sure you don't get a runtime error or some sort of error. And you can even alias your values. There's numbers of things you can do with provide and inject, for sure. So yeah, we'll put a link. I will put a link to the. the View Docs, View 3 on Provide and Inject for your reading pleasure. Anything else you wanted to cover on Provide and Inject before we move on?
Valeri_Karpov:
Let's see. Nothing in particular.
Steve_Edwards:
Okay.
Valeri_Karpov:
Yes, yeah, it just works really well with Vue.reactive. Lots of good stuff you can do there. I guess I'm kind of, I guess I... I only talked about passing one reactive state property, but one thing I end up doing as well is breaking up that state property so into smaller components for larger apps. So things like, okay, I store the auth state as a separate thing that you can inject and you can break up the one monolithic state into smaller substates. Like I have an app where I'm like, okay, I provide like, I provide an auth state, like a search results state, things like that, and things that the component, that the chat components can then pull in using inject. So like that kind of helps make, well helps make the monolithic state a little bit more manageable sometimes.
Steve_Edwards:
well okay so provide is just one you know method that you call in your parents so you just have like uh... you say you break it up so you talk about an object with different key
Valeri_Karpov:
Yeah,
Steve_Edwards:
values
Valeri_Karpov:
no, you can provide multiple values. So like I provide auth, auth is a reactive view object. I provide search results, search results as a reactive view object.
Steve_Edwards:
Okay so you can have multiple instances of the provide method inside
Valeri_Karpov:
Yeah,
Steve_Edwards:
your
Valeri_Karpov:
you can provide arbitrarily many things and inject them wherever you want.
Steve_Edwards:
but they have to have their own return statements from Provide.
Valeri_Karpov:
uh... what do you mean uh...
Steve_Edwards:
Is that true? Well, so since I'm looking at your blog post here, and you got your high grandma
Valeri_Karpov:
Yeah.
Steve_Edwards:
example, right? So you've got in your view created app, you've got provide, and then that returns
Valeri_Karpov:
Ha.
Steve_Edwards:
an object with a key of state and a value of high grandma, right? So if you wanted to return multiple values as you were talking about, would those be like, you're still returning only one object with different keys within that object or different instances of the provide method?
Valeri_Karpov:
No, you would return different keys, but that syntax is a little strange. I don't really use that syntax very much. If you scroll down to the second code example, you'll see something a little bit better, where you see it's calling view.provide. Just you see kind of like this is like the more composition API way of doing things where instead of like having a provide property on your app or component, you have you call view dot provide within your app or component within the
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
setup
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
function. The second example that second example is a little bit better where it's like okay view dot provide state comma state.
Steve_Edwards:
All right.
Valeri_Karpov:
That's kind of how I do things for smaller apps. For larger apps, sometimes I provide multiple subsections of state where I provide auth, which contains, OK, is the user logged in? Who is the logged in user? Things like that. Provide search results, which contains, OK, what results do I have? What parameters were? What were people searching for? Those are a couple of examples.
Steve_Edwards:
Okay, and this is the row your boat
Valeri_Karpov:
That's yeah, the row
Steve_Edwards:
example
Valeri_Karpov:
your boat example.
Steve_Edwards:
in his blog post
Valeri_Karpov:
Yeah,
Steve_Edwards:
on Provide and Inject.
Valeri_Karpov:
well you'll see like if you click the add button adds more rows, but the interesting thing about this example is you see how like the grandchild injects state. And then that's where, that's kind of where Provida Inject comes in, where like the top level component has like this state property that it provides down the tree. So then any child can access state.
Steve_Edwards:
Okay. Yep, yep. Visually it makes a little more sense. Definitely have to play with
Valeri_Karpov:
Yeah,
Steve_Edwards:
it. At least speaking
Valeri_Karpov:
yeah, hard
Steve_Edwards:
for
Valeri_Karpov:
to... I
Steve_Edwards:
myself.
Valeri_Karpov:
know, it's like, it's hard to talk about code and describe it in a
Steve_Edwards:
Mouth
Valeri_Karpov:
way that
Steve_Edwards:
coding.
Valeri_Karpov:
makes sense. Mouth coding is tough. It's a skill that
Steve_Edwards:
Yes.
Valeri_Karpov:
I don't think I have fully mastered yet, but I'm working on it.
Steve_Edwards:
Cool. All righty. So with that, mouth coding of Provide and Inject will move on. And we're going to talk about testing view apps with server-side rendering in Cheerio.
Valeri_Karpov:
Yeah.
Steve_Edwards:
And no, we're not talking about Serial. That's Cheerios. This is Cheerio, like the greeting, Cheerio. I'm guessing.
Valeri_Karpov:
Yeah, exactly. At least I think so.
Steve_Edwards:
s-
Valeri_Karpov:
I can't speak for Matt Mueller, the original author.
Steve_Edwards:
Okay. So tell us about this. This is new to me once you brought it to my attention, so I'm just curious to see how this library works.
Valeri_Karpov:
Yeah, oh, Cheerio is... The idea behind Cheerio is like you give it an HTML string and then you can basically do kind of like jQuery style selectors on that string. Now the idea behind using that Cheerio for testing is like you can now kind of like test a view component in Node.js without actually rendering it in a browser. is like when it comes to rendering something in a browser that comes with more operational headache, right? Like most likely you would run, most likely you would have to ship your code into like a puppeteer instance or a playwright instance or do something with Karma, all these tools for kind of controlling real live browsers or do something with JS DOM. I'm not a huge fan of JS DOM, but like. where Cheerio and Vue server-side rendering come in is like, Vue surprisingly works very well in Node, just without any extra additions. Like if you require Vue in Node and define a component, you can just render that component in Vue and render it as a string. So like in Vue 3, what happens, there's like, you can require in Vue slash server render. And that basically will take in a view app and render it to a string in Node. So now you can basically take the current state of a view component and render it as an HTML string, pass it into Cheerio and query to make sure, okay, I have a v4 that goes over a list of users. So now I can use Cheerio to be like, okay, I'm going to assert that there are three allies in this, that have this particular class in the string output or in this HTML string that view server render plugged out. So it gets testing, but testing like
Steve_Edwards:
you
Valeri_Karpov:
that view is outputting the correct HTML, if that makes sense.
Steve_Edwards:
Right, so this is what you would call more, is this sort of a comparison to something like Jest in terms of testing or is this different?
Valeri_Karpov:
Um, I like, you could probably use this pattern in Jest, but I don't know. I really dislike Jest. I mean, you know,
Steve_Edwards:
and he
Valeri_Karpov:
well,
Steve_Edwards:
doesn't say that in jest. Anyway.
Valeri_Karpov:
no, I don't Jest. I just don't recommend anyone ever use Jest for any reason. Maybe,
Steve_Edwards:
Oh, okay.
Valeri_Karpov:
maybe fine if you like, if you're just doing like some very like dedicated front end stuff where it makes sense, but like, honestly, uh, always a mistake to use Jest to test node app apps. So I guess we're talking views on view, so I can't speak for using just test view applications. But in my humble opinion, if you're using just the test node code, you're doing it wrong.
Steve_Edwards:
Okay, yeah I've used Jest before in previous place and it was already set up when I took over the app. It was more, what do you call it, functional testing, unit testing of the view code. This seems, I don't know, so Charyo, is your testing the structure of your HTML and not so much the output of your template?
Valeri_Karpov:
Yeah, you're testing kind of the structure of the HTML. So you're thinking about your app as something that outputs an HTML state, or just HTML. And you have the HTML as a string, and you're asserting that the string has kind of the correct elements. If that makes sense.
Steve_Edwards:
Right, okay, so you're testing it but you're not doing it with a browser, you're not having to spin up a browser and make sure that everything looks pretty. That's more along the lines, excuse me, more
Valeri_Karpov:
Yep.
Steve_Edwards:
along the lines of like a Cypress or a Dusk. Dusk is what I deal with on a regular
Valeri_Karpov:
Yeah,
Steve_Edwards:
basis
Valeri_Karpov:
yeah.
Steve_Edwards:
where you're
Valeri_Karpov:
I believe
Steve_Edwards:
clicking
Valeri_Karpov:
that's
Steve_Edwards:
buttons
Valeri_Karpov:
like...
Steve_Edwards:
and testing UI components.
Valeri_Karpov:
I believe that's like... is that what they call snapshot testing?
Steve_Edwards:
Now not so much
Valeri_Karpov:
Yeah.
Steve_Edwards:
snaps out as an end to end testing. I don't think it's snapshot. Snapshot is more like, now snapshot testing the way I envision is more from a design standpoint where you get a screenshot of a page and you want to, okay, this is in the right place, then this is here, and this is here, and this is here. You haven't really changed the output where the end to end that I'm talking about is, do your buttons work? Does it bring up this page? Do you get these values in a checkbox? Does this go away? You know, that kind of stuff. So. All kinds of testing. It's hard to keep up with all of them.
Valeri_Karpov:
Yeah, yeah, it is hard to kind of keep up with all the different testing patterns. And I mean, this testing pattern is it like a way, it doesn't solve all problems. I like it because it kind of lets me test like that things are rendering correctly
Steve_Edwards:
Uh huh.
Valeri_Karpov:
or like approximately correctly
Steve_Edwards:
Uh huh.
Valeri_Karpov:
in a way that's like fast and not very brutal, as in my
Steve_Edwards:
Uh
Valeri_Karpov:
experience,
Steve_Edwards:
huh.
Valeri_Karpov:
like I used to, I used to write like a lot of karma tests back like. seven, eight years ago. What always
Steve_Edwards:
Uh huh.
Valeri_Karpov:
happened with Karma was just like, random test flakes, timeouts. So I just kind of got burned out from browser testing and just decided that I like the idea of running my tests purely in Node so I don't have to worry about, okay, spin up a full browser, worry about timeouts and things going wrong. Things just run quickly and without as much issue.
Steve_Edwards:
Hmm.
Valeri_Karpov:
if that makes sense.
Steve_Edwards:
Yeah, interesting. So I'm reading through the front page on the Cheerio site, cheerio.js.org. And one of the points that it makes is that it's familiar syntax. Cheerio implements a subset of core jQuery. Cheerio removes all the DOM inconsistencies and browser crufts in the jQuery library, revealing its truly gorgeous API. So, you know, jQuery, you know, is still out there a lot and it seems to be on the downswing in terms of popularity for any number of reasons. You know, probably the biggest of which is that a lot of the stuff that jQuery did, the browsers have implemented, you know, so the problems that jQuery is trying to solve don't exist in a large case. And there's, you know, there's other various issues with it. But what it's talking about here, I found in a case a number of years ago when I was working on an app, using the form.io platform and I've had Travis on JavaScript Jabra a couple times to talk about that. But I had to navigate a ton of XML. A particular design app for large industrial vessels would generate a huge XML file and I had to parse it and get all kinds of different data, specific data and import it into my app to allow for project estimation, cost estimation. And jQuery is what I used.
Valeri_Karpov:
Yeah.
Steve_Edwards:
because it worked really well to be able to navigate children and parents and finding different elements and returning them and so on. From a visual standpoint, I haven't used jQuery in a long time since I was last dealing with Drupal. But from a core API standpoint, it does have some really cool features that make it easy for navigating things like this, XML, HTML, and getting what you need.
Valeri_Karpov:
Yeah, it's really neat. Although, I mean, in a lot of ways, I feel like Cheerio claiming it's like a jQuery-like almost feels like a bit of a misnomer. You can also say that Cheerio kind of implement is like document.querySelector, but for HTML strings. Well, is
Steve_Edwards:
Okay.
Valeri_Karpov:
that more correct? It was also pretty correct in the sense that, OK, it lets you do exactly kind of what you said. have like use like query select, like the selector syntax that jQuery made popular and then like, and then the browser implemented and things like document.querySelector. Use that same syntax to navigate an HTML string or an XML string for that matter. Because I think technically HTML is, is HTML a subset of XML?
Steve_Edwards:
Or is it the other way around?
Valeri_Karpov:
Or is it
Steve_Edwards:
I
Valeri_Karpov:
the
Steve_Edwards:
forget.
Valeri_Karpov:
other way around? Or is it kind of different? I think like the thing things like dock type tend to throw off like the exact relationship. I don't know. I'm not gonna pretend I know.
Steve_Edwards:
Well, I mean, it's not, I don't think it's claiming to be like jQuery, I think it says it implements it,
Valeri_Karpov:
Yeah.
Steve_Edwards:
a subset of core jQuery, so I haven't looked at the code, but I'm gonna, sounds like if you go in there, you'd see it importing some specific parts of jQuery.
Valeri_Karpov:
I don't know. I'd say kind of like one of the downsides of testing, like the way that I do it is interactions don't really work. Let's put it this way. So like you can't really do things like say click a button. That's
Steve_Edwards:
Right.
Valeri_Karpov:
not something you can really do in the browser. However, I like to structure my apps in the sense that like, okay, like a, how to put it? A button just calls a method, basically. So I don't test that clicking a button calls this particular method, but I test that calling that method on that component with this particular state gives me this particular HTML output, if that makes sense.
Steve_Edwards:
Right. Yeah. Yeah. So you're by, you're bypassing the UI triggers and just calling the code directly. And then it's, it's, it's basically unit testing is what it sounds like. You know, you're
Valeri_Karpov:
Yeah,
Steve_Edwards:
testing
Valeri_Karpov:
yeah.
Steve_Edwards:
do if I call this function, does it give me what I want? You know, regardless of how it's initiated from the UI.
Valeri_Karpov:
Yeah, in many ways it's like a unit test, depending on how you define what a unit test is, because that's a really nuanced topic that we can talk about all day. But yeah, it's, yeah, you do stub out, sometimes I do stub out the backend side of things. Sometimes I have ways to fake having a backend, or actually talk to a backend for those sorts of tests. But yeah, the big downside is no interactions, but the big upside is fast, reliable, and kind of, yeah, fast, not brittle, and minimal setup in the sense that, like, okay, if you write your apps in a way that mostly works for this already, then it's a neat pattern. You don't really need to do much other than like import view slash server renderer. And all of a sudden you can take a component or an app and chug out the, chug out what the HTML would be if it was rendered in a browser. So it's really cool.
Steve_Edwards:
Yeah, yeah, that makes sense. You know, you mentioned real quick, mocking of APIs. That's one headache I've never really gotten good at. I know there's a bazillion different ways to do them. You can do it in Postman if you wanna use a tool like that. There's JavaScript libraries that I've used in the past where you can mock up an API and then just call that. I know there's a number of tools. It's just one thing I've never really gotten good at. I always just use the real API if I can. This gets us a lot easier.
Valeri_Karpov:
Yeah,
Steve_Edwards:
for sure.
Valeri_Karpov:
if you want to make a test, it's a little bit trickier because then you need to spin up the API, right? And
Steve_Edwards:
Sure.
Valeri_Karpov:
that adds friction that may or may not be worth it, depending on your use case. It also
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
makes tests slower.
Steve_Edwards:
Right.
Valeri_Karpov:
So, like, yeah.
Steve_Edwards:
For sure, for sure. Yeah, testing and mock APIs, that's we could probably talk for days about that.
Valeri_Karpov:
She had that too.
Steve_Edwards:
So, all right, anything else about Cheerio and server-side view testing?
Valeri_Karpov:
Well, I guess on a related note we can talk about about using view to render email templates or we
Steve_Edwards:
Sure.
Valeri_Karpov:
can I guess that's something that I like to they also like to discuss is like well Right now I have I've switched to using view for for rendering server side emails So I you know, I when someone like checks out something and then checks it back in I sent when I send the receipt That's that's a view template rather it's sent through mailgun, but I use view to generate the HTML. And like, it's actually really neat. I'm a huge fan just because like it makes it very easy to say, okay, I'm passing in, uh, I pass in some props. I have like a name for like the email template I'm trying to send. So like, I, so when I say, uh, when I want to send the receipt email, what I do is I say like, okay, uh, you know, uh, uh, send email, uh, string receipt. That's the name of the, uh, the template. properties, bunch of options, whatever. And then we have like a receipt.html file that basically contains like, okay, how does the receipt file look like? Oh, I have a layout component that like renders the kind of the boilerplate for the email. So like the header, the unsubscribe link. service, whatever, and then the particular details of the receipt all in view. So like the four online items, all the neat things that you would expect to do in view, but done on the server side for rendering HTML emails.
Steve_Edwards:
So you're doing this from Node,
Valeri_Karpov:
Yeah.
Steve_Edwards:
obviously, right? So
Valeri_Karpov:
Yeah.
Steve_Edwards:
is that, can, is it similar to do something like that from other languages, like, you know, I deal with Laravel and PHP all day, is that, could you do something similar from like a PHP, or is that JavaScript specific the way that you're utilizing the view template?
Valeri_Karpov:
I think it's pretty JavaScript specific just because I rely pretty heavily on the fact that Vue more or less runs in Node.
Steve_Edwards:
Okay.
Valeri_Karpov:
So I can import Vue in Node and use that to render a bunch of HTML. Or I can just create an app, pass in a template as an HTML string, and then, okay, there I have something that I can render, basically. So I'm not
Steve_Edwards:
Okay,
Valeri_Karpov:
sure.
Steve_Edwards:
yeah, that would make sense.
Valeri_Karpov:
I'm not sure you could do that in Laravel because like, I mean, Vue doesn't run on PHP as far as I know.
Steve_Edwards:
Right, well, duh, that would sort of make sense, wouldn't it?
Valeri_Karpov:
Hahaha
Steve_Edwards:
So anyway, yeah, that's just where I live all day, so my work, so I'm just curious. But yeah, that makes sense that you could only do it from Node.js since it is JavaScript.
Valeri_Karpov:
Yeah, and honestly...
Steve_Edwards:
I mean, that's similar to anything else with the templating language, right? You just, you know, here's my template I wanna use. I mean, even if you're using Vue on the front end, that's what you're doing. Here's my data, my template renders it for me and spits it out.
Valeri_Karpov:
Yeah, that's kind of why I think of Vue more as like almost like a templating library or like a really good reactive templating library rather than as a framework right now. At least that's
Steve_Edwards:
Uh huh.
Valeri_Karpov:
kind of how I use it more right now. It's like I use it for like rendering on backend. I use it for rendering on front end. I love how like I'm just able to just like use HTML and CSS. And then just plug that into plug that into Vue.
Steve_Edwards:
Mm-hmm.
Valeri_Karpov:
and then kind of like standardize all my templating on Vue. Because at previous roles we kind of had it so like, okay on front end we have like React code, but on backend for email templating, we're using some ungodly mixture of handlebars and pug and whatnot
Steve_Edwards:
Hahaha.
Valeri_Karpov:
and it would just be like, why can't I just have one templating language that mostly makes sense for all use cases. So I've decided that Vue is that templating language for me, and I'm just gonna use it for just about everything that I can. And in Vue's defense, it does a pretty good job at all those things. So that's one of the things I love, or what I really love most about Vue, is kind of how versatile it is. Like I can plug it into all sorts of different places, and it mostly just works. Whereas, I don't know, I remember trying to... Go back six years, I tried to implement email templating in JSX, but there were issues with things like... I forget the exact issue, but I ran into some issue where I'm just like, okay, I can't do this, we're going back to handlebars, guys. Whereas, I
Steve_Edwards:
Hehehehehehe
Valeri_Karpov:
have not, I've been sending emails for years and can't be happier.
Steve_Edwards:
So, okay, so the way you're talking about using the view templates is basically the template portion of the view template within Node.js. So you're passing in, you know, whatever data you want to be passed in there. So, you know, the single file component has the template and it also has the script and style section isn't obviously so relevant here. Maybe it is. But when you're doing it inside Node like that, are you also using JavaScript in the script section? of a single file template, maybe for computed properties or some other feature in there or are you just using the template portion and in Node you've already generated all the text that you want to be in the template.
Valeri_Karpov:
I mean, you can use like computer properties and whatnot, and that works well as well. However, I don't really use single file components for that. I just, I don't use single file components in general. Kind
Steve_Edwards:
Oh, okay.
Valeri_Karpov:
of like, you know, view.component in JavaScript as opposed to a.view file. And again,
Steve_Edwards:
Gotcha,
Valeri_Karpov:
like,
Steve_Edwards:
okay.
Valeri_Karpov:
I guess that's one thing, that's another thing we were gonna talk about is like,
Steve_Edwards:
Yes.
Valeri_Karpov:
The fact that I like to have like separate HTML and CSS files for my components. So like, you know, like if I have a navbar component on my front end, like the way that looks is like, okay, folder navbar. The navbar folder contains navbar.js, which contains the component definition. Navbar.html, which contains the HTML template and navbar.css, which contains the CSS. I do similar things on the, I do pretty much the same thing on the backend for emails with the caveat that, well, you know, inline CSS for emails. So no CSS files there.
Steve_Edwards:
So your HTML file is just raw, HTML, no V4s, I mean obviously it's
Valeri_Karpov:
Well,
Steve_Edwards:
just
Valeri_Karpov:
it
Steve_Edwards:
straight.
Valeri_Karpov:
does have to have a v4 and it does use like v4 and vf and whatnot.
Steve_Edwards:
Oh, inside your HTML templates?
Valeri_Karpov:
Yeah. Yeah. But.
Steve_Edwards:
And then you just, so, okay, so you've got your.html file, your.js file, and your.css file, your
Valeri_Karpov:
Yeah.
Steve_Edwards:
styles, correctly? Okay, so from Node, you're calling the.js file, which imports the HTML and the CSS and sort of generates. one
Valeri_Karpov:
Yeah.
Steve_Edwards:
template.
Valeri_Karpov:
I don't
Steve_Edwards:
So
Valeri_Karpov:
know.
Steve_Edwards:
the data is being passed into the JS file, right? And then when it calls the template, that's where it says, okay, this goes here, this goes here.
Valeri_Karpov:
Yeah, exactly.
Steve_Edwards:
Hmm, okay.
Valeri_Karpov:
Yeah, so that's how things work on the back end.
Steve_Edwards:
And this is, but this is where you're using, your JS is using the view.component and then defining every everything
Valeri_Karpov:
Yeah,
Steve_Edwards:
inside
Valeri_Karpov:
exactly.
Steve_Edwards:
of there.
Valeri_Karpov:
So what I have is a send email function that basically does, OK, view.createApp, put in the properties that are passed in as data, either as data
Steve_Edwards:
Mm, okay.
Valeri_Karpov:
or as props. I forget exactly off the top of my head. But by the way, create an app. put the data into the app, pull the template that was passed in using a fs.read file, and generate the HTML, send the email.
Steve_Edwards:
Yeah, I guess the one thing that always makes me nervous about template strings like that and view.component and stuff is when you're dealing with quotes and making sure you know you got single quotes inside double quotes and you don't have double quotes and double quotes and all the, you know, quoting of strings and making sure you don't have any errors. Is this where the Cheerio testing would come into play? Does it test this kind of stuff to make sure that everything is... is being constructed properly and actually being output.
Valeri_Karpov:
I mean, Cheerio would help with that, but honestly right now, I don't have anything too sophisticated there. I just kind of like, okay, there's HTML. It seems to work, so I'm good. Also, syntax highlighting helps with that. And again, one of the neat things about using HTML for templating is just about every code editor has built-in support for HTML syntax highlighting, so I don't really need to do any extra work to get.
Steve_Edwards:
Oh, right, okay.
Valeri_Karpov:
So you pull it up in GitHub and GitHub will probably highlight places where you've got incorrect HTML syntax. And then again, I'm sure there's a bazillion linters out there that can lint HTML for you. And I think I could be wrong, but I would imagine it's easier to set up something that lints plain old HTML files as opposed to something that lints of USFC, but I could be wrong.
Steve_Edwards:
Okay, yeah this is one of those things that I'm gonna have to sort of see, see how it works because I'm trying to imagine my head and my head is spinning. So that happens all the time anyway. So excellent. Alright I think we've covered everything we talked about covering, unless I'm incorrect. Anything else you want to talk about real quick or that we've missed before we move on to picks?
Valeri_Karpov:
Let me see here... Whatever we want. Oh, we did talk about how you import HTML on the front end.
Steve_Edwards:
Yes, that would be good to know. That's one topic you hear about. I've heard mentioned frequently in other places a frustration with the HTML spec is that you can't do that. Just straight HTML unless there's been something slid in that I've missed recently. But the way frameworks do it all the time, import one component into another and it would be nice to be able to do that with straight HTML. So how are you doing that?
Valeri_Karpov:
I mean, Webpack and Webpack, well, Webpack 5 has like built-in support for pulling in kind of like assets as plain strings. So there is, let me pull, what was it again? Oh, yeah. And so like Webpack's config, like module.rules, you can tell, you can tell Webpack to pull in.html and.css files as what's called like type colon asset slash source. And that basically tells Webpack that like if I'm importing an HTML file, that you should just give me that the contents of the HTML file as a plain old JavaScript string. Or a.css file, get me the contents as a string. So like if you're using Webpack for that, that just makes it about as easy as it can be. You just get like an HTML string and you plug it into Views template property and that's done. Easy work.
Steve_Edwards:
Easy peasy.
Valeri_Karpov:
Yeah, easy peasy. And then on Node, it's also kind of easy because there's, Node has like this require.extensions thing, which basically lets you very easily tell Node like, oh, if you require a.txt file or a.html file or a.css file, just get me that as a string. So like just do fs.readfilesync. So that one, so yeah, it's surprisingly quite easy. And I would like, I find it kind of surprising that other people don't do that as often. Just because like, you know, A lot of advantages to using HTML and CSS files for templating, most notably, at least in my experience, it's like much easier to just like hire someone who just is gonna like put together some HTML and CSS for you, and then you can kind of integrate that into your view application, as opposed to kind of getting someone set up, just working with the entire, the entire front end app. So like, one of the things I often do is like, oh, I have, I play it like. client asks for this new, this new like, what do you call it, this new page. The page is complicated, okay. I'm probably can just like, you know, throw it off to someone to do this HTML and CSS and then like kind of clean up the HTML and CSS and integrate it into Vue on the way back, as opposed
Steve_Edwards:
Right.
Valeri_Karpov:
to having someone go in and just set up the entire Vue app, set up the backend, set up a seed script, make sure their entire dev environment is set up. So I... Having HTML and CSS gives you like this neat little separation where you can say, okay, like now I'm just, now this is just going to be an HTML and CSS land. And it doesn't have anything to do with view or the backend or anything. It's just a, just pure design. And then once that comes back into the, uh, comes back into the app, now we can do some stuff to integrate it, make it reactive, make it interactive, all that.
Steve_Edwards:
Yeah, that's one of the strengths of the View Single Pile component, as I've seen mentioned, is that it is, for the most part, HTML, although you have custom components and stuff like that, that you could... It's easier to give to a designer than maybe something in JSX, right?
Valeri_Karpov:
Yeah.
Steve_Edwards:
But yeah, for someone like that who's not familiar with JavaScript and just wants to make it look good, having base HTML certainly makes sense that it would be a lot easier.
Valeri_Karpov:
Yeah, yeah, it lets them do what they do well without having to get all set up with, well, the entire stack.
Steve_Edwards:
Right. Right. All right, excellent. Well, we've covered a decent amount of topics today in our short time, so thank you for coming on. With that, we'll move to picks. Did you have anything to share with us?
Valeri_Karpov:
Let's see. When I was on summer vacation recently, I was reading the new World White novel that came out in July called Dread God. It's really good. It's book 11 in the Cradle series. It's a very, very long series, but it's a lot of fun. I'm enjoying it. It's kind of like my favorite thing to just read and relax on like a lazy Sunday afternoon.
Steve_Edwards:
So what genre is that series? Is that like fantasy
Valeri_Karpov:
Um,
Steve_Edwards:
or science fiction or?
Valeri_Karpov:
mostly fantasy with a little bit of sci-fi sprinkled in. Like, I kind of joke that like the Cradle trilogy is just like a really long extended Naruto with like a little bit of space, with a little bit of like space gods thrown in. It's, yeah, that's pretty good summary of it, but no, I'm a big fan. It's like a really compelling read. Good page turner.
Steve_Edwards:
Good, okay. For my picks, I haven't had anything really standing out that I want to talk to. I will say that I've been reading through, just my son and I, my 11 year old son, we read every night and so we finished The Hobbit. So now we are on to The Lord of the Rings. So enjoying reading through that for sure. It's interesting. You know, I haven't read the books in... I don't know, 20 years, I think, Lord of the Rings, maybe a little less, it's been a long time. But I've seen the movies, like many people have, and have them on DVD, and so I've watched them a few times. And it's interesting after seeing the movies, and the movies that are, were a pretty good representation of the book. I think that was one, as compared to The Hobbit movies that they made after that were god awful. But it's interesting to go back to the books and then realize a lot of the stuff that the movies had to leave out. and some of the other details like in the first book there's the whole interaction with Tom Bombadil, you
Valeri_Karpov:
Yeah.
Steve_Edwards:
know, the scouring of the Shire at the end and stuff, but it's interesting. It's fun reading them again, especially with my son. He's really into them. You know, we're pulling up
Valeri_Karpov:
Yes.
Steve_Edwards:
interactive maps that there are on the web about, you know, Middle-earth, Third Age of Middle-earth, and where everything is just so you can sort of envision the journey and where they were traveling and stuff, but definitely fun reading through that again.
Valeri_Karpov:
Yeah, that is really cool.
Steve_Edwards:
with my
Valeri_Karpov:
And
Steve_Edwards:
son.
Valeri_Karpov:
I'm actually, well, when I started reading Dread God, I was about halfway through to Towers because like I honestly have never finished reading the Lord of the Rings trilogy. So I'm like hoping to make
Steve_Edwards:
Oh
Valeri_Karpov:
my
Steve_Edwards:
really?
Valeri_Karpov:
way. When I was 14, I tried to read Fellowship. I got like two thirds of the way through. But I think like I was maybe like one or two years too young to really get into it. I think like if I had read it when I was 16, I would have absolutely loved it. But at 14 and 13, I was like a little. It didn't really, it wasn't really as compelling. I did read The Hobbit and The Hobbit was great. Like, yeah, now that I'm like halfway through the Two Towers novel, like I was pretty, one thing I was surprised about was like, um, like in the Two Towers movie, like half of the movie was just the Battle of Helm's Deep. And like, which was great, it was, it was like really just amazing, like, special effects and great to watch. But in the book, it just seemed like the Battle of Helm's Deep was like three pages, where it's just like, oh, and the orcs started attacking. And then it's like, oh, and then it's morning and the orcs have been defeated three pages later.
Steve_Edwards:
Hahaha
Valeri_Karpov:
I was like, oh, I expected that to have like a little bit more beat on it, given like how much weight it was given in the movies.
Steve_Edwards:
Oh, right. Yeah, I mean, I was like you. I did the exact same thing when I was probably early teens. I won't say how long ago that was, but where I got about halfway through the Fellowship of the Ring and it was pretty slow and just didn't capture my attention for whatever reason. But then years later, probably in my 20s, I was in my 20s, I think, that I picked them up and read them. I remember getting... so caught up in one of the particular battles I think. I think it was in the two towers. Back then I would ride my bus into work in downtown Portland and I remember missing my stop time or two because I was so engrossed in this book that it kept me going. Now in terms of movies also, some of you may remember, there was a Hobbit movie made in 1977 and it's animated and it has a number of actors Orson Bean I remember was one of the primary actors. He played the Gandalf or Bilbo I don't remember. Have to look it up. And so my son and I went back and watched that. I dug it up on the way back machine I think. You can get it on Amazon Prime too but it's about an hour and 20 minutes but some places it's pretty good but some places it's really bad. But it really condensed a lot of things, really skipped over a lot of things in the Hobbit. But given the time and technology that was available at the time, it's not bad. It gives a pretty good overview of the story
Valeri_Karpov:
Yeah,
Steve_Edwards:
and how it all went.
Valeri_Karpov:
that sounds like fun. I wanna check that out. And I'm excited for when my daughter gets old enough to read books like that. Right now, she's just gotten to the stage where she appreciates where's spot. Or like she always just...
Steve_Edwards:
Thanks.
Valeri_Karpov:
She's finally gotten old enough where she like, she realizes that like when I open the flap and say no, she just laughs every single time. It's great. So I
Steve_Edwards:
See
Valeri_Karpov:
am...
Steve_Edwards:
you spot, see you spot run, run spot run.
Valeri_Karpov:
I know, like, Worst Spot is just like, Worst Spot, he hasn't finished his supper. Is he in the cupboard? No. And every time I open up a flap and say no, my daughter just loses her mind laughing. It makes me so happy.
Steve_Edwards:
And the simple games like Candyland, right, or something like that.
Valeri_Karpov:
Yeah, yeah.
Steve_Edwards:
So anyway, onto the dad jokes of the week. These are, I know for some people, the absolute highlight of any of my podcast episodes, but they're still good. So when I was young, I was poor, but after years of struggle, I'm no longer young. Thank you. Thank you. You know, a lot of people always talk about side hustles or ways to make money outside of the regular work and so on. And so, you know, investing is a common like stock market investing. Some people will play in that. So I've started investing in stocks. First I invented it, excuse me, invested in chicken and then beef, now vegetable. So despite the potential risk, I believe one day I will be a billionaire. And then finally, sometimes I think about inventing things, just to try something new to help people out. Sort of like software, you know, you scratch in it, you put something out there and people like it. And so I decided I wanted to create a product that's a combination of things. It is a laxative, but it also contains Advil for the pain. I'll call it Ibuprofen. Thank you, thank you.
Valeri_Karpov:
I'm working on my second million, the first one didn't work out so well. That
Steve_Edwards:
Yes, exactly.
Valeri_Karpov:
was a good one.
Steve_Edwards:
I sk-
Valeri_Karpov:
That was another finance
Steve_Edwards:
Yes.
Valeri_Karpov:
one that I thought was great. I settled.
Steve_Edwards:
Yeah, and that's true. I am working on my second million. I gave up on the first one a long time ago. All right, with that we will wrap it up for this week. Thank you, Val, for coming on yet again and enlightening us with your knowledge. Where can people get a hold of you if they want to hear your wisdom or give you money or something like that?
Valeri_Karpov:
Oh, yeah, thanks for having me, Steve. Yeah, you can find me on masteringjs.io. I'm on GitHub as well, vcarpov15. And on Twitter, I am at code underscore barbarian.
Steve_Edwards:
And me, myself, and I, I am wonder95. You can find me there on Twitter and GitHub and just about anywhere else really. That's my name from many moons ago. Thank you again, Valve, for coming on and we will talk at everybody next time on Views on View.
Providing, Injecting, Testing, and Templating Using Vue with Valeri Karpov - VUE 194
0:00
Playback Speed: