前端脚手架工具

1. 脚手架介绍

1. 脚手架的本质作用

创建项目基础结构、提供项目规范和约定

约定:

  • 相同的组织结构
  • 相同的开发范式
  • 相同的模块依赖
  • 相同的工具配置
  • 相同的基础代码

eg: 举个例子

IDE 创建项目的过程就是一个脚手架的工作流程

例如iOS项目在使用XCode的新建项目时,选择好选项点击创建,最后生成的项目文件及目录就是一个脚手架的执行结果

前端脚手架

  1. 脚手架的作用
  2. 常用的脚手架工具
  3. 通用脚手架工具剖析
  4. 开发一款脚手架
常用的脚手架工具
  1. React项目 -> create-reace-app
  2. Vue项目 -> vue-cli
  3. Angular项目 -> angular-cli

都是根据信息创建对应的项目基础结构

还有通用型

  1. Yeoman 根据一套模板生成一个对应的项目结构
  2. Plop 项目开发过程中用于生成特定类型的文件
    • 例如创建一个组件 / 模块所需要的文件

2. 脚手架的工作原理

2. Yeoman、Generator

Yeoman

The web's scaffolding tool for modern webapps

1. Yeoman的基本使用

  • 在全局范围安装yo
npm install yo --global
# 或者
yarn global add yo
  • 安装对应的generator

github.com/yeoman/generator-node

npm install generator-node --global
# 或者
yarn global add generator-node
  • 通过yo运行generator

cd path/to/project-dir

mkdir my-module

yo node

2. Yeoman (Sub Generator)

子集生成器

yo node:cli

# 为了执行该模块命令可以如下操作
npm link
[module_name] --help # 查看一下

3. 常规使用步骤

  1. 明确你的需求;
  2. 找到合适的Generator;
  3. 全局范围安装找到的Generator;
  4. 通过Yo运行对应的Generator;
  5. 通过命令行交互填写选项;
  6. 生成你所需要的项目结构;

4. 自定义 Generator

基于Yeoman搭建自己的脚手架

4.1 创建Generator模块

Generator 本质上就是一个NPM模块

  • Generator 基本结构

模块名称必须是 generator-<name>

# 1. 创建
mkdir generator-sample

# 2. 进入
cd generator-sample

# 3. 创建身份证
npm init

# 4. 安装 yeoman-generator (生成器的基类)
npm i yeoman-generator

// 目录结构
// generators/app/index.js
// 在index.js当中
module.exports = class extends Generator {
  writing() {
    // Yeoman 自动在生成文件阶段调用此方法
    // 我们这里尝试往项目目录中写入文件
    this.fs.write(
      this.destinationPath('temp.txt'),
      Math.random().toString()
    )
  }
}
  • 将该模块link到全局 npm link
  • 进入到新目录(脚手架创建的新项目) 执行yo sample

4.2 根据模板创建文件

模板文件夹 templates

// 创建模板文件夹  templates
writing() {
    // Yeoman 自动在生成文件阶段调用此方法

    // 通过模板方式写入文件到目标目录
    // 1. 模板文件路径
    const tmpl = this.templatePath('foo.txt')
    // 2. 输出目标路径
    const output = this.destinationPath('foo.txt')
    // 3. 模板数据上下文
    const context = { title: 'Hello zce~', success: false }

    this.fs.copyTpl(tmpl, output, context)
  }
  • 相对于手动创建每一个文件,模板的方式大大提高了效率

4.3 接收用户输入

prompting() {
    // Yeoman 在询问用户环节会自动调用此方法
    // 在此方法中可以调用父类的 prompt() 方法发出对用户的命令询问
    return this.prompt([
      {
        type: 'input', // 用户输入的方式
        name: 'name', // 得到结果的键
        message: 'Your project name', // 给用户的提示
        default: this.appname // appname 为项目生成目录的文件夹的名称
      }
    ]).then(answers => {
      // answers = { name: 'user input value' }
      this.answers = answers
    })
  }

4.4 Vue Generator案例

  • 示例代码
