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 lint
Eslint syntax checks to avoid syntax errors and unify code styles before compilation.npm test
Running unit testsnpm run doc
Generate documentation from commentsnpm run changelog
According to thegit log
Generate project log, change records at a glancenpm run prebuild
Syntax checking, running tests, and generating documentation before compilationnpm run build
Compile 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…