如何开发一个Vue脚手架

4,095 阅读4分钟

如何开发一个Vue脚手架

实现一个脚手架之前我们必须知道什么是脚手架?通俗来说脚手架就是帮我们自动完成一些重复做的内容,比如大名鼎鼎的Vue脚手架Vue-Cli,只需要执行一行代码就能帮我搭建好Vue环境的项目,它帮我们自动创建了一个Vue的开发环境项目,我们不需要每次都自己搭建环境了。
vue-cli create

脚手架做了哪些事?

Vue-Cli脚手架帮我们做了哪些事呢?我认为它做了三件事:

  • 接受用户输入的信息
  • 创建项目package.json并且安装依赖
  • 创建空项目(可以理解为:复制预先配置好的项目文件)

使用Yeoman开发脚手架

Yeoman是一个社区热门的搭建工具链的一个库。具体内容就不介绍了,移步官方地址 Yeoman

为什么要使用Yeoman

Yeoman提供现成的命令行交互,模板文件复制,npm相关操作,为工具链为生的库,当然你也可以通过node来实现这些功能。

搭建脚手架项目环境

创建项目

新建项目generator-vue-cli,进入目录执行npm init,项目名必须generator开头,vue-cli为脚手架名字
安装yo:

npm install yeoman-generator --save-dev
npm install -g yo

目录结构

generator-vue-cli目录下新建:

├───package.json
└───generators/
    ├───app/
    │   └───index.js
    └───templates/      

必须按照上面目录结构创建文件

编写构建逻辑

app/index.js是构建脚手架的入口文件,编写以下代码:

var Generator = require('yeoman-generator');
module.exports = class extends Generator {
  method1() {
    this.log('step 1');
  }

  method2() {
    this.log('step 2');
  }
};

在项目目录下执行npm link后再非项目目录下执行yo vue-cli执行我们的脚手架.

vue-cli create
我们发现方法是从上往下依次执行的,看到这个效果后我们接着之前的思路完成脚手架开发,首先定义三个方法:

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

module.exports = class extends Generator {
  constructor(args, opts) {
    super(args, opts);
    this.answers = null;
  }
  // 1.获取用户输入信息
  async getUserEnter() {
  }
  // 2.安装相关依赖创建package.json
  async installPackage() {
    
  }
  // 3.复制模板文件
  async copyTemplateFiles() {
  }

};

接受用户输入的信息

`Yeoman`提供了`prompt`方法来在命令行交互:   
// 1.获取用户输入信息
async getUserEnter() {
  // 获取用户输入的项目名
  const answers = await this.prompt([
    {
      type: "input",
      name: "name",
      message: "Your Vue project name",
    }
  ]);
  /// 保存用户输入的信息
  this.answers = answers;
  this.destinationRoot(this.answers.name);
}

运行效果:
交互

this.destinationRoot配置目根目录.

创建项目package.json并且安装依赖

// 2.安装相关依赖创建package.json
async installPackage() {
  const pgkJSON = {
    name: this.answers.name,
    version: "1.0.0",
    main: "./src/index.js",
    license: "ISC",
    scripts: {
      build:"webpack",
      watch: "webpack --watch",
      dev: "webpack-dev-server --open"
    },
    devDependencies: {
      "webpack": "^4.35.2",
      "webpack-cli": "^3.3.6",
      "webpack-dev-server": "^3.7.2"
    },
    dependencies: {
    }
  };
  // 创建package.json
  this.fs.extendJSON(this.destinationPath('package.json'), pgkJSON);
  // 安装依赖 相当于执行了npm install 会安装package.json配置的包
  this.npmInstall();
  // 安装指定包 相当于执行了npm install vue
  this.npmInstall(["vue"], { "save-dev": false });
  // 安装指定包 相当于执行了npm install xxx --save-dev
  this.npmInstall(
    ["@babel/core", "@babel/preset-env", "babel-loader", "css-loader", "html-webpack-plugin", "style-loader", "vue-loader", "vue-template-compiler"],
    { "save-dev": true }
  );
}

