Yeoman, or Yo for short, is a great tool to learn from for most front-end teams, providing a proven way to develop, distribute, and use a project scaffolding, speed up project launches, and reuse project structures for front-end projects.

This article takes generator-iView-admin as an example to briefly explain the development process of the scaffolding, namely generator.

To prepare

To develop the Yeoman template, you need to install Yo:

npm i -g yo
Copy the code

Yo has carefully prepared the scaffolding generator for our scaffolding project:

npm i -g generator-generator
Copy the code

After installation, go to the development directory and run:

yo generator
Copy the code

The project structure

After the preceding command is executed, the following files are generated:

├─.yo-rc.json ├─ Package. json ├── app │ ├─ templates │ ├ myFile.txt │ ├─ index.jsCopy the code

Among them

  • .yo-rc.jsonIt is used for storage project configuration. It is not required
  • package.jsonNPM project information file, focusing on the author and version fields
  • generatorsThe directory is the project template code
  • generators/templatesUsed to store project template files
  • generators/app/index.jsDefines the code for the project scaffolding

The development of

Each generator inherits the Yeoman-Generator class, the generators/app/index.js file described above. This class has several important lifecycle nodes:

  1. initializing– Initialization method, which is used to obtain project status and configuration
  2. prompting– callinquireMethod to get user input
  3. configuring– Save the configuration and create.editorconfigAnd other documents
  4. writing– Perform file write operations, that is, write project files to the file system
  5. install– This parameter is required to perform installation operationsthis.installDependenciesmethods
  6. end– Last execution, can clear temporary files, etc

All of the above methods support returning a Promise to implement asynchronous operations, and only perform the next step if the returned Promise instance resolve is returned.

Step 1. Obtain the user configuration

First, we need to ask the user configuration in the Only Insurgent category (the full example is here) :

prompting() {
  // Have Yeoman greet the user.
  this.log(yosay('Welcome to the divine ' + chalk.red('generator-iview-admin') + ' generator! '));

  const prompts = [{
    type: 'input'.name: 'name'.message: 'Your project name'.default: this.appname
  }, {
    type: 'confirm'.name: 'lint'.message: 'Use ESLint to lint your code? '
  }, {
    name: 'lintStyle'.type: 'list'.message: 'Pick an ESLint preset',
    when(answers) {
      return answers.lint;
    },
    choices: [{
      name: 'Airbnb (https://github.com/airbnb/javascript)'.value: 'airbnb'.short: 'Airbnb'
    }, {
      name: 'Standard (https://github.com/feross/standard)'.value: 'standard'.short: 'Standard'}}]];return this.prompt(prompts).then((props) = > {
    // To access props later use this.props.someAnswer;
    this.props = props;
  });
}
Copy the code

Here, you configure the results entered by the user into the this.props object for subsequent access.

Step 2. Define the template

At the heart of Yo, which is essentially modifying template files on demand, there are three general methods:

  1. For simple objects such as JSON, you can use initPackage. That is, read templates, modify objects according to configurations, and write files
  2. For complex files, you can write them using the template (EJS) engine provided by Yo.
  3. Modifying files using the AST tree You can parse the syntax tree to deeply understand the template content, which is generally used to modify existing files. You are advised to use Esprima and Cheerio to parse AST.

Using ejS mode as an example, write a template (full example here):

The < %if(vueFile==='standalone') {% >// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.The < %} % >.../* eslint-disable no-new */
new Vue({
  el: '#app',
  router,<% if(vueFile==='runtime'){ %>
  render: h= > h(App)<% } else if(vueFile==='standalone'){ %>
  template: '<App/>'.components: { App }<% } %>
});

Copy the code

Step 3. Write as required

Once you get the configuration, you can start writing the template to hard disk (full example here) :

writing() {
  this.initPackage();
  this.renderTplFile();
}

initPackage() {
  let pkg = this.fs.readJSON(this.templatePath('package.json'), {});
  const {
    props
  } = this;

  pkg = _.merge(pkg, {
    name: props.name,
    description: props.description }); . this.fs.writeJSON(this.destinationPath('package.json'), pkg);
}

renderTplFile() {
  let target = [
    ...
    'src/components/Hello.vue',];if (this.props.unitTest) {
    target = target.concat([
      ...
      'build/webpack.test.conf.js']); }... _.forEach(target, (file) => {this.fs.copyTpl(
      this.templatePath(file),
      this.destinationPath(file),
      this.props
    );
  });
}
Copy the code

Yo provides the mem-Fs-Editor instance interface, which contains a series of FS tools:

  • this.fs.read– Read files
  • this.fs.readJSON– Read files in JSON mode
  • this.fs.write– write files
  • this.fs.writeJson– Write files in JSON mode
  • this.fs.append– Appends the content to a file
  • this.fs.extendJSON– Extends the content of the JSON file
  • this.fs.delete– Delete files

In addition, there are a series of road and template interface:

  1. this.fs.copyTpl– Copies the template file, parses the template content according to parameters, and writes the template content to the target file
  2. this.templatePath– Returns the template file path, as described abovegenerator/app/templatesFile path in
  3. this.destinationPath– Returns the target file path, that is, the path where the yo command is executed to generate the template file
  4. this.registerTransformStream– Life hook interface for converting file contents, compatiblegulpThe plug-in

At this point, we know all the interfaces we need to develop a Yo template.

Adding a subtemplate

Yo allows you to add any number of child templates by executing:

yo generator:subgenerator [name]
Copy the code

Take Yo Generator: Subgenerator test as an example. The following files are generated:

└ ── generators │ ├─ app │ ├─test│ ├─ Templates │ ├─ ├.txt │ ├─ index.jsCopy the code

Templates, index.js files do the same and can be developed directly.

A test run

You can add a project to the local Generator library by:

npm link
Copy the code

After that, you can execute the following command to generate the scaffolding:

yo [your template name]
Copy the code

release

After the template is developed, run the following commands to publish the template:

npm publish
Copy the code

Note:

  1. If NPM is not logged in, run this commandnpm adduserOperation Login
  2. Publishing NPM packages must be usedhttps://registry.npmjs.org/Source, remember to switch.