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
環境變數。
Babel Configuration
.babelrc
{
"presets": [
"@babel/preset-env"
],
"plugins": [
"@babel/transform-runtime"
]
}
在 project 根目錄下建立 .babelrc
,使用剛剛安裝的 @babel/preset-env
的設定將 ES6+ 轉譯。
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
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_ENV
為production
,並使用 Babel 轉譯成 Node 能執行的 jsyarn 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:build
與 yarn prod
類似,差異只在最後 docker:build
包成 image。
使用了 $npm_package_name
與 $npm_package_version
直接讀取 package.json
的 name
與 version
。
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
稍後 COPY
、RUN
與 CMD
都會在此目錄下。
第 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
。
.env
TAG=1.0.0
PORT=4000
設定 docker-compose.yml
的環境變數。
Start Node
$ yarn serve
使用 yarn serve
啟動 Node,適合 development 使用。
Babel Transpile
$ yarn build
使用 yarn build
命令 Babel 將 src
目錄下所有 js 轉譯成 Node 能執行的 js 到 dist
目錄下。
Build Image
$ yarn docker:build
使用 yarn docker:build
命令 Babel 重新轉譯,並切包成 Docker image。
Run Docker
$ yarn docker:up
使用 yarn docker:up
啟動 Docker。
Stop Docker
$ yarn docker:down
使用 yarn docker:up
結束 Docker。
Conclusion
- Node 也能享受 ES6+ 最新語法與 ES Module,只要設定好 Babel 環境即可