Shared Configs
Setting up shared TypeScript, ESLint and Prettier configs
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
- |
Lesson Transcript
[00:00 - 00:13] One of the nice things about using a mono repo is that it makes it very easy to share configuration files across the projects. And we're going to be doing that for TypeScript and also for ESLint and prett ier and possibly some other tools.
[00:14 - 00:23] But let's start with TypeScript. So let me actually just start by committing this to Git and I'm just noticing a typo here.
[00:24 - 00:27] Let me just fix that real quick. And I will add all of this.
[00:28 - 00:35] We should also create a gitignore. Let me just do that and then actually create a gitignore.
[00:36 - 01:08] I tend to use this gitignore.io for just creating a quick file. So if we take this and we add gitignore file here, this is just a predefined one for node and it has a bunch of things that we don't really need but this works reasonably well and it will work well enough for all that we're going to be doing here.
[01:09 - 01:18] So we'll add that to our repo and then we should be good to go. I think I misspelled there again.
[01:19 - 01:21] I can't see my keyboard here. I apologize.
[01:22 - 01:38] So in order to set up TypeScript, we're going to go to the, we're already in the root folder. So we'll install TypeScript like so and then we're going to need some configuration and TypeScript is heavily configurable.
[01:39 - 01:56] So that can be a bit of a jungle to navigate. I tend to use this package on npm called TSConfig which has a bunch of recommended configurations that I tend to use as long as I can at least and TypeScript configurations are quite easy to append to.
[01:57 - 02:01] So we're going to be doing that. So we're going to be starting just with a recommended configuration.
[02:02 - 02:09] So I'll add this package, TSConfig/recommended. You can see it's been added there.
[02:10 - 02:20] And I can now create a TypeScript configuration in the root folder here. So I'll make TSConfig.json file here.
[02:21 - 02:42] And I'll just say this should extend the recommended TSConfig and I think I need to specify like so. So this is a very basic now we're simply using the TSConfig/recommended setup.
[02:43 - 02:56] It has, the package has recommended for specific setups like node specific versions and other things. But this is a fine place to start and I like to do this and just expand whenever it's necessary.
[02:57 - 03:10] One of the things we're going to want to do immediately is we want to tell Type Script about our packages, specifically our schema package. The reason why we're doing this is that it helps our IDE.
[03:11 - 03:22] So if you're using any IDE, like Visual Studio Code that has the TypeScript language server, you can go to definition or go to implementation. And it's just a bit nicer when TypeScript knows about where that package is.
[03:23 - 03:44] So it won't just try and go into the node modules folder and look at the .d.ts file. So we can do that by extending it with compiler options and we'll add first a base URL that says packages.
[03:45 - 04:02] And we will add a path entry and that will wait here we will refer to our schema package. And that needs to be in Ray.
[04:03 - 04:17] And that is the path to our schema package. Now TypeScript should be able to go to the definition of anything in the schema package by actually going to the folder where it's implemented instead of the node modules folder.
[04:18 - 04:23] This is obviously in the root. So this is not actually what any of our projects are going to be using.
[04:24 - 04:34] What we need to do is to create specific TS configs in the folders for our project. So let's create one in the backend folder.
[04:35 - 04:53] I should mention maybe that TSC, the TypeScript compiler has an init function just the way we used NPM in it and get init for that matter. That can create a TS config file for you and you can specify some things there and you will get a nicely formatted configuration file with lots of comments in it.
[04:54 - 05:04] So it's fairly easy to navigate. I just find that when I'm using these recommended configurations it's much easier to create the configuration file by hand like I'm doing at the moment.
[05:05 - 05:21] So you could be using TSC-in-it but will it just be using this, be doing this like so. So what I need to do now for my backend TypeScript configuration file is reference the root TS config here which again then references the recommended configuration.
[05:22 - 05:34] So it's a little bit of a chain of configurations but it works perfectly fine. So here we will start by adding an extends and we will say that it extends.
[05:35 - 05:39] This is the services folder. This is the root folder.
[05:40 - 06:03] TS config.json. And then we can now add some specific things to our backend configuration and the only thing that we really need to add here is we want the library to just be ES next because we simply want to just use the latest version of the JS libraries.
[06:04 - 06:17] This is something you can change if you find that your setup for whatever reason doesn't work with this library but as it is we're going to be using this. And then we will specify an out directory.
[06:18 - 06:39] So this is where the compiler will add everything and we want this to go into a dist folder like so. Finally we want to include everything in the source folder which we don't actually have yet but we can create one of those.
[06:40 - 06:58] Let's just copy all of this and create a similar TS config file in the schema folder. The only thing I want to add here is that because the schema is a shared library that's going to be referenced from the backend and the front end we want declarations created.
[06:59 - 07:18] So this is option in the compiler options as well. So declarations mean a .d.ts file which specifies the types of things and we want that created for our schema so that all those types that we're going to be referencing are actually available to us.
[07:19 - 07:40] Right. We obviously need to set up a TypeScript for our front end as well but the reason I'm not doing anything for the front end just yet is that we're going to be using V IT which is the bundler for creating a scaffolding for our front end and that includes some various configurations both for linting but also for TypeScript.
[07:41 - 07:51] So we're going to be using that first and then we'll be refining it a little bit from there. So this is a good start for the backend and the schema configuration.
[07:52 - 08:07] We want to make sure that the schema configuration or the schema is referenced correctly so we'll go into the package JSON and change this. So we are not going to be having our index.js in just the root folder of the schema package.
[08:08 - 08:25] It's going to be in the dist folder which doesn't exist right now but Type Script will create that for us. And we will add to this that there will be types going into the dist folder as well and you can see that copilot is helping me here.
[08:26 - 08:31] I thought I disabled it but I will just do that now because that feels like cheating. All right.
[08:32 - 08:45] So now the schema package should specify correctly that the types and the compiled output will be sitting in the dist folder. That's we're going to add prettier.
[08:46 - 08:58] Critier is a code formatter that is highly opinionated and quite aggressive about how it formats your code. If you're not familiar with it or not used to it and you're anything like me, it might make you a little bit uncomfortable.
[08:59 - 09:09] It certainly did for me when I started using it but I can tell you now from experience that I would hate to work on a project that doesn't use it. It is incredibly addictive once you get used to it.
[09:10 - 09:16] You just start being used to saving and then everything is formatted so you don 't even have to think about it anymore. It is very, very nice.
[09:17 - 09:24] So if you're not used to it, I encourage you to try this out. Let's install it in our project here.
[09:25 - 09:45] We will start by adding prettier to the root and then we will create a configuration file. This is actually an optional step and you could even argue that it's a little bit of an anti-pattern because prettier is opinionated for a reason.
[09:46 - 09:56] It's not really supposed to be configured a whole lot. I just happen to like semicolons and single quotes so much that I tend to configure it like this but this is a very optional step.
[09:57 - 10:17] If you don't like that configuration or you don't care, then definitely you don 't do this. I might even add that I've worked personally on other projects with different configurations and once you're used to working with prettier, because it formats everything the way it's supposed to be when you save, you just stop caring about whether you used one or the other and it almost doesn't matter.
[10:18 - 10:37] So this is a very optional step but we will do the way I normally do right here and so that is I like semicolons. So we'll set that to true and I like single quotes so we'll set that to true as well and that is our configuration of prettier.
[10:38 - 10:54] Now we want to enforce this formatting on CI. So I like to have prettier format everything when I save and I encourage everybody to do that but in order to make sure that the formatting is kept, we will make ESLint check for it.
[10:55 - 11:06] But ESLint isn't even installed yet and ESLint is one of the other things that we will have shared configurations for. So I'm going to install that together with a bunch of packages that we need for ESLint.
[11:07 - 11:12] So let me just add that here. Let me just go through these real quick.
[11:13 - 11:24] So ESLint is the Lintra package itself. Then we add the plugin for prettier and the configuration for prettier and there's a very good reason why these are two separate things and I'll get into that in a minute.
[11:25 - 11:42] We also add the TypeScript parser for ESLint and the TypeScript plugin for ESL int. So once that's installed, we will create a ESLint configuration file and that is called ESLint rc.json.
[11:43 - 11:55] I believe they're working on a new configuration system. They're revamping the whole thing quite heavily but at the time of writing that isn't out yet so this is still the way you configure ESLint.
[11:56 - 12:10] I'm just going to quickly copy the setup that I have from the article and then we will go through it quickly. So we want this to be the root config.
[12:11 - 12:33] What this means is that ESLint is not going to go up any parent directory and look for configuration files further up. That is both a performance issue but also even though you might be tempted to have your own personal preferences sitting in top folder somewhere that ESLint would always enforce, I think that is a bad way to go about it.
[12:34 - 12:49] Every repository should be completely self-contained and you want everything to work the same way when you check it out on a new machine as it did the previous machine. So having the root folder contain the root ESLint configuration just seems like the right thing to me.
[12:50 - 12:58] We specify that we're going to be using the TypeScript parser and we give it some options. This could probably be like latest instead.
[12:59 - 13:07] This is just how I have it said right now so 2017 ECMA version works. Fine, maybe it's time to update that but we'll leave that be.
[13:08 - 13:23] We're using modules as a source type and we should use the TS configuration that sits out here. We're then adding the TypeScript ESLint plugin which adds some TypeScript rules that we're going to be enforcing and then we add the prettier plugin.
[13:24 - 13:31] The extends is the configuration itself. So we're going to be extending the recommended ESLint configuration.
[13:32 - 13:41] I think this is a nice way to go about things. There are a bunch of rules here that apply to almost any JavaScript or Type Script project that you might want to use.
[13:42 - 13:49] So I just always add this one when I'm setting up something new. The same goes for the TypeScript recommended set.
[13:50 - 14:01] There are very few exceptions to this. And then we add the prettier setting as the configuration as the last step and it's important that that comes last because that needs to override anything that comes before it.
[14:02 - 14:12] So any ESLint recommended rule that has anything to do with formatting, we don 't want to care about. ES, sorry, prettier is what takes care about formatting now.
[14:13 - 14:31] And this set of configurations and this plugin will take care of making sure that ESLint respects how we're formatting things with prettier. So with this in place, it means that when we run ESLint on CI, it will fail if some code is being checked in that isn't actually correctly formatted.
[14:32 - 14:54] So even if a member on your team doesn't have auto format on save setup, this will still be enforced and so you can go and tell them that they did something wrong. We're configuring some rules just a little bit and the only really thing that really is interesting here is that we're turning off the recommended no unused variables and no undefined variables.
[14:55 - 15:09] And the reason why we're turning these off is that we're enabling the Type Script equivalents right below it. So with this one, we're configuring it so it works for TypeScript instead and then we're adding an ignore pattern.
[15:10 - 15:25] So I think that it's very nice to allow parameters and variables to be named underscore something and then have ESLint accept those as, okay, we're not, these are not being used anywhere. For whatever reason, they still exist.
[15:26 - 15:38] Maybe it's a parameter that needs to be in place because we are, it's not a name parameter, what's the opposite placement parameter? And we need the preceding or the succeeding parameter to be there.
[15:39 - 15:49] Or maybe it's a variable that we're not using at the moment or for whatever reason JavaScript needs it in some other way that isn't very explicit. So this is a helpful pattern I think.
[15:50 - 16:00] Finally, we're disabling the no explicit any because we're going to be using that a little bit here. And you can argue that that is a TypeScript anti-pattern.
[16:01 - 16:11] I think it's okay. I think it's good to have no implicit any anywhere in your code, which is what the strict setting and TypeScript will do per default.
[16:12 - 16:22] But if I explicitly type any somewhere in my code, I know that I'm doing something that's a little bit on the edge, and there is a good reason why I'm doing it. So I'm going to allow myself this.
[16:23 - 16:49] We will turn that specific check off. We'll add another file called .es lint ignore, which will tell you, yes lint that node modules and dist folders should not be checked because obviously that would be a huge performance issue and also completely incorrect.
[16:50 - 16:55] Finally we'll add a script to our package JSON to run lint. And I like to do it.
[16:56 - 17:01] Let me just copy this line. So we have our package JSON and the root here.
[17:02 - 17:04] We just have the test script. We'll paste this in here.
[17:05 - 17:14] So I like to run .es lint with this format or called Visual Studio. I can't show you just yet because we don't have any code, but as soon as I can you will see what the difference is.
[17:15 - 17:25] So the normal format for .es lint will sort of group things together by file and then it would say online 2 and online 10 and online 13. There are errors in this file.
[17:26 - 17:39] With this particular format, you will get the file name and then the line number in a parenthesis, which means that you can click on it right down here in the terminal if you're using the built-in terminal in VS code. So I just think that's a nice little thing.
[17:40 - 17:47] So that's why I specify this in my lint rule here. Then we specify that and it runs through TS and TSX extensions.
[17:48 - 17:54] That is just what we need to do here. So that sums up .es lint and prettier.