如何在NodeJS項目中優雅的使用ES6

如何在NodeJS項目中優雅的使用ES6

NodeJs最近的版本都開始支持ES6(ES2015)的新特性了,設置已經支持了async/await這樣的更高級的特性。只是在使用的時候須要在node後面加上參數:--harmony。可是,即便如此node也仍是沒有支持所有的ES6特性。因此這個時候就須要用到Babel了。javascript

項目地址:https://github.com/future-challenger/petshopjava

如今開始Babel

在開始使用Babel以前,假設node

  1. 你已經安裝了nodejs,而且已經熟悉了Js。
  2. 你也可使用npm安裝各類依賴包。
  3. 並且你也對ES6(後來改成ES2015)有必定程度的熟悉。

同時假設你已經安裝了yarn,而且也熟悉了yarn。Yarn最大的優勢就是它比npm要快不少,由於yarn只把須要的庫下載一次,以後用到的時候直接使用本地緩存的版本。npm每次都會下載這些庫。這簡直就是浪費生命。若是你尚未安裝yarn,也沒有關係,下面也會有npm的使用方法。git

接下來開始安裝配置Babel。安裝babel-clies6

yarn add babel-cli --dev   // npm install --save-dev babel-cli

安裝babel的presets。github

yarn add babel-preset-es2015 --dev    // npm install --save-dev babel-preset-es2015

這個時候你就可使用ES2015的特性了。可是,這還不夠,好比我不想用Promise我想用更加方便的async/await語法。只有es2015這個preset是不夠的。web

Babel的plugin和preset

Babel自己不處理語言特性的轉碼。這些功能都是由pluginpreset實現的(preset也是一個plugin的集合)。如上文所述,要使用es2015的內容就須要安裝babel-preset-es2015這個preset。要使用async/await那麼就須要安裝對應的preset或者插件。爲了簡單咱們安裝preset:babel-preset-stage-0。preset stage-0包含了async/await相關的插件: babel-plugin-syntax-async-functionsbabel-plugin-transform-regeneratorexpress

yarn add babel-preset-stage-0 --dev // npm install --save-dev babel-preset-stage-0

這樣仍是不能在項目中使用es7的async/await了。還須要更多的配置,有兩種方法能夠達到目的:npm

  1. 使用babel-polyfill。有一個很差地地方,babel-polyfill會污染global對象,因此不適合於library之類的使用。僅適合於web app使用。
  2. 使用babel運行時轉碼工具,transform-runtime插件。使用這個方法正好彌補了上面的方法的不足之處。它是尤爲適合於library一類的項目使用。

分別介紹這兩種方法。
安裝babel-polyfill:json

yarn add babel-polyfill --dev // npm install --save-dev babel-polyfill

以後,在你的項目的入口文件的最上方引入babel-polyfill。好比我如今有一個Express的Web App,那麼的入口文件就是開啓這個app的index.js文件。在這個文件的最上方引入polyfill,require('babel-polyfill')。或者你的入口文件已是ES2015的寫法了,那麼就直接import,import 'babel-polyfill'

使用transform-runtime也很是簡單。安裝:

yarn add babel-plugin-transform-runtime --dev // npm install --save-dev babel-plugin-transform-runtime

另外還須要安裝babel-runtime:

yarn add babel-runtime  // npm install --save babel-runtime

以後在.babelrc文件中添加以下的配置,兩個二選其一便可:

// without options
{
  "plugins": ["transform-runtime"]
}

// with options
{
  "plugins": [
    ["transform-runtime", {
      "helpers": false, // defaults to true
      "polyfill": false, // defaults to true
      "regenerator": true, // defaults to true
      "moduleName": "babel-runtime" // defaults to "babel-runtime"
    }]
  ]
}

剩下的就是歡暢的使用async/await了。

另外若是要使用Object.assing這樣的方法的話,也可使用插件:babel-plugin-transform-object-assign,若是要使用解構賦值可使用插件:babel-plugin-transform-object-rest-spread。固然這些都包含在了stage-0這個preset中。

如今就開始寫ES2015的代碼吧。在項目中安裝ExpressJs,建立一個index.js文件。咱們來試着建立一個小小的web app做爲練習:

import Express from 'express'

let app = Express()

app.get('/', (req, res) => {
  res.send('hello world')
})

app.listen(8080, () => console.log('server is running at http://localhost:8080'))

運行命令:

./node_modules/.bin/babel-node index.js --preset es2015, stage-0

使用命令*babel-node**就可讓代碼運行起來,後面的參數指定了在轉義js代碼的時候使用的preset和plugin。

