AngularJS + CoffeeScript 前端開發環境配置詳解
AngularJS 號稱 ‘第一框架’ (‘The first framework’) 確實是名不虛傳。由其從jQuery中完全轉入AngularJS後就有無法離開他的感覺了。雖然AngularJS的學習曲線很陡峭,入門的門檻相比較高,但這些付出都是值得的相信用過的朋友都會與我有同感吧。為何我如此
地偏愛AngularJS? 或者這樣說吧,用AngularJS開發的話其實是給我了一種工業化開發的概念,我對軟體工業化的淺顯理解簡單歸結為幾點就是:
- 自動化
- 智慧化
- 注重質量
- 注重工藝
前端開發比後端開發要求開發人員做更多繁雜的事,例如:js和css 的壓縮、依賴引入、更新,圖片壓縮、“糖果語言(coffeescript/less/sass)”的語法檢查與編譯、靜態圖片/靜態網頁壓縮,單元測試、E2E測試、等等。這些鎖事往往很耗時間。
再者,當引入AngularJS作為主前端框架的話,大量的js原始檔管理對檔案結構與模組結構合理規劃就顯得更為之重要。所幸的是,google 是AngularJS工業化的主力推手,為了增加前端開發人員的生產力他們也不遺餘力地做了很多工作,最為突出的就是[Yeoman|http://www.yeoman.io],他能快速地為我們建立各種型別專案的腳手架(專案模板),以他們的“最佳實踐”為基礎快速地為我們完成這一系列繁瑣的工作。
我在實際專案開發覺得官方提供的 angular 生成器並不是十分合用,在經歷了好幾個專案的磨合後我在 google 官方的 yeoman angular 腳手架專案上進行了一些定製與修改,也在此作一些分享,由於時間關係還沒有去將其成一個generator 所以只能在此以博文方式共享了。
如果對Yeoman不瞭解也不用要,本文將會獨立於yeoman 一步一步詳細地解釋如何部署一個可以用於生產AngularJS前端開發環境。
工具
以下這些可謂是前端開發必備了,如果不清楚具體用法那麼就先請去他們的官網先腦補吧:
npm
Node的依賴包管理工具,可以到 [nodejs 官方下載|http://nodejs.org/download/]頁面獲取安裝包。
** bower **
bower 是由twitter開發的客戶端依賴包管理工具
npm install -g bower
** grunt **
自動化任務管理工具,是整個自動化工程的核心。
npm install -g grunt-cli
安裝此三大工具後我們就可以著手開始了。
實現的目標功能
- 基於 CoffeeScript並支援自動編譯
- 能支援 livereload(一但任何程式碼、資源發生更改瀏覽器會自動重新整理)
- 自動編譯 less
- 支援 ngdocs 從 CoffeeScript 自動提取註釋生成 API文件網站
- 自動 連線、最小化靜態資源,包括:指令碼、圖片、網頁
- 自動將bower引入的依賴包注入頁面
- 配備 Karma 的單元測試
- 配備基於 protractor 的e2e測試
基本目錄結構
以下是基本專案目錄的構成以及每個目錄的功能說明
專案目錄/
├── app // 應用程式目錄
│ ├── bower_components // bower 元件目錄 (由 bower 生成)
│ ├── fonts // 字型
│ ├── images // 圖片資源
│ ├── styles // 樣式目錄 可存放 .css 和 .less
│ └── scripts // 應用程式指令碼
│ └── app.coffee // angularJS 應用程式檔案
│ └── index.html // HTML HOME 檔案
├── dist // 釋出後的程式目錄
├── test // 測試程式目錄
│ ├── mocks // 存放mocks元件檔案目錄
│ ├── e2e // e2e測試檔案目錄
│ └── spec // 單元測試檔案目錄
├── node_modules // NodeJS 的元件目錄 (由 npm 生成)
├── docs // 存放生成文件
├── .tmp // 臨時檔案目錄 (由 grunt 任務自動生成)
├── .bowerrc // bower 路徑規則指定檔案
├── conffeelint.json // CoffeeScript 語法檢查規則
├── Gruntfile.js // grunt 配置檔案
├── karma.conf.js // karma 配置檔案
├── protractor.conf.js // protractor 配置檔案
├── package.json // nodes 依賴包描述檔案
└── bower.json // bower 依賴包描述檔案
流程及原理
此專案環境主要提供三種主要的執行方式,分別適用於專案生命週期中的不同的時期,更準備地說應該是適用於不同的場景。
生成模式 – build
將所有的檔案生成至產品交付目錄 dist
內,執行包括:
- coffeescript/less
- 編譯
- 連結
- 壓縮
- 引用修正,包括 angular 動態注入修正
- 拷貝
- 輸出必要的靜態檔案
- 網頁
- 圖片
- 字型檔
- 輸出註釋文件並生成文件網站
指令:
grunt build
測試模式 – test
多用於開發期,進行自動化單元測試或是e2e測試,考慮到e2e測試的使用頻率相對於單元測試要低,故此 test指令只預設執行所有單元測試,
而要執行e2e測試則需加入 e2e
引數作明確指定。
指令:
grunt test
- e2e -
grunt test:e2e
如果加入 keepalive
引數的話,test 指令將直接執行於後臺,且會檢測所有的檔案變化,一但檔案發生更改測試將會自動被重新執行。
這種情況多適用於測試程式的編寫與除錯。
grunt test:keepalive
除錯模式 – debug
主要用於手工除錯與HTML介面設計之用,當啟用 debug 模式後,livereload 功能將會被自動載入,也就是所有 app
目錄下的任何
變更都能被捕獲且瀏覽器能自動重新整理應用更改。
指令:
grunt debug
Gruntfile.js 檔案的設計
首先需要安裝 load-grunt-tasks 和 time-grunt 兩個外掛
npm load-grunt-tasks --save-dev npm time-grunt --save-dev
基本的 Gruntfile.js
'use strict'; module.exports = function (grunt) { // 自動載入所有可用的grunt 任務 require('load-grunt-tasks')(grunt); // 可以顯示每個任務執行的實際時間,可以便於以我們優化任務 require('time-grunt')(grunt); // 配置主要路徑 var config = { app: require('./bower.json').appPath || 'app', dist: 'dist', tmp: '.tmp', tasks: grunt.cli.tasks }; grunt.initConfig({ // 任務配置 });
配置 CoffeeScript
首先是令CoffeeScript能支援語法檢查,需要安裝 [coffeelint|http://www.coffeelint.org] 外掛:
npm install coffeelint --save-dev
此外掛安裝後可以與大名鼎鼎的 jshint一樣將語法檢查規則放在一個獨立的檔案內,本專案中就是專案根目錄下的 coffeelint.json
,
如果需要增加更多的CoffeeScript語法檢查規則可以修改此檔案 。
在Gruntfile.js內的配置如下:
coffeelint: { options: { configFile: 'coffeelint.json' }, all: ['<%= config.app %>/scripts/**/*.coffee'], //檢查應用程式目錄下的 CoffeeScript指令碼 test: { files: { src: ['tests/**/*.coffee'] //檢查所有測試指令碼 } } }
然後是安裝CoffeeScript編譯外掛: [coffee-script|http://github.com/jashkenas/coffeescript]
npm install grunt-contrib-coffee --save-dev
由於我們編譯出來的 javascript 不會直接使用,因為還要進行連線、壓縮和拷貝過程,所以我們將所有的輸出目錄設定為 .tmp
目錄。
在即使修改時也可以通過livereload 從.tmp目錄直接將變更後的指令碼直接載入到瀏覽器內,方便除錯之用。
還有一點需要特別指出的是 coffee 選項中我將 sourceMap
設定為true,只有這個選項開啟,當生成map檔案後在瀏覽器除錯時才能準確地將被壓縮後的
檔案正確地重新對映至未壓縮的程式原始檔。關於 source map的具體用法可以參考 [javascript source map的使用|http://www.cnblogs.com/Ray-liang/p/4018162.html]
一文。
coffee: { options: { bare: false, sourceMap: true, sourceRoot: '' }, dist: { files: [ { expand: true, cwd: '<%= config.app %>/scripts', src: '{,*/}*.{coffee,litcoffee,coffee.md}', dest: '.tmp/scripts', ext: '.js' } ] }, test: { files: [ { expand: true, cwd: 'test/spec', src: '{,*/}*.coffee', dest: '.tmp/spec', ext: '.js' }, { expand: true, cwd: 'test/e2e', src: '{,*/}*.coffee', dest: '.tmp/e2e', ext: '.js' } ] } }
配置 Less
Grunt 提供了官方的less 編譯安裝包 [grunt-contrib-less|https://github.com/gruntjs/grunt-contrib-less]
npm install grunt-contrib-less --save-dev
與配置coffee 編譯器的原理一樣我們需要將 styles 目錄下的 .less檔案預先編譯成為 .css並存放在 .tmp/styles下,以備後處理
和livereload 之用。
less: { all: { files: [ { expand: true, flatten: true, cwd: '<%= config.app %>/styles', src: ['{,*/}*.less'], dest: '.tmp/styles', ext: '.css' } ] } }
壓縮與連線
在這部分我並沒有直接採用 Grunt 官方的 uglify,concat 而是使用了 usemin 外掛這是延續了 yo generator-angular 的做法。他是 yeoman專案的官方外掛,這個外掛同樣是依賴於 uglify,concat 的,然而他增加了對檔案自動引用的支援,可以從頁面讀出指令碼檔案的引用而不是通過hardcore的方式寫在Gruntfile中。另外,他還能增加對bower_components內的依賴進行合成而取代人工合成,這是一個很棒的功能可以省去我們從bower_components下找輸出檔案的麻煩,只需要關注bower.json檔案內管理包而不是在Gurntfile.js進行硬編碼了。
usemin是一個合成包需要以下這些外掛同時支援,為了節省篇幅以下的指令都是以 npm install [包] --save-dev
方式安裝
- [grunt-usemin|https://github.com/yeoman/grunt-usemin]
- [grunt-svgmin|https://github.com/sindresorhus/grunt-svgmin]
- [grunt-contrib-cssmin|https://github.com/gruntjs/grunt-contrib-cssmin]
- [grunt-contrib-htmlmin|https://github.com/gruntjs/grunt-contrib-htmlmin]
- [grunt-contrib-imagemin|https://github.com/gruntjs/grunt-contrib-imagemin]
- [grunt-contrib-uglify|https://github.com/gruntjs/grunt-contrib-uglify]
- [grunt-contrib-concat|https://github.com/gruntjs/grunt-contrib-concat]
以下配置是從 generate-angular 中拷貝過來用的:
// Reads HTML for usemin blocks to enable smart builds that automatically // concat, minify and revision files. Creates configurations in memory so // additional tasks can operate on them useminPrepare: { options: { dest: '<%= config.dist %>' }, html: [ '<%= config.app %>/index.html' ] }, // Performs rewrites based on rev and the useminPrepare configuration usemin: { options: { assetsDirs: [ '<%= config.dist %>', '<%= config.dist %>/images' ] }, html: ['<%= config.dist %>/{,*/}*.html'], css: ['<%= config.dist %>/styles/{,*/}*.css'] }, // The following *-min tasks produce minified files in the dist folder imagemin: { dist: { files: [ { expand: true, cwd: '<%= config.app %>/images', src: '{,*/}*.{gif,jpeg,jpg,png}', dest: '<%= config.dist %>/images' } ] } }, svgmin: { dist: { files: [ { expand: true, cwd: '<%= config.app %>/images', src: '{,*/}*.svg', dest: '<%= config.dist %>/images' } ] } }, htmlmin: { dist: { options: { customAttrAssign: [/\?=/], collapseBooleanAttributes: true, collapseWhitespace: true, removeAttributeQuotes: true, removeCommentsFromCDATA: true, removeEmptyAttributes: true, removeOptionalTags: true, removeRedundantAttributes: true, useShortDoctype: true }, files: [ { expand: true, cwd: '<%= config.dist %>', src: ['{,*/}*.html', 'views/{,*/}*.html', 'templates/{,*/}*.html'], dest: '<%= config.dist %>' } ] } }
這裡需要說明的是 app/index.html檔案,也就是在配置中:
useminPrepare: { html: [ '<%= config.app %>/index.html' ] }
這個選項是給 usemin 外掛去找指令碼引用的,這裡預設只是設定了 index.html 檔案,因為這是一個Angular SPA專案,所以只有一個index.html檔案作為主入口,如果你具有多個不同的檢視模板,而且所引用的 script 都不要一樣的話,可以將這些模板頁明確地放在這個 html
陣列選項中。
關於usemin的詳細用法可以參考google的官方文件,以下只是對最常用的部分進行講解,力求不去看官方那個龐大的英文文件也能快速地使用起來。
開啟 index.html :
<!doctype html> <html ng-app="app"> <head> <meta charset="utf-8"> <title>Project Title</title> <!-- build:css styles/vendor.css --> <!-- bower:css --> <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="bower_components/fontawesome/css/font-awesome.css" /> <!-- endbower --> <!-- endbuild --> <!-- build:css styles/main.css --> <link rel="stylesheet" href="styles/main.css"> <!-- endbuild --> <!-- build:js scripts/vendor.js --> <!-- bower:js --> <!-- endbower --> <!-- endbuild --> <!-- build:js({.tmp,app}) scripts/index.js --> <!-- endbuild --> <base target="_blank"> </head> <body ng-strict-di> <div ui-view></div> </body> </html>
如果你足夠細心你會發現這裡有一些“與眾不同的”標記,<!--build:js--><!-- endbuild -->
和 <!--build:css--><!-- endbuild -->
實際上這不是註釋,他們其實是 usemin 的專用配置標記。其中 <!-- bower:js--><!--endbower-->
是另一個外掛 bowerInstall 的
配置標記,我會在下文再詳細講解。
這個標記其實很簡單將他翻譯過來就是:<!-- build:型別[js|css] 生成的目標檔案>
, 原始檔目錄就是當前html所在的目錄,如果要指定多個
源目錄可以通過<!-- build:型別({目錄1,目錄2}) 生成的目標檔案>
的方式指定。
按照這個來理解的話,這裡的設定就會輸出三個檔案:
- vendor.js //第三方依賴的合成壓縮指令碼
- index.js //專案內的的合成壓縮指令碼
- vendor.css //第三方依賴的合成壓縮樣式表
- main.css //專案內的合成壓縮樣式表
好吧,先來說說 vendor.*
,如果裝了 bowerInstall 這個外掛在<!-- bower:型別 --><!-- endbower-->
內的引用是由 bowerInstall 自動加入的,他加入後會修改index.html原始檔,我們不需要手工加入。而對於某些比較坑爹的第三包,這裡指的坑爹是他的最終輸出檔案放在一些古怪的深層目錄中,而不是在他的釋出目錄的根下,那麼我們才需要手工加入引用。如 ace-builds 這個包,他的釋出檔案是在 ace-builds/src/ace.js,同時他又提供了ace-build/src-min/ace.js 檔案,對於這類包我們就不得不手工將具體的引用檔案加入到 <!-- bower-->
標記內,否則bowerInstall是不知道應該引用哪一個檔案的。
而輸出位置就是前面我們在 usemin選項中設定的:
useminPrepare { options: { dest: '<%= config.dist %>' } }
也就是 專案目錄/dist
。
接下來是 main.css
和 index.js
,這兩個是從不同的源來生成的,main.css
沒有指定源,所以他會在當前的index.html所在位置中找 styles 目錄也就是專案目錄/app/styles
,那麼具體需要引用那些自定的css(之前通過 less生成的)就在此設定。
解釋得更為清楚一點就是 假設有一個 app/styles/custom.less 檔案,那麼在 index.html內加入這個引用應該是:
<!-- build:css styles/main.css --> <link rel="stylesheet" href="styles/main.css"> <link rel="stylesheet" href="styles/custom.css"> <!-- endbuild -->
雖然custom.css在設計期並不存在,但他會被less編譯器最終輸出,所以引用時只要名字對了就行了。
同樣的 build:js
的設定也是這理,只是這裡增加了 .tmp
作源搜尋目錄,就是說在 .tmp
找不到的原始檔 可以到 app/scripts
下找,反之亦然。
bowerInstall
緊接上文,就是這個 bowerInstall 外掛了,他就是可以從bower.json檔案自動識別我們的專案引入了哪些第三方依賴,然後就將依賴的檔案自動地注入到 <!--bower:js-->
和<!--bower:css-->
標記裡面。
npm install grunt-bower-install --save-dev
配置如下:
bowerInstall: { app: { src: ['<%= config.app %>/index.html'], ignorePath: '<%= config.app %>/' } }
bowerInstall 有一個替代品,叫 wiredep ,但這個外掛很笨,經常會出現引用錯誤的問題,所以這裡還是推薦使用bowerInstall
Angular 的自動依賴注入
接下來就是要為 Angular 環境作專門的配置了,首先要配置的是依賴注入。先來看來來Angular官方推薦的依賴注入方法:
angular.main('myApp',[]).controller('MyCtrl',['$scope','$log','$http','$resource',($scope,$log,$http,$resource)-> #我們的程式碼在此 ])
光是為依賴注入我們其實是很無趣地編寫這些對應的白痴式引用,當然只有一兩個當然沒什麼問題,但如果注入得多了那麼這個定義就變得
極為之難讀。如果我們將上面的程式碼寫成這樣:
MyCtrl=($scope,$log,$http,$resource)-> #控制器程式碼在此 @ angular.main('myApp',[]).controller 'MyCtrl',MyCtrl
這樣是否更容易讀呢?為了實現這個效果,我們可以使用 [ngAnnotate|https://www.npmjs.com/package/grunt-ng-annotate] 外掛幫我們實現這
種動態式的插入,使得我們的程式碼可讀性可以大大地增加。
npm install grunt-ng-annotate --save-dev
ngAnnotate: { dist: { files: [ { expand: true, cwd: '.tmp/concat/scripts', src: ['*.js', '!oldieshim.js'], dest: '.tmp/concat/scripts' } ] } }
自動生成 Angular API 文件
這是一個我認為很 Cool 的外掛,他能直接從原始碼中直接抽出註釋並生成一個API參考網站,對於開發產品專案幫助極大。這個外掛叫 [ngdocs|https://www.npmjs.com/package/grunt-ngdocs]
npm install ngdocs –save-dev
這個外掛配置很是簡單,但他不能支援coffeescript,那麼我們只能從生成的javascript檔案作為註釋文件生成源:
ngdocs: { all: ['.tmp/scripts/**/*.js'] }
關於 ngdocs 這個主題以後我會專門花時間再詳細寫一篇文章來具體說明一下。
指令碼模板
在使用Angular的 Routing、directive或是其它的外掛,如 angular-ui 都可能使用到模板。如:
MyDirective=-> restrict:'E' tempalteUrl:'scripts/directives/MyDirective.tpl.html' angular.module('myApp').directive 'MyDirective',MyDirective
對於使用了 tempalteUrl
指定的模板是無法在Karma的測試中找到的,因為jasmine只能找到指令碼而不能找到html檔案。這樣一來就會令得 directive 成為一個不可測試的元件。可以使用 [html2js|https://github.com/karlgoldstein/grunt-html2js] 解決這一問題(angularJS官方推薦)。這個外掛的最大作用是將html檔案直接編譯為js檔案,而無需要改動我們的原始碼,這樣一來既可在測試上解決這個問題也可以將html模板檔案封裝為可釋出的指令碼(如果你細心一點會發現 angular-ui 就是樣做的,angular-ui-tpl.js 就是模板檔案)。
npm install grunt-html2js --save-dev
這個配置會有點點複雜
html2js: { options: { base: 'app', target: 'coffee', module: 'myApp.templates', //模板會生成至模組內,需要明確指定模組的名稱 singleModule: true, useStrict: true, htmlmin: { collapseBooleanAttributes: true, collapseWhitespace: true, removeComments: true, removeEmptyAttributes: true, removeRedundantAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true } }, main: { src: ['<%= config.app %>/scripts/**/*.tpl.html'], dest: '<%= config.app %>/scripts/templates.coffee' } }
有幾點在使用時需要注意:
- 這裡只檢測 app 目錄下所有的以 *.tpl.html結尾的HTML檔案(視為模板檔案)
- 這個檔案會生成至源目錄(app/scripts/)下的templates.coffee 待coffee編譯進行後處理
- 在 app.coffee 檔案內需要明確地引入由
module
所指定的模板模組,否則會引用失敗
另外考慮到本文的篇幅問題,這裡就略過了 copy, watch 和 connect 三個最為常用的任務配置,具體的可以從本文內附的原始碼內參考。
karma
Karma runner 應該屬於時下最流行的測試執行器之一了。他的配置在Gurnt貌似很簡單,而然事實並非如此。他有獨立的配置檔案在本專案中為karma.conf.js,他的配置選項比較多在此就不一一地詳細解釋了,這裡我是將Karma配置成能支援 coffee script並基於 [PhantomJS|http://phantomjs.org] 作為宿主瀏覽器,以 [jasmine|http://jasmine.github.io/] 作為測試執行架構的的單元測試環境。所有的單元測試檔案存放在 test/spec 目錄下。
他需要的依賴外掛分別有:
- karma-coffee-preprocessor
- karma-coverage
- karma-jasmine
- karma-junit-reporter
- karma-chrome-launcher
- karma-phantomjs-launcher
- karma-requirejs
- karma-story-reporter
安裝後的配置如下:
karma: { unit: { configFile: 'karma.conf.js', singleRun: true } }
這裡需要注意的是,在 karma.conf.js
配置的檔案的 files
和 exclude
兩個選項,files
內需要配置整個專案執行期
需要用到的 bower 依賴包,如:
files: [ 'app/bower_components/angular/angular.js', 'test/spec/{,*/}*.coffee' ]
如使用到其它的angular外掛引用需要在此加入,則會可能會導致單元測試因找不到依賴包而導致注入失敗。
而 exclude
就當然是無需要載入的檔案。
由於國內網路環境問題 安裝 phantomJS 可能會偏慢,如果無法下載phantomJS可以將其刪除,而使用 chrome 代替。
protractor
對於e2e測試(白盒測試/整合測試)也可以使用Karma+angular-scenario來配置,但這個在AngularJS官方已作為過時配置而不被推薦。取而代之的當然是 [protractor|http://angular.github.io/protractor/#/] 他為jasmine所擴充套件的matcher很多,用起來確實是
很好用。然而 protractor 可能比較新吧(發展了才一年多的時間)他的安裝包下載是極其慢的,由其是 [selenium|http://www.seleniumhq.org]的安裝。
他的配置有點像 karma 也是通過一個外部的 protractor.conf.js檔案作為額外的附加配置的,在 Gruntfile.js 內:
protractor: { options: { keepAlive: true, configFile: "protractor.conf.js" }, all: {} }
然而值得一談的是他所依賴的 Webdriver 的安裝過程。
安裝protractor包
npm install protractor --save-dev
protractor 安裝後會得到一個 webdriver-manager 的命令列工具。protractor 依賴於 selenium 伺服器,且selenium是一個基於java開發的,so 在此之前則需要先安裝好JDK。
另外 protractor 只能支援 chrome 和 ie 兩種瀏覽器驅動,需要在完成 protractor安裝後手動執行:
webdriver-manager update
不知是否人品問題(我絕對不認為天朝的網路有問題的),這個命令我是總執行不成功!這個命令會從 google的官網上下載一個chrome的模擬驅動程式至本機的/usr/local/lib/node_modules/protractor/selenium/chromedriver/
目錄,如果你的人品與我一樣,也是無法下載的話,那麼你可以直接在google上下去載 [chromedriver|https://sites.google.com/a/chromium.org/chromedriver/] 的驅動然後手工解壓到這個本地目錄下即可。(BTW 我的環境是OSX,在Linux下我不知道是什麼情況,試過的朋友請給我留言作為補充吧)
由於各種的不成功,最後我是直接將 protractor 的配置指向本絕對目錄地址的,如果你有同樣的情況出現就將以下的兩個配置加入到protractor.conf.js中吧
seleniumServerJar: '/usr/local/lib/node_modules/protractor/selenium/selenium-server-standalone-2.44.0.jar', chromeDriver: '/usr/local/lib/node_modules/protractor/selenium/chromedriver/'
protractor 有一點比較好的是可以與 WebStorm 以下是具體配置的辦法:
WOO
一不小心寫了這麼長一篇,光是附上文章貌似不太地道,那麼如果對這個腳手架專案有興趣的朋友請到[我的 github|http://www.github.com/dotnetage/]上下載這個專案吧。專案地址是:https://github.com/DotNetAge/Angular-CoffeeScript-Seed。下載後,需要分別執行
sudo npm install
bower install
對本文所述的包進行一次性安裝。暫時還沒時間將這個包寫成 Yeoman Generator ,不過飯還是一口一口吃吧,或者你可以直接Fork這個專案噢。
相關文章
- CoffeeScript的Sublime Text 2開發環境配置開發環境
- 開發環境配置開發環境
- emacs開發環境配置(4)——rust開發環境Mac開發環境Rust
- phpwamp開發環境搭建詳解,phpwamp綠色整合環境開發環境一鍵搭建PHP開發環境
- 前端開發環境搭建前端開發環境
- 配置開發環境、生成環境、測試環境開發環境
- 從零開始配置基本的前端開發環境(windows)前端開發環境Windows
- react 配置開發環境React開發環境
- js開發環境配置JS開發環境
- Java開發環境配置Java開發環境
- weex開發環境配置開發環境
- Arduino開發環境配置UI開發環境
- Ubuntu開發環境配置Ubuntu開發環境
- CentOS 6.5 搭建 Java 開發環境詳解CentOSJava開發環境
- Spring(環境搭建&配置詳解)Spring
- Docker配置PHP開發環境DockerPHP開發環境
- MacOS 配置 Flutter 開發環境MacFlutter開發環境
- MacOS PHP 開發環境配置MacPHP開發環境
- (二) electron 開發環境配置開發環境
- Mac 基本開發環境配置Mac開發環境
- Webpack 配置 React 開發環境WebReact開發環境
- 配置Groovy開發環境(Windows)開發環境Windows
- Libgdx開發環境配置開發環境
- Windows下配置NodeJS環境詳解WindowsNodeJS
- 前端開發環境工具彙總前端開發環境
- [ 從零開始配置一個 Windows 前端開發環境 ] - 一:WT + WSLWindows前端開發環境
- archlinux配置安卓開發環境Linux安卓開發環境
- Flutter開發環境配置(MAC版)Flutter開發環境Mac
- Nginx開發環境跨域配置Nginx開發環境跨域
- mac pro配置php開發環境MacPHP開發環境
- Mac 配置 Flutter 安卓開發環境MacFlutter安卓開發環境
- Mac OS配置QT開發環境MacQT開發環境
- Webpack(開發、生產環境配置)Web
- 驅動篇——開發環境配置開發環境
- 我的Ubuntu 開發環境配置Ubuntu開發環境
- webpack配置React開發環境(上)WebReact開發環境
- React + Typescript + Webpack 開發環境配置ReactTypeScriptWeb開發環境
- 開發環境配置 - Linux(Ubuntu)開發環境LinuxUbuntu