Lesson Description

The "Extracting Server Package" Lesson is part of the full, TypeScript Monorepos: Architect Maintainable Codebases course featured in this preview video. Here's what you'd learn in this lesson:

Mike demonstrates breaking and factoring out from the UI package into a server package, resulting in three packages: models, server, and UI. The process involves organizing folder structures, moving code and tests, setting up package JSON, handling dependencies, and ensuring a working build process with pnpm.

Preview
Close

Transcript from the "Extracting Server Package" Lesson

[00:00:00]
>> Mike North: In this next section, what we're going to take on is breaking, like factoring another concern out of the UI package. We have a server. We have that express server and the data that it needs in order to produce an API response when you ask for it. And we're going to factor that out of the UI project so that we'll end up with three packages.

[00:00:23]
At the end of this, we're going to have the models package and both the server package and the UI package will depend on models. We will now have a nice setup where we can examine how does a shared dependency work and we can start to poke at different tasks and how they can operate while being aware of that dependency.

[00:00:50]
Step one, let me give us a little clean folder structure here. So we're gonna make a server folder, mkdir -p packages/server/src and tests. There we go. Step two, we're going to move the. We're going to go into the UI project and we're going to move the data folder into Server.

[00:01:26]
We're going to grab all of the TypeScript modules in Source Server. We're going to grab all those and we're going to bring those into Source up here. And I'm not going to update imports. We're going to like. We'll figure that out. And then finally, tests. There is a server test and I'm gonna move that into server/tests.

[00:01:59]
So we've moved over all the source code and the tests and the data. We can delete these two server folders if you want, just to be nice and clean, but it won't matter if you leave them alone. Cool, all right, we need a very basic package.json for our new server project.

[00:02:18]
And I'm just going to borrow. I'm going to grab actually all three of these things, both TS configs and the package JSON from our models project, because a lot of it's going to be the same. These essentially are just, they're both sort of Node libraries that don't involve any fancy UI of some sort.

[00:02:39]
And we should be able to sort of make all that work with some minor adjustments. Oop, sorry, I'm gonna copy them and we're gonna make some adjustments. So here we'll say this is server. We'll keep our convention here, although bluntly it matters less because the server kind of has an NPM script to start.

[00:03:03]
If it exported a function that started the server, we would care about downstream dependencies. But this is a leaf level dependency. Maybe we delete it just in case it prevents someone from accidentally importing stuff. All right, looking at tests, this all still applies. Linting still applies, build still applies.

[00:03:22]
This is all exactly what we want here. It's still like, we have excess dependencies here. I'm leaving them because we have a tool for that and it'll help us clean all that up. But I think this is a good starting point here. Now we depend on models. So if we look in our code, it's not there, it's in load-data for sure.

[00:03:49]
This is now broken. We just had it working and it's broken now. And the reason is we haven't described that inter-workspace dependency where server depends on the models package. So just as before, we have to go and take care of that. It's not a dev dependency, it is a dependency.

[00:04:15]
Again, the PNPM thing. Workspace. Great. Let's see if this works. So I'm going to go into packages server. Wait, first we touched a package.json, we've gotta run pnpm i. Okay, if we look at our node_modules folder, got some nice sym linking here. Great. Hey look, there's seeds. So it's showing up.

[00:04:59]
It's actually interestingly, it's going to be. If we take a peek in our pnpm state here, just going for seeds, wherever that is. S. It's not here. There's probably some other mechanism where that was happening. I was curious, is it going to actually symlink it in this node_modules folder?

[00:05:25]
But importantly here, if we were to go into source and do this, it's the same file, so it's symlinking right into our workspace. Same file but different undo redo stack apparently. Great. So we did pnpm i PNPM build. We have a build output in dist. Let's try to start the server.

[00:06:08]
And taking a look at our NPM tasks, we have a dev thing here, but this is more about watch the build and do a rebuild when files change. Dev means something different in the context of our server. What we want is to use TSX which if you use TS node and haven't checked out TSX yet, give it a look.

[00:06:34]
It does same thing better, more support for modern module systems. TS node. You can use experimental loaders for things, but TSX is pretty sweet. There is a task that was defined in our original project that takes care of starting our server and it's in our UiProjects package JSON.

[00:06:55]
Here it is. So we're saying TSX watch preserve watch output and it's just running the TypeScript file natively. So we're not worried about an incremental build happening. All of that's taken care of for us already. So I'm going to grab this line here. It doesn't really mean anything in the context of the UI project anymore.

[00:07:18]
Granted, this task depends on it. So we've broken our holistic pnpm dev experience, we're gonna get around to fixing that. So what we are going to be able to do is start this server up and see that it listens on localhost 3000, and we can hit it, and we will work our way towards actually being able to see data.

[00:07:48]
Okay, error file not found. Well, what does that mean? File server Source server index ts. So that clearly means this, right? It's just src/index ts now. This was a server subfolder of src in the UI project, now it's just index ts. Try again, and we're going to click on this link.

[00:08:17]
And we're gonna say /api seeds and we get our seed data there. Now, we benefited from something nice here, and that is we dragged our data folder in from we have placed our data folder in a spot where the relative path to that data folder is unaltered between the load data file here.

[00:08:47]
So if you put that data folder in a different place, this line of code here, the data file path is what to troubleshoot if you didn't see that seed data coming through. But now we have a working ui, we have a working models package. We can see the dependencies between all of them.

[00:09:05]
If we back out, we can see that we have a holistic build process that first starts in models and then builds the UI and then builds server. This is pnpm having an awareness sort of of the DAG, the directed graph of our dependencies. And it knows to build the things everything depends on first and then works its way towards the leaf level dependencies.

[00:09:39]
So we should be able now to run pnpm build, pnpm check, pnpm build, pnpm test. It's a lot of dopamine right there. Lots of green check marks. Everything looks good.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now