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 themselves
npx 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
- Commander Specifies the command package
- Colors allows you to print different colored log packages on the console, mainly for aesthetic use
- Prompts the bag that prompts a command line interaction
- Fs-extra Package for FS-related control
- . 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 entry
vite-eslint-cli
We can start executing our scaffolding from the command line- If the project has not been published to NPM, it can be run
npm link
To global link, do it againvite-eslint-cli
To run the
- If the project has not been published to NPM, it can be run
{
"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-ins
commander
To perform thenpx vite-eslint-cli my-app
- After the above code is executed, you can choose the execution tool. This effect is actually passed
prompts
Plug-ins to achieve - Next look at the implementation logic of the source code
- We use plug-ins
/ * * *@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
-
- Implement the built-in Vite initialization, which we correspond to
viteRun.ts
File. In fact, our tools are also built into Vite, running Vite generates a basic structure on which to modify
- Implement the built-in Vite initialization, which we correspond to
-
- Git init. The corresponding is
gitInitRun.ts
File. The logic is as simple as executing the command linegit init
. Because all git hooks, commitLint are based on.git files
- Git init. The corresponding is
-
- Perform esLint-related configurations. The corresponding is
eslintRun.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
- Perform esLint-related configurations. The corresponding is
-
- Example Configure the prettier function. The corresponding is
prettierRun.ts
File. Similar to ESLint
- Example Configure the prettier function. The corresponding is
-
- Perform git hook configuration. The corresponding is
gitHooksRun.ts
File. Mainly responsible for some submission specifications related content. For example, CommitLint
- Perform git hook configuration. The corresponding is
-
- To configure the replacement template, run the following command. The corresponding is
replaceTplRun.ts
The original VUE project template is replaced by the prepared template. When you start a project, you can have the page you want
- To configure the replacement template, run the following command. The corresponding is
-
- 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. through
The next function
Call in turn, passParameters of the callback
Function 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.