Vue.js is one of the most popular front-end frameworks at present, so developing a component based on vue. js is the wish of every front-end. Each time a new vue.js component is developed, the following things are done:

  • Create a project directory
  • Git initialization
  • NPM initialization
  • Setting up the development environment
    • Grammar testing
    • The code to compile
    • The code package
    • Local preview and thermal reloading
  • Set up production environment
    • Grammar testing
    • The code to compile
    • Code packaging and compression
  • Configuration for continuous integration

So why not effectively distill the work and let him generate it with one click? There are many one-click generation tools, such as Yeoman. Yeoman scaffolding projects require yeoman scaffolding packages. Yeoman’s scaffolding package is essentially a project template with a complete file structure that users manually download locally and yeoman automatically generates various projects based on the scaffolding package.

Yeoman was easy to use, but there was always the hassle of having to download the scaffolding package. Cli technology is also popular in the market, where templates for remote repositories are pulled locally based on some configuration. Obviously cli mode is very good, do not need to download. We built ourselves a scaffold called Fecli based on this principle.

Technology stack

  • Development environment: OS X El Capitan 10.11.6
  • Development tool: Atom
  • Node.js: The entire scaffolding environment. Node.js version of this scaffold: 9.11.1.
  • Es6: New syntax for JavaScript.
  • Commander: A tool developed by TJ to better organize and process command line input. The commander version of this scaffold is 2.15.1.
  • Co: asynchronous process control tool. Co version of this scaffold: 4.6.0.
  • Co-prompt: Receives user input step by step. Co-prompt version of this scaffold: 1.0.0.
  • Chalk: Colorful terminal tool. Chalk version of this scaffold: 2.3.2.
  • Ora: Elegant terminal spinner that controls terminal output. Ora version of this scaffold: 2.0.0.

Project core

A diagram illustrates the overall architecture. ⤵ ️

About template

Templates are what the future pulls down. This template usually has some configuration for environment, syntax checking, unit testing, continuous integration, etc.

Information about templates is stored in the templates.json file. You can also manipulate the contents of templates.json with commands.

Scaffolding file structure

Run. ├ ─ ─ the bind / # entry documents │ └ ─ ─... ├ ─ ─ lib / # core code │ ├ ─ ─ table. Js # template list form of encapsulation │ ├ ─ ─ tip. Js # terminal message encapsulation │ ├ ─ ─ cli / # command management │ │ └ ─ ─... │ ├ ─ ├ ─ ├ ─ 08.07.02 ├─ ├─ ├─ ├─ ├─ ├─ └─ templates. Json #

Configure global usage

Create a new directory mkdir fecli and go to CD fecli. And then NPM initializes NPM init. To be used globally, we need to set this in package.json:

"bin": {
  "fe": "./bin/fe.js"
},
Copy the code

For local debugging, run: NPM link in the project root directory. The fecli command can be bound globally, so that the command can start with fe.

Entry file Settings

Json and execute NPM install or YARN install:

"Dependencies" : {" chalk ":" ^ "2.3.2," co ":" ^ 4.6.0 ", "co - prompt" : "^ 1.0.0", "commander" : "^ 2.15.1", "ora" : "^ 2.0.0"}Copy the code

Create a fe.js file in the \bin folder in the root directory. The bin/fe.js file is the entry file to the entire scaffold, so we’ll write it first.

We’ll start with some initialization code, which simply references the command management file (lib/cli/index.js) :

require('.. /lib/cli/');Copy the code

Command Management (lib/cli/index.js)

First, a few initialization things:

const program = require('commander'); const packageInfo = require('.. /.. /package.json'); program .version(packageInfo.version)Copy the code

We 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.

Description (' generate a project ').alias(' I ').action(() => {require('.. /cmd/init')(); }); Program.command ('add') // fe add.description ('add new template ').alias('a') // short.action(() => {require('.. /cmd/add')(); }); Program.command ('list') // fe list.description (' view template list').alias('l') // short.action(() => {require('.. /cmd/list')(); }); Program.command ('delete') // fe delete.description (' view template list ').alias('d') // short.action(() => {require('.. /cmd/delete')(); });Copy the code

If there are no arguments, run the help method. Next, parse the parameters in program.args:

program.parse(process.argv); if(! program.args.length){ program.help() }Copy the code

Results after running FE:

The specific usage of COMMANDER is not explained here. You can go to the official website for detailed documentation.

Processing user input

