[fed-task-02-01]開發腳手架及封裝自動化構建工做流

簡答題

一、談談你對工程化的初步認識,結合你以前遇到過的問題說出三個以上工程化可以解決問題或者帶來的價值。

工程化是一個能夠提高開發體驗、提升開發效率和質量的規劃或者工做流架構,一切以提升效率、下降成本、質量保證爲目的的手段都屬於工程化。javascript

工程化帶來的價值:css

  • 開發時可使用 ES6+ 新特性,經過工程化的手段將新語法轉換成兼容性好的語法,而後發佈
  • 可使用熱更新提高開發體驗和效率,能夠將代碼壓縮等這樣重複機械的工做交給計算機完成
  • 團隊協做開發時,可使用一些編碼規範檢查的工具,使得項目代碼風格統一,質量獲得保證
  • 可使用 Mock.js 這樣的插件完成假數據的編寫,開發階段時,讓前端能夠不依賴後端接口去完成相應工做

二、你認爲腳手架除了爲咱們建立項目結構,還有什麼更深的意義?

更深的意義在於,腳手架也爲咱們提供了項目規範和公共約定。包括相同的組織結構、相同的開發範式、相同的模塊依賴、相同的工具配置、相同的基礎代碼等等,對於公司裏的大多數產品,前端均可以使用同一套腳手架,不只能夠統一各個項目,當項目成員切換團隊時,也能夠直接上手,提升效率,相關模塊依賴更新或者配置須要改動時,能夠一步到位更新全部產品,更利於維護。前端

編程題

一、概述腳手架實現的過程,並使用 NodeJS 完成一個自定義的小型腳手架工具

腳手架的實現流程vue

  1. 經過命令行交互詢問用戶問題;
  2. 根據用戶回答的結果,再結合一些模板文件,最後生成項目結構。

基於 NodeJS 的自定義小型腳手架工具 lxc-scaffolding,參見 https://github.com/luxiancan/...java

二、嘗試使用 Gulp 完成 項目 的自動化構建

參見 https://github.com/luxiancan/...node

三、使用 Grunt 完成 項目 的自動化構建

還沒完成。。。react

項目文件說明

https://github.com/luxiancan/...git

  • notes : 筆記
  • lxc-scaffolding : 使用 NodeJS 完成的一個小型腳手架
  • lxc-gulp-proj : 使用 Gulp 完成項目的自動化構建案例
  • introduce_video.m4v : 實現思路的視頻介紹

學習筆記

前端工程化

經過工程化提高戰鬥力github

工程化主要解決的問題

  • 傳統語言或語法的弊端
  • 沒法使用模塊化、組件化
  • 重複的機械式工做
  • 代碼風格統1、質量保證
  • 依賴後端服務接口支持
  • 總體依賴後端項目

一切重複的工做都應該被自動化

建立項目 => 編碼 => 預覽/測試 => 提交 => 部署vue-cli

工程化不等於工具

一些成熟的工程化集成

  • create-react-app
  • vue-cli
  • angular-cli
  • gatsby-cli

腳手架工具

前端工程化的發起者

腳手架工具的本質做用:建立項目基礎結構、提供項目規範和約定。

  • 相同的組織結構
  • 相同的開發範式
  • 相同的模塊依賴
  • 相同的工具配置
  • 相同的基礎代碼

經常使用的腳手架工具

  • React 項目 -> create-react-app
  • Vue 項目 -> vue-cli
  • Angular 項目 -> angular-cli

它們能夠根據信息建立對應的項目基礎結構

Yeoman: 一款通用型腳手架工具,建立項目時,能夠根據模板生成對應的項目結構,很靈活、易於擴展

Plop: 用於在開發過程當中,建立一些特定類型的文件

Yeoman

Yeoman 基礎使用

  • 在全局範圍安裝 yo

$ npm install yo --global # or yarn global add yo

  • 安裝對應的 generator

$ npm install generator-node --global # or yarn global add generator-node

  • 經過 yo 運行 generator
$ cd path/project-dir
$ mkdir my-module
$ cd my-module
$ yo node

Yeoman 使用步驟總結

  1. 明確你的需求;
  2. 找到合適的 Generator;
  3. 全局範圍安裝找到的 Generator;
  4. 經過 Yo 運行對應的 Generator;
  5. 經過命令行交互填寫選項;
  6. 生成你所須要的項目結構;

自定義 Generator

Generator 基本結構

