认识前端工具链(一)之脚手架

认识前端工具链(一)

前端工具链综述

工具链在前端领域扮演着很重要的角色。如何为Javascript生产环境构建去构建一套工具链,来覆盖前端各个开发环节,是我们需要了解学习的。而一套高效的工具链体系,对于每一个前端团队来说都有着至关重要的意义,它不仅可以提高团队的开发效率,还可以在一定程度上规范前端开发的各个环节,进而为团队节省一些人员协作和调整的成本。

综上,前端工具链旨在友好开发体验,提升开发团队开发效率

而要构建一个工具链,首先我们先要了解在前端开发领域有哪几个环节:

  • 项目初始化
  • 开发、调试、构建
  • 单元测试
  • 发布

所以一个前端工具链,它大致都会包含上面这一系列功能。而一个典型的示例就类似于下面:

  • Yeoman
  • Webpack
  • Mocha
  • 发布系统

我们可以将进而将它总结成下面几块:

  • 脚手架
  • 构建⼯具
  • 测试工具
  • 发布系统

而上了规模的团队也都会针对以上的流程,制定一个工具链,并将它包装成一个黑盒形式,让程序员在每个环节只需要运行简单命令行,即可进入开发流程。

而从整体上了解工具链相关的知识体系,熟悉其大致结构以及运作方式,也是十分重要的。

所以,下面这里是本人将对于工具链相关基础知识的一些整理。这一篇我们首先来介绍的是,工具链中的脚手架

脚手架

所有的工具的开端就是我们的脚手架,但脚手架和工具链并不是一回事,我们可以将gennerator称为脚手架。

什么是脚手架?

做开发的,当然对于脚手架这个词并不陌生,按照我的理解,脚手架是构建一个标准项目模板的生成器。

我们每次开发新的项目,我们都要使用对应类型项目的脚手架,去初始化一个新项目,它会一个通用的目录结构,配置好我们所需要的工作环境。

常见的脚手架有:

  • Vue的脚手架:vue-cli
  • Angular的脚手架:angular-cli
  • React的脚手架:create-react-app

如何创建脚手架?

具体脚手架并不是凭空产生的,即脚手架也有它的gennerator。

Yeoman是现在社区比较流行的脚手架生成器,即gennerator的gennerator,通过Yeoman的这个框架可以轻易的开发一个能够初始化项目创建模板的工具。

官网的介绍如下:

Yeoman是一个通用的脚手架系统,允许创建任何类型的应用程序。它允许快速开始新项目并简化现有项目的维护。

Yeoman 的使用

1. 基本使用

  • 空文件夹,npm init ,安装yeoman依赖
  • 包名必须为generator开头
// package.json
{
  "name": "generator-toolchain",
  "version": "1.0.0",
  "description": "",
  "main": "gennerator/app/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "yeoman-generator": "^4.13.0"
  }
}
  • 目录结构
|—— package.json
|—— generators
		|——— app
			|—— index.js
			|—— templates
				|—— index.html
  • 拓展生成器代码
    Yeoman提供了一个基本生成器,您可以扩展它来实现自己的行为。该基本生成器将添加您希望简化任务的大多数功能。
    在生成器的index.js文件中,以下是扩展基本生成器的方法:
// gennerators/app/index.js
var Generator = require('yeoman-generator');

module.exports = class extends Generator {
    // 覆盖构造函数
    constructor(args, opts) {
      super(args, opts);
    }
  // 添加自己的功能
    method1() {
      this.log('method 1 just ran');
    }
    method2() {
      this.log('method 2 just ran');
    }
};

运行generator

  • npm link
    • 由于我们是在本地开发生成器,因此尚未作为全局npm模块提供。可以使用npm创建一个全局模块并将其符号链接到本地模块。
    • 在命令行上,从生成器项目的根目录(在generator-name /文件夹中),键入:npm link
    • 这将安装我们的项目依赖项,并将全局模块符号链接到本地文件。
  • Yo yeoman 启动项目
    • 全局安装yeoman npm install -g yo
Yeoman的使用笔记

Yeoman支持的功能:

  • 同步、异步的method
  • this.log: 用于输出
  • this.prompt:用于与用户输入交互