prompting() {
        return this.prompt([
            {
                type: 'input',
                name: 'projectName',
                message: 'Your project name',
                default: this.appname
            }
        ]).then(answers => {
            this.answers = answers
        })
    }

    writing() {
        const templates = [
            '.browserslistrc',
            '.editorconfig',
            '.eslintrc.js',
            '.gitignore',
            'babel.config.js',
            'package.json',
            'README.md',
            'tsconfig.json',
            'public/favicon.ico',
            'public/index.html',
            'src/assets/logo.png',
            'src/components/HelloWorld.vue',
            'src/store/index.ts',
            'src/App.vue',
            'src/main.ts',
            'src/shims-tsx.d.ts',
            'src/shims-vue.d.ts',
            'tests/unit/example.spec.ts'

        ]

        templates.forEach(item => {
            this.fs.copyTpl(
                this.templatePath(item),
                this.destinationPath(item),
                this.answers
            )
        })
    }

4.5 发布 Generator

3. Plop

Plop

一个小而美的脚手架工具;
创建项目中特定类型文件的小工具;
类似于Yeoman的Sub Generator

  • 举例:比如说react项目中 每次创建一个页面时需要有3个文件
    • Header.css
    • Header.js
    • Header.test.js
  • 可以将这个封装成一个模板

1. Plop 的具体使用

  • 在根目录下创建 plopfile.js 文件,需要导出一个函数,接收一个 plop 对象
  • 创建模板文件夹plop-templates/xxxxx.hbs
```javascript
// 模板文件举例

import React from 'react'

export default () => {
    <div className="{{name}}">
        <h1>{{name}}</h1>
    </div>
}


module.exports = plop => {
    // arg1 生成器的名称
    // arg2 配置选项
    plop.setGenerator('component', {
        description: 'create a compoent', // 描述
        // 命令交互
        prompts: [
            {
                type: 'input',
                name: 'name', // 键
                message: 'component name', // 问题描述
                default: 'MyComponent', // 默认值
            }
        ],
        actions: [
            {
                type: 'add', // 代表添加文件
                path: 'src/components/{{name}}/{{name}}.js',
                templateFile: 'plop-templates/components.hbs'
            }
        ]
    })
}
  • 执行
yarn plop component  # (component是生成器的名称)

总结:

使用plop的步骤

  1. plop 模块作为项目开发依赖安装
  2. 在项目根目录下创建一个 plopfile.js 文件
  3. plopfile.js 文件中定义脚手架任务
  4. 编写用于生成特定类型文件的模板
  5. 通过 Plop 提供的 CLI 运行脚手架任务

4. 脚手架的工作原理

使用nodejs创建一个脚手架

npm init
  • pagkage.json中添加一个 "bin": "cli.js"

  • cli.js

#!/usr/bin/env node

// Node CLI 应用入口文件必须 要有这样的文件头
// 如果是 Linux 或者 macOS 系统下还需要修改此文件的读写权限为 755

console.log('cli working!')
// scaffolding-cli


// 脚手架的工作过程:
// 1. 通过命令行交互询问用户问题
// 2. 根据用户回答的结果生成文件
// 使用 inquirer

const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer')
const ejs = require('ejs')

inquirer.prompt([
  {
    type: 'input',
    name: 'projectName',
    message: 'Project name',
    default: 'scaffolding-cli'
  }
]).then(answers => {
  console.log(answers)


  // 模板目录
  const tempDir = path.join(__dirname, 'templates')
  // 目标目录
  const destDir = process.cwd()

  // 将模板下的文件全部输出到目标目录
  fs.readdir(tempDir, (err, files) => {
    if (err) throw err;

    files.forEach(file => {
      // console.log(file)
      // 通过模板引擎渲染文件
      ejs.renderFile(
        path.join(tempDir, file),
        answers,
        (err, result) => {
          if (err) throw err;

          // 将结果写入目标目录
          fs.writeFileSync(path.join(destDir, file), result)
        }
      )
    })
  })

})



©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容