Scaffold out Files and Projects from Templates in a Node.js CLI

Shawn Wang
InstructorShawn Wang
Share this video with your friends

Social Share Links

Send Tweet

One of the killer apps of CLIs is with templating (or scaffolding). The rails generate and ng generate commands are famous for this. By immediately reducing the pain of boilerplate, you can also make it easy to write standardized code, with in-place reminders for comments and developer warnings (it is easier to delete generated code than write code, though of course one can overdo it). There is no standardized tooling for doing scaffolding, since you can use everything from the Express.js templating languages to writing your own, but we explore this problem space with the tiny copy-template-dir library to prove out the developer experience of adding scaffolding to your CLI.

Instructor: [0:00] One of the trademark features of Ruby on Rails is the rails generate command, which helps you scaffold out any number of very common Rails boilerplate. The value proposition is literally that, saving a large amount of time by printing out boilerplate code into your project.

[0:19] This makes template scaffolding a very good CLI use case for any sort of framework. It is such a big jump in developer productivity that I've actually compared it before to cheating at developer experience because you're literally copying and pasting working code into the user's project.

[0:40] The closest the JavaScript ecosystem has to anything like the Ruby on Rails rails generate command is Angular's ng generate command, which does a lot of the same things, but it also helps to modify files based on a particular schematic that a particular file conforms to. This can be very handy. It's a more advanced use case.

[1:02] For other frameworks, the primary player has been Yeoman, which is a generic tool for scaffolding new projects and apps. However, the developer experience is very much controlled by the yo CLI. You may wish to take matters into your own hands within your own CLI.

[1:19] There are many options to implement your own scaffolding, particularly writing your own in Node.js, but you can use some libraries for it. We're going to try out copy-template-dir today as something with a very, very simple API which we can just drop into a project. It has a very small footprint.

[1:39] Let's head back to our terminal. I'm going to create a dedicated folder just to hold our templates. I am going to imaginatively call it templates. I'm going to open it in finder because I plan to drag-and-drop in a pre-prepared template.

[1:53] I'm going to open another finder window where I have my pre-prepared template. I'm going to look for my pre-prepared template. I think it's called volup-react. This is a running app that I wish to make into a project that I can just scaffold easily.

[2:11] I can go into my templates folder over here and paste it in. Now, within my templates folder I have a fully working project. This has all the dependencies that I wish to scaffold out. Of course, this is a fully working app, in this case creating a create-react-app clone, but you may wish to just scaffold singular working files, for example.

[2:35] I want to tie this up together with my init command. First of all, I'm going to install copy-template-dir. I'm going to use it inside of my code, const copy = require copy-template-dir. The code for copy-template-dir has an in dir and out dir and a vars. We'll talk about those in turn. I'm also going to need the path module from Node.js.

[3:13] Let's assume that I have everything boiling down to flags.name. I'm just going to get rid of this log as well. Let's assume that my goal of my init command now is to scaffold out this new project. My in directory should be the sibling folder of this commands folder.

[3:34] I'm going to type, "use path.resolve" and use the dir name to refer to this specific file I'm working with. I'm going to tell it to get out of this folder, go into templates folder, and go into rollout-react. I expect it to copy everything within rollout-react. Inside of the out dir, I'm going to do path.join.

[4:00] When the user runs this, this will be the value of the current working directory, process.cwd. I'm going to append to that the name that I've resolved. What is the folder name, for example? copy-template-dir has a standard Node.js callback API. We can just make sure that this is an instance of error, as well as the creative files are an array of string. That should do the trick.

[4:29] Now when I'm in my sample CLI, I can run yarn mycli init. I don't have any config set. It's going to ask me for the folder name. I can just say, "My New App." It's going to copy out all these files into a new "My New App" folder. When I check out these files, this is all usable code which I just scaffolded out from my templates.

[4:54] Sometimes you may want to customize the app. copy-template-dir has very simple templating for you to do that. I'm going to delete this copied out app. We'll see this in action. Instead of the init command, we have this vars variable. This vars object is just a simple key-value mapping of what needs to be written into the template.

[5:17] I can take, for example, project name and assign it the name of the directory. Now I have this project name variable, I can use Mustache templates to replace any particular string I might want to be dynamically injected.

[5:34] For example, in the project name field and maybe the repository field in package.json. Make sure there's no spaces around the Mustaches. Now when I run yarn mycli init, it's going to prompt me again for a new folder name.

[5:48] I can give it a new folder name, Foo App, that is going to scaffold out a new folder with all the stuff that I wanted but also the contents replaced accordingly to the variables that I've supplied. This can be very useful for simple templating.

[6:03] You can absolutely keep going with more ideas. For example, imagine having a bunch of different templates at your disposal.

[6:10] In the init command, you're reading the templates folder to see what's available, sticking that into a prompt with an autocomplete field, asking the user what they want to scaffold out, then taking that result, and then copying out the correct folder into the destination that they desire.

[6:31] It really is only limited by your creativity as to the kind of productivity you want to have with your CLIs. For more complex templating solutions, you might wish to reach for some other tools, like Consolidate, EJS, and Pupa.

[6:45] There are a whole bunch of other custom-built tools that involve the Express templating ecosystem that you might want to look into as well. All in all, this is probably the highest-bang-for-your-buck activity that you can get right out the door to prove out the value of CLIs for your team.