前端工程化概述与脚手架工具

文章说明:本文章为拉钩大前端训练营所做笔记和心得,若有不当之处,还望各位指出与教导,谢谢 ! 

一、工程化的定义和主要解决的问题 

从传统的网站到现在的H5,移动app,桌面应用以及小程序,前端对开发人员的要求发生了翻天覆地的变化。

面临的问题

  • 想要使用ES6+,但是兼容有问题(传统语言或语法的弊端)
  • 想要使用Less/Sass/PostCSS增强CSS的编程性,但是运行环境不能直接支持(无法使用模块化/组件化)
  • 部署上线前需要手动压缩代码及资源文件,部署过程需要手动上传代码到服务器(重复的机械式工作)
  • 多人协作开发,无法硬性统一大家的代码风格,从仓库中pull回来的代码质量无法保证(代码风格统一、质量保证)
  • 部分功能开发时需要等待后端服务接口提前完成(依赖后端服务接口支持、整体依赖后端项目)

二、一个项目过程中工程化的表现

工程化表现:一切以提高效率、降低成本、质量保证为目的的手段都属于工程化。

一切重复的工作都应该被自动化。工程化不等于某一个具体的工具。工程化的核心是对某个项目整体的一种规划或者架构,而工具在这个过程当中只是用来帮我们落地,去实现这种规划或者架构的一种手段。

三、工程化与Node.js

没有node.js就没有今天的前端。

工程化:

  • 脚手架工具开发
  • 自动化构建系统
  • 模块化打包
  • 项目代码规范化
  • 自动化部署

四、脚手架工具概要与常见的脚手架工具

脚手架的本质作用:创建项目基础结构、提供项目规范和约定,通常开发相同的项目时都会有一些相同的约定:

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

通过脚手架工具搭建特定类型的骨架,然后基于这个类型的骨架进行后续的开发工作。比如IDE创建项目的过程就是一个脚手架的工作流程。

常用的脚手架工具:

  • React项目 =》create-react-app
  • vue.js => vue-cli
  • Angular项目 =》angular-cli

无外乎都是根据信息创建对应的项目基础结构,还有就是以yeoman这种通用型脚手架工具为代表的,他们可以提供一套模板生成一个对应的项目结构,这种类型一般都很灵活,而且很容易扩展。还有一种类型的脚手架工具像plop,他们用来在项目的开发过程当中创建一些特定类型的文件,例如创建一个组件\模块所需要的的文件。

五、yeoman

Yeoman是一款创造现代化web项目的脚手架工具,不同于vue-cli,yeoman更像是一个脚手架的运行平台,可以通过yeoman搭配不同的generator去创建任何类型的项目,也就是说可以创建自己的generator从而去定制属于我们自己的前端脚手架工具。在很多专注基于框架开发的人员眼中,yeoman它过于通用,不够专注。

使用npm在全局范围安装:yarn global add yo。

yeoman要去搭配特定的generator去使用,要找到所建对应项目类型的generator,使用generator-node,先全局安装generator:yarn global add generator-node

yo node 命令安装特定的generator,若是有yo不是内部或外部命令,则没全局安装,使用全局安装命令:

然后再用yo node

生成的基础项目结构和代码

Sub Generator

有时候我们只需要在已有的项目基础之上去创建一些特定类型的文件,例如给一个已经存在的项目创建一个readme,又比如我们在原有项目类型上去添加一些类型的配置文件,如eslint、babel。若是这样的需求,可以使用Yeoman提供的Sub Gennerator。

自定义Generator:

基于Yeoman搭建自己的脚手架,Generator本质上就是一个NPM模块。

Generator基本结构:

如果需要提供多个的server generator,可以在app的同级目录添加新的同级目录

除了特定的结构,还有一个不同的是,yeoman的Generator的模块名称为Generator-<name>:

$ mkdir generator-sample //创建Generator的文件夹

使用yarn创建并初始化package.json文件

yarn init

安装yarn-generator的一个模块,这个模块提供了生成器的一个机制,这个机制当中提供了一些工具函数,让我们创建生成器的时候更加便捷

生成器中的入口文件:

通过yarn link的方式把这个模块链接到全局范围,使之成为全局模块包,这样的话yeoman哦工作的时候找到我们自己写的Generator-sample了

yarn link

在项目目录里执行yeoman操作