├── generators/ ·········································· 生成器目錄
│   ├── app/ ············································· 默認生成器目錄
│   |    └── index.js ···································· 默認生成器實現
|   └── component/ ······································· 其餘生成器目錄
│        └── index.js ···································· 其餘生成器實現
└── package.json ········································· 模塊包配置文件

自定義 Generator 的詳細操做步驟:

1.建立 generator 文件目錄

$ mkdir generator-lxc-test
$ cd generator-lxc-test

2.給項目初始化一個 package.json
$ npm init -yes # or yarn init -yes

3.安裝 yeoman 依賴
$ yarn add yeoman-generator

4.新建 generator 入口文件
$ code generators/app/index.js

// 此文件做爲 Generator 的核心入口
// 須要導出一個繼承自 Yeoman Generator 的類型
// Yeoman Generator 在工做時會自動調用咱們在此類型中定義的一些生命週期方法
// 咱們在這些方法中能夠經過調用父類提供的一些工具方法實現一些功能,例如文件寫入

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 // appname 爲項目生成的目錄名稱
            }
        ])
        .then(answers => {
            // answers => { name: 'user input value' }
            this.answers = answers;
        });
    }
    // Yeoman 自動在生成文件階段調用此方法
    // 咱們這裏嘗試往項目中寫入文件
    writing () {
        this.fs.write(
            this.destinationPath('temp.txt'),
            Math.random().toString()
        )
    }
}

5.若是使用到模板,須要在 app 目錄下新建 templates 目錄存放模板文件,使用 EJS 語法寫入變量

這是一個模板文件
內部可使用 EJS 模板標記輸出數據
例如:<%= title %>

其餘的 EJS 語法也支持

<% if (success) { %>
哈哈哈
<% }%>

6.完成 index.js 後,將咱們建立的 generator 連接到全局,在 generator-lxc-test 目錄下執行:
$ yarn link

7.使用咱們建立好的 generator

$ cd path/project-dir
$ mkdir my-test-proj
$ cd my-test-proj
$ yo lxc-test

Plop

  • 一個小而美的腳手架工具,通常用於建立項目中特定類型文件的小工具;
  • 能夠大大提升咱們在項目中建立重複文件的效率;
  • 通常不會獨立使用,會集成到項目中,自動化的建立同類型的文件;

Plop 的基本使用

1.安裝 plop
$ yarn add plop --dev

2.在項目根目錄下建立模板文件 plop-templates/component.hbs

<template>
    <div class="{{name}}">
        <h1>{{name}} Component</h1>
    </div>
</template>

<script>
    export default {
        name: '{{name}}',
        data() {
            return {};
        },
    }
</script>

<style scoped lang="scss">
    .{{name}} {}
</style>

3.在項目根目錄下建立 plop 入口文件 plopfile.js

// plopfile.js
// Plop 入口文件,須要導出一個函數
// 此函數接收一個 plop 對象,用於建立生成器任務
module.exports = plop => {
  plop.setGenerator('component', {
    description: 'create a component',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'component name',
        default: 'MyComponent'
      }
    ],
    actions: [
      {
        type: 'add', // add 表明添加文件
        path: 'src/components/{{name}}/{{name}}.vue',
        templateFile: 'plop-templates/component.hbs'
      }
    ]
  })
}

4.利用咱們剛剛註冊的生成器的名字啓動 plop
$ yarn plop component

自動化構建

一切重複工做本應自動化

源代碼 => 自動化構建 => 生產代碼

自動化構建工做流

  • 做用:脫離運行環境兼容帶來的問題
  • 使用提升效率的語法、規範和標準

    • ECMAScript Next
    • Sass
    • 模板引擎
  • 構建轉換那些不被支持的特性

自動化構建初體驗

利用 package.json 中的 script 屬性,配置一些簡單的自動構建命令

"scripts": {
    "build": "sass scss/main.scss css/style.css --watch",
    "serve": "browser-sync . --files \"css/*.css\"",
    "start": "run-p build serve"
  },

經常使用的自動化構建工具

  • Grunt ,最先的前端構建系統,工做過程是基於臨時文件實現的,因此構建速度相對較慢,插件生態很是完善
  • Gulp ,構建是基於內存實現的,支持同時執行多個任務,效率較高,使用方式更直觀易懂,插件生態也很完善
  • FIS ,百度的前端團隊推出的前端構建系統,至關於捆綁套餐,將一些典型的需求都集成在內部

Grunt 的使用

