From the front end of Thunder

The original address: greenfavo. Making. IO/blog/docs / 0…

When creating a new project, we usually have to design the directory structure, do various configurations, deal with packaging and compiling, and start over each time we create a new project, or copy the original project and change it again. Can you write a template, and then support personalized automatic creation? Today I’m going to share with you how to customize your own project scaffolding to improve development efficiency.

The concept of scaffolding is introduced here. What is scaffolding? Scaffolding acts as a template for a project that helps us get started quickly, like vue-CLI, which provides a terminal interface for users to customize project content.

Yeoman introduction

Yeoman is a universal scaffolding system that allows you to create any type of application (Web, Java, Python, C#, etc.). Writing scaffolding in Yeoman is very easy, yeoman provides yeoman-Generator for us to quickly generate a scaffold template, and our main job is to write the template file. Now let’s use Yeoman to write a scaffolding that generates a javascript plug-in.

Scaffolding function:

  • Automatic build compilation and packaging
  • Es6 syntax is supported
  • Unit testing support
  • Support for JSDoc document generation
  • Eslint syntax checking is supported
  • Changelog is automatically generated

The preparatory work

Yo and generator-generator need to be installed globally first

npm install yo -g
npm install generator-generator -g
Copy the code

Generate scaffold templates

yo generator
Copy the code

Enter project name, description and other project information in this terminal interface. Note that the project name should be in generator-xxx format so that the user can install your scaffold via Yo XXX.

The generated scaffold template directory structure is as follows:

. ├ ─ ─ generators / │ └ ─ ─ app / │ ├ ─ ─ index. The js │ └ ─ ─ templates / │ └ ─ ─ dummyfile. TXT ├ ─ ─ the editorconfig ├ ─ ─ the eslintignore ├ ─ ─ . Gitattributes ├ ─ ─. Gitignore ├ ─ ─. Travis. Yml ├ ─ ─. Yukio okamoto, - rc. Json ├ ─ ─ LICENSE ├ ─ ─ the README. Md ├ ─ ─ package. The json └ ─ ─ __tests__ / └ ─ ─ app. JsCopy the code

Generators /app/index.js next we will write the scaffolding logic in generators/app/index.js.

Write your own scaffolding

Scaffolding does:

  • Receiving user input
  • Generate a template file based on user input
  • Copy the template file to the target directory (usually the directory where the user is running the scaffolding)
  • Install dependencies

Yeoman provides a basic generator that you can extend to implement your own behavior. This basic generator will take most of your workload off your plate. In the generator’s index.js file, here are ways to extend the base generator:

var Generator = require("yeoman-generator");

module.exports = class extends Generator {};
Copy the code

The Yeoman lifecycle functions are executed in the following order:

  • Initializing – The initialization function
  • Only last targets – Receives user input stage
  • Configuring – Saves configuration information and files
  • Default – Executes custom functions
  • Writing – Generates the project directory structure stage
  • Conflicts – Handles conflicts coherently, such as whether the file to be generated already exists or not
  • Install – Install dependency phase
  • End – The end phase of the generator

Only initializing, only chosen by insurgents, default, Writing, and Install are the most commonly used life-cycle functions. Here’s an example:

"use strict";
const Generator = require("yeoman-generator");
const chalk = require("chalk"); // make console.log output with color
const yosay = require("yosay");
const mkdirp = require("mkdirp"); // Create directory

module.exports = class extends Generator {
  initializing() {
    this.props = {};
  }
  
  // Accept user input
  prompting() {
    // Have Yeoman greet the user.
    this.log(
      yosay(
        `Welcome to the grand ${chalk.red(
          "generator-javascript-plugin"
        )}generator! `));const prompts = [
      {
        type: "confirm".name: "someAnswer".message: "Would you like to enable this option?".default: true}];return this.prompt(prompts).then(props= > {
      // To access props later use this.props.someAnswer;
      this.props = props;
    });
  }

  // Create the project directory
  default() {
    if (path.basename(this.destinationPath()) ! = =this.props.name) {
      this.log(`\nYour generator must be inside a folder named
        The ${this.props.name}\n
        I will automatically create this folder.\n`);

      mkdirp(this.props.name);
      this.destinationRoot(this.destinationPath(this.props.name)); }}/ / write file
  writing() {
    // Copy the templates directory code to the target directory
    Generators /app/templates is the default path for the templates directory
    this.fs.copy(
      this.templatePath("dummyfile.txt"),
      this.destinationPath("dummyfile.txt"));this._writingPackageJSON();
  }

  // Private methods begin with an underscore _
  _writingPackageJSON() {
    // this.fs.copyTpl(from, to, context)
    this.fs.copyTpl(
      this.templatePath("_package.json"),
      this.destinationPath("package.json"),
      {
        name: this.props.name,
        description: this.props.description,
        keywords: this.props.keywords.split(","),
        author: this.props.author,
        email: this.props.email,
        repository: this.props.repository,
        homepage: this.props.homepage,
        license: this.props.license
      }
    );
  }

  // Install dependencies
  install() {
    this.installDependencies(); }};Copy the code

Writing template code

We have written the basic framework of a scaffold before, it can accept user input content, can write files, can install dependencies, but receive user input data how to use? What file? What dependencies are installed? These are all things that template files do. Now comes the main part: writing the template file.

A template file is a project demo that you generate for the user, so the user can look at the sample code and get to work. The user should just focus on the business logic, not the packaging and building.

Create the template directory first:

├─.EditorConfig ├─.Eslintignore ├─.Eslintrc.js ├─.Eslintrc.js ├─.Eslintrrc ├─.JsDoc.json ├─.Md ├─ Package. The json ├ ─ ─ the build / └ ─ ─ a rollup. Js ├ ─ ─ SRC / └ ─ ─ index. The js ├ ─ ─test/ └ ─ ─ index. JsCopy the code

We already have these commands in our package.json template:

"scripts": {
  "prebuild": "npm run lint && npm run test && npm run doc",
  "build": "node ./build/rollup.js",
  "lint": "eslint --ext .js, src",
  "test": "mocha --require babel-register --require babel-polyfill --bail",
  "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
  "doc": "jsdoc -c ./jsdoc.json"
}
Copy the code
  • npm run lintEslint syntax checks to avoid syntax errors and unify code styles before compilation.
  • npm testRunning unit tests
  • npm run docGenerate documentation from comments
  • npm run changelogAccording to thegit logGenerate project log, change records at a glance
  • npm run prebuildSyntax checking, running tests, and generating documentation before compilation
  • npm run buildCompile the package

We can use template syntax like <%= name %> to use the context in the scaffolding, either user-entered data or the program’s own variables:

{
  "name": "<%= name %>"."description": "<%= description %>"."version": "1.0.0"."private": false."main": "dist/<%= name %>.umd.js"."module": "dist/<%= name %>.es.js"
}
Copy the code

Please go to Github for details.

Run the test case

To ensure the robustness of the code, we must do unit tests. We already have a sample of the scaffolding code we generated with the generator, so we can use our own logic to test our scaffolding logic. Now let’s test whether the file is generated:

'use strict';
const path = require('path');
const assert = require('yeoman-assert');
const helpers = require('yeoman-test');

describe('generator-javascript-plugin:app', () => {
  beforeAll((a)= > {
    return helpers
      .run(path.join(__dirname, '.. /generators/app'))
      .withPrompts({ someAnswer: true });
  });

  it('creates files', () => {
    assert.file(['build/rollup.js']);
    assert.file(['dist']);
    assert.file(['src']);
    assert.file(['test']);
    assert.file(['package.json']);
    assert.file(['.babelrc']); . }); });Copy the code

Execute the command

npm test
Copy the code

Running scaffold

At this point, our scaffolding development is finished, and then the actual operation to see if it is correct.

Since our scaffolding is still locally developed, it is not yet available as a global NPM module. We can use NPM to create global modules and symlink them to local modules. Run from project root:

npm link
Copy the code

You can then call yo javascript-Plugin to run the scaffolding. You can see it in action on the terminal.

release

Scaffolding is written so that more people can use it. Publishing scaffolding is like publishing any other NPM package. How to publish?

Making the address

Generator -javascript-plugin This scaffold has been published on NPM and the source code can be downloaded or accessed.

Source code address: github.com/greenfavo/g…

Scan a concern about the thunder front public number