yo sample

根据模板创建文件:

根据模板创建文件,相对于手动创建每一个文件,模板的方式大大提高了效率。

有了模板文件之后,我们在生成文件时就不用借助于fs的write方法去写入文件,通过模板方式写入文件到目标目录

接收用户输入数据:

对于模板的动态数据,例如项目标题,项目名称,一般通过命令行交互的方式询问使用者得到。在Generator当中,想要发起一个命令行交互的询问,我们可以通过实现Generator类型当中的promiting方法

Vue Generator 案例

  • 创建Generator文件夹,并初始化,然后安装yeoman-generator模块 
  $ mkdir generator-vue
  $ cd generator-vue
  $ yarn init # 或者 npm init
  $ yarn add yeoman-generator # or npm install yeoman-generator -D
  • 将vue生成的目录结构拷贝到Generator 的templates中,将其作为模板文件

vue生成的项目目录:

拷贝到Generator后:

  • 按照自定义Generator步骤,修改writing方法(不再像之前写入单个文件,它需要批量把我们刚刚所提前准备好的结构给它批量生成,创建一个templates目录,把我们创建的结构拷贝到templates当中):
const Generator = require('yeoman-generator')

module.exports = class extends Generator{
    prompting(){
        return this.prompt([
            {
                type:'input',
                name:'name',
                message:'Your project name',
                default:this.appname
            }
        ])
        .then(answers =>{
            this.answers = answers
        })
    }

    writing(){//不再像之前写入单个文件,它需要批量把我们刚刚所提前准备好的结构给它批量生成,创建一个templates目录,把我们创建的结构拷贝到templates当中
        //把每一个文件都通过模板转换到目标路径

        const templates = [
            '.browserslistrc',
            '.editorconfig',
            '.env.development',
            '.env.production',
            '.eslintrc.js',
            '.gitignore',
            'babel.config.js',
            'package.json',
            'postcss.config.js',
            'README.md',
            'public/favicon.ico',
            'public/index.html',
            'src/App.vue',
            'src/main.js',
            'src/router.js',
            'src/assets/logo.png',
            'src/components/HelloWorld.vue',
            'src/store/actions.js',
            'src/store/getters.js',
            'src/store/index.js',
            'src/store/mutations.js',
            'src/store/state.js',
            'src/utils/request.js',
            'src/views/About.vue',
            'src/views/Home.vue'
          ]

          templates.forEach(item =>{
              //item =>每个文件路径
              this.fs.copyTpl(
                  this.templatePath(item),
                  this.destinationPath(item),
                  this.answers
              )
          })
    }
}
  • 创建空文件夹(my-proj)根据模板生成对应项目文件:

yo Generator的名称

生成的新vue项目文件:

 发布Generator

发布Generator实际上就是发布一个Generator模块,写好的Generator模块通过npm publish 这样一个命令去发布成一个公开的模块就可以了,这样做之前我们将项目源代码托管到公开的源代码仓库上面.

git init//初始化本地仓库
git add .
git commit -m"feat:initial commit"
git remote add origin https://gitee.com/lyle1111/generator-zce-vue.git//添加远程仓库
git push -u origin master //提交

在界面执行发布命令:

第一次执行时,会要求输入mpm的用户名,邮箱和密码,以后输入时只要输入密码就可以了。

登录,登出时的命令:

yarn login 或者 npm login
yarn logout 或者 npm logout

下面这个错误表示需要去邮箱激活你的账号:

若是出现下面错误,则是发布的generator名称跟别人冲突:

在package.json里改掉名称就可以了

如果使用淘宝的镜像资源,会出现下列错误,因为淘宝镜像是只读的,不能讲模块发布。

可以修改镜像资源

  $ npm config set registry https://registry.yarnpkg.org  # yarn 镜像源
  $ npm config set registry https://registry.npmjs.org # node 默认镜像源

或者在命令后面直接跟上相关的镜像资源

  $ yarn publish --registry-https://registry.yarnpkg.com # yarn 镜像源
  $ yarn publish --registry-https://registry.npmjs.org # node 默认镜像源

最后运行完成:

 去npm官网看看刚刚发布的模块:

 发送到npm后,这个模块就可以在全局范围通过npm或yarn方式去安装,然后再通过yeoman去使用它(yo 这个Generator)。

Plop

