preface

Here let me teach you how to make your own scaffolding from 0 to 1, viet-eslint-CLI as an example to implement, see what steps we need to go through??

About vite eslint — cli

1. What does this scaffold do

  • 💡 implements project and specification integration deployment based on Vite
  • ⚡️ can be rapidly deployed from 0 to 1
  • 🛠️ Built-in vue3/ ts/ ESLint/prettier/ commitlint/ husky/ Pinia persistence/VuE-router
  • 📦 can be quickly implemented from the code and specification of the build

2. How is it different from Vite

  • 💡 Built-in Vite creation is no different than using Vite alone
  • ⚡️ has the built-in ESLint specification, for example: Prettier, ESLint, CommitLint, Husky
  • 🛠️ provides the vue3 family bucket configuration. For example, pinia, pinia-plugin-persist, vue-router
  • The Pinia persistence scheme is provided at 📦
  • 🔩 has vue-Router built in as well as pinia cases
  • 🔑 can replace vite –template with the –template argument

3. Where can I go

  • Making the address

4. The result

  • I won’t show you the effect. The iron bars can run by themselvesnpx vite-eslint-cli myapp --template vue-ts. Let’s see what happens. That’s the end of the commercial break, and we’re ready to get down to business

Implement from 0 to 1

1. What packages are used? Here we have a brief introduction

  1. Commander Specifies the command package
  2. Colors allows you to print different colored log packages on the console, mainly for aesthetic use
  3. Prompts the bag that prompts a command line interaction
  4. Fs-extra Package for FS-related control
  5. . There are rollup and TS configuration packages. See the GitHub source for more information

2. What is the directory structure?

The above is the general directory, more detailed directory can refer to GitHub source, at the same time you can also build their own directory. Is ok

3. Where do I start?

Note: Relative directories are all relative to the root directory

1. Set up a dedicated rollup configuration

We use TS to write the entire scaffold, in principle, ts to JS can be converted. However, the specific configuration or see you. Next I paste out my own package configuration file

File location: build/rollup.config.js

const path = require('path')
const { nodeResolve } = require('@rollup/plugin-node-resolve')
const commonjs = require('@rollup/plugin-commonjs')
const typescript = require('rollup-plugin-typescript2')
const json = require('@rollup/plugin-json')
const del = require('rollup-plugin-delete')
const resolvePath = url= > path.resolve(__dirname, url)
const copy = require('rollup-plugin-copy')