Babel官方推薦的方法是時候用.babelrc文件,這一方式能夠更加靈活。在項目的更目錄上建立.babelrc文件,在裏面添加你安裝的preset和plugin的描述:

{
    "presets": ["es2015", "stage-0"]
}

這樣能夠直接使用babel-node來執行代碼,或者使用命令babel來轉義代碼。如:

babel -w code/ -d build/

babel命令會從配置文件中讀取配置,來變異code/目錄下的文件,並把轉義以後的JavaScript文件導出到build/目錄下。還有命令行裏的參數-w,這個命令參數指定的是watch,每次code目錄的文件修改後都會觸發babel命令的再次執行。

在文件中使用Source Maps

上面看起來很不錯了。可是還有一個問題,在你調試代碼的時候,你調試的實際是babel命令轉碼以後的js,不是原來你編寫的源代碼所在的文件。調試的不是源文件,多少會有些不便。好比下面的文件會拋出一個異常:

async function errorAsyncFunc() {
  try{
    throw new Error('Async function error')
  } catch(e) {
    throw e
  }
}

errorAsyncFunc()

在轉碼命令中加一個--source-maps能夠解決這個問題:

babel code/ -d build/ --source-maps

最後在package.json裏添加scripts節點:

"scripts": {
  "build": "babel src -d build --source-maps",
  "start": "node build/index.js"
},

接下來:

npm run build

Gulp出場

上文講述瞭如何使用Babel實現ES201x的開發。可是在正式的開發中,上面的這些配置還略顯不足,尤爲是你的項目包括web端、server端,尤爲web端不只處理ES201x的代碼還須要處理。因此須要Gulp出場。

這玩意兒看起來很複雜,你定義了編譯的過程。其實掌握了之後很好用,尤爲是能夠自動處理不少東西,節約大把時間。要使用Gulp,必須先安裝NodeJS。這個基本是標配。而後你會用到它的命令行工具。

安裝Gulp

在最新發布的Gulp裏有一點調整。gulp-cli從gulp分離出來做爲單獨的一部分使用。因此,若是你已經安裝過gulp以前的版本須要先刪除:

npm rm --global gulp

安裝gulp-cli

yarn global add gulp-cli  // npm install --global gulp-cli

在--dev模式下安裝gulp

yarn add gulp --dev     // npm install --save-dev gulp

建立gulp配置文件

就像Babel要用.babelrc做爲配置文件同樣,gulp也須要一個配置文件。這個配置文件就是gulpfile.js, 可是和babel同用的狀況下把gulpfile.js重命名爲gulp.babel.js

mv "gulpfile.js" "gulpfile.babel.js"

gulp的使用仍是很簡單的,主要就是在gulpfile.babel.js文件中添加各類task。在這些task中必定要添加一個叫作default的task,gulp命令的執行起點就是從這裏開始。

假設有這麼一個場景:

  1. 使用eslint檢查代碼,發現代碼風格和潛在的錯誤。
  2. 自動實現ES201x -> ES5的代碼轉碼,並把轉碼後的代碼放在指定目錄下。
  3. 在轉碼的時候添加sourcemaps。

以上這些「任務」都是用gulp自動實現。該如何配置呢?

gulp和eslint

要在gulp中使用各類請他的相似於eslint這樣的功能的時候須要使用在gulp上的對應的插件。沒錯,gulp的設計思路和gulp基本同樣:插件機制。

那麼咱們就須要首先下載eslint的插件

yarn add --dev gulp-eslint    // npm install --save-dev gulp-eslint

在開始編寫咱們的第一個task以前, 作最後的準備工做。首先須要配置.eslintrc文件。eslint會根據這個文件定義的規則檢查代碼的風格。咱們不許備大批的配置規則,這樣很是耗時間並且也照顧不到不少咱們項目已經保留下來的編碼風格。因此,airbnb的一套規則拿來使用時最好的辦法。

安裝eslint
yarn add --dev eslint  // npm install --save-dev eslint

而後你能夠運行命令來初始化配置:./node_modules/.bin/eslint --init。你也能夠忽略這個命令,直接建立一個.eslintrc的文件。

安裝eslint的airbnb擴展

要使用airbnb的一套規則就須要安裝他們的eslint擴展:

yarn add eslint-config-airbnb --dev  // npm install --save-dev eslint-config-airbnb

命令執行以後會提示有些依賴項沒有安裝,分別是eslint-plugin-import@^2.2.0eslint-plugin-import@^2.2.0eslint-plugin-jsx-a11y@^3.0.2。依次安裝這些依賴項就好。

