How to properly create and publish a Deno CLI tool

One cool thing about the Ember framework is that it has the Ember CLI to generate a component, a template, or a route. It’s a big time saver, and even more, the ember generate component generates not only the component but also a test file for QUnit. Let’s see how to create a Deno CLI tool to do something similar for React.

In this Deno tutorial, we’ll see how to create a Deno CLI tool with TypeScript, how to load dependencies from Deno standard library. We’ll explore how to read a directory and write a file. Finally, we’ll learn to publish our Deno module to GitHub and run it directly from that location and also to install it locally so it can work without connection.

Overview

Install Deno

Read command line parameters in Deno

Write files with Deno

Local test

Publish a Deno module

Use the module published online

Install our published Deno CLI tool

Deno CLI tool to generate a React component

Overview

The CLI tool that we’ll built in this Deno tutorial will accept a component name passed through the command line and will generate a directory and a file with the code for a React functional component.

I did create a more complete version of this that also creates a SASS stylesheet and a test file suitable for Jest and Enzyme. Will be adding more customization and component templates (like those using hooks, or Redux, or Router, or all of them) soon.

For the sake of simplicity though, this Deno tutorial will cover the essentials: reading parameters and writing files and we’ll write a single file. The rest is string manipulation and more content writing, nothing particularly especial. You can access the full Deno CLI tool to generate a React component with SASS and Jest in the repo at the end of this article.

Install Deno

To run this Deno CLI tool, you need to have the runtime installed. If you’re already using Homebrew on macOS, you can quickly install Deno with:

brew install deno

If you’re not using Homebrew, you can install it using CURL:

curl -fsSL https://deno.land/x/install/install.sh | sh
Code language: JavaScript (javascript)

Other installation methods and systems are described in the Deno Manual.

Read command line parameters in Deno

The most essential thing we need for our generator is to take the name of the component. We need to be able to pass the component name to the Deno tool. Create a directory and add a file called mod.ts and paste this in it:

const { args: [name] } = Deno;
console.log( `Writing component ${ name }` );

Now, when you add the Deno variable, you’ll probably get a warning, depending on your code editor and its TypeScript support, saying that it cannot find the Deno name. If you’re in VS Code, you can solve this using the official VS Code extension to add Deno support. JetBrains also has published a plugin to provide Deno support for JetBrain IDEs.

Now run this module with:

deno run mod.ts HelloWorld

This will respond with the parameter “HelloWorld” we passed:

Writing component HelloWorld

Nice! It’s working!

Write files with Deno

Let’s write the file now. We first need the content for it, so add this to the mod.ts file. We’ll make use of JavaScript template literals to create a single string and insert the name of the component and even call a string method to make it lowercase:

const compoContent: string = `import React from 'react';
import PropTypes from 'prop-types';

${name}.propTypes = {
    
};
function ${name}(props) {
    return (
        <div className="${name.toLowerCase()}">
        </div>
    );
}
export default ${name};
`;

To write this to a file, we first need to check if the directory exists. We’ll use the ensureDir function, part of the Deno standard library, for this. It will create the directory or directories if they doesn’t exist. To tell Deno to use this dependency, just add this at the top of the file:

import { ensureDir } from "https://deno.land/std/fs/ensure_dir.ts";

When we run our tool, Deno will download this module to use it. It’s finally time to write the file using writeTestFile, a command in the Deno runtime. Paste the following at the end of the file:

const compoPath: string = "./app/components/" + compoName + "/";

ensureDir(compoPath)
  .then(() => {
    Deno.writeTextFile(compoPath + "index.js", compoContent);
    console.info("Done!");
});

Local test

We’re done coding our Deno CLI tool and we can now test it. Deno is built as a secure-first runtime so operations like reading the filesystem or writing to it are denied by default. You need to explicitly ask Deno to allow filesystem access. It’s separated in read access and write access. In this case, we need reading permission, because ensureDir first needs to read the directory and check if it exists. If it doesn’t it will create it and then we’ll create the file. For the last two tasks, we need writing permission. So this is how you can run it:

deno --allow-read --allow-write mod.ts button

And you’ll have the directories created along with the file, all relative to the folder where you’re executing this, like app/components/Button/index.js.

Publish a Deno module

Distributing a Deno module is simple. We covered this in detail in a previous post about creating and publishing a Deno module on GitHub. You need to initialize a local git repo:

git init

add and commit your files:

git add .
git commit -m "Initial commit"

create a repository on GitHub or similar service, and push it. For example, if you create a repo named a-deno-module on GitHub you can run this locally to push it online:

git remote add origin git@github.com:YOUR-GITHUB-USER/a-deno-module.git<br>git push -u origin master

Use the module published online

Deno can run modules directly from the Internet and install its dependencies automatically. Now that it’s deployed, you can run our Deno CLI tool directly from GitHub:

deno run --allow-read --allow-write https://raw.githubusercontent.com/YOUR-GITHUB-USER/a-deno-module/master/mod.ts button
Code language: PHP (php)

Deno will download the tool, check the dependencies, and install them if needed. The result will be the same than above, it will create the directories and the file.

Install our published Deno CLI tool

To avoid having to write all that (or look for it in the shell) Deno allows you to install this tool so it works offline:

deno install --allow-read --allow-write --name denomodu https://raw.githubusercontent.com/YOUR-GITHUB-USER/a-deno-module/master/mod.ts
Code language: PHP (php)

The tool will be named denomodu. What this does, is to create an executable file with the command line in a certain directory, like /Users/%your-username%/.deno/bin in macOS. Its content is the command to run the tool and accept parameters:

#!/bin/sh
# generated by deno install
deno "run" "--allow-read" "--allow-write" "https://raw.githubusercontent.com/eliorivero/react-generate-component/master/mod.ts" "$@"

So when the process finish, if you haven’t added the ./deno/bin path to your PATH environment variable, Deno will prompt you to do so, so you can run the tool.

Once you add the path to your PATH variable, you can now invoke the tool:

denomodu button

It’s much shorter and now it works without being connected to the Internet. Congratulations! You’ve created a Deno CLI tool, you published it, and installed it locally.

Deno CLI tool to generate a React component

As mentioned at the beginning of this Deno tutorial, I created a more complete version of this, and you can access the repo for this tool here:

https://github.com/eliorivero/react-generate-component

It’s only one Deno module created on TypeScript and creates these files:

  • index.js, a React functional component
  • style.scss, its SASS stylesheet
  • test.js, a simple test using Jest and Enzyme

The gif below shows how this Deno tool works after being installed:

Deno CLI tool to generate a React component

It accepts compound names separated by a dash. For example, passing nav-bar will create a component named NavBar. You can also specify a custom directory path other than the default `app/components`, or not, and continue using the default path.

Leave a Reply