What is scaffolding
Baidu explanation: scaffolding is to ensure the smooth construction process and set up the working platform, it is so long…
So what are we talking about scaffolding in development? Scaffolding usually refers to a tool that allows developers to quickly frame projects, files, or simply copy template generation files. Scaffolding can do more than just “copy”, but this is the most common one.
Do it!!
Initialize the project
Run the following command on the CLI
mkdir my-cli
cd my-cli
npm init
npm link
Copy the code
Mkdir my-cli Create the my-cli folder. In this folder (CD my-cli switch to my-cli file) execute NPM init to initialize the project. NPM link generates package-lock.json file.
Create the scaffolding entry file cli.js in the root directory and configure it in packGage. Json
Next, let’s start writing our first scaffolding. cli.js
#! /usr/bin/env node
console.log("This is my-cli!");
Copy the code
#! The /usr/bin/env node must be written in a header to tell the operating system where to find the Node interpreter when executing the script.
Run the my-cli test in the current directory:
OK, it’s flying!
Generate files using templates
Now that our scaffold is flying, let’s make it replicate. The logic is simple: first read the contents of file A, then create A file B, write the contents of A to B.
First, create the templates folder to hold the template files, and then create the template file index.vue:
/** * templates\index.vue * */
<template>
<div>
<section class="search-area">This is the search area</section>
<section class="table-area">Here is the table area</section>
</div>
</template>
<script type="text/javascript">
export default {
name: "template".data(){
return {
// Query data
searchData: {},
// Table data
tableData: []}},created(){
this.getDataList();
},
methods: {
// Get data
getDataList(){},
// Add data
addData(){},
// Edit data
editData(){},
// Delete data
deleteData(){}}}</script>
<style lang="scss">
</style>
Copy the code
Modify the cli. Js:
#! /usr/bin/env node
const fs = require("fs"); // Node.js file handling module
const path = require("path"); // Node.js handles files and directory paths
const templatePath = path.join(__dirname, "templates/index.vue"); // Get the templates absolute path
const currentPath = process.cwd(); The process. CWD method returns the current working directory of the Node.js process
const writePath = path.join(currentPath, "index.vue"); // Write path to the file
// readFileSync reads the contents of the file
fs.readFile(templatePath, {}, function (err, fileContent) {
if(err) throw err;
// writeFileSync Writes file contents
fs.writeFileSync(writePath, fileContent);
});
Copy the code
Run the my-cli test in the current directory:
The template files we copied are in the my-CLI folder.
Commander Receives command line command parameters
Now that our file has been “copied” successfully, but we don’t want it to be called index.vue, what if we want to customize the name of the “copied” file?
This is where commander, the command line interaction tool, comes in.
NPM install commander install Commander, modify cli.js:
#! /usr/bin/env node
const fs = require("fs"); // Node.js file handling module
const path = require("path"); // Node.js handles files and directory paths
const { program } = require("commander");
/** * command Sets the command * create as a custom command name * <> The name of the package is a mandatory parameter. If you do not input this parameter, an error will be reported. * Action is the command callback, and the parameter is the parameter configured in Commond ** */
program
.command("create <name>")
.action((name) = > {
createFileByTemplate(name);
});
/** * Parse handles command line arguments * process.argv returns command line arguments. Process is the Node.js process control module **/
program.parse(process.argv);
function createFileByTemplate(name){
const templatePath = path.join(__dirname, "templates/index.vue");
const currentPath = process.cwd();
const writePath = path.join(currentPath, `${name}.vue`); // Use the name parameter to set the write path of the file
// readFileSync reads the contents of the file
fs.readFile(templatePath, {}, function (err, fileContent) {
if(err) throw err;
// writeFileSync Writes file contents
fs.writeFileSync(writePath, fileContent);
});
}
Copy the code
Run my-cli create xx on the command line to test:
As you can see, an error is reported when name is not entered because it is a required argument.
Inquirer command line interaction
Command parameters received, that can receive the user real-time input, and interact with the user? Inquirer, a command-line interaction tool, is here to stay.
Const inquirer = require(“inquire”); const inquirer = require(“inquire”) , change the cli. Js:
function createFileByTemplate(name){
const templatePath = path.join(__dirname, "templates/index.vue");
const currentPath = process.cwd();
const context = { name };
prompt(templatePath, currentPath, context);
}
function prompt(readPath, writePath, context){
// Use inquirer to interact
inquirer.prompt({
type: "input".// Interaction type: input
message: "confirm name: ".// Prompt message
name: "name".// Parameter name
default: context.name / / the default value
}).then(answer= > {
// Answer Is the user input answer
writePath = path.join(writePath, `${answer.name}.vue`);
loadFile(readPath, writePath, answer);
});
}
// Load the file
function loadFile(readPath, writePath, context){
fs.readFile(readPath, context, function (err, fileContent) {
if(err) throw err;
fs.writeFileSync(writePath, fileContent);
});
}
Copy the code
Execute the command line:
You will be prompted to confirm the file name, press Enter will use the default value, otherwise use the name entered here:
Ejs passes data to the template
Now that the file name has been changed, what if we also want to change the component’s name property?
Using ejS template engine, of course!
NPM install ejs: const ejs = require(“ejs”);
Modify the loadFile method,
function loadFile(readPath, writePath, context){
ejs.renderFile(readPath, context, (err, result) = > {
if(err) throw err;
fs.writeFileSync(writePath, result)
});
}
Copy the code
Modify the index.vue template:
Execute the create command again to check the name property in the build file, which is already our custom name:
Process multiple template files
We have already “copied” a single template file, but usually we need to “copy” more than one file. Add our template like this:
In this case, we need to go through the files in the directory, copy one by one, modify cli.js:
function createFileByTemplate(name){
const templatePath = path.join(__dirname, "templates");
const currentPath = process.cwd();
const context = { name };
prompt(templatePath, currentPath, context);
}
function prompt(readPath, writePath, context){
// Use inquirer to interact
inquirer.prompt({
type: "input".// Interaction type: input
message: "confirm name: ".// Prompt message
name: "name".// Parameter name
default: context.name / / the default value
}).then(answer= > {
// Answer Is the user input answer
writePath = path.join(writePath, answer.name);
loadDirectory(readPath, writePath, answer);
});
}
// Load the directory
function loadDirectory(readPath, writePath, context = {}){
writePath = createDirectory(writePath);
// readdir Reads the contents of the readPath directory. Files is the list of files under the directory
fs.readdir(readPath, (err, files) = > {
if(err) throw err;
// Iterate over the list
files.forEach(file= > {
const _readPath = path.join(readPath, file); // The absolute path of the file to be copied
const _writePath = path.join(writePath, file); // The absolute path of the file to be written
// stat Gets the file object description
fs.stat(_readPath, (err, stats) = > {
if(err) throw err;
if(stats.isDirectory()){
/ / directory
loadDirectory(_readPath, _writePath, context);
} else if(stats.isFile()){
/ / fileloadFile(_readPath, _writePath, context); }}); }); }); }// Create file (folder)
function createDirectory(directory){
// If the file (folder) does not exist, create a new one
if(! fs.existsSync(directory)) {// Create file (folder)
fs.mkdir(directory, (error,result) = > {
if(error) throw error;
});
}
return directory;
}
Copy the code
Run my-cli create user again:
We did it again!!
Published to the NPM
The so-called good things to everyone to share, quickly share your scaffolding to friends shake up ~~~ root directory execution:
npm adduser
npm publish
Copy the code
NPM install my-cli -g
Then we can use my-CLI globally!