This article source has been included in github, welcome to the little brothers miss sisters star, continue to update.
preface
In the first two articles, 10 minutes will take you to upgrade Webpack 5. In the first two articles, from 0 to 1, we will take you to draw a set of Webpack + Vue project template. We will teach you how to manually build a front-end project template from 0 to 1. It is obviously inefficient to generate a new project simply by copying the built project template. How do you get around inefficient copying? The answer is scaffolding /CLI. Then, based on the project template we built manually in the previous article, we will quickly generate the project we want by one key in the form of scaffolding /CLI.
Why scaffolding /CLI
The CLI is a command line interface.
What are the benefits of scaffolding?
- Avoid inefficient manual copying of project templates
- Standardize the project development directory structure
- Unified team unified development style, facilitate cross-team cooperation, and later maintenance, reduce the cost of new recruits
- Provide one-click front-end project creation, configuration, local development, plug-in extension and other functions, so that developers can focus more time on business
Scaffolding /CLI workflow
- A complete scaffold usually contains these:
Project creation
,Add and delete project modules
,Project package
,Unified project testing
,Project released
And so on; - Below is a simple illustration of the scaffolding workflow:
Different ends
->Execute various scaffolding commands
->Pull different project templates from the remote end
->Develop projects according to different templates drawn
->After developing the self-test, submit the code to the remote repository
;
Scaffolding /CLI dependency analysis needed
The package name | Functional description |
---|---|
commander | Processing console command |
chalk | Beautify the style of our output on the command line |
fs-extra | File operations |
inquirer | Console query |
handlebars | Template engine rendering |
log-symbols | Print Log Reminder |
ora | Command line loading active effect |
download-git-repo | Remotely Downloading templates |
How to write a minimalist scaffolding /CLI
Let’s give the scaffolding a name first, caoyp-cli
Complete step disassembly:
- Create a project (
create
) - Custom scaffold start command (
commander
) - Ask the user for information about the creation (
inquirer
) - Download the template you need from Github (
download-git-repo
) - Release project (
npm
)
1. Create projects
Before creating the project, let’s briefly define our project structure
├─ ├─ class.txt # ├─ class.txt # class.txt # class.txt # class.txt # class.txt # class.txt # class.txt # class.txt # class.txt # class.txt # class.txt # class.txt └ ─ package. JsonCopy the code
Create a project on Github
git clone https://github.com/Paulinho89/caoyp-cli
cd caoyp-cli
Copy the code
Execute in project directory:
npm init -y
Copy the code
This will automatically help us generate a package.json file in the project root directory
{
"name": "caoyp-cli"."version": "1.0.0"."description": "One-page front end scaffold"."main": "index.js"."scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"caoyp-cli"."caoyp".scaffolding]."author": "caoyp"."license": "ISC"
}
Copy the code
Knocking on the blackboard, here is the key!!
Next we’ll add a bin field to package.json, and at installation time NPM will symlink the file to prefix/bin for global installation or./node_modules/.bin/ local installation. This way, it can be used globally. For example, the following uses caoyp-cli as the command name, and the execution file is index.js in the root directory;
{
"name": "caoyp-cli"."version": "1.0.0"."description": "One-page front end scaffold"."main": "index.js"."bin": {
"caoyp": "./bin/cli.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"caoyp-cli"."caoyp".scaffolding]."author": "caoyp"."license": "ISC"
}
Copy the code
/bin/cli.js
#! /usr/bin/env node
console.log('caoyp-cli working ~~')
Copy the code
#! /usr/bin/env node — this is a code that tells your scripting tool (bash/ ZSH) that you want to run it under node environment.
To facilitate debugging, use the NPM link to link globally
➜ caoyp-cli git:(main) npm link
npm WARN [email protected] No description
npm WARN [email protected] No repository field.
audited 51 packages in1.7s found 0 December /usr/for1local/bin/caoyp-cli -> /usr/local/lib/node_modules/caoyp-cli/cli.js
/usr/local/lib/node_modules/caoyp-cli -> /Users/caoyp/study/caoyp-cli
Copy the code
Test it by typing caoyp on the command line
➜ caoyp-cli git:(main) caoyp
caoyp-cli working ~~
Copy the code
Finish the test and print out the results we want.
2. Customize the scaffolding start command
So first of all, what do we have to do?
- We’re going to use
commander
To implement the - reference
vue-cli
To initialize some common commandscreate
,help
, etc. - If the project already exists, you need to prompt the user whether it is needed
Forced to cover
2.1 Installation Dependencies
npm i commander --save
Copy the code
2.2 Creating Commands
In./bin/cli.js
#! /usr/bin/env node
const program = require('commander')
program
// Define commands and parameters
.command('create <app-name>')
.description('create a new project')
-for --force Forcibly creates a directory. If the created directory exists, the directory is overwritten directly
.option('-f, --force'.'overwrite target directory if it exist')
.action((name, options) = > {
// Prints the execution result
console.log('name:', name, 'options:', options)
})
program
// Set the version number
.version(`vThe ${require('.. /package.json').version}`)
.usage('<command> [option]')
// Parses the parameters passed by the user to execute the command
program.parse(process.argv);
Copy the code
Test it by typing caoyp on the command line
➜ caoyp-cli git:(main) caoyp
Usage: caoyp <command> [option]
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
create [options] <app-name> create a new project
help [command] display help for command
Copy the code
Create [options]
= caoyp create = caoyp create = caoyp create = caoyp create = caoyp create = caoyp create = caoyp create = caoyp create = caoyp create = caoyp
➜ caoyp-cli git:(main) caoyp create
error: missing required argument 'app-name'➜ caoyp-cli git:(main) caoyp create my-project >>> name: my-project options: {} ➜ caoyp-cli git:(main) caoyp create my-project -f >>> name: my-project options: {force:true} ➜ caoyp-cli git:(main) caoyp create my-project --force >>> name: my-project options: {force:true }
Copy the code
At this point, we can get our input information at the command line.
2.3 Running Commands
Create a lib folder and create a create.js
module.exports = async function(name, options) {
console.log('-----create.js', name, options);
}
Copy the code
/bin/cli.js introduces create.js
const program = require('commander');
program.command('create <app-name>')
.description('create a new project')
-for --force Forcibly creates a directory. If the created directory exists, the directory is overwritten directly
.option('-f, --force'.'overwrite target directory if it exist')
.action((name, options) = > {
// Perform the creation task in create.js
require('.. /lib/create.js')(name, options)
})
Copy the code
Execute caoyp create my-project again and print the result
➜ caoyp-cli git:(main) caoyp create my-project
-----create.js
my-project {}
Copy the code
As described above, we need to consider whether the project directory exists at all when we execute the create;
- If yes, a message is displayed indicating that the project already exists. If the value of -f is added to the existing project directory, the command is executed forcibly. In this case, the old directory is deleted and a new directory is created
- If no, create a new directory
We need to use another plug-in fS-Extra to help us judge whether the file exists or not. Meanwhile, we need to install log-Symbols so that we can give users a more friendly reminder when printing logs
Install fs-extra and log-Symbols
npm i fs-extra log-symbols --save
Copy the code
We will continue to improve create.js along these lines
const path = require('path');
const fs = require('fs-extra');
const symbols = require('log-symbols');
module.exports = async function(name, options) {
const cwd = process.cwd();
// Directory address to be created
const targetAir = path.join(cwd, name);
// Check whether the directory already exists
if(! fs.existsSync(targetAir)) {// TODO: create a new directory
} else {
console.log(symbols.error, chalk.red('Project already exists'));
// Whether to force creation
if (options.force) {
await fs.remove(targetAir);
// TODO: asks the user if they are sure to overwrite}}}Copy the code
The logic for labeling TODO is explained in more detail below.
2.4 Improve help commands
For those of you who are careful to use vue-CLI, –help will find a number of help commands that can guide you to use scaffolding ✅.
➜ ~ vue -help
Usage: vue <command> [options]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
init generate a new project from a template
list list available official templates
build prototype a new project
create (for v3 warning only)
help [cmd] display help for [cmd]
Copy the code
So, here we also imitate vue-cli to improve our help command, and first install Chalk to beautify the command line. Figlet helps us print our own logo.
const program = require('commander');
const figlet = require('figlet');
const chalk = require('chalk');
program
.on('--help', () => {
console.log('\r\n' + figlet.textSync('caoyp', {
font: 'Ghost',
horizontalLayout: 'default',
verticalLayout: 'default',
width: 80,
whitespaceBreak: true
}));
console.log(`\r\nRun ${chalk.cyan(`caoyp <command> --help`)} for detailed usage of given command\r\n`)
})
Copy the code
Run caoyp –help to see what is printed
➜ caoyp-cli git:(main) caoyp --help
Usage: caoyp <command> [option]
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
create [options] <app-name> create a new project
help [command] display help for command
('-. _ (`-. ( OO ).-. ( (OO ) .-----. / . --. / .-'), -- -- -- -- -- -., -. _. ` \' .--./ | \-. \ ( OO'.....'\ `.'/ (__... --' '| | -'-.. - '-. / '| | | | | | -') / | / | |
/_) |OO )\| |_.' |\_) | |\| |(OO \ / | |_.'| | | | ` -. "| | - | \ | | | | | / / \ _ | ___. '
(_' '--'\ | | | | `' The '-' '` -. / /. __) | | ` -- -- -- -- --' `--'` -'` -- -- -- -- --'` -' `--' Run caoyp --help for detailed usage of given command Copy the code
3. Ask the user to obtain the creation information
So again, before we do this, let’s analyze how to ask for user information, okay?
- Perfecting the previous TODO step: Ask the user if they want to overwrite the existing directory to download the latest one
const path = require('path');
const fs = require('fs-extra');
const symbols = require('log-symbols');
module.exports = async function(name, options) {
const cwd = process.cwd();
// Directory address to be created
const targetAir = path.join(cwd, name);
// Check whether the directory already exists
if(! fs.existsSync(targetAir)) {// Create a new directory
fn(name, targetAir);
} else {
console.log(symbols.error, chalk.red('Project already exists'));
// Whether to force creation
if (options.force) {
await fs.remove(targetAir);
// Create a new directoryfn(name, targetAir); }}}Copy the code
- Customize template information
const fn = (name, targetAir) = > {
// Customize template project information
inquirer.prompt([
{
name: 'version'.message: 'Please enter the project version'.default: '1.0.0'
},
{
name: 'description'.message: 'Please enter project description information'.default: 'This is a custom scaffold generation project'
},
{
name: 'author'.message: 'Please enter author name'.default: ' '
}
]).then(res= > {
// TODO downloads the Github template})}Copy the code
Caoyp create my-project: caoyp create my-project: caoyp create my-project: If you enter caoyp create my-project -f, you will find that the my-project directory created last time has been removed. Let’s enter the corresponding template information again and create a new template project.
4. Download the required template from Github
As usual, let’s first analyze how to download a user’s template from Github.
github
We have uploaded the default download in advanceThe template
- With the help of
download-git-repo
Auxiliary Download template
Install a dependency on Download-git-repo to download templates from Github. Handlebars user dynamic rendering template prompts; Ora gives a loading effect when downloading.
npm i download-git-repo handlebars ora --save
Copy the code
Create a generator.js file in./lib
const ora = require('ora');
const symbols = require('log-symbols');
const inquirer = require('inquirer');
const fs = require('fs-extra');
const downloadGitRepo = require('download-git-repo');
const chalk = require('chalk');
const handlebar = require('handlebars');
class Generator {
constructor(name, targetDir, res) {
this.name = name;
this.targetDir = targetDir;
this.res = res;
}
async download() {
// 1) Add the download address
const requestUrl = `github.com:Paulinho89/webpack5-single-template#master`;
const spinner = ora('Downloading template, source address:${requestUrl}`);
spinner.start();
// 2) Call the download method
await downloadGitRepo(
// Direct download, default download master
requestUrl,
this.targetDir,
(error) = > {
if (error) {
spinner.fail();
Console. log(symbol. error, chalk. Red (error));
} else {
spinner.succeed();
const fileName = `The ${this.name}/package.json`;
// The command line prompts are displayed after the download is successful
const meta = {
name: this.name,
version: this.res.version,
description: this.res.description,
author: this.res.author
}
// {{name}}/package.json if the path exists
if (fs.existsSync(fileName)) {
// Read the prompt message
const content = fs.readFileSync(fileName).toString();
const resultContent = handlebar.compile(content)(meta); // Write a prompt to the package.json text of the template project
fs.writeFileSync(fileName, resultContent);
}
console.log(symbols.success, chalk.green('Project initialization successful'))
console.log(symbols.info, `\r\n cd ${chalk.cyan(this.name)}`)
console.log(symbols.info, `\r\n npm install`)
console.log(symbols.info, 'npm run start\r\n')}})}}module.exports = Generator;
Copy the code
Git clone status 128 git clone status 128 git clone status 128
Solution:
Wrong way to write:
- Go directly to the Github template link as the first parameter passed directly
- Use {clone: true}
downloadGitRepo('https://github.com/Paulinho89/webpack5-single-template', name, {clone: true}, (err) = > {
console.log(err ? 'Fail' : 'Success')})Copy the code
Correct way to write it:
- Use github.com: username/template name # branch name
- Remove the {clone: true}
downloadGitRepo('github.com:Paulinho89/webpack5-single-template#master', name, (err) = > {
console.log(err ? 'Fail' : 'Success')})Copy the code
- Complete the previous TODO step: After the download is successful, fill in the customized template information entered each time into the template project
package.json
in
The version, Description, and Author fields in the package.json of the template project can be written as dynamic rendering modes.
{
"name": "webpack-single-template"."version": "{{version}}"."description": "{{description}}"."main": "index.js"."scripts": {
"start": "webpack serve --config build/webpack.config.dev.js"."build:test": "rimraf dist && webpack --config build/webpack.config.test.js"."build:prod": "rimraf dist && webpack --config build/webpack.config.prod.js"."lint": "eslint --fix --ext .vue,.js src build"."lint-staged": "lint-staged"."build:stats": "webpack --config build/webpack.config.prod.js --json > stats.json"."analyz": "cross-env NODE_ENV=production ANALYZE=true npm_config_report=true npm run prod"."dll": "webpack --config build/webpack.config.dll"
},
"pre-commit": [
"lint-staged"]."lint-staged": {
"*.{js, vue}": [
"eslint --fix"."git add"]},"author": "{{author}}"."license": "ISC"
}
Copy the code
const Generator = require('./generator');
const fn = (name, targetAir) = > {
// Customize template project information
inquirer.prompt([
{
name: 'version'.message: 'Please enter the project version'.default: '1.0.0'
},
{
name: 'description'.message: 'Please enter project description information'.default: 'This is a custom scaffold generation project'
},
{
name: 'author'.message: 'Please enter author name'.default: ' '
}
]).then(res= > {
// Create the project
const generator = newGenerator(name, targetAir, res); generator.download(); })}Copy the code
When the download template is complete, the user’s input is rendered to package.json.
5. Publish projects
After the above logic sorting, the simple scaffolding we built has been completed, and we need to release it to the NPM warehouse when we actually use it.
Release process:
- Sign up for a
NPM account
If the account is newly registered, you must log in to the email address for verification. Otherwise, the account fails to be advertised.
- perfect
package.json
To determine the release number
{
"name": "caoyp-cli"."version": "1.0.0"."description": "One-page front end scaffold"."main": "index.js"."bin": {
"caoyp": "./bin/cli.js"
},
"directories": {
"lib": "lib"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git"."url": "git+https://github.com/Paulinho89/caoyp-cli.git"
},
"author": "caoyp"."keywords": [
"caoyp-cli"."caoyp".scaffolding]."license": "ISC"."bugs": {
"url": "https://github.com/Paulinho89/caoyp-cli/issues"
},
"homepage": "https://github.com/Paulinho89/caoyp-cli#readme"."dependencies": {
"axios": "^ 0.21.1"."chalk": "^ 4.4.1"."commander": "^ 7.2.0"."download-git-repo": "^ 3.0.2." "."figlet": "^ 1.5.0." "."fs-extra": "^ 10.0.0"."handlebars": "^ 4.7.7"."inquirer": "^ 8.1.1"."log-symbols": "^ 3.0.0"."ora": "^ 5.4.1." "}}Copy the code
- use
npm publish
release
npm publish
Copy the code
After successful publishing, you can go to the NPM repository and see the packages you have published.
Follow our readme.md setup command to install the scaffold to our local, then create, restart, and everything is fine; OK, now our scaffolding from project construction to release the whole process is over.
Wrote last
- At the moment, the scaffolding is a bit more simple, and some steps need to be refined, such as when we pull templates from the remote warehouse, which we usually do during actual development
Multiple versions of templates
, and every template will have itDifferent tag
; Each pull can be done by selecting different version templates, different tags, adding more templates, deleting templates, and so on. Next, I will continue to improve these functions into scaffolding.
If you feel that this article is a little help to you, you are welcome to give me a thumbs up, comments, attention and support after reading, your support is my writing motivation, thank you ~~😁