// app/index.js  
async prompting() {
    const answers = await this.prompt([
      {
        type: "input",
        name: "name",
        message: "Your project name",
        default: this.appname // Default to current folder name
      },
      {
        type: "confirm",
        name: "cool",
        message: "Would you like to enable the Cool feature?"
      }
    ]);

    this.log("app name", answers.name);
    this.log("cool feature", answers.cool);
  }
  • 文件模板系统
// 目录结构
├───package.json
├───app/
	 └───templates
	 		└───index.html
   └───index.js

index.html:

<html>
  <head>
    <title><%= title %></title>
  </head>
</html>
// app/index.js  
var Generator = require('yeoman-generator');

module.exports = class extends Generator {
    // The name `constructor` is important here
    constructor(args, opts) {
      // Calling the super constructor is important so our generator is correctly set up
      super(args, opts);
    }
    writing() {
      this.fs.copyTpl(
        this.templatePath('index.html'),
        this.destinationPath('public/index.html'),
        { title: 'Templating with Yeoman' } // 这个json参数会覆盖模板里面的类似 <%= title %>这样的代码部分
      );
    }
};

然后在别的文件夹里运行yo toolchain命令就会生成public以及index.html

  • 依赖系统
// app/index.js
var Generator = require('yeoman-generator');

module.exports = class extends Generator {
    // The name `constructor` is important here
    constructor(args, opts) {
      // Calling the super constructor is important so our generator is correctly set up
      super(args, opts);
    }
    writing() {
      const pkgJson = {
        devDependencies: {
          eslint: '^3.15.0'
        },
        dependencies: {
          react: '^16.2.0'
        }
      };
  
      // Extend or create package.json file in destination path
      this.fs.extendJSON(this.destinationPath('package.json'), pkgJson);
    }
    install() {
      this.npmInstall();
    }
};
Vue项目的generator实战

generator项目结构

|—— package.json
|—— generators
	|——— app
		|—— index.js
		|—— templates		
			|—— index.html		
			|—— main.js
			|—— webpack.config.js
			|—— HelloWorld.vue

generator代码:

// app/index.js
var Generator = require('yeoman-generator');

module.exports = class extends Generator {
    // The name `constructor` is important here
    constructor(args, opts) {
      // Calling the super constructor is important so our generator is correctly set up
      super(args, opts);
    }
    async initPackge () {
      const answers = await this.prompt([
        {
          type: "input",
          name: "name",
          message: "Your project name",
          default: this.appname // Default to current folder name
        },
        {
          type: "input",
          name: "title",
          message: "Your html title",
          default: this.appname // Default to current folder name
        }
      ]);
      const pkgJson = {
        "name": answers.name,
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1"
        },
        "author": "",
        "license": "ISC",
        "devDependencies": {
        },
        "dependencies": {
        }
      };
      this.fs.extendJSON(this.destinationPath('package.json'), pkgJson);
      this.npmInstall(['vue'], {'save-dev': false});
      this.npmInstall([
        'webpack',
        'vue-loader', 
        'vue-template-compiler', 
        'vue-style-loader', 
        'css-loader',
        'copy-webpack-plugin'
      ], {'save-dev': true});
      this.fs.copyTpl(
        this.templatePath('HelloWorld.vue'),
        this.destinationPath('src/HelloWorld.vue'),
        {}
      );
      this.fs.copyTpl(
        this.templatePath('webpack.config.js'),
        this.destinationPath('webpack.config.js'),
        {}
      );
      this.fs.copyTpl(
        this.templatePath('main.js'),
        this.destinationPath('src/main.js'),
        {}
      );
      this.fs.copyTpl(
        this.templatePath('index.html'),
        this.destinationPath('src/index.html'),
        { title: answers.title }
      );
    }
};

使用了上述generator初始化,并使用webpack打包之后的项目结构如下:

// vue-demo目录结构
├───package.json
├───webpack.config.js
├───dist
		└───main.js
		└───index.html
├───src
	 └───main.js
	 └───index.html
   └───HelloWorld.vue

参考附录

工具链:什么样的工具链才能提升团队效率?

React系列四 - React脚手架

Yeoman

后记

我是彤爱,一个在沉溺于寂寞代码海洋里的前端程序员

上一篇:navicat连接时:client does not support authentication protocol requested by server; consider upgrading M


下一篇:error: The requested URL returned error: 401 Unauthorized while accessing