Writing in the front
You’ve probably used a lot of front-end scaffolding tools, but have you ever wondered how to write your own scaffold? I wrote a simple version of scaffolding before, if you just want to understand this, this article may be helpful to you, the following code logic combing, you can also go to experience
npm install duffy-cli -g
The flow chart
Technology stack
- Development environment: Win7
- Development tool: VScode
- Required dependency packages:
Node.js: The entire scaffolding environment. The node. js version of this scaffold is V8.11.1.
Es6: New syntax for JavaScript.
Commander: A tool developed by TJ to better organize and process command line input.
Chalk: Colorful terminal tool.
Ora: Elegant terminal spinner that controls terminal output, mainly used for loading effects on the command line.
Download-git-repo: used to download remote repositories to GitHub, GitLab, and Bitbucket
Handlebars: A well-known template engine
Ini: INI format parser and serializer for a node
Inquirer: Used to interact with developers on the command line
Metalsmith: Static web site generator
Request: a tool for sending HTTP requests.
Rimraf: equivalent to the UNIX rm -rf command
Semver: version number processing tool
User-home: used to obtain the root directory of the user
Babel-preset -env: New features not supported by the target environment are selected for translation
Project structures,
Initialize the project
After creating the project directory, execute NPM init to complete the initialization of the project as prompted.
Configure global usage
To be used globally, we need to set this in package.json:
"bin": {
"dfcli": "./bin/www"
},
Copy the code
For local debugging, run: NPM link in the project root directory. You can bind the duffy-cli command globally so that you can start the command directly with dfcli
Install dependencies
Dependency is the dependency package above,
npm install semver rimraf .....
Copy the code
Entry file Settings
Current project folder New folder bin create www.js file
#! /usr/bin/env node
require('.. /dist/main.js')
Copy the code
Command management (SRC /main.js)
Use commander to set different commands.
- The command method sets the name of the command.
- The description method sets the description.
- The alias method is a shorthand for setting.
- The action method sets the callback.
Object.keys(configMap).forEach((action) => {
program
.command(action)
.alias(configMap[action].alias)
.description(configMap[action].description)
.action(function () {
if (action == 'new'CheckVersion (()=>{main(action,... process.argv.slice(3)) }) }); })Copy the code
Each time you execute the master file, check whether the version is up to date and prompt
Processing user input (\ SRC \config.js)
Create a.bgrc file under the root directory and write the following content, which is used to store the user managed platform name, warehouse address, template information, etc. Template information is still under development, the template information will be put out for special processing.
Handle user input commands (\ SRC \utils\rc.js)
New/Modified
dfcli config set <key> <value>
Copy the code
The set function has two functions, the first implementation of user input to add and modify, the second implementation of initialization rc file.
Implementation code:
export let set = async (k,v) => {
let has = await exist(rcUrl)
if (k && v) {
let opts
if (has) {
opts = await readFile(rcUrl, 'utf-8')
opts = decode(opts)
opts = Object.assign(opts,{[k]: v})
} else {
opts = Object.assign(DEFAULT,{[k]: v})
}
await writeFile(rcUrl, encode(opts), 'utf-8')}else{// rc initializationif (has) return
await writeFile(rcUrl, encode(DEFAULT), 'utf-8')}}Copy the code
View/Obtain
dfcli config get <key>
Copy the code
If there is no get followed by a key, getAll() is used to obtain all the contents of the BGRC file
Eg: dfcli config get
export let get = async (k) => {
let has = await exist(rcUrl)
let opts
if (has) {
opts = await readFile(rcUrl, 'utf-8')
opts = decode(opts)
console.log(opts[k])
} else {
return ' '}}export let getAll = async () => {
let has = await exist(rcUrl)
let opts
if (has) {
opts = await readFile(rcUrl, 'utf-8')
return decode(opts)
} else {
return ' '}}Copy the code
delete
dfcli config remove <key>
Copy the code
Code implementation:
export let remove = async (k) => {
let has = await exist(rcUrl)
let opts
if (has) {
opts = await readFile(rcUrl, 'utf-8')
opts = decode(opts)
if (opts.hasOwnProperty(k)) {
delete opts[k]
}
await writeFile(rcUrl, encode(opts), 'utf-8')}else {
return ' '}}Copy the code
Changing the Template Address
dfcli config set repertroy github:owner
Copy the code
dfcli config set username yourname
Copy the code
View the template list (\ SRC \list.js)
dfcli list
Copy the code
Initialize the project (\ SRC \install.js)
Command:
dfcli init
Copy the code
Get the name of the template hosted on Github according to the configuration of the.bgrc file:
// List of template nameslet getTplNameList = async () => {
let loading = ora('Loading template list ....... ')
loading.start()
let list = await getTplList()
loading.succeed('template list complete.')
let name = list.map((list) => list.name)
return name
}
Copy the code
After obtaining a list of template names, let the user select a template
const promptList = [{
type: 'list',
message: 'Please select a template: ',
name: 'tpl_name',
choices: tplnameList
}]
let ans = await inquirer.prompt(promptList)
console.log(ans.tpl_name)
Copy the code
1. Check whether the current template is cached locally. If yes, ask the user whether the template is overwritten
2. After selecting the template, ask the user to enter the project name and the project target folder
3. Generate the render template to the specified location
// Check whether there is a template locallylet localCheckTpl = (tmpName) => {// Remote template address const tmpRepo=path.resolve(userHome,'.tpl'Const tmpDest=path.join(tmpRepo,tmpName) const tmpDest=path.join(tmpRepo,tmpName)return{isExist: exists(tmpDest), tmpDest}} // Download the templateletDownloadTplAndGenrate = async (proName) => {// Remote template address const tmpRepo=path.resolve(userHome,'.tpl'Const tmpDest=path.join(tmpRepo,proName) // Local template store const tmpDest=path.join(tmpRepo,proName)let all = await getAll()
letloading = ora(`download template start... `) loading.start() await download( `${all.repertroy}/${proName}`, home + '/.tpl/' + proName)
loading.succeed(`template download complete.`)
await generate(tmpDest)
}
// generate.js
exportDefault Async (tmpPath)=>{// Initialize Metalsmith object const Metalsmith =Metalsmith(tmpPath) // User enters the project name and target folderlet answer = await inquirer.prompt([{
type:'input',
name:'name',
message:'Please enter your project name:',
default:'dfcli-project'}, {type:'input',
name:'destination',
message:'Please enter the path where your project will be stored:'. Default :process.cwd()}]) // Project generation path const destination=path.join(absolutePathFormat(answer.destination),answer.name) const loading = ora('generating... '// Add a new global variable object.assign (metalsmith.metadata(),answer) // console.log(metalsmith.metadata()) load.start () metalsmith .source('. ')
.destination(destination)
.clean(false)
.build(function(err) {
loading.stop()
if (err) throw err
console.log()
console.log(chalk.green('Build Successfully'))
console.log()
console.log((`${chalk.green('Please cd')} ${destination} ${chalk.green('to start your coding')}`))
console.log()
})
}
Copy the code
Description of project Structure
| - bin | ` - WWW / / master file entry, Start to run the main. Js | - package. Json ` - SRC | -- config. Js configuration of the rc file to add and delete. | - create js new to create a single page or template | -- the generate. | - generated js building project content Index. js Executes different commands (dfcli init, dfcli config, dfcli list, dfcli new) according to user input action commands. Specific tasks separately from here | - the js template initialization (dfcli init) | -- list. Js local template list (dfcli list) | -- main. Js by commander initialization and set different command | - New. Create the realization of a page or template ` js -- utils | -- checkVersion. Js package version check | -- constant. Js need some constants | -- gitHandle. | - js git related operationslocalPath.js Path check '-- rc.js RC file add, delete, change check specific operation methodCopy the code