复制模板文件

templates准备好了我们的项目模板文件:
模板文件
模板文件就是已经搭建好的基于webpackVue开发环境。

复制模板文件也很简单:

// 3.复制模板文件
async copyTemplateFiles() {
  this.fs.copyTpl(
    this.templatePath('public/index.html'),
    this.destinationPath('public/index.html'),
    {
      title: this.answers.name
    }
  );
  this.fs.copyTpl(
    this.templatePath('src/main.js'),
    this.destinationPath('src/main.js'),
  );
  this.fs.copyTpl(
    this.templatePath('src/App.vue'),
    this.destinationPath('src/App.vue'),
  );
  this.fs.copyTpl(
    this.templatePath('src/components/HelloWorld.vue'),
    this.destinationPath('src/components/HelloWorld.vue'),
  );
  this.fs.copyTpl(
    this.templatePath('webpack.config.js'),
    this.destinationPath('webpack.config.js'),
  );
}

copyTpl接受两个参数,一个是模板文件路径和复制到项目的路径。

完整代码

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

module.exports = class extends Generator {
  constructor(args, opts) {
    super(args, opts);
    this.answers = null;
  }
  // 1.获取用户输入信息
  async getUserEnter() {
    // 获取用户输入的项目名
    const answers = await this.prompt([
      {
        type: "input",
        name: "name",
        message: "Your Vue project name",
      }
    ]);

    this.answers = answers;
    this.destinationRoot(this.answers.name);
  }
  // 2.安装相关依赖创建package.json
  async installPackage() {
    const pgkJSON = {
      name: this.answers.name,
      version: "1.0.0",
      main: "./src/index.js",
      license: "ISC",
      scripts: {
        build:"webpack",
        watch: "webpack --watch",
        dev: "webpack-dev-server --open"
      },
      devDependencies: {
        "webpack": "^4.35.2",
        "webpack-cli": "^3.3.6",
        "webpack-dev-server": "^3.7.2"
      },
      dependencies: {
      }
    };
    // 创建package.json
    this.fs.extendJSON(this.destinationPath('package.json'), pgkJSON);
    this.npmInstall();
    this.npmInstall(["vue"], { "save-dev": false });
    this.npmInstall(
      ["@babel/core", "@babel/preset-env", "babel-loader", "css-loader", "html-webpack-plugin", "style-loader", "vue-loader", "vue-template-compiler"],
      { "save-dev": true }
    );
  }

  // 3.复制模板文件
  async copyTemplateFiles() {
    this.fs.copyTpl(
      this.templatePath('public/index.html'),
      this.destinationPath('public/index.html'),
      {
        title: this.answers.name
      }
    );
    this.fs.copyTpl(
      this.templatePath('src/main.js'),
      this.destinationPath('src/main.js'),
    );
    this.fs.copyTpl(
      this.templatePath('src/App.vue'),
      this.destinationPath('src/App.vue'),
    );
    this.fs.copyTpl(
      this.templatePath('src/components/HelloWorld.vue'),
      this.destinationPath('src/components/HelloWorld.vue'),
    );
    this.fs.copyTpl(
      this.templatePath('webpack.config.js'),
      this.destinationPath('webpack.config.js'),
    );
  }

};

使用脚手架

在非当前脚手架目录下执行yo vue-cli,输入项目名vue-demo
使用脚手架
vue-demo运行项目npm run dev
运行项目

发布脚手架

发布到npmnpm publish,发布之前需要先登录npm adduser,注意如果存在同名的库会发布失败

模板文件地址

Github generator-vue

本篇文章只是简单介绍如何开发一个脚手架思路,整个代码非常简单。如需要增加一些复杂功能,例如想要做到像vue-cli这么强大还有很多需要功能完善,例如复杂的命令行交互,下载进度条的支持等。