工程化是一個能夠提高開發體驗、提升開發效率和質量的規劃或者工做流架構,一切以提升效率、下降成本、質量保證爲目的的手段都屬於工程化。javascript
工程化帶來的價值:css
更深的意義在於,腳手架也爲咱們提供了項目規範和公共約定。包括相同的組織結構、相同的開發範式、相同的模塊依賴、相同的工具配置、相同的基礎代碼等等,對於公司裏的大多數產品,前端均可以使用同一套腳手架,不只能夠統一各個項目,當項目成員切換團隊時,也能夠直接上手,提升效率,相關模塊依賴更新或者配置須要改動時,能夠一步到位更新全部產品,更利於維護。前端
腳手架的實現流程vue
基於 NodeJS 的自定義小型腳手架工具 lxc-scaffolding,參見 https://github.com/luxiancan/...java
參見 https://github.com/luxiancan/...node
還沒完成。。。react
https://github.com/luxiancan/...git
經過工程化提高戰鬥力github
建立項目 => 編碼 => 預覽/測試 => 提交 => 部署vue-cli
一些成熟的工程化集成
前端工程化的發起者
腳手架工具的本質做用:建立項目基礎結構、提供項目規範和約定。
它們能夠根據信息建立對應的項目基礎結構
Yeoman: 一款通用型腳手架工具,建立項目時,能夠根據模板生成對應的項目結構,很靈活、易於擴展
Plop: 用於在開發過程當中,建立一些特定類型的文件
$ npm install yo --global # or yarn global add yo
$ npm install generator-node --global # or yarn global add generator-node
$ cd path/project-dir $ mkdir my-module $ cd my-module $ yo node
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
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
一切重複工做本應自動化
源代碼 => 自動化構建 => 生產代碼
自動化構建工做流
使用提升效率的語法、規範和標準
利用 package.json 中的 script 屬性,配置一些簡單的自動構建命令
"scripts": { "build": "sass scss/main.scss css/style.css --watch", "serve": "browser-sync . --files \"css/*.css\"", "start": "run-p build serve" },
// 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); }); }
const done = this.async(); ... done(false);
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 }); }
module.exports = grunt => { grunt.initConfig({ clean: { // temp: 'temp/app.js' // temp: 'temp/*.txt' temp: 'temp/**' } }); grunt.loadNpmTasks('grunt-contrib-clean'); }
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
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(); });
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);
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(); }); }
輸入 => 加工 => 輸出讀取流 => 轉換流 => 寫入流