Create a /lib/cmd folder in the root directory of your project to store command processing files. Templates. Json file in the root directory and write the following to hold template information:

{"tpl":{}}
Copy the code

Add a template (fe add)

Go to /lib/cmd and create the add.js file.

'use strict' const co = require('co'); const prompt = require('co-prompt'); const fs = require('fs'); const table = require('.. /table'); const tip = require('.. /tip'); const tpls = require('.. /.. /templates'); Const writeFile = (err) => {// Handle error if (err) {console.log(err); Tip. Fail (' Please run again! '); process.exit(); } table(tpls); Tip. Suc (' New template added successfully! '); process.exit(); }; const resolve = (result) => { const { tplName, gitUrl, branch, description, } = result; // Avoid repeating if (! tpls[tplName]) { tpls[tplName] = {}; tpls[tplName]['url'] = gitUrl.replace(/[\u0000-\u0019]/g, ''); TPLS [tplName]['branch'] = branch; tpls[tplName]['description'] = description; } else {tip.fail(' Template already exists! '); process.exit(); }; Json fs.writefile (__dirname + '/.. /.. /templates.json', JSON.stringify(tpls), 'utf-8', writeFile); }; Module.exports = () => {co(function *() {const tplName = yield prompt(' template name: '); Const gitUrl = yield prompt('Git HTTPS: '); Const branch = yield prompt('Git branch: '); Const description = yield prompt(' template description: '); return new Promise((resolve, reject) => { resolve({ tplName, gitUrl, branch, description, }); }); }).then(resolve); };Copy the code

Deleting a template (fe delete)

Go to /lib/cmd and create the delete.js file.

'use strict' const co = require('co'); const prompt = require('co-prompt'); const fs = require('fs'); const table = require('.. /table'); const tip = require('.. /tip'); const tpls = require('.. /.. /templates'); const writeFile = (err) => { if (err) { console.log(err); Tip. Fail (' Please run again! '); process.exit(); } tip.suc(' New template deleted successfully! '); if (JSON.stringify(tpls) ! == '{}') { table(tpls); } else {tip.info(' Template not added yet! '); } process.exit(); }; Const resolve = (tplName) => {if (TPLS [tplName]) {delete TPLS [tplName]; } else {tip.fail(' Template does not exist! '); process.exit(); } // write to template.json fs.writefile (__dirname + '/.. /.. /templates.json', JSON.stringify(tpls), 'utf-8', writeFile); }; Module.exports = () => {co(function *() {const tplName = yield prompt(' template name: '); return new Promise((resolve, reject) => { resolve(tplName); }); }).then(resolve); };Copy the code

Initialize the project (fe init)

Go to /lib/cmd and create the init.js file.

Const exec = require('child_process'). Exec; const co = require('co'); const ora = require('ora'); const prompt = require('co-prompt'); const tip = require('.. /tip'); const tpls = require('.. /.. /templates'); Const spinner = ora(' generating... '); const execRm = (err, projectName) => { spinner.stop(); if (err) { console.log(err); Tip. Fail (' Please run again! '); process.exit(); } tip.suc(' Initialization complete! '); tip.info(`cd ${projectName} && npm install`); process.exit(); }; const download = (err, projectName) => { if (err) { console.log(err); Tip. Fail (' Please run again! '); process.exit(); } // Delete git file exec(' CD '+ projectName +' && rm -rf. git', (err, out) => {execRm(err, projectName); }); } const resolve = (result) => { const { tplName, url, branch, projectName, } = result; Const cmdStr = 'git clone ${url} ${projectName} && CD ${projectName} && git checkout ${branch}'; spinner.start(); exec(cmdStr, (err) => { download(err, projectName); }); }; Module.exports = () => {co(function *() {// const tplName = yield prompt(' template name: '); Const projectName = yield prompt(' projectName: '); if (! TPLS [tplName]) {tip.fail(' Template doesn't exist! '); process.exit(); } return new Promise((resolve, reject) => { resolve({ tplName, projectName, ... tpls[tplName], }); }); }).then(resolve); }Copy the code

Display template list (fe list)

Go to /lib/cmd and create the list.js file.

'use strict' const table = require('.. /table'); module.exports = () => { table(require('.. /.. /templates')); process.exit(); };Copy the code

Now that our fecli scaffolding tool is set up, let’s give it a try!

Use the test

  • fe addAdd the template

  • fe deleteAdd the template

  • fe listAdd the template

  • fe initAdd the template

Program source code

For more information, go to fecli.