What is scaffolding, Baidu Encyclopedia explanation is: scaffolding is to ensure the smooth construction process and set up the working platform. In front end work, I think of it as a set of tools that allow us to focus on our business code development without having to spend time doing repetitive work that is often done.
preface
Pig with qi hand grain, we are working people 🤣.
The use of three king Kong front-end development partners must have used various scaffolding tools, DO not know if there is a hand itching to try to write, la la la, anyway, I looked at the author’s article is itching. I’ve always wanted to learn NodeJS scaffolding development, but I’ve been defeated by my laziness every time, so I’ve spent some time writing a small DEMO, which is a notepad tool in the article. This tool does not involve git download (see other articles in the article). As for how to publish NPM packages, you can see my other article 🍖, which is a step-by-step guide to publishing NPM packages. This article is more about the workflow of a scaffold and the use of common tools. Without further ado, let’s get started!
Code annotation written more clearly, expect every small partner can understand. Of course, the author itself is only a primary front-end, which if there is what to say wrong, also please big guys point out, thank you 🙈, of course, if feel that write well, might as well give three even yo.
Initializing the Environment
1, requirements,
2. Project dependency
- NodeJS: v12.18.3
3. Tool library
- Chalk: Modify the text color of input and output and add the icon of success and failure
- Commander: Command line assistance library. You can add command prompts and parse parameters
- Inquirer: Command line interaction, input, options, etc
- Minimis “: command line parameter resolution, can be replaced by commander
- Ora: Terminal rotator, beautify progress
- Prettier: Code formatting
- Dayjs: time formatting tool
4. Project structure
Files that need attention
├── ├─ ├─ new exercises, ├─ new exercises, new exercises, new exercises, new Exercises, new Exercises, new Exercises, new Exercises, new Exercises - the command directory │ │ ├ ─ ─ the add. Js │ │ ├ ─ ─ del. Js │ │ ├ ─ ─ the exit. The js │ │ ├ ─ ─ the find, js │ │ ├ ─ ─ the list. The js │ │ └ ─ ─ open. Js │ ├ ─ ─ the config - configuration file directory │ │ └ ─ ─ index. The js │ ├ ─ ─ service. Js - entry documents │ └ ─ ─ utils - tool class encapsulates │ ├ ─ ─ the file. The js │ └ ─ ─ utils. Js ├ ─ ─ package. The jsonCopy the code
5, case
git clone https://github.com/taosiqi/notepad-cli.git
cdNotepad -cli yarn NPM link // Link to global notepad-cli open or NPM install -g notepad -CLI installation experienceCopy the code
An introduction to case
1. Create a project
1Mkdir notepad-cli && CD notepad-cli2Create a directory based on the directory structure above3Install the libraries mentioned aboveCopy the code
NPM init creates package.json, which should produce a file like this
{
"name": "notepad-cli"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": []."author": ""."license": "ISC"
}
Copy the code
Adding the bin command
"bin": {
"notepad-cli": "bin/notepad-cli.js" // Scaffolding can be used with notepad-cli after executing NPM link
},
Copy the code
This is what it looks like when you add the dependencies
{
"name": "notepad-cli"."version": "1.0.0"."description": "Node Notebook"."main": "lib/service.js"."homepage": "https://github.com/taosiqi/notepad-cli"."author": {
"name": "siqiJson"
},
"keywords": [
"notepad"."cli"]."bin": {
"notepad-cli": "bin/notepad-cli.js"
},
"license": "MIT"."repository": {
"type": "git"."url": "https://github.com/taosiqi/notepad-cli"
},
"dependencies": {
"chalk": "^ 4.1.0." "."commander": "^ 6.2.1." "."dayjs": "^ 1.9.8"."inquirer": "^ 7.3.3." "."minimist": "^ 1.2.5." "."ora": "^ 5.1.0"."prettier": "^ 2.1.1"}}Copy the code
2. Simple examples
Create the /bin/notepad-cli.js file
#! /usr/bin/env node
// The first line is essential because it tells the system that the script needs to be executed using the Node interpreter.
console.log('NodeJS Scaffolding')
Copy the code
Project root type NPM link, which links the specified execution file globally (equivalent to NPM -g install XXX) so that we can use the scaffolding tool globally.
NPM link error can be first uninstall scaffolding NPM -g uninstall notepad-cli
Executing notepad-cli will execute the /bin/notepad-cli.js file
F:\notepad-cli>notepad-cli nodejs scaffoldingCopy the code
Case analysis
The following is the basic code annotation, friends refueling!
1, entry file notepad-cli
#! /usr/bin/env node
// The first line is essential because it tells the system that the script needs to be executed using the Node interpreter.
// This file is mainly used to handle the entry file that accepts parameters,
const Service = require('.. /lib/service') // Import our entry file
const service = new Service() // Instantiate Service
const rawArgv = process.argv.slice(2)
console.log(rawArgv) //[ 'open' ]
const args = require('minimist')(rawArgv) // Parse command line arguments
console.log(args) //{ _: [ 'open' ] }
const command = args._[0]
// Perform initialization
service.run(command, args, rawArgv)
Copy the code
2. Run the service command
Run (command, args, rawArgv) will execute the /lib/service.js file
const program = require('commander') // Add version command prompt
const { packageInfo, open } = require('./config') // Config file
const {readDoc}=require('./utils/file') // File manipulation
module.exports = class Service {
constructor() {
readDoc() // Save the file under doc to a global variable for easy operation
setupDefaultCommands() // Set the default command
registerCommands() // Register custom commands
}
run(_id, _args = {}, rawArgv = []) {
program.parse(rawArgv, { from: 'user' }) // Execute the corresponding command}}// Set the default command
const setupDefaultCommands = () = > {
program.version(packageInfo.version, '-v, --version'.'Output current version number')
program.helpOption('-h, --help'.'Get Help')
program.addHelpCommand(false)}// Register the command
const registerCommands = () = > {
return program.command('open').description('Open Notepad').alias('o').action(() = > {
open.apply(program.args)
})
}
Copy the code
3. Open the Notepad command open
/lib/service.js file to register the custom command open, run notepad-cli open.
const inquirer = require('inquirer') //// Command line interaction
const { readKey } = require('.. /utils/file')// File manipulation
async function init(commands) {
const promptList = {
type: 'list'.message: 'Welcome to siqi Notepad, please select the function you want to operate :'.name: 'tools'.choices: () = > {
let promptList = []
// Read commands all commands, push options, for the user to select
for (const commandsKey in commands) {
promptList.push({
name: commands[commandsKey].description,
value: commandsKey
})
}
return promptList
}
}
return promptList
}
module.exports = {
description: 'Open Notepad'.apply: async() = > {let commands = await readKey()
let promptList = await init(commands)
await inquirer.prompt(promptList).then(async (answers) => {
await commands[answers.tools].apply() // Execute the selected command
const command = require(`${__dirname}/open.js`)
await command.apply() // Return to the current page after performing the above functions}}})Copy the code
4. Add Notepad add
const inquirer = require('inquirer') // Command line interaction
const { succeed } = require('.. /utils/utils') // Encapsulate the prompt type log
const { add } = require('.. /utils/file') // File manipulation
const dayjs = require('dayjs')
const promptList = [
{
type: 'input'.message: 'Please enter title :'.name: 'title'.validate: (val) = > {
returnval ! = =' '}}, {type: 'input'.message: 'Please enter :'.name: 'content'.validate: (val) = > {
returnval ! = =' '}}]module.exports = {
description: 'Add notes'.apply: async() = > {await inquirer.prompt(promptList).then(async (answers) => {
// Construct the file structure
const timestamp = new Date().getTime()
constdata = { ... answers,time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
timestamp: timestamp
}
// Create a notepad file
add(data, timestamp)
})
succeed('Added successfully')
return Promise.resolve()
}
}
Copy the code
Delete notepad del
const { del } = require('.. /utils/file')
const { succeed, info } = require('.. /utils/utils')
const inquirer = require('inquirer')
function init() {
const promptList = {
type: 'input'.message: 'Please enter the record serial number you want to delete :'.name: 'del'.validate: (val) = > {
// We can make rule judgments here
let value = parseInt(val)
return (
typeof value === 'number'&&!isNaN(value) &&
value > 0 &&
value < articleList.length + 1)}}return promptList
}
// Get the list of notes
function initLog() {
let log = ' '
articleList.forEach((item, index) = > {
log += `${index + 1}:${item.title} \n`
})
return log
}
module.exports = {
description: 'Delete notes'.apply: async() = > {let promptList = await init()
let log = await initLog() // Displays a list of all articles
info(log)
await inquirer.prompt(promptList).then(async (answers) => {
await del(answers['del'])
succeed('Deleted successfully')
return Promise.resolve()
})
}
}
Copy the code
6. Exit Notepad exit
const { succeed } = require('.. /utils/utils')
module.exports = {
description: 'Exit chronicle'.apply: async (env) => {
succeed('Exit successful')
process.exit(1)}}Copy the code
7, Find notepad
const inquirer = require('inquirer')
const { info, underline } = require('.. /utils/utils')
// Enter the search keyword
function init() {
const promptList = {
type: 'input'.message: 'Please enter the key words of note article :'.name: 'find'.validate: (val) = > {
returnval ! =' '}}return promptList
}
// Filter by keyword
function filtrate(keyWord) {
const filtrateData = {
type: 'list'.message: 'Diary list :'.name: 'tools'.choices: () = > {
let promptList = []
const data = articleList.filter((item, index) = > {
return( item.title.indexOf(keyWord) ! = -1|| item.content.indexOf(keyWord) ! = -1
)
})
data.forEach((item, index) = > {
promptList.push({
name: item.title + ' ' + item.time,
value: index
})
})
return promptList
}
}
return filtrateData
}
module.exports = {
description: 'Find notes'.apply: async() = > {let promptList = await init()
let keyWord = ' '
await inquirer.prompt(promptList).then((answers) = > {
keyWord = answers.find
})
let filtrateData = await filtrate(keyWord)
if(filtrateData.choices().length ! = =0) {
await inquirer.prompt(filtrateData).then((answers) = > {
console.log(underline(articleList[answers.tools].content))
})
} else {
info('Contents not found')}}}Copy the code
8, Notepad list list
const inquirer = require('inquirer')
const { info, underline } = require('.. /utils/utils')
function init() {
const promptList = {
type: 'list'.message: 'Diary list :'.name: 'tools'.choices: () = > {
let promptList = []
articleList.forEach((item, index) = > {
promptList.push({
name: item.title + ' ' + item.time,
value: index
})
})
return promptList
}
}
return promptList
}
module.exports = {
description: 'List of notes'.apply: async() = > {let promptList = await init()
if(promptList.choices().length ! = =0) {
await inquirer.prompt(promptList).then((answers) = > {
console.log(underline(articleList[answers.tools].content))
})
} else {
info('Contents not found')}}}Copy the code
9. Configure file config/index
module.exports = {
packageInfo: require('.. /.. /package.json'), // Get the package file to display the version number
open: require('.. /commands/open')// Get the open file
}
Copy the code
10, file operation file
// Notepad operations on files are placed in this area, where a global variable articleList is created to store the contents of notepad for the first time
const fs = require('fs')
const path = require('path')
const docPath = path.join(__dirname, `.. /.. /doc`)
const commandPath = path.join(__dirname, `.. /commands`)
module.exports = {
// Add file
add: (data, timestamp) = > {
fs.writeFile(
`${docPath}/${timestamp}.txt`.JSON.stringify(data),
(error) = > {
if (error) {
console.error('Write failed')}else {
articleList.push(data)
}
}
)
},
// Delete files
del: (name) = > {
fs.unlinkSync(`${docPath}/${articleList[name - 1].timestamp}.txt`)
articleList.splice(name - 1.1)},// Read commands from the commands directory
readKey: () = > {
let commands = {}
fs.readdirSync(commandPath).forEach((paths) = > {
const command = require(`${commandPath}/${paths}`)
if (Object.keys(command).length ! = =0) {
let commandName = paths.slice(0, -3)
commands[commandName] = command
}
})
return commands
},
// Read the contents of the doc file
readDoc: () = > {
global.articleList = []
fs.readdirSync(docPath).forEach((fileName) = > {
fs.readFile(
`${docPath}/${fileName}`.'utf-8'.function (err, data) {
if (err) {
console.error(err)
} else {
articleList.push(JSON.parse(data))
}
}
)
})
articleList.reverse()
}
}
Copy the code
11. Text prompt util
const ora = require('ora')
const chalk = require('chalk')
module.exports = {
// Log information
log: (message) = > {
console.log(message)
},
// Success message
succeed: (. message) = > {
ora().succeed(chalk.greenBright.bold(message))
},
// Prompt message
info: (. message) = > {
ora().info(chalk.blueBright.bold(message))
},
// Error message
error: (. message) = > {
ora().fail(chalk.redBright.bold(message))
},
// Underline important information
underline: (message) = > {
return chalk.underline.blueBright.bold(message)
}
}
Copy the code
conclusion
The DEMO does not use difficult things, mainly to give you a basic understanding of scaffolding development. If you still don’t understand your friends, you can download the Github case and run. It is best to copy it and rewrite it again. A good memory is better than a bad pen, I believe you will have a deeper understanding.
After watching the friends can move their hands to point a “like” and then go oh, your support is the biggest encouragement to me!!
reference
- deploy-cli-service
- NodeJS Chinese website