module.exports = {
  input: resolvePath('.. /src/index.ts'),
  output: {
    file: resolvePath('.. /dist/index.js'),
    format: 'cjs'
  },
  plugins: [
    del({
      targets: 'dist/*'
    }),
    typescript({
      exclude: ['node_modules'].cwd: resolvePath('.. / ')
    }),
    commonjs(),
    nodeResolve(),
    json(),
    copy({
      targets: [{src: 'src/template'.dest: 'dist/'}]}]}Copy the code

2. Scaffold entrance

File location: package.json

  • Bin is the name of our scaffold execution entryvite-eslint-cliWe can start executing our scaffolding from the command line
    • If the project has not been published to NPM, it can be runnpm linkTo global link, do it againvite-eslint-cliTo run the
{
  "name": "vite-eslint-cli"."version": "1.0.1"."description": "Eslint prettier deployment based on vite + vue3/ vite + React, built-in vite vue3 runtime, code construction and ESLint deployment in one. Built-in (Pinia, Vue-Router, etc.)"."bin": {
    "vite-eslint-cli": "entry/index.js"
  },
  "scripts": {
    "build": "rollup -c build/rollup.config.js"
  },
  "files": [
    "dist"."entry"]."keywords": [
    "rollup"."vue3"."react"."eslint"."commitlint"."prettier"]."repository": {
    "type": "git"."url": "https://github.com/a572251465/vite-eslint-cli.git"
  },
  "bugs": {
    "url": "https://github.com/a572251465/vite-eslint-cli/issues"
  },
  "homepage": "https://github.com/a572251465/vite-eslint-cli"."author": "lihaohao"."license": "MIT"."devDependencies": {
    "@rollup/plugin-commonjs": "^ 21.0.2"."@rollup/plugin-json": "^ 4.1.0." "."@rollup/plugin-node-resolve": "^ 13.1.3." "."@types/commander": "^ 2.12.2"."@types/node": "^ 17.0.21"."@types/prompts": "^ 2.0.14"."colors": "^ 1.4.0." "."commander": "^ 9.0.0"."eslint": "^ 8.10.0"."fs-extra": "^ 10.0.1." "."prettier": "^ 2.5.1." "."prompts": "^" 2.4.2."rollup": "^ 2.69.0"."rollup-plugin-copy": "^ 3.4.0"."rollup-plugin-delete": "^ 2.0.0." "."rollup-plugin-typescript2": "^ 0.31.2"."tslib": "^ 2.3.1." "."typescript": "^ 4.6.2." "}}Copy the code

3. Node executes the entry file

File location: Entry /index.js

#! /usr/bin/env node
require('.. /dist/index')
Copy the code

This address will point to the wrapped index.js file, and the real entry file is the pre-wrapped TS file. This can be seen through the rollup configuration

4. Write code entry files.

Almost all scaffolding lets you select a variety of options and command creation after the selection is passed, and this scaffolding is no exception. See below:

  • From the figure above, we can know that we will enter the interactive command mode first, and after a selection, we can create the project. Let’s take a look at the code:
    • We use plug-inscommanderTo perform thenpx vite-eslint-cli my-app
    • After the above code is executed, you can choose the execution tool. This effect is actually passedpromptsPlug-ins to achieve
    • Next look at the implementation logic of the source code
/ * * *@author lihh
 * @description Run the commander entry */

import { Command } from 'commander'
import { getCommanderOptions, getConfigFile } from './utils'
import { ICmdOptions, IExecOptions } from './types'
import prompts from 'prompts'
import run from './core'

const path = require('path')

/ * * *@author lihh
 * @description Represents the hearing function *@param TPL stands for template */
const promptHandle = async (tpl: string) => {
  let baseOptions = [{
    type: 'select'.name: 'tool'.message: 'please select a running tool'.choices: ['npm'.'yarn'.'pnpm'].map(item= > ({ title: item, value: item }))
  }] as prompts.PromptObject[]

  const res = await prompts(baseOptions)

  return { ...res, isPinia: true.isVueRouter: true}}const program = new Command()
// Get configuration information of package file
const configInfo = getConfigFile()
// Obtain commander options configuration information
const commanderOptions = getCommanderOptions()

program
  .name(configInfo.name)
  .description(configInfo.description)
  .version(configInfo.version)

program.argument('<project-name>'.'Please enter the project name ')

commanderOptions.forEach(item= > {
  program.option(item.keyword, item.description)
})

program.action(async (projectName: string) => {
  const params = program.opts() as ICmdOptions

  // Whether to create it quickly
  const isY = params.y || false
  // Indicates using a template
  const tpl = isY ? 'vue-ts' : params.template || 'vue-ts'

  // Select the execution tool
  const tool = await promptHandle(tpl)
  const rootPath = process.cwd()
  const projectPath = path.resolve(rootPath, projectName)
  constoptions = { tpl, ... tool, rootPath, projectName, projectPath }as IExecOptions

  // Start running the command
  await run(options)
})

program.parse()
Copy the code

The run function in the above code is actually the entry point to our program

5. Take a look at the logic of the main implementation

    1. Implement the built-in Vite initialization, which we correspond toviteRun.tsFile. In fact, our tools are also built into Vite, running Vite generates a basic structure on which to modify
    1. Git init. The corresponding isgitInitRun.tsFile. The logic is as simple as executing the command linegit init. Because all git hooks, commitLint are based on.git files
    1. Perform esLint-related configurations. The corresponding iseslintRun.ts. I’m mainly responsible for some ESLint-related configuration installation and some ignored file writing. That’s where all the esLint-related processing happens
    1. Example Configure the prettier function. The corresponding isprettierRun.tsFile. Similar to ESLint
    1. Perform git hook configuration. The corresponding isgitHooksRun.tsFile. Mainly responsible for some submission specifications related content. For example, CommitLint
    1. To configure the replacement template, run the following command. The corresponding isreplaceTplRun.tsThe original VUE project template is replaced by the prepared template. When you start a project, you can have the page you want
    1. I will explain the main files below, the above mentioned files you can write or look at the source line.

6. Core documents of the control process

import { IExecOptions } from '.. /types'
import viteRun from './viteRun'
import gitInitRun from './gitInitRun'
import { successLog } from '.. /utils'
import eslintRun from './eslintRun'
import prettierRun from './prettierRun'
import gitHooksRun from './gitHooksRun'
import startupProjectRun from './startupProjectRun'
import replaceTplRun from './replaceTplRun'

const execStacks = [viteRun, gitInitRun, eslintRun, prettierRun, gitHooksRun, replaceTplRun]
/ * * *@author lihh
 * @description The command * is executed@param Options Parameters */ collected by shell and entry
const run = async (options: IExecOptions) => {
  const len = execStacks.length

  // indicates a successful callback
  async function success() {
    successLog(`end: Project initialization succeeded`)

    // Start the post-hook
    await startupProjectRun.apply(options)
  }

  async function next(index: number) {
    const instance = execStacks[index]
    awaitinstance.apply({ ... options,callback: async(flags? : string) => {const currentIndex = index + 1
        // If there is a value for flags, the CLI is interrupted
        if (currentIndex === len || (flags && flags === 'end')) {
          await success()
        } else {
          await next(currentIndex)
        }
      }
    })
  }

  await next(0)}export default run
Copy the code

A quick explanation of the above code

  • Each file we need to execute (viterun.ts, etc.) is a class that must contain apply methods. This function is the entry point for class execution
  • We put all the files that need to be executed into an array, in the order we want them to be executed. throughThe next functionCall in turn, passParameters of the callbackFunction to notify the next file to execute until the end.

The end of the

I’ve explained the core of the scaffolding. If it is helpful to you, please give me a star. If you have any questions, you can issue me directly.