Yeoman
start
Yeoman’s workflow is simple, using Yeoman to run a plugin-like generator, which we call a generator, you can quickly set up a specific project.
First, install the Yeoman module globally:
npm install -g yo
Copy the code
Then find a generator that meets your project requirements, which is essentially an NPM package and therefore also installed in the global directory:
npm install -g generator-webapp
Copy the code
Then execute Yoman’s scaffolding start instruction:
yo webapp
Copy the code
Command line input during execution allows you to select file options that match the project design, and you end up with a complete scaffolding project, ready to use right out of the box.
generator
Generators are the cornerstone of the Yeoman ecosystem. These are plug-ins that Yo runs to generate files for the end user.
As you can see, Yeoman is the platform on which the scaffolding is executed, the logic for actually generating the scaffolding is controlled by the Generator, and this plug-in flow approach is the basis for its general use.
There are some useful genarators available, from which we can find generators that are suitable for our intended project, or if they are not, we can also customize a generator. For details, see yeoman.io/authoring/.
A custom generator
At the heart of the generator is a Node.js module.
In fact, the official documentation has been written in detail, as an example to demonstrate.
The basic organizational structure of the generator
As the core of the Generator is a Node.js module, we create a directory and initialize it with NPM, but note that:
- The package name, namely the folder name, must be
generator-name
Format, wherename
Is the name of the generator. npm init
The generatedpackage.json
File,keywords
Properties must contain"yeoman-generator"
And the REPO must have a description in order toGenerator pageThe index.- Make sure the latest version is set
yeoman-generator
Is a dependency. files
The property must be an array of files and directories used by the generator.
{
"name": "generator-name"."version": "0.1.0 from"."description": ""."files": [
"generators"]."keywords": ["yeoman-generator"]."dependencies": {
"yeoman-generator": "^ 1.0.0"}}Copy the code
The generator file tree
In addition to the above requirements for module information, Yeoman’s functionality depends on how the directory tree is built. Each child generator is contained in its own folder.
The default generator yo name used when called is the APP generator. This must be included in the app/ directory. The subgenerator yo Name: SubCommand used when invoked is stored in the exact same folder as the subcommand.
The directory tree might look like this:
├ ─ ─ ─ package. Json └ ─ ─ ─ generators / ├ ─ ─ ─ app / │ └ ─ ─ ─ index. The js └ ─ ─ ─ the router / └ ─ ─ ─ the index, jsCopy the code
Yeoman allows for two different directory structures. It will look for./ and generators/ register available generators. So the directory tree might also look like this:
├ ─ ─ ─ package. Json ├ ─ ─ ─ app / │ └ ─ ─ ─ index. The js └ ─ ─ ─ the router / └ ─ ─ ─ the index, jsCopy the code
But make sure that the files field in package.json contains directory information:
{
"files": [
"app"."router"]}Copy the code
Basic module structure
/ / generators/app/index.js/generator.js/generators/app/index.js
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
constructor(args, opts) {
super(args, opts);
this.log('App init');
}
method() {
this.log('method is run');
}
method2() {
return new Promise((res, rej) = > {
this.log('method2 is run');
setTimeout(() = > {
this.appname = 'new appname';
res();
}, 100);
});
}
method3() {
this.log('appname=>'.this.appname); }};Copy the code
Note that generator functions are called automatically from Object.getPrototypeof (Generator). For asynchronous functions, return a Promise Object. If you want to avoid the function being called, use the _ prefix as the function name.
The user interaction
Ask users to obtain their project preferences and update some user Settings. Yoman uses the prompt function to accomplish this task, which is the wrapper tool function of Inquirer.
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
constructor(args, opts) {
super(args, opts);
this.log('App init');
}
prompting() {
return this.prompt([{
type: "input".name: "title".message: "Your project name?".default: this.appname
},
{
type: "confirm".name: "cool".message: "Would you like to enable the Cool feature?"
}]).then(answer= > {
this.answer = answer; }); }};Copy the code
File interaction
The ultimate purpose of generators is to create files, and Yoman encapsulates the FS module and provides fs utility functions to facilitate file-related operations.
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
constructor(args, opts) {
super(args, opts);
this.log('App init');
}
writing() {
const temp = this.templatePath('index.html'); // Module path (the default path is the genrators/ Templates directory under the generator project)
const dest = this.destinationPath('pages/index.html'); // Target path (default path is current execution environment)
this.fs.copyTpl(temp, dest, this.answer); }};Copy the code
The copyTpl function templates the file using ejS template engine.
Publish generator module
Once the user and file interaction logic is complete, the generator logic is almost complete. For ease of use, you can publish the generator to the NPM website, just like a normal module.
Polp
Plop is a small tool that can save you time and help your team build new files in a consistent manner.
Plop is a nice little scaffolding tool even smaller than Yoman, and you can’t even think of it as a scaffolding tool, just a gadget for quickly reusing files on projects.
Plop uses the same logic as Yoman: it queries users and writes files based on user input.
Simple to use
First install the Plop module in the project:
npm install --save-dev plop
Copy the code
Create a plopfile.js entry file in the project root directory:
module.exports = function (plop) {
// controller generator
plop.setGenerator('controller', {
description: 'application controller logic'.// User interaction
prompts: [{
type: 'input'.name: 'name'.message: 'controller name please'}].// File interaction
actions: [{
type: 'add'.path: 'src/{{name}}.js'.templateFile: 'plop-templates/controller.hbs'}}]); };Copy the code
Then add the script plop to package.json to run.
How scaffolding works
It can be found that the essence of scaffolding is a CLI application. Through interaction with users, preset engineering scaffolding files are set according to user preferences, and these files are automatically created for users.
Now let’s just simulate this very briefly.
Create a Node module:
mkdir scaffold-application
cd scaffold-application
npm init -y
Copy the code
Write the package.json bin field to specify the cli entry file:
{
bin: "cli.js"
}
Copy the code
Write the cli. Js
Cli applications are no different from Node.js, except that they have a fixed file header. The /usr/bin/env node is used as an identifier.
#! /usr/bin/env node
// Use inquirer. Js for user interaction
const inquirer = require('inquirer');
const path = require('path');
const ejs = require('ejs');
const fs = require('fs');
inquirer.prompt({
type: 'input'.name: 'name'.message: 'App name',
}).then(anwser= > {
// Render the template using EJS, then write the file using fs module
const tempDir = path.resolve(__dirname, 'templates');
const destDir = process.cwd();
fs.readdir(tempDir, (err, files) = > {
if (err) throw err
files.forEach(file= > {
ejs.renderFile(path.join(tempDir, file), anwser, (err, res) = > {
if (err) throw err
fs.writeFileSync(path.join(destDir, file), res);
});
});
});
})
Copy the code
This is then global via NPM linklink, which is then used by the scaffolds-application command.