點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Babel 打造 Node 開發環境

Sam Xiao's Avatar 2021-10-24

Node 在後端除了可提供 GraphQL API,如傳統 REST API、Cron Job 也可以由 Node 開發,本文使用 Babel + Node + Docker 打造開發環境。

Version

Node 12.4.0
Babel 7.6.4

Add Package

$ yarn add @babel/core @babel/cli @babel/preset-env @babel/node --dev
$ yarn add @babel/runtime
$ yarn add @babel/plugin-transform-runtime --dev
$ yarn add nodemon rimraf cross-env --dev

安裝 Node + Babel 所需 package。

$ yarn add @babel/core @babel/cli @babel/preset-env @babel/node --dev

安裝 Babel 相關 package,由於只是轉譯用,安裝成開發用的 devDependency 即可,將來不必包在 docker 內。

其中 @babel/node 負責將 ES6+ 轉譯成 Node 能執行的 js。

$ yarn add @babel/runtime
$ yarn add @babel/plugin-transform-runtime --dev

為避免 regeneratorRuntime 錯誤而安裝的 package。

其中 @babel/runtime 為 production 使用,而 @babel/plugin-transform-runtime 為 development 使用。

$ yarn add nodemon rimraf cross-env --dev

安裝 nodemon 可監控檔案修改重新 Babel 轉譯與重啟 Node。

安裝 rimraf 可令 yarn clean 跨平台刪除 dist 目錄。

安裝 cross-env 可跨平台設定 NODE_ENV 環境變數。

babel000

Babel Configuration

.babelrc

{
  "presets": [
    "@babel/preset-env"
  ],
  "plugins": [
    "@babel/transform-runtime"
  ]
}

在 project 根目錄下建立 .babelrc,使用剛剛安裝的 @babel/preset-env 的設定將 ES6+ 轉譯。

babel001

Nodemon Configuration

nodemon.json

{
  "exec": "yarn dev",
  "watch": ["src/*"],
  "ext": "js, json",
  "env": {
    "NODE_ENV": "development"
  }
}
  • exec:當有變動時,將執行 yarn dev
  • watch:Nodemon 將持續觀察的目錄
  • ext:Nodemon 將持續觀察的 extension
  • env:設定 Nodemon 執行時的 environment variable

babel002

NPM Script

"scripts": {
  "serve": "nodemon",
  "start": "node ./dist/index.js",
  "dev": "babel-node ./src/index.js",
  "prod": "NODE_ENV=production yarn clean && yarn build && yarn start",
  "clean": "rimraf dist",
  "build": "babel ./src --out-dir dist",
  "docker:build": "NODE_ENV=production yarn clean && yarn build && docker build -t $npm_package_name:$npm_package_version .",
  "docker:up": "docker-compose up -d",
  "docker:down": "docker-compose down"
},

本文最關鍵的就是 Yarn script 配置。

"serve": "nodemon",

yarn serve 執行 nodemon

"start": "node ./dist/index.js",

yarn start 使用 node 執行 Babel 轉譯後的 js。

"dev": "babel-node ./src/index.js",

yarn dev 使用 babel-node 將 ES6+ 轉譯成 Node 能執行的 js 在記憶體內並執行之。

"prod": "yarn clean && cross-env NODE_ENV=production yarn build && yarn start",

yarn prod 依序執行以下步驟:

  • yarn clean 刪除 dist 目錄
  • yarn build 設定 NODE_ENVproduction,並使用 Babel 轉譯成 Node 能執行的 js
  • yarn start 使用 node 執行 Babel 轉譯後的 js
"clean": "rimraf dist",

yarn clean 刪除 dist 目錄。

"build": "babel ./src --out-dir dist"

yarn build 使用 Babel 將 src 目錄下的 ES6+ 轉譯成 Node 能執行的 js 到 dist 目錄下。

將來要包進 Docker 的 js 也是 dist 目錄,而非 src 目錄

"docker:build": "yarn clean && cross-env NODE_ENV=production yarn build && docker build -t $npm_package_name:$npm_package_version .",

yarn docker:buildyarn prod 類似,差異只在最後 docker:build 包成 image。

使用了 $npm_package_name$npm_package_version 直接讀取 package.jsonnameversion

babel003

Dockerfile

FROM node:lts-alpine
WORKDIR /usr/app
COPY package.json .
RUN apk add tzdata
RUN yarn install --production
COPY dist/* ./
CMD [ "node", "index.js" ]

server 目錄下建立 dockerfile,由於我們要另外安裝 package,且將自己寫的 js 包進 Docker image,因此不可直接使用 docker-compose.yml

第 1 行

FROM node:lts-alpine

使用最新 LTS 版的 node:lts-alpine 為基底建立 image。

建議使用 alpine 為 production image,size 會小很多

第 2 行

WORKDIR /usr/app

將 working directory 切換到 /usr/app,相當於:

mkdir /usr/app
cd /usr/app

稍後 COPYRUNCMD 都會在此目錄下。

第 3 行

COPY package.json .

將根目錄的 package.json 複製到 Docker 內的 /usr/app,因為要使用 yarn install 安裝 package。

第 4 行

RUN apk add tzdata

另外使用 apk 新增 tzdata,稍後可調整 timezone。

第 5 行

RUN yarn install --production

執行 yarn install 安裝 dependencies 下的 package。

不需安裝 Babel 所需套件進 Docker,因此加上 --production

第 6 行

COPY dist/* ./

將 Babel 編譯過的 js 複製進 Docker 內的 /usr/app

第 7 行

CMD [ "node", "index.js" ]

執行 Docker 內的 /usr/app/index.js 啟動 Node。

Docker Compose

version: "3"
services:
  node:
    image: node-babel:${TAG}
    container_name: MyNode
    restart: always
    ports:
      - ${PORT}:4000
    environment:
      - TZ=Asia/Taipei

第 9 行

environment:
  - TZ=Asia/Taipei

設定 Docker 的 timezone 為 Asia/Taipei

babel004

.env

TAG=1.0.0
PORT=4000

設定 docker-compose.yml 的環境變數。

babel005

Start Node

$ yarn serve

使用 yarn serve 啟動 Node,適合 development 使用。

babel006

Babel Transpile

$ yarn build

使用 yarn build 命令 Babel 將 src 目錄下所有 js 轉譯成 Node 能執行的 js 到 dist 目錄下。

babel007

Build Image

$ yarn docker:build

使用 yarn docker:build 命令 Babel 重新轉譯,並切包成 Docker image。

babel008

Run Docker

$ yarn docker:up

使用 yarn docker:up 啟動 Docker。

babel009

Stop Docker

$ yarn docker:down

使用 yarn docker:up 結束 Docker。

babel010

Conclusion

  • Node 也能享受 ES6+ 最新語法與 ES Module,只要設定好 Babel 環境即可