创建项目中特定类型的文件的小工具。类似于Yeoman中的Sub Generator,但是他一般不会独立使用,而是集成在项目中,用来自动化的创建同类型的项目文件,例如 创建一个组件 / 模块所需要的文件。Plop 可以提高创建重复文件的效率。

步骤:

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

使用:

在项目中集成plop,安装plop模块

  yarn add plop --dev # 或者 npm install plop -D

在项目根目录下,新建一个profile.js文件,定义Plop脚手架任务

//Plop 入口文件,需要导出一个函数
// 此函数接收一个 plop 对象,用于创建生成器任务

module.exports = plop => {
    //setGenerator接收两个参数,一个是生成器的名字,一个是生成器的配置选项
    plop.setGenerator('component',{
        description:'create a component',
        prompts:[
            /*
                可以在这个Generator当中指定工作的时候会发出的命令行问题,这些命令行问题会出现交互环节
            */
            {
                type:'input',//指定这个问题的输入方式
                name:'name',//指定这个问题的返回值的一个键
                message:'component name',//屏幕上给出的提示
                default:'MyComponent'//这个问题的默认答案
            }
        ],
        actions:[
            /*
                actions是这个生成器在完成命令行交互过后需要执行的一些动作,可以是一个数组,这个数组当中为每一个动作对象
            */
            {
                type:'add',//这个动作的类型,为add,代表添加文件,
                path:'src/components/{
   
   {name}}/{
   
   {name}}.js',//指定需要添加的文件会被添加到哪个具体的路径
                templateFile:'plop-templates/component.hbs'//模板文件
            },
            {
                type:'add',//代表添加文件,
                path:'src/components/{
   
   {name}}/{
   
   {name}}.css',
                templateFile:'plop-templates/component.css.hbs'
            },
            {
                type:'add',//代表添加文件,
                path:'src/components/{
   
   {name}}/{
   
   {name}}.test.js',
                templateFile:'plop-templates/component.test.hbs'
            }
        ]
    })
}

创建对应的模板文件,模板文件采用Handlebars模板引擎进行书写,一般放置在根目录下的plop-templates下:

模板文件(component.hbs):

import React from 'react';
//这些文件遵循handlebars 模板语法
export default () =>(
    <div className = "{
   
   {name}}">
        <h1>{
   
   {name}} Component</h1>
    </div>
)

在安装 plop 时,Plop 提供了一个 CLI 的应用程序,由于yarn会自动找到node_modules下的bin目录下的命令行工具,所以可以通过 yarn 去启动这个程序

  yarn plop component //yarn plop 定义的Generator名称

成功后: 

 

六、脚手架工作原理:

脚手架工具其实就是一个node cli的应用。

  •  新建一个文件夹使用yarn init 初始化,然后再初始化后的package.json里面添加属性bin,设置入口文件,用于指定CLI应用的入口文件

  • 安装 inquirer 模块,通过使用 inquirer 这一模块,实现用户交互
 yarn add inquirer // 或者 npm install inquirer
  • 安装 ejs 模块,进行文件渲染
 yarn add ejs // 或者 npm install ejs
  • 编写cli.js文件
#!/user/bin/env node
  
// Node CLI 应用入口文件必须要有这样的文件头
// 如果是 Linux 或者 macOS 系统下还需要修改此文件的读写权限为 755
// 具体就是通过 chmod 755 cli.js 实现修改

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

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

inquirer.prompt([
    {
        type: 'input',
        name: 'name',
        message: "Project name?"
    }
]).then(answers => {
    // 根据用户回答的结果生成文件

    // 模板目录
    const tmplDir = path.join(__dirname, 'templates')

    // 目标目录
    const destDir = process.cwd()

    // 将模板下的文件全部转化到目标目录
    fs.readdir(tmplDir, (err, files) => {
        if (err) throw err
        files.forEach(file => {
            // 每一个file都是相对于templates下的相对路径
            // 通过模板引擎渲染文件,这里采用 ejs
            /**
             * renderFile() 方法 接收三个参数
             * 一,文件的绝对路径
             * 二,渲染的数据
             * 三,回调函数
             */ 
            ejs.renderFile(path.join(tmplDir, file), answers, (err, result) => {
                if (err) throw err

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

猜你喜欢

转载自blog.csdn.net/weixin_41962912/article/details/110392787