Grunt 的基本使用

  • 先要安裝 grunt ,yarn add grunt
  • 在項目根目錄建立 Grunt 的入口文件 gruntfile.js
  • 用於定義一些須要 Grunt 自動執行的任務
  • 須要導出一個函數
  • 此函數接收一個 grunt 的形參,內部提供一些建立任務時能夠用到的 API
// gruntfile.js
module.exports = grunt => {
    grunt.registerTask('foo', () => {
        console.log('hello grunt~');
    });

    grunt.registerTask('bar', '任務描述', () => {
        console.log('other task~');
    });

    grunt.registerTask('default', ['foo', 'bar']);

    // 執行異步任務
    grunt.registerTask('async-task', function () {
        const done = this.async();
        setTimeout(() => {
            console.log('async task working~');
            done();
        }, 3000);
    });
}

Grunt 標記任務失敗

  • 在 registerTask 第二個參數,也就是回調函數裏 return false 便可
  • 處理多個任務,其中一個任務失敗的狀況,能夠用 --force 命令強制執行全部任務
  • 異步任務,標記失敗的處理:const done = this.async(); ... done(false);

Grunt 的配置方法

  • 使用 grunt.initConfig() 這個方法進行配置
  • 在 registerTask 第二個參數,也就是回調函數裏經過 grunt.config('foo') 獲取配置
module.exports = grunt => {
    grunt.initConfig({
        // foo: 'bar'
        foo: {
            bar: 123
        }
    });
    grunt.registerTask('foo', () => {
        // const foo = grunt.config('foo');
        // console.log(foo); // bar
        const bar = grunt.config('foo.bar');
        console.log(bar); // 123
    });
}

Grunt 多目標任務

  • 多目標模式,可讓任務根據配置造成多個子任務
  • 經過 grunt.registerMultiTask('build', function () {}) 執行多任務
  • 經過 grunt.initConfig({ build: {...} }) 配置多個子任務

Grunt 插件的使用

  • 先下載相關插件 yarn add grunt-contrib-clean
  • 經過 grunt.loadNpmTasks('grunt-contrib-clean') 導入插件
  • 經過 grunt.initConfig() 配置插件
module.exports = grunt => {
    grunt.initConfig({
        clean: {
            // temp: 'temp/app.js'
            // temp: 'temp/*.txt'
            temp: 'temp/**'
        }
    });
    grunt.loadNpmTasks('grunt-contrib-clean');
}

Grunt 經常使用插件介紹

yarn init -yes
yarn add grunt grunt-sass sass --dev
建立 gruntfile.js 文件
yarn grunt sass

yarn add grunt-babel @babel/core @babel/preset-env --dev
yarn add load-grunt-tasks --dev

Gulp 的使用

Gulp 的基本使用

yarn init -yes
yarn add gulp
建立 gulpfile.js 文件
yarn gulp my-task 執行指定任務
yarn gulp 執行默認的 default 任務

// gulpfile.js  gulp 的入口文件

exports.foo = done => {
    console.log('foo task working~');
    done(); // 標識任務完成
}
exports.default = done => {
    console.log('default task working~');
    done();
}

// gulp 4.0 版本以前,建立任務的方式
const gulp = require('gulp');
gulp.task('bar', done => {
    console.log('bar working~');
    done();
});

Gulp 的組合任務

const { series, parallel } = require('gulp');
const task1 = done => {
    setTimeout(() => {
        console.log('task1 working~');
        done();
    }, 1000);
}
// ...
// 建立串行任務
exports.foo = series(task1, task2, task3);

// 建立並行任務
exports.bar = parallel(task1, task2, task3);

Gulp 的異步任務

exports.promise = () => {
    console.log('promise task~');
    return Promise.resolve();
}
exports.promise_error = () => {
    console.log('promise task~');
    return Promise.reject(new Error('task failed!'));
}

const timeout = time => {
    return new Promise(resolve => {
        setTimeout(resolve, time);
    });
};
exports.async = async () => {
    await timeout(1000);
    console.log('async task~');
}

// 處理文件流
const fs = require('fs');
exports.stream = done => {
    const readStream = fs.createReadStream('package.json');
    const writeStream = fs.createWriteStream('temp.txt');
    readStream.pipe(writeStream);
    readStream.on('end', () => {
        done();
    });
}

Gulp 構建過程核心原理

輸入 => 加工 => 輸出讀取流 => 轉換流 => 寫入流

相關文章
相關標籤/搜索