I remember at the beginning of learning vue, directly import vue. Js file to learn, then use VUE-CLI, has been using, recently suddenly remembered how vue-CLI is implemented, so I went to see the scaffolding construction
Now, the way I know how to build,
- Put the template in the Github repository and run commands to pull code from Github locally
- Using Yeoman-generator, place the template in the generator and use yo to pull the template from the generator locally
So simple, just put the code in a certain place, when you need to pull the code to a local, but in addition to pull the related file to local, used the scaffold students must know, at the time of initialization, scaffolding will put forward some problems, according to different input we choose, the final configuration is different also, Git clone and Yo <name> can be used to scaffold scaffold
I wrote two simple scaffolding, SCav-cli and generator-wxfile respectively, corresponding to the above two methods. Since I started writing generator just to write a generator, I wrote the name like that directly, and did not change it temporarily. The following content is the original version. I have updated both of them later, so when downloading and using, I still directly read the corresponding documents I wrote. Scav-cli is to pull the vUe-related templates to the local using Git Clone
Generator-wxfile takes the files from the template to the currently created project directory using the yo command
scav-cli
I’m going to use a couple of NPM packages here
Inquirer: used to ask questions and get answers from the user chalk: changes the style of the content printed on the command line. Child_process: used to execute commands on the command line. Commander: used to define your own commands
Initialize scaffolding
Here you first initialize your own scaffolding
mkdir scav-cli
cd scav-cli
npm init
Copy the code
After initialization, write the corresponding development dependencies in package.json
"Dependencies" : {" chalk ", "^ 3.0.0", "child_process" : "^ 1.0.2", "commander" : "^ 4.4.1", "the inquirer" : "^ 7.0.4"},Copy the code
npm i
Copy the code
Download the relevant NPM packages to node_modules, and then start scaffolding, creating scav.js files in the bin folder to define the relevant commands
Define related commands
The first step is to define the scaffolding file path, introduce the related dependency packages, and define the scaffolding version
#! /usr/bin/env node --harmony
'use strict'
// Define the scaffold file path, __dirname is the current file path
process.env.NODE_PATH = __dirname + '/.. /node_modules/'
const program = require('commander')
// Get version from package.json as the project version number
program.version(require('.. /package').version)
// Define the use of scaffolding, as shown in the program.help method
program.usage('<command>')
Copy the code
Define initialization commands for scaffolding
/* command indicates the command to be executed. Description indicates the description of the command. Alias indicates the action of the command
program
.command('init')
.description('init a vue-based project')
.alias('i')
.action((a)= >{
console.log('I'm the initialization method')})// program.parse(arguments) handles arguments and unused options are stored in the program.args array
program.parse(process.argv)
Copy the code
Execute the following command in the root directory
node bin/scav init
Copy the code
If the following information is displayed, the configuration is successful
"bin": {
"scav": "bin/scav.js"
},
Copy the code
Then use the NPM link to go global and use scAV init directly on the command line, as shown
// If an option is placed in program.args, that is, not processed by program.parse, the default is to use program.help() to print out commands that the NPM package can execute
// Help can be customized with program.on('--help', function(){}
if (program.args.length) {
program.help()
}
Copy the code
We can print out program.args before we decide
console.log('program.args: ', program.args);
Copy the code
Write specific operations
To define the initialization methods, create a command folder in the root directory to store the command operations and create init.js to write the initialization operations
// init.js
const inquirer = require('inquirer')
const chalk =require('chalk')
const {exec} = require('child_process')
chalk.level = 3 // Set chalk level to 3
module.exports = (a)= >{
console.log(chalk.green('Start initializing file'))
console.log(chalk.gray('Initializing... '))
console.log(chalk.green('Initialization completed'))}Copy the code
Call the init.js file in the init.js file
program
.command('init')
.description('init a vue-based project')
.alias('i')
.action((a)= >{
require('.. /command/init.js')()
})
Copy the code
Try the initialization command again, as shown in the figure
module.exports = (a)= >{
console.log(chalk.green('Start initializing file'))
inquirer.prompt([{
type:'input'.// The question type is fill-in-the-blank
message:'your projectName:'.// Problem description
name:'projectName'.// The attribute corresponding to the problem
validate:(val) = >{ // Determine the input value
if(val==="") {return chalk.red('Project name cannot be empty, please re-enter')}return true
}
}]).then(answer= >{
console.log(chalk.gray('Initializing... '))
console.log(chalk.green('Initialization completed'))})}Copy the code
The effect is shown in figure
module.exports = (a)= >{
inquirer.prompt([{
type:'input'.// The question type is fill-in-the-blank
message:'your projectName:'.// Problem description
name:'projectName'.The user input is stored in the property corresponding to the first parameter in the then method
validate:(val) = >{ // Determine the input value
if(val==="") {return chalk.red('Project name cannot be empty, please re-enter')}return true
}
}]).then(answer= >{ // Perform various operations through user input
console.log(chalk.green('Start initializing file \n'))
console.log(chalk.gray('Initializing... '))
const gitUrl = 'https://github.com/QZEming/vue-temp.git'
exec(`git clone ${gitUrl} ${answer.projectName}`,(error,stdout,stderr)=>{
if (error) { // Print an error if there is an error and exit the operation
console.log(chalk.red(error))
process.exit()
}
console.log(chalk.green('Initialization completed'))
process.exit() Exit the command line operation})})}Copy the code
The configuration is successful as shown in the figure
Modify the generated file
Json, the name is vue-temp, which is not what we expected. So we need to introduce a FS module to read and write the package.json. To get the path to the current command line, use process.cwd()
const fs = require('fs')
module.exports = (a)= >{
inquirer.prompt([{
type:'input'.// The question type is fill-in-the-blank
message:'your projectName:'.// Problem description
name:'projectName'.The user input is stored in the property corresponding to the first parameter in the then method
validate:(val) = >{ // Determine the input value
if(val==="") {return chalk.red('Project name cannot be empty, please re-enter')}return true
}
}]).then(answer= >{ // Perform various operations through user input
console.log(chalk.green('Start initializing file \n'))
console.log(chalk.gray('Initializing... '))
const gitUrl = 'https://github.com/QZEming/vue-temp.git'
exec(`git clone ${gitUrl} ${answer.projectName}`,(error,stdout,stderr)=>{ // Clone the template and go to the project root directory
if (error) { // Print an error if there is an error and exit the operation
console.log(chalk.red('Failed to copy file'))
process.exit()
}
fs.readFile(`${process.cwd()}/${answer.projectName}/package.json`,(err,data)=>{
if(error){
console.log(chalk.red('File reading failed'))
process.exit()
}
data= JSON.parse(data.toString())
data.name = answer.projectName
fs.writeFile(`${process.cwd()}/${answer.projectName}/package.json`.JSON.stringify(data,""."\t"),err=>{
if(err){
console.log(chalk.red('Failed to write file'))
process.exit()
}
console.log(chalk.green('Initialization completed'))
process.exit() Exit the command line operation})})})})}Copy the code
When we open package.json, we find that it is the same as the project name we entered
I have published the scaffolding to NPM, the relevant code on Github, can also be NPM I scav-cli -g try related content
generator-wxfile
The basic function
In this case, I used Yeoman to generate duplicate files, and in this case I used Plop to do this, and I used Yeoman to pull the original files locally
- Ask the user to build the project name, which is the folder name by default, and write it to the project.config.json file
- Ask the user for the APPID used in the build, which is simply written to the project.config.json file
- Ask the user for the file name of the default page when building the project, build the corresponding folder and file, and write the corresponding route in app.json
- Ask the user if plop is enabled to quickly build duplicate files, and if so add plopfile.js and template files to the project
- Use the plop tool to write duplicate files to the Pages folder, and write corresponding routes to app.json
File directory
The basic file directory is the same as that in the tempPage file, except that the syntax of the replacement text is different. The replacement text in the tempPage file is written using Yeoman, so it uses ejS syntax, <%= prop%> syntax. The files in the Plop-temp folder are templates used when the plop tool is used, using {{prop}} syntax instead
github
Yeoman implements the initialization process
Asks the user
As mentioned above, I want to implement the method of asking the user. The NPM package inquire can be used here, but since yeoman already has this functionality, I will use the Prompt method of yeoman-generator directly
The yeoman-generator package is first introduced, and a class is exported, where the this.prompt method is called in the only insurgent method, with the following code
const Generator = require("yeoman-generator")
module.exports = class extends Generator{
prompting(){
return this.prompt([{ // Ask the user for the name of the project to create
type:"input".name:"projectName".message:"your project name is".default:this.appname // The name of the folder where the project is located}, {// Ask the user what the appID is
type:"input".name:"appID".message:"your appID is"}, {// Ask the user what is the first page name to initialize
type:"input".name:"pageName".message:"the initialized page name is".default:"index" // The index page is created by default}, {// Ask the user whether to use the plop tool
type:"confirm".name:"isPlop".message:"do you use plop".default:true // By default
}]).then(answer= >{
this.answer = answer // Place the answer in the answer property}}})Copy the code
Writes files based on user input
Above we get the user’s input into this.answer. In writing we use these answers to change the name of the corresponding page to be written. The pageName obtained above is the name of the folder in the page that we initialized. And the names of js, JSON, WXSS and WXML files under the folder, and according to the isPlop obtained above to determine whether to add the contents of the plopfile.js folder and plopfile.js file to the project, because it involves the creation of folder, so the FS module is introduced here, the code is as follows
const Generator = require("yeoman-generator")
const fs = require("fs")
module.exports = class extends Generator{
prompting(){
// ...
}
writing(){
const answer = this.answer
const pageName = answer.pageName
// Process the page template file
let tempPageFiles = ["tempPage.js"."tempPage.json"."tempPage.wxml"."tempPage.wxss"]
.map(path= >"tempPage/"+path)
// List of other files
let tempOtherFiles = ["app.js"."app.json"."app.wxss"."project.config.json"."sitemap.json"."package.json"]
// Merge all template files
let tempFiles = [...tempPageFiles,...tempOtherFiles]
// Process the page output file
let outputPageFile = [`${pageName}.js`.`${pageName}.json`.`${pageName}.wxml`.`${pageName}.wxss`]
.map(path= >`pages/${pageName}/${path}`)
// Merge all output files
let outputFiles = [...outputPageFile,...tempOtherFiles]
if(answer.isPlop){ // If you use the plop tool, write the corresponding file
tempFiles=[...tempFiles,...["plop-temp"."plopfile.js"]]
outputFiles=[...outputFiles,...["plop-temp"."plopfile.js"]]}// Create a folder and call the callback function to write the file after the folder is created
fs.mkdir(`pages/${pageName}`.'1', () = > {// File write
for(let i=0; i<tempFiles.length; i++){this.fs.copyTpl(this.templatePath(tempFiles[i]),this.destinationPath(outputFiles[i]),answer)
}
})
}
}
Copy the code
The file that needs to be replaced with text
Plop writes repeated files
The preparation of the plopfile. Js
The plop tool asks the user for the name of the page to be added, creates a file based on that name, and writes the route to package.json. Since plop doesn’t have the ability to read and write files, I’ve introduced the FS module. Use plop.setActionType to implement a new type. The full action code for using this type in setGenerator actions is shown below
const fs = require('fs')
module.exports = plop= >{
plop.setActionType('changeRouter',(answers,config,plop)=>{
fs.readFile('app.json',{},(err,data)=>{ // Read the app.json file
let d= JSON.parse(data.toString())
d.pages.push(`pages/${answers.pageName}/${answers.pageName}`) // Write the current addition to app.json
d = JSON.stringify(d,""."\t")
fs.writeFile('app.json',d,err=>{
if(err)
throw err
})
})
})
plop.setGenerator('wxfile', {// Wxfile is a self-defined name that is used on the command line
description:'create the repeat wxfile'.// Here is the function description of this plop
prompts:[{
type:'input'.// The type of problem
name:'pageName'.// The question corresponds to the variable name of the answer, which can be used in actions
message:'your pageName is'.// A problem at the command line
default:'page' // The default answer to the question}].actions: [{type:'add'.// Operation type, here is add file
path:'pages/{{pageName}}/{{pageName}}.json'.// The path to the added file
templateFile:'plop-temp/tempPage.json' // Path to the template file}, {type:'add'.path:'pages/{{pageName}}/{{pageName}}.js'.templateFile:'plop-temp/tempPage.js'}, {type:'add'.path:'pages/{{pageName}}/{{pageName}}.wxss'.templateFile:'plop-temp/tempPage.wxss'}, {type:'add'.path:'pages/{{pageName}}/{{pageName}}.wxml'.templateFile:'plop-temp/tempPage.wxml'}, {// Modify the route in app.json
type:'changeRouter'})}}]Copy the code
The file that needs to be replaced with text
Method of use
If yo is not available locally, install Yo globally
npm i yo
Copy the code
So let’s do that
yo wxfile
Copy the code
If you want to use the plop tool, if you don’t have a ploP locally, you can just
npm i
Copy the code
You can put ploP into the project as a development dependency and execute it
plop wxfile
Copy the code
You can use the corresponding function