.eslintrc
{
  "env": {
    "es6": true
  },
  "rules": {
    "semi": "off",
    "import/no-extraneous-dependencies": ["error", {
      "devDependencies": true, 
      "optionalDependencies": false, 
      "peerDependencies": false
    }]
    ,"quotes": ["error", "single", {"allowTemplateLiterals": true}]
  },
  "extends": "airbnb"
}

env指定環境是支持es6的,rules指定的是一些補充內容,好比字符串使用單引號仍是雙引號等。這個是根據我的喜愛配置的,你能夠選擇添加你須要的規則。最後是extends,這裏配置airbnb就用上了airbnb的一套eslint編碼檢查規則。

gulp-eslint插件用起來
import gulp from 'gulp'
import eslint from 'gulp-eslint

// 配置須要處理的文件目錄和轉碼以後文件的存放目錄
const paramConfig = {
  source: 'src/**/*.js',
  dest: 'build',
}

引入相關模塊以後開始寫任務:

gulp.task('lint', () => {
  // eslint配置,使用配置的文件目錄。排除node_modules下的所有文件。
  return gulp.src([paramConfig.source, '!node_modules/**'])
    .pipe(eslint())
    .pipe(eslint.result(result => {
      console.log(`ESLint result: ${result.filePath}`);
      console.log(`# Messages: ${result.messages.length}`);
      console.log(`# Warnings: ${result.warningCount}`);
      console.log(`# Errors: ${result.errorCount}`);
    }))
    .pipe(eslint.format())
    .pipe(eslint.failOnError())
})

如前文所述,default任務是必須:

gulp.task('default', ['lint'], function () {
    // lint任務成功執行以後執行這個方法
});

跳轉到項目的目錄下,運行gulp命令。會獲得以下的輸出:

$ gulp
[21:43:01] Requiring external module babel-register
[21:43:01] Using gulpfile ~/Documents/test-polyfill/gulpfile.babel.js
[21:43:01] Starting 'lint'...
[21:43:02] Starting 'babel-sourcemaps'...
ESLint result: ~/Documents/test-polyfill/src/index.js
# Messages: 0
# Warnings: 0
# Errors: 0
ESLint result: ~/Documents/test-polyfill/src/test.js
# Messages: 0
# Warnings: 0
# Errors: 0
[21:43:02] Finished 'lint' after 605 ms
[21:43:02] Finished 'babel-sourcemaps' after 653 ms
[21:43:02] Starting 'default'...
gulp default task!
[21:43:02] Finished 'default' after 98 μs

gulp和babel

此次同時處理babel和sourcemaps的問題。
首先安裝插件:

yarn add --dev gulp-babel   // npm install --save-dev gulp-babel

import gulp-babel插件:

import babel from 'gulp-babel'
import sourcemaps from 'gulp-sourcemaps'

添加任務:

gulp.task('babel-sourcemaps', () => {
  return gulp.src(paramConfig.source)  
    .pipe(sourcemaps.init())
    .pipe(babel())
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(paramConfig.dest))
})

修改default任務:
javascript gulp.task('default', ['lint', 'babel-sourcemaps'], () => { console.log('gulp default task!') })

若是你不想用sourcemaps的話,能夠這麼寫:
javascript gulp.task('babel', () => { return gulp.src(paramConfig.source) .pipe(babel()) .pipe(gulp.dest(paramConfig.dest)) })

把gulp放在npm命令體系下

babel老早就配置好了,如今和配置好了gulp。gulp每次輸入命令基本上就是手動執行。如今應該讓這個命令半自動執行了。

修改package.json文件,在其中添加scripts節點:

"scripts": {
    "build": "gulp",
    "start": "node build/index.js"
  },

如此一來,不少的命令均可以像gulp同樣放在npm的scripts裏執行。好比,如今能夠在命令行李輸入以下命令來實現lintbabel轉碼:

npm run build

開始執行:

npm start

總結

使用bebel能夠提早使用最新的JavaScript語言特性,這樣編寫不少代碼的時候會變得簡潔高效。而且babel轉碼以後生成的代碼也是很是規範的ES5寫法,同時是在嚴格模式下的。因此,咱們在寫ES201x代碼的時候不須要再添加'use strict';標識。

使用gulp又可使不少不大不小可是很費時間的事自動處理。

把這二者結合在一塊兒會讓你的項目開發效率提高不少。因此,看到這裏你不以爲你應該趕快在項目裏使用這些技術,讓開發進入快車道嗎!!!???

相關文章
相關標籤/搜索