Join us for a workshop in which you’ll deploy a simple Node.js app built with Web Components and set up a Continuous Integration (CI) workflow. You’ll learn about the power of the Lightning Web Runtime (LWR) and GitHub Actions.
Deploy a Web Component App and Set Up a Continuous Integration Workflow
AI Generated Video Summary
We'll be using Node version 14 or 16 and GitHub Actions for continuous integration. We'll create a Lightning Web Runtime application and assemble web components into a single-page app. We'll add code quality tools and explore configuration files. We'll set up testing, create a Git repository, and configure CI workflows using GitHub Actions. Finally, we'll explore bonus tasks such as adding badges to the readme and creating pre-commit hooks with Husky.
1. Introduction to Workshop
We'll get started with the workshop. We'll be using Node version 14 or 16 and GitHub Actions for continuous integration. We'll create a Lightning Web Runtime application and assemble web components into a single-page app. Then, we'll set up code-quality tools and put the product in a new GitHub repository. In the third part, we'll configure a workflow using GitHub Actions and test the continuous integration workflow. Finally, we have bonus tasks if we make good progress. Let's get started with the first part of the workshop, where we'll create a Lightning Web Runtime application using the NPM in its LWR scaffolding tool.
We'll get started. One of the key things you want to check looking at the prerequisites is making sure you have the right Node version. We're looking for Node version 14 or Node version 16. You want to run Node-v in your terminal to make sure that you are using the correct version for Node. Some people may have multiple Node versions in their systems. So let's make sure you don't bump in any surprises by not using the right version.
All right. Well, let's get started. Hello, everyone. Thanks for joining. My name is Philippe Oziel. I'm a DevOps Advocate at Salesforce. In today's workshop, we're going to take a look at how you can use Web Components app and how you can set up a continuous integration workflow using GitHub Actions. So, all of the instructions, again, are in this GitHub repository. You can find the link in the chat there. And we're going to be together for the next two hours. I'm going to be giving you the instructions and you can try to replicate those on your computer. One thing I want to stress out is that I'll be trying to look at the chat, but don't hesitate to ask questions as we go forward. This is an interactive format. I'll try my best to answer while moving forward. We will also try to do a break in the middle so that people who are late can catch up.
2. Exploring Project Structure and Files
Thanks for the answers that I provided. And it will retrieve them from the NPM registry. So this can take a couple of seconds depending on your network speed. And it's assembling the list of dependencies here. The next step is going to be to open a code editor. So here you're very free to use whatever editor you prefer. For my part I use VS code. So I'm just going to do code and dots for the current product, but you can use another editor if you want.
The idea here is that you want to open the... But you're going to open the project repository. So before I give you the next instructions, I want to give you a tour of the products. I'm going to wait just a few seconds for you to catch up. Let me know when you're ready to proceed. And we're going to look at the project structure, the different files and folders that were created and how they were structured. And then we're going to look at the code as a whole. The files and folders that were created thanks to the scaffolding tool. If the build script is still running in the background, don't worry, you can follow what's going on here. Let's take a look at what has been generated for us.
So, first of all, we're going to look at package.json. This is a very simple node project descriptor. You'll see that there are very little dependencies here, there are two of them actually. The first one, LWC, is the framework that we use to build web components. So, it's Lightning Web Components. It's a Salesforce framework that builds on standard web components with just a bit of syntactic sugar to make it easy to use and quick to deploy. And the second thing that we have is LWR for Lightning Web Runtime. And this is really the backend side of Lightning Web Components. So this is a framework that runs on Node.js that will help us aggregate a number of Lightning Web Component pages. It will be doing routing, caching, and things like that that are more on the backend of our server. And these are really the two dependencies we have in a default project. Now, there are a number of scripts also that are available here that we'll be using later on, and I will explain some of them. The one we're going to be relying on for this workshop is the dev one. And this is essentially running the Node server in watch mode. And we have a little shortcut. Instead of just running directly Node, we are using the LWR script to setup our server so that it runs the right tasks for us in the background. And we're using serve mode, which does live updates. So let's look further down in the different files we have.
3. Exploring Web Component Structure and Live Update
We explored the structure of a Hello World application using web components in the Lightning Web Runtime. We learned about the template HTML5 tag and how it allows us to inject fragments of pages as web components. We also discussed the concept of shadow root, which provides isolation and protection for web component content. Additionally, we saw how to run the developer mode for our application and observed the live update feature in action. Finally, we examined the lwr-cache folder, which contains compiled code and modules for efficient performance.
For example, here we're using the template HTML5 tag. So this is a standard tag that is part of the HTML5 spec. And it allows us to build fragments of pages that can be injected as web components. And everything that is inside this template will be injected as an HTML component or web component within a page.
So very simple, but this is the structure of our Hello World application. Now let's move on to the next step, and this is where I'll need you to type npm run dev in a terminal. So at this point, if your IDE supports it, you can run these tasks directly within your IDE. So for example, here in my VS Code, I can just open a new terminal, and I can run this directly from here, npm run dev. I will close my other terminal. We no longer need this one. And we can have everything here in a single window.
So at this point, we've run the developer mode for our Lightning Web Runtime application, and we can see that our application is running on port 3000. So all we need to do now is open this URL localhost 3000 to get it running. And I'm going to do that in a new tab. Here you can see as I opened the app, the Node server is actually watching the changes for the resources that are being viewed in the app. And this is the Hello World app that is represented by this template here that we built. So just an image that is in the assets folder and our Hello World H1 element here. Very simple, right?
Now let's take a look at this and see how it's interesting because you can do this with raw HTML, but I'm going to show you why this is a bit more advanced than just a static HTML site. What I did here that you cannot really see is that I pressed F12 on my computer, on my browser. So that I could open the developer console for Chrome. And if I inspect my elements, for example, if I inspect Hello World, I can now open the elements of my pages.
So at this point, I hope everyone was able to see the hello world application, that everyone was able to configure it. And what we're going to do now is make sure that the live update works. So we're going to be opening our HTML file here, the app.html file that is under modules, examples and app, and we're going to be changing something here and making sure that the app refreshes because we're supposed to be in watch mode. So let me just close this, put it a bit on the side. And I'm just going to replace the keyword here called world with lwr. And if everything goes well, our browser will refresh. So I'm changing the file, and now one thing that I forgot to write in the instructions, but it is actually very important, you need to save the file because otherwise the change won't be detected. So as soon as I hit Cmd S or Ctrl S to save the file, here you can see that my browser got the change and recompiled our code. You can see here, it detected the changes and updated the page. So this is how the watch mode works, and this is how you can do development at runtime. And you can see that in my product I have a folder called lwr-cache, which contains our compiled code or modules, all of the different web components that are inside our project trapped in a convenient cache. So I won't go into the content of the cache, but just to show you that when you're building this, there is a cache that is being put in place so that it goes really fast. Obviously the cache is not being used that much when we are in watch mode, but as you're moving into production mode, the cache here is pretty fast and efficient.
I hope that everyone's still following I'll be looking at the rest of the instructions now. So we have our first web component application, I'll show you the elements, I went a bit faster here to show you the different elements. Of our application, you can also do this yourself if you want to inspect the components and see, again, the custom elements, the shadow long root, the shadow root elements. And you can really see the basics of web components. So this is the first part of the workshop. Really, the basics of setting up a project, and let's continue with the second part now. Unless you have questions, obviously, which I can take any time. For the second part, we'll be looking at how we can add some code quality tools. Right now, we saw that our product has a minimum number of dependencies, it's not doing much.
4. Adding Code Quality Tools
In this part, we'll add code quality tools to our project. We'll modify the package.json file to remove the 'type module' and add a list of development dependencies for testing, formatting, and linting. These dependencies include Jest, Preacher, and ESLint, along with their respective plugins. We'll also add scripts to run these tools and copy the necessary configuration files. This will ensure that our project has the necessary code quality tools and configurations in place.
For the second part, we'll be looking at how we can add some code quality tools. Right now, we saw that our product has a minimum number of dependencies, it's not doing much. And so, we can improve it a bit by adding some tooling. So, what we're going to do now is we're going to open again our package.json file, which contains the project dependencies. And we're going to modify a few things.
The first thing we want to do here is remove the type module. The reason why we're doing this is that we're going to be adding some tests later on in the project. And we're going to be using Jest for this, but Jest doesn't really work well with modules. So we're going to go back to regular projects. So I'm just going to remove this line, test module, and we're going to work in classic Node project here. And then I'm saving this.
The next thing I want to do after this is adding a bunch of dependencies. So here, there's a large list of dependencies, and I will go over them just as the script runs. There's a big, big, big line of dependencies we're going to add. I suggest that you use this little convenience icon here for copying the entire line instead of just trying to wrap everything because you don't want to miss anything here. So just copy the line here with all the dependencies and these are all development dependencies. So you can see here there's quite a few of them. And I'm going to hit enter, and this is going to add all of these dependencies to my project. So while this is working, we'll see in a few seconds the list of dependencies being added here. And I'm going to explain a bit what these do. Because I think it's important that we understand the list of dependencies. We're essentially adding three key things. We're adding Jest for testing, Preacher for formatting, and ESlint for linting.
5. Exploring Configuration Files
In this part, we'll explore the different configuration files for our developer dependencies. We'll discuss the purpose and content of each file, such as .eslintrc for linting rules and eslint.config.lwc for recommended ESLint rules. We'll also cover the importance of excluding certain files and folders, like cache and coverage, from the git repository. Additionally, we'll examine the pre-ture ignore file for preserving automatically generated files and the PreToRC file for setting formatting rules, including the override for Lightning Web Components. Finally, we'll look at the jest-config file, which extends the defaults for the Jest plugin and provides shortcuts for module imports.
It doesn't matter. We'll be using the content of the CI folder in other steps. But for now, I need you to grab.ts.link,.gnore,.pretyoregnore,.preturerc, and just a config file. All of these are specific configuration files for our developer dependencies. I will just do that. I'll just copy this here. Preetify. Actually, we want to put them at the root of our project and in the subfolder. Be careful to place them in the right level. I will explain the content of these files just after I want to make sure everyone has enough time to copy the content here.
For git-ignore we have quite a few things, mostly junk temporary files that are being added here. It's not critical, if you forget about it. But one thing that is important, I would say, specific to this folder, to this project, is adding the cache to the ignore list because you don't want to include cache in your git repository because it can generate a lot of noise and unnecessary changes. So make sure that you at least have this one, the other ones are more optional. The next one is the pre-ture ignore. Pre-ture is going to be looking at the formatting for a lot of different folders and files, and so we want to make sure that we do not change certain files that are automatically generated. So VS Code, in my case, it's my VS Code preferences. Slash coverage is if you generate the code coverage for the tests for your project, it will create a coverage folder at the root of your project. So you don't want to change this, because this is automatically generated. And by the way, this is also something you want to exclude from Git. The dist folder is when you build the package. We're not going to redistribute the package, we're not going to use the production mode so we won't have a dist folder. And there's, again, the caching and the resources. The resources here are excluded, and actually it's... I made a mistake. It's not resources, it should be assets here, but this is only important if you start adding some text in your assets, static assets, like if you have a JSON file for data, but you want to keep track of so you don't rewrite it, you could be excluding assets. In the end, most of what will be rewritten is the configurations of the root of the product and also everything that is under modules when you work with any web components.
The next one is PreToRC, which is pretty close to a template with the base formatting rules. You can obviously fine-tune them to your liking, but this is, I would say, a basic set of instructions. I will not detail all the rules here, but I think what is really important here is the override, which is really important, critical for working with Lightning Web Components. When you are working with Lightning Web Components, most of the syntax in your HTML file is standard HTML, but there are certain rules, certain things, like templating, which are specific to Lightning Web Components. So we need an override and not use the default HTML parser, we need to use the Lightning Web Components parser for PreToR when working with HTML files. Otherwise, you'll see some errors. So it's important to have this particular override when looking at HTML files in PreToR. And finally, the last thing we need is the jest-config. This is going to be useful when we're going to be adding tests, and what it does is that it extends the defaults for the Jest plugin for Lightning Web Components. That's a good start. And then it also provides shortcuts for our modules. And you've noticed that our first Web Component is nested pretty deep— not pretty down, but several levels down in our project center. I saw C-module's example app. So the class app.js is something which you would need to call with a long path. And instead of having to import it by using the full relative path, we're actually building a shortcut here with a regular expression. So when we want to refer to the app.js class here, we can just import it with example-app.
6. Setting Up Testing and Git Repository
This is a pretty convenient shortcut we'll be using in our tests. And another thing we are using is... here is a parameter for the landing web component test mode using Native Shadow DOM. That is because there are several other options for configuring Shadow DOM. You can actually use a synthetic Shadow DOM, which is a polyfill for older browsers but does not support the Native Shadow DOM. But here, we're using the real thing, we're using Native Shadow DOM supported by the browser itself.
All right, now we've set up all of the dependencies for tooling, at least to run in our local environment, we can move forward and start pushing our code to a source-controlled repository, and we'll be using GitHub to do that. Oh, the first thing we need to do before even talking about GitHub, we need to set up our local Git repository. And here we're going to be using the Git CLI to do a couple of things. I'm going to run the git init command here, and this creates an empty Git repository on my machine. So this is just on my computer, this is not online or anything, and there's no history information at this point. But you can see already that my command line changed here. I'm working on a main branch at this point, and I do have some changes in my product. Obviously, we can do this with the command line, but we could also use a more graphic user interface here to do this. And you can see here that these are all the files that I have in my project, obviously without the files that are covered by git ignore. So we're going to be using the CLI here so that we can move forward very quickly. I'm going to do git add dot at the root of my product. This is essentially adding all the files that have been modified in my product. I'm going to put them in staging mode. So when I do this, it will take the 14 files that I have modified and put them in staging mode so that they're ready to be committed. And I will run the last command here, which is a commit, with a message. I've used here a message from my comment. I'm using the conventional comment style here. If you're interested, you can read more. It's basically a structure to describe what these comments do. There's a comment prefix, whether it's a feature, it's a fix, or something that deals with the build or CI, and then a short message just after. So here I'm just saying this is a feature, this is the initial comment for my repository. And then I commit my changes, and now I have a local Git repository with a small comment history of just one comment with my changes in there. Again, everything is just in my computer at this point. Nothing is in GitHub. So the next step is to go to GitHub, and you want to log in there and you want to create a new repository. So I'm going to just use this URL here. I'm going to create a new project here.
7. Creating GitHub Repository and Setting Up CI
To start from scratch, delete the previous project and create a new repository on GitHub with the same name as the project. Follow the provided instructions to set up the remote repository and push the local main branch to GitHub. After completing the instructions, reload the GitHub page to see the files in the repository. In part three, we'll focus on continuous integration by adding CI to our GitHub repository.
Actually, I will need to delete. I had a previous project. So I'll just make sure that I delete my previous project before. And my repositories, let's see. Yeah, here, let me just get rid of the previous product that I did for my tests. And I will re-create and we can go over it together as I re-create the project. All right, deleting this project. There you go. So now I can start from scratch.
So when you're on the GitHub home page, you can already have next to recent repositories a new button that you can use. I think this is the simplest way to go forward. So I'm going to click on new here. And this will ask me some basic questions on how I can create my repository. For the sake of simplicity, I'm going to keep the same name as the project. So I'm going to call it LWR project. And this is the name that you should have in your editor at this point. The root product is the default name when we created the project. So I'm going to keep it this way. You can put it public or private. It doesn't really matter here. For what we're going to do it, we can keep it private. It's perfectly fine. And you don't have to check anything here. Just go directly at the bottom and click create repository.
Now that the repository is created, you have a URL that you can remember easily to get back to it. And there are set of instructions here. Now, what we want to do is follow this second set of instructions, because we already have a local repository. So we want to follow the instructions from here. So simply copy this whole block of free lines here, and you want to run it in your terminal, inside your project. So copy, paste. There you go. The first thing adds a remote origin, saying that there's going to be a remote repository tracking your local repository. The next thing, the second line is actually not needed. We're already on the main branch, but this would force the local branch to be renamed to main. So this is not really needed. And the third one is really important. We are pushing the local main branch on the remote origin, so on GitHub. And we are making sure that we keep track of this branch as we move forward with all the comments. So I'm going to go enter, and it will do everything for me. Now, you want to make sure that the last line here is correctly saying that branch main is set up to track origin main. Or origin being the remote, which is GitHub.com. If everything went well when you did these instructions, you can now go back to the page here on GitHub and just try to do a reload or refresh, and you should be seeing all the files from your product. And obviously the readme is just the boilerplate readme, but at least you have your own configuration files that you just added, and you can see in the package.json that you do have the extra script you added, everything we did so far.
I'm going to leave you a few seconds to make sure that everyone catches up. So this is the end of part two, and we'll be looking at the next step afterwards. Just keeping waiting a few more seconds for everyone to get ready for part three. In part three, we'll be looking at continuous integration. So we'll be using our GitHub repository, and we'll be adding CI to it, so that we can run the code quality tool we set up locally to be run remotely first.
8. Setting Up CI Workflows
We'll be building two CI workflows: one for the main branch and another for checking pull request content. The workflows will ensure that the main branch passes a set of checks and that pull requests are verified before merging. Although the workflows will be similar, production environments may have different checks for the main branch and pull requests.
All right. I'm going to give you a couple more seconds, and we'll be looking at GitHub Actions to test on project and set up CI workflows. We're essentially going to be building two CI workflows. One of them is going to be running on the main branch. So it's going to be making sure that everything is on the main branch, passes a set of checks. And we're going to be adding another one, which will be checking the content of pull requests. So the scenario we're going to follow is actually each time someone does a pull request, we want to verify the content of the pull request before merging it into main. And then once it's been merged into main, we want to rerun a check to make sure that the main branch is always valid and always passes CI. The two workflows are going to be very identical. Obviously, in a production environment, you would have different checks that you'll be running. You'd probably have more checks running on the main branch than you have on PRs, for example.
9. Setting Up CI Workflows
For continuous integration, we'll use GitHub Actions. Set up GitHub Actions by creating two folders, .github and .workflows, and copying the provided CI YAML files. The workflows are triggered by a push on the main branch or a pull request on any branch. The CI workflow includes a job that runs preacher, ESLint, and Jest to check formatting, linting, and run tests. The unit test part is commented out to ensure CI passes before adding tests. Commit and push the configuration files to the remote GitHub repository. Check the status of the CI workflow on the GitHub website in the Actions tab.
All right, let's take a look at part three now. So for continuous integration, we're going to use GitHub Actions. And to set up GitHub Actions, it's pretty simple. You need a special set of directories and files. And everything is going to be taking place in our project file folder. So what I'm going to do now is I'm going to create some new folders. At the root of my project, I'm going to create a dot GitHub slash workflows folders, so two folders. The first one is dot GitHub, and then we have dot workflows under GitHub. Now, we are going to be copying two files that were provided in the base repository with the instructions here. If you copied them over from the previous part, you can just move the content of the CI folder directly under workflows here. If you haven't copied those two files here already, you can go and open the directory here and copy the content of these two files. So that's what I'm going to do here. I'm going to create the two files CIPR-YAML with its contents and CI.YAML. As you can see by the name of these files, these are two workflows and CI workflows. And one of them is working directly on the main branch. The other is the one that is going to be running on the pull requests. So on other branches that you want to merge in in Main. So I mentioned this earlier, but the two files are very similar. If you want to compare them, you'll see that there's very little difference. There's only four lines that are different. Obviously the name is different, but also the trigger for the workflow, the CI workflow is different. But the rest, all the steps are identical. So let me carve basically really quickly the base structure of a GitHub Actions CI workflow. The CI workflow is configured as a YAML file, it has a name. This is what the, what is gonna be used in user interface that you can see in GitHub to follow the execution of your tasks. It has a set of triggers that are described by the on property here. There are a number of triggers. The first one that I've added here is a manual trigger. Workflow dispatch means that you can use the github.com user interface to manually trigger the CI workflow. If you don't have this trigger here, you cannot start it manually. So this one is very convenient for testing. If something goes wrong, you can execute manually at any time a workflow. The other one, which is different from the two branches, workflows is the trigger. This one is the base CI workflow, and it's actually being triggered when there's a push on the branch and the main branch. It's kind of simple to read. When there is a push on the main branch, it will run the CI workflow. Now after that, the file is structured in jobs. Jobs are the high level sets of groups of tasks I would say that are visible in the user interface. And in our case, we only have one job, which is called format lit and test. And this is the same set of instructions that I've instructed you to test when we're working on the part 2. It's going to run preacher, it's going to run ESLint, and it's going to run jest to run tests. And then, most importantly, you have the list of steps that you're going to follow. So I'm not going to cover all of these in details, but what we're going to do is check out the content of the GitHub repository, install a couple of node dependencies. We have some specific instructions to cache the dependencies so that it goes faster. And then if you scroll down to the end, these three last instructions are the ones that are really important. We're gonna use our scripts that we've added earlier to check the formatting. Here, we're gonna use the verified version of the format script, because we are not gonna rewrite the file. We just wanna make sure that they match the creature configuration style rules. Then we're gonna run linting. And finally, we will run tests. Notice that the last part, the unit test part is actually commented out, and the reason why I've commented this out is that you do not have tests at this point in your project, so we want to make sure that CI passes before we start adding tests. So this one is disabled for the moment. We will enable it later on. But you already have the template in here so that you can move forward faster. Cool, so we saw our two YAML files. Again, very similar files. They just have different triggers because one is working on a push on the main branch and the other one is working on a pull request on any branch. All right, so now that we have our two configuration files for the CI workflows, what we need to do now is to commit them. And I'm gonna be running the same commands I ran earlier to add these two files to my remote GitHub repository. So I'm gonna be doing git add.github, which is the name of the folder that contains my YAML files. So this will stage my folder, my.github folder. I'll add a comment message, Git commit CI added CI workflow, notice again the conventional comment style, this is a task that has to do with CI, so I'm adding a little CI prefix here. And once I have committed locally, now I'm going to push my local commits to the remote GitHub repository, so I'm going to do git push. All right, and at this point, the CI workflow is going to be deployed to my remote repository and it will start to run. So the next step is to use the GitHub website to check the status of my CI. So I'm going to go back in my project here and you can look at the Actions tab here which tracks the execution of the different CI workflows. If I click on the Actions tab, you can see now that there is one workflow job running at the moment, and this is based on the commits I just did, this is the name of my commit, ci-add-ci-workflows. I can click on the workflow run now to see more details. Here, you can see the list of jobs. In my case, there's only one job in my CI workflow.
10. Fixing CI Formatting Issue and Taking a Break
In this part, we fixed the formatting issue in our CI workflow. We intentionally introduced the error to demonstrate how to diagnose and fix it. By running the formatting scripts, we rewrote the YAML files and pushed the changes to the GitHub repository. The CI workflow was rerun and this time it succeeded. We then took a break before moving on to the next part, which involves contributing to the app.
So I can click on the name of the job, and here I can see the steps of my workflow. So it's gonna be installing my workflow. I have a bunch of warnings, but nothing serious here. And we're gonna see all the different steps being executed one by one, and we'll see if there are some errors. Alright, so here in this first run, you'll notice that there is an error. And this is actually intentional. This is something that I have made on purpose in the instructions. You'll see that the pre-ture formatting failed. And when you open this step here, you can see the detail of the step, and you can look at the output for a particular step. You can see the command that was run. So NPM run format verify. This was the command from this particular step. And below, you can see the output of the command itself. And what you can see here is that pre-ture reporting, formatting issues for the two YAML files we added for our CI rules. And to give you the truth here, I made this on purpose. I've added extra spaces in the configuration file so that we had a first PR CI run that would fail so that we can see how we can diagnose these errors. So CI failed here. Okay, that's fine. We can fix it. So in order to fix it, all we need to do is go back in our project. We need to run our formatting scripts, so NPM run format, and this will rewrite our two YAML files. So if I open a bit more, this window here, you can see that these two have been modify. On my terminal, these show up as white instead of gray. This is because they have been rewritten. And you can see here, I have some files which have been changed and that I need to push and comment. So I will do the same bit of logic that I did earlier. I will add everything, comment with a conventional comment message, and push my changes. So copying all of those three instructions and dumping them in my terminal and that's it. So what this does is that it fixes the formatting and we push our changes to the GitHub repository. Now, because I made a change again, directly on main, which is again, which is not really the best practice for generally want to work with pull request. It will rerun our CI workflow. So I can go back now to the homepage of my product and go into the actions tab. And because I just sent another comment to the main branch, it triggered another workflow run. And you can see our workflow run with the name of our comments, again, fixed formatting. So let's take a look at it. Let's take a look at our job and wait for the different steps to run. And this time, because I ran Preacher and it fixed my formatting, we should have the first workflow that succeeds. So we'll just wait a couple of seconds for it to run and we can see the output. Generally installing the NPM dependencies is a bit the long part, but this is even shorter now because you have normally a cache that should be working. For some reason, I still find this kind of long. I wonder if my cache is really working, maybe there's something wrong with the computation. So much as good point. If it's not working for somebody, see if you're not using a master or main as a name of the branch. So normally in the bunch of instructions that are provided at when you were linking your local repository with the remote repository, there was an instruction that was git branch minus capital M main, which was supposed to rename your local branch to main so that would avoid any conflicts. The other question was, what was the change you did in the preacher config again? So what I did in preacher was I rerun it so that it removes some extra spaces in the CI files. Okay. So I don't remember exactly where, but I left some extra blank space at the end of the line and this was forcing a CI to fail. Once you fix this, you'll see that new CI workflow format all files and doesn't report any errors. All matched files use preacher code style. And then again, there's a bunch of other things we do, but it's running fine. Cool. All right. So this is how you set up CI and we'll be adding tests later on to the workflow as we add some tests and as we contribute to the app. Before we jump into contributing to the app, I suggest we all do a small break. This will allow people who are struggling a bit behind to catch up. So let's take a five minute break and join again in five minutes. I will keep online and I will, oh yeah, good point. Cache wasn't created because the workload didn't finish the first time. Good point, thanks. Yes I did, I didn't do the post checkout source code and post caching. It's a good point, thanks. So yes, let's take a five-minute break and resume in five minutes. I will stay online here for questions if there are. Otherwise it's a good time to stretch your legs grab a drink. And after that we'll move on to part number four. Part number four, which will be contributing to the app. All right, let's see. I think we're done, so let's take a look. Oops, let's take a look at the next step. So we're gonna be doing a contribution to the app.
11. Creating New Web Component and Adding Tests
12. Creating Test for Hello World Component
The name of the subdirectory and file is important. It needs to end with .test.js. Use the same name as the component for all files. Copy the provided template code and we'll explain what the test does before running it.
Now, the name of this subdirectory is important. Oops. Because there is a specific filter for the file named template that will pick up tests in this directory. So make sure you do name it correctly. And then under this new directory, you wanna create a hello.test.js. Again, the name of the subdir is going to be again, the name of the file is important. The previous suffix here is important. It needs to end with.test.js. Otherwise, the test will not be picked up. And as a convention, we use the same name as the component for all files. So it's always named hello with different extensions afterwards. I'm gonna grab the provided template again, make sure to copy the entire block of code. It's a bit more verbose and what we did so far because I'm obviously running tests is a bit more complex than just writing the component itself. I'll let you do this and I will explain a bit what the test does. And after that, we'll be running a test, obviously, just to make sure that it does pass. Just give you a couple more seconds to copy everything.
13. Exploring Test Suite Code
Let's take a look at the code in our test suite. We import the Lightning Web Components runtime method to create elements and a reference to our Hello class. The import path uses a shortcut mapper for convenience.
All right, let's take a look at the code in our test class, not class, sorry, test suite. So what we have are a couple of imports. The first import is a method, import from the Lightning Web Components runtime. Not Lightning Web Components framework, sorry, that allows us to create elements. And it's something that we'll need to use to inject the element on our test page. Then we import a reference to our Hello class, which contains our Lightning Web Components. You'll notice the import path here, which is using the configuration we saw in Jest content. There is a shortcut mapper for the import path. Instead of calling SRC modules, example slash Hello, Hello.js, we could just use example Hello because we have this shortcut pattern being placed here for the module mapper.
14. Test Suite and Clean Page
We have a first test suite in Jest where we add web components to an empty document. After each test, we remove any child from the body to ensure a clean page for the next test.
We have a first test suite. This is a Jest test suite. And inside this test suite, we have one test and we have also a after each special set of instructions that are gonna run after each test. And the way we work with test, when we're running with Jest here, is that we have an empty document and we're gonna be adding our web components to document. But between test, we may need to make sure that we don't have anything leftover between the different test runs. So after each test is run, we make sure that we remove any child from the body of our test page. So whatever it is, we just loop on, making sure, well, there's a first child attached to our body document, we remove it. Very simple. This way, we can make sure that the page is clean during each test.
15. Running Test for Hello World Component
16. Testing Web Component and Pushing to GitHub
To check the content of the H1 element within a web component, we need to access its shadow root. We programmatically simulate input events to update the component's variable and check if it re-renders correctly. After running the test, we can push the changes to GitHub, add the test file to the repository, and enable the tests in the CI workflows. Remember to uncomment the necessary lines in the YAML files and run 'npm run format' to avoid formatting issues. Finally, commit and push the changes to create a remote branch on GitHub.
17. Submitting Pull Request and CI Workflow
Now, we're gonna do the next step as a contributor. We'll submit a pull request and wait for the CI workflow to run. After confirming the merge, we can delete the branch. The CI workflow will be triggered and run successfully. GitHub Actions is a powerful framework that allows for different sets of instructions based on branches.
Now, we're gonna do the next step, just like if we're a contributor. So the contributor would be able to submit a request and click on compare and pull requests. And here you can see that you can provide a message for your pull request. If you look down various lists of your comments, you can see the comments that were done, you can see on the list of change files, this is what I did earlier, so adding new component, changing some files there. I can put a name, I'll just keep the default one, I think it's good enough. If you want, you can also do a conventional-style comment, so adding a feet in front of it, and removing the uppercase here, this is following the conventional comment. Normally you would add also probably some comments, describe a bit what you've been doing, and once you're ready, you can just create a pull request.
Right, now wait a couple of seconds, and this page is gonna refresh automatically, and you're gonna see that the CIPR workflow now is being triggered, and the thing after the slash here is the name of the first job that is being worked on. Format-lint-test is actually the only job for this workflow, so it's the only one that will appear. We can click on Details here, and we can see the live updates of what's going on here. You can see that at this point, the cache was there, so it was very fast to install the dependencies. It ran my only test, my test passed, and it automatically completed. So yeah, the overall test run just lasted less than 10 seconds or something like that. Very, very fast. Now that the cache is properly set up, installing the NPM dependencies, you can see here was skipped because we were able to restore the node cache there. And all of the steps here succeeded because of the style and formatting was okay. Our test test passed and linting also went great. We don't have any linting issues. You can always open the details of the steps here to look at the outputs of the steps. You can see here our test passed successfully. And this is how you have the first CI run, successful CI run. Anytime you can go back now to your pull request, click on pull request and you can see there's a little check mark next to it now showing that it's a successful run. And you can see the detail now at the bottom of the PR showing you the different steps the workflows and jobs that ran on this particular branch.
So that's part two. We did the PR, we merged the PR, we waited for the CI workflow to run. And now we can actually merge the pull request now that we've seen that the workflow is valid. Now what I'm not showing you yet is that at this point, we don't have any protection on the merge pull request button. But what you can do in your real life production projects is add a protection on this button and disable it when you see that jobs are not passing. And this is something that I highly recommend. It can prevent merging pull requests when there are some issues with the CI jobs. This is part of the bonus steps for the workshop, but I want to make sure I finish the basic steps first and we can talk about the bonuses after. So let me just finish this part. All I need to do now is confirm the merge. I can add another comment or say something else with my merge, and I can confirm. Now the branch is merged. I can delete my branch. Same thing here, this is the default behavior. By default, the branch is kept alive here in GitHub.com. GitHub.com, we generally don't need it. So there's an option that you can set up in your Git project to automatically delete the branches that have been merged. If not, you can just manually delete them because you won't be using them afterwards. So I'm deleting the branch here. And what I can do now is go back in my project and I can see that my pull request was merged. I can see my comment messages. And what is gonna happen also, if I move to the action tab, we're gonna see that we have a new CI run. And actually it went so fast I didn't even have time to finish talking. It was already validated. So what happened is that, sorry, I went a bit fast here. What happened is that when we had our pull request, we ran the CI PR workflow. This is the workflow that runs on the pull request. But after we merged the pull request, it triggers the CI workflow. In our case, it doesn't make much difference because the two files are pretty much identical. These two files are running the same tasks. But again, you could have different set of instructions depending on which type of workflow you're running. And so obviously, since the first one, CI PR passed, CI also passed very quickly because, well, there's no difference between the two really. They are doing the same tasks. But it's interesting to see how you can play with multiple branches. And for example, you can have a user acceptance testing branch that has a different set of instructions. You have a release branch, for example, which has our instruction branch and other instructions. You can use regular expressions in the name of your branches on the filters here. I've directly named my main branch here, which you can do more advanced patterns using regular expressions. If you're interested in looking into this, we have some examples for this. If you look at, for example, one of the projects I maintain at Salesforce, it's called the Sample Applications on Trailhav's LWC recipes. I have a bunch of more advanced GitHub actions and one of the things we use in our workflows, for example, is we have a pre-release branch. And what this does is that we use regular expression patterns here to specifically run our CI workflows on specific branches. So, spring with the year number, so spring 22, for example, summer 22, which are specific releases for Salesforce. So when we name our branches with these names, pre-release slash the name of the release, we have a specific CI workflow for pre-releases. That's something I think that is very convenient. Obviously there are a lot of things you can learn from GitHub Actions. So, it's a very powerful framework.
18. Exploring Bonus Tasks and GitHub Settings
So that's a wrap. We covered really the main steps that you need to see when working with a small project. I gave you a sense of what LWR is, Lightning Web Runtime, and how Lightning Web Components helps you to create web components very quickly. We saw how we can configure CI workflows to run automatically with GitHub Actions. And we saw also the basic setup for the developer tooling also on our local machine.
Now, I'm still going to answer some questions and I will probably go over also the bonus tasks, if you want. These are not described with step-by-step instructions, but these are things you would want to do if you were to take this project and move it a bit closer to a more production-ready projects. So, for example, the first thing in this list would be to making sure that the merge button on the pull request is disabled as long as the job does not pass. So that's pretty simple to do, it's just a bunch of things in GitHub. Another thing we can do in the bonus task is add a CI badge on the project readme, that would show the status of CI directly on the homepage of the project. Another thing we can do is create something called a pre-comment hook. And we use two libraries to do that, Paskey and Lintstage, which would automatically apply Preacher and Linting on our code before we comment. So it would be automated and this would avoid us from having issues by forgetting to run a Preacher before commenting. And lastly, another thing that's pretty convenient and totally optional again, is to keep track of code coverage with a tool like CodeCoff. This tends to be useful because when you have, especially when we have open-source applications, people can do a lot of contributions and not necessarily take the time to write proper tests. And with CodeCoff, you can make sure that you have certain rules that would make a PR fail if it doesn't provide sufficient code coverage. All right, so if you have questions please go ahead, otherwise I'll be taking a look at those bonus tasks and I can get you over them. All right. All right, I'll go ahead and cover those bonus tasks. The first thing I wanna do is gonna make this, the CI PR job mandatory for merging pull requests. So I'm on my project homepage here and let me open it a bit more. We have a Settings tab here and I'm gonna do two things. The first thing I'm gonna do on the Base General page is I'm gonna do one thing which is actually not something I added in the bonus parts but I think that is worth adding. When you scroll down you have a checkbox called automatically delete head branches. This is not mandatory again and it's totally up to you but one thing I like to do is automatically delete the branches once I have merged my Pull Requests. So I suggest that you check this one out because yeah, it removes a bit of noise as you merge your Pull Request in your project. It's under Pull Request and automatically delete head branches. The other thing we wanna do which is more specific to the way we control or code is in the Branch Menu here, Branches Menu and we can have something called Branch Protection Rules. Oh, hi. I just realized that this is not a default setting. Okay. Well, all right. I forgot about this because I always use my Enterprise Grid when working with GitHub, but I can actually show you this in another project, you may not be able to do it if you're using the free GitHub version, but what you can do is basically specify some rules for specific branches. And if you work with an Enterprise Application, you can go into settings, branches and from there, you can have Branch Protection Rules. So Branch Protection Rules, like, for example, this one on main, allow you to specify some requirements for merging on these branches. So first of all, you can prevent people from pushing directly to your branch. I think this is a really good best practice. You wanna work with pull requests so that your team have the ability to do some code reviews before accepting incoming changes. You can also require approval by the list of code owners. Basically you can select a list of people which are approvers for your pull requests. And going down a bit further, you can also require some status checks to pass before merging. So these are basically selecting jobs from your CI workflows that are mandatory for PRs. So in my case here on my main branch, I have two jobs that are mandatory. And if these two jobs haven't passed, people cannot merge the pull requests. So I wanna have scratch org tests and format linked lwc tests And once these tests are passed and I have approval for one of my coders only then can I merge pull requests. Obviously there's an exception project administrators are enabled to, sorry. Project administrators are able to bypass these rules and can force merge any PR. Ooh, Oh, oh, ooh. Sorry. Excuse me, just a moment. Sorry for the interruption there. All right. The interruption was my, sorry. The interruption was my child barging in, but yeah, we're almost done. Yeah. So branch protection rules. Sorry. I totally forgot that this isn't a GitHub enterprise feature, but I think it's very important when you work on a production to make sure that you, you have some level of control on who does what and who can merge. Otherwise it can quickly become chaos. So that was the first thing I wanted to show you in, you may or may not be able to do it. The next step is pretty easy to do.
19. Adding Badges to Readme and Using a Dashboard
To add a badge to your product's readme, go to your project homepage, click on actions, and select the CI workflow. Create a status badge and copy the code to your readme. You can preview the badge and commit the changes. Badges are convenient for tracking project status and can be used in a dashboard to monitor multiple products. Clicking on a badge takes you to the workflow and allows you to view job details.
And actually I think it's quite important to do. It is adding a badge on your product, read me. So to do this, it's pretty straightforward. You want to go in your project homepage. You want to click on actions and from there you want to pick one of the workflows. For example, you want to take CI because obviously you want to track the CI workflow for your read me. Don't want to use the branches or CPR workflow. And from the free little dots there, you can create a status batch. And this gives you the default code that you need to place on your read me to have the batch here. So I'm just going to grab this and after that, obviously you can do this in your ID or you can just do this quickly and dirty and just pick your read me file here, edited directly with the web ID, the web browser, add the markdown for your badge and you can already preview it here. And you can see CI is passing and I could just commit it by going down there and just leaving the default commit directly to the main branch and commit changes. There we go. And now you can see that on my product homepage, I now have this little CI passing batch. Now, if I make some mistakes and if I introduce some errors, obviously this will turn red and you'll see that CI is no longer passing. Another thing that is convenient with this batch is that you can click on it directly to jump to the workflow and this automatically filters all your workflow runs on this particular CI workflow. Here you saw that I've updated the readme and this triggered another CI run on my project. I was lucky I did not include any white space or something like that because obviously Preacher could have failed here. Yes, so where I got the batch is from the three little dots there after selecting CI on the three little dots here, we have create status batch. And this brings us some templates here for adding the batch. The default options are fine. You want to take default branch and the default events for it, you copy it and you add it to your readme file. So obviously it's convenient for the project. And as you go forward, you can add more badges. So if I go back to my other sample applications, like this one, we can add more badges. For example, you can add other CI workflows and also code coverage with other tools, for example. And this is just a small subset, obviously people have more than these, but badges are really convenient when you have a project to keep track of everything at hand. You can also do something more advanced. That's something I did because I managed quite a few apps. So I did a little dashboard for myself and using those badges, I was able to take them in another project. So here I did a little dashboard view and you can see here I have some products which are failing. So that's another example when you wanna monitor multiple products and you don't wanna navigate around the place, well, you can include those badges in like, for example, an internal... It's not really a project. It's just readme file, but you can easily display them in the central place. I think this is very convenient. And from this interface, obviously I can click on one of my workflows and navigate directly to the jobs that are failing or not. So I click on Packaging Failing here and see what's going on, maybe what's the error, what's the problem. So, I think that's a little useful thing you can do when working with the badges.
20. Creating Pre-Commit Hooks with Husky
We won't have time to cover everything, but I will show you how to create pre-commit hooks with Husky. You can publish LimeWare components at NPM or CDN by separating them into other NPM modules. The LWR config file allows you to manage other bundles, import dependencies, build other routes, and do more advanced configurations. To set up Husky, create a .husky folder and add dependencies for Husky and lint-staged. Then, create a pre-commit script in your Node project and a post-install script to install Husky. Provide specific instructions for lint-staged to filter and run operations on relevant files.
21. Running Tests and Formatting with Husky
We rerun tests for changed files, ensuring quick execution. After running npm install, Husky Git hooks are installed, enabling triggers for the pre-comment hook. By adding changes and committing them to GitHub, Husky automatically reformats files using Preacher and runs tests to catch errors. To make the pre-comment file executable, change permissions using chmod. Once executable, Husky detects changes in stage files, runs pre-commit to fix formatting issues, and performs tests before pushing the code online.
We just rerun test for files that have been changed. So this is very quick. Right. So let's see. Now that I've added all of this, I'm gonna run again npm install so that it does call the post install script. And we're gonna see at the end of my install call, if I scroll back up, I can see this line, which is very important. Husky Git hooks installed. And this means that husky is installed and has triggers with my pre-comment hook. If I did everything correctly at this point, I can now do a git add. Add everything. Actually, let me add some preacher issues. I'm gonna add some white space here and you can see it working. So this normally would need to be reformatted using preacher. So I'm gonna add all my change files to my changes here, and I'm just gonna copy it directly, commit it directly to GitHub. Some changes, oops. And English comments. Oh, yeah. Well, I will need to making sure that the pre-comment file is executable. So that's something I need to do on the pre-comment script it's not executable, so I need to change permissions. So this will depend of course on your OS, but I will need to go in a C.husky and I will need to do a chmod to make the file executable. So it's a plus X to make this file executable and pre-comment. Now that script is executable, I will, whatever, I will, yeah, introduce some new changes, redo the comments so that we detect the change. Go again, commenting and, oh, I need to pull my, oh, yeah. I'm still in my branch. Okay, nevermind. I got burned by, because I was, I'm going off script. But you see the point, now, if I was back on my main branch, I would comment and husky would be looking at my stage files and it would automatically run pre-train and fix the formatting issues on the files that are gonna be commented. So that I would not have any issues, and it will also run tests, so that I could catch basic errors in the code that I'm trying to push online.