DEV Community

Mark
Mark

Posted on

Building Vue3 Component Library from Scratch #10 Create Cli Scaffold

This article will implement the development of a scaffold called create-stellarnovaui. With just one command, npm init stellarnovaui, you can pull the entire component library development framework to your local environment.

Create Cli Package

Firstly, we create a new cli directory under the packages directory, initialize it by running pnpm init, and then change the package name to create-stellarnovaui.

What needs to be known here is that when we execute npm init xxx or npm create xxx, we are actually executing npx create-xxx. So when we execute npm init stellarnovaui, we are actually executing npx create-stellarnovaui.

When we execute create-stellarnovaui, it will execute the path corresponding to bin in package.json. Therefore, we modify package.json as follows.

{
  "name": "create-stellarnovaui",
  "version": "1.0.0",
  "description": "",
  "bin": "index.js",
  "keywords": [],
  "author": "",
  "license": "MIT"
}
Enter fullscreen mode Exit fullscreen mode

At the same time, create index.js as the entry file. Note that you need to add #! /usr/bin/env node at the beginning.

#! /usr/bin/env node
Enter fullscreen mode Exit fullscreen mode

Processing User Input Commands with command-line-args

There are actually many plugins for handling user input parameters, such as CAC, Yargs, Commander.js, command-line-args, etc. However, in my view, command-line-args is the simplest to use, so here we use command-line-args for user parameter parsing.

pnpm add command-line-args
Enter fullscreen mode Exit fullscreen mode

Create cli.js to handle the logic of our scaffold. Here, let's simply write a -v version command.

import commandLineArgs from "command-line-args";
import { readFile } from "fs/promises";

const pkg = JSON.parse(
  await readFile(new URL("./package.json", import.meta.url))
);
//"Configure command parameters."
const optionDefinitions = [{ name: "version", alias: "v", type: Boolean }];
const options = commandLineArgs(optionDefinitions);
if (options.version) {
  console.log(`v${pkg.version}`);
}
Enter fullscreen mode Exit fullscreen mode

Image description

We can also use the command-line-usage plugin to provide us with help commands.

pnpm add command-line-usage
Enter fullscreen mode Exit fullscreen mode

Only the relevant code is posted here.

import commandLineArgs from "command-line-args"
import commandLineUsage from "command-line-usage"
...

//Help command
const helpSections = [
  {
    header: 'create-stellarnovaui',
    content: 'A scaffold for quickly setting up a component library environment'
  },
  {
    header: 'Options',
    optionList: [
      {
        name: 'version',
        alias: 'v',
        typeLabel: '{underline boolean}',
        description: 'Version number'
      },
      {
        name: 'help',
        alias: 'h',
        typeLabel: '{underline boolean}',
        description: 'Help'
      }
    ]
  }
];

if (options.help) {
  console.log(commandLineUsage(helpSections))
  return
}
Enter fullscreen mode Exit fullscreen mode

Image description

Interactive Commands

When we use some scaffolding, such as create-vite, it will give us some options to choose from.

Image description

So our scaffolding should also have this feature, but how should this be implemented?

It's actually quite simple, all we need is the prompts plugin. It can configure what the user inputs, whether it's single or multiple choices, etc.

Firstly, install prompts.

pnpm add prompts
Enter fullscreen mode Exit fullscreen mode

Then in cli.js

import prompts from "prompts";
const promptsOptions = [
  {
    type: "text",
    name: "user",
    message: "User",
  },
  {
    type: "password",
    name: "password",
    message: "Password",
  },
  {
    type: "select", //
    name: "gender",
    message: "Gender",
    choices: [
      { title: "Male", value: 0 },
      { title: "Female", value: 1 },
    ],
  },
  {
    type: "multiselect",
    name: "study",
    message: "Select Framework",
    choices: [
      { title: "Vue", value: 0 },
      { title: "React", value: 1 },
      { title: "Angular", value: 2 },
    ],
  },
];

const getUserInfo = async () => {
  const res = await prompts(promptsOptions);
  console.log(res);
};
getUserInfo();
Enter fullscreen mode Exit fullscreen mode

Image description

Then we can deal with different logic based on the corresponding values. Of course, our scaffolding doesn't need so many parameters, we can change it to the following options.

const promptsOptions = [
  {
    type: 'text',
    name: 'name',
    message: 'Please enter the project name'
  },
  {
    type: 'select', //Single Choice
    name: 'template',
    message: 'Please select a template',
    choices: [
      { title: 'stellarnovaui', value: 1 },
      { title: 'stellarnovaui2', value: 2 }
    ]
  }
];
Enter fullscreen mode Exit fullscreen mode

Then we can pull different repositories based on the user's choices.

Pulling Remote Repository Templates

To pull remote repositories, we can use the download-git-repo tool and use its clone method. At the same time, we need to install a loading plugin ora and a log color plugin chalk.

pnpm add download-git-repo ora chalk
Enter fullscreen mode Exit fullscreen mode
//gitClone.js

import download from "download-git-repo";
import chalk from "chalk";
import ora from "ora";

export default (remote, name, option) => {
  const downSpinner = ora("Downloading template...").start();
  return new Promise((resolve, reject) => {
    download(remote, name, option, (err) => {
      if (err) {
        downSpinner.fail();
        console.log("err", chalk.red(err));
        reject(err);
        return;
      }
      downSpinner.succeed(chalk.green("Template downloaded successfully!"));
      resolve();
    });
  });
};

//cli.js
const remoteList = {
  1: "https://github.com/markliu2013/StellarNovaUI.git",
  2: "https://github.com/markliu2013/StellarNovaUI.git",
};
const getUserInfo = async () => {
  const res = await prompts(promptsOptions);
  if (!res.name || !res.template) return;
  gitClone(`direct:${remoteList[res.template]}`, res.name, {
    clone: true,
  });
};
Enter fullscreen mode Exit fullscreen mode

After execution, the template we need is in the directory.

Finally, we can publish our 'create-stellarnovaui'. The publishing process has been introduced before, so I won't go into detail here. I have already published it, so let's try to run 'npm create stellarnovaui' in any folder. You can see stellarnovaui will be cloned.

Image description

The final source code: https://github.com/markliu2013/StellarNovaUI

Top comments (0)