PM2與Babel踩坑


PM2與Babel踩坑

PM2是node進程管理工具,可以利用它來簡化很多node應用管理的繁瑣任務,如性能監控、自動重啟、負載均衡等,而且使用非常簡單。官方文檔 中文快速入門

Babel 是一個工具鏈,主要用於將 ECMAScript 2015+ 版本的代碼轉換為向后兼容的 JavaScript 語法,以便能夠運行在當前和舊版本的瀏覽器或其他環境中。官方文檔 中文

項目背景

node服務,采用es6語法,import模塊導入、async/await語法糖、箭頭函數等等,以及koa-swagger-decorator自動生成swagger.json(api接口的注解,通過注解在swagger頁面展現出每個api接口的詳細描述)
項目部署采用pm2,集群 + 環境區分(開發、測試、生產)

babel

如果使用koa-swagger-decorator,在github倉庫中說明了使用時依賴babel-plugin-transform-decorators-legacy這個babel插件,但是This plugin is specifically for Babel 6.x. If you're using Babel 7, this plugin is not for you.(npm原話),如果你使用Babel7的話,你可以使用@babel/plugin-proposal-decorators, 但是在.babelrc中必須如下設置

"plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
  ]

好, 我們用babel-7.4.0試一下 安裝babel依賴

"dependencies": {
    "@babel/cli": "^7.4.4",
    "@babel/core": "^7.4.5",
    "@babel/plugin-proposal-decorators": "^7.4.4",
    "@babel/plugin-transform-runtime": "^7.4.4",
    "@babel/preset-env": "^7.4.5",
    "@babel/runtime": "^7.4.5",
    "@babel/runtime-corejs3": "^7.4.5",
    ...你的其他依賴
}

完整的.babelrc配置

{
    "presets": [
        ["@babel/preset-env", {
            "targets": {"node": true},
            } 
        ]
    ],
    "plugins": [
    // 可以做到最小化加載babel-polyfill減小項目體積,雖然在node環境中無所謂
        ["@babel/plugin-transform-runtime", {
            "corejs": 3 // 可選 false | 2 | 3
        }],
        ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ]
}

ok 通過上述的babel安裝及.babelrc設置試一試轉碼

  • 入口文件app.js
import config from './config'
import eurekaServer from './eureka'
import {connectDB} from './db'
import Koa from 'koa';
import router from './swagger/index'
import responseHandler from './middleware/response_handle'
import mqServer from './mq/MQServer'
import cron from './cron'

const koaCors = require('koa-cors');
const koaBody = require('koa-body');
const app = new Koa();
async function initApp (){
    //連接mysql
    await connectDB();
    //連接mq
    await mqServer.connect();
    //啟動Eureka
    await eurekaServer.start();
    //Eureka心跳
    app.use(eurekaServer.info()); 
    //啟動定時拉取微信公眾號圖文及統計任務
    await cron();
    app.use(async function (ctx, next) {
        ctx.response.get("Access-Control-Allow-Origin", "*");
        ctx.response.set("Access-Control-Allow-Headers", "Content-Type,Content-Length,Accept,X-Requested-With,token");
        ctx.response.set("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
        if (ctx.request.method == "OPTIONS") ctx.response.status = 200;
        await next();
    })         
            
    //restful 中間件
    app.use(responseHandler.restify());
    app.use(koaCors());
    app.use(koaBody({ multipart: true }));
    app.use(router.routes());
    app.use(router.allowedMethods());
    app.listen(config.port, _ =>  console.log(`app started at port ${config.port}`));
    return app;
}

initApp()
.catch(err => `未知服務錯誤:${err.message}`)

  • 項目目錄

src/
 'app.js',
 'config/',
 'controllers/',
 'cron/',
 'dao/',
 'db/',
 'domain/',
 'eureka/',
 'middleware/',
 'model/',
 'mq/',
 'repository/',
 'swagger/',
 'util/' 
 
  • 下一步 在package.json 中build

"scripts": {
  "build": "babel src -d dist"
},

  • 啟動 node dist/app.js
pan@ubuntu18:~/disk/panyanan/project/website_node$ node dist/app.js 
加載local環境的配置文件成功
sequelize deprecated The logging-option should be either a function or false. Default: console.log node_modules/sequelize/lib/sequelize.js:193:13
Executing (default): SELECT 1+1 AS result
connect MQ queues: {"queueNames":["q.upa_logs_node"],"connectOption":{"vhost":"OuterHost","hostname":"192.168.10.200","port":5672,"username":"admin","password":"123456"}}
registered with eureka:  NTDWebsit/192.168.10.49:8989
eureka注冊成功
koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md dist/app.js:47:7
app started at port 8989

用babel-6.0+試一下 安裝依賴


 "dependencies": {
   "babel-cli": "^6.26.0",
   "babel-core": "^6.26.3",
   "babel-preset-env": "^1.7.0",
   "babel-plugin-transform-decorators-legacy": "^1.3.5",
   "babel-polyfill": "^6.26.0",
   ...其它依賴
   }
   

.babelrc


{
   "presets": [
       ["env", {
               "targets": {"node": true},
               //會加載所有polyfill
               "useBuiltIns":true
           }
       ]
   ],
   "plugins": [
       "transform-decorators-legacy"
   ]
}

轉碼


"scripts": {
"build": "babel src -d dist"
  },
  

bable6中轉碼過程會顯示所有被轉碼的文件

> selected@1.0.0 build /home/pan/disk/panyanan/project/website_node
> babel src -d dist

src/app.js -> dist/app.js
src/config/config.dev.js -> dist/config/config.dev.js
src/config/config.local.js -> dist/config/config.local.js
src/config/config.pred.js -> dist/config/config.pred.js
src/config/config.prod.js -> dist/config/config.prod.js
src/config/index.js -> dist/config/index.js
src/controllers/article_controller.js -> dist/controllers/article_controller.js
src/controllers/category_controller.js -> dist/controllers/category_controller.js
src/cron/articleTask.js -> dist/cron/articleTask.js
src/cron/index.js -> dist/cron/index.js
src/dao/article_dao.js -> dist/dao/article_dao.js
src/dao/article_day_summary_dao.js -> dist/dao/article_day_summary_dao.js
src/dao/category_dao.js -> dist/dao/category_dao.js
src/db/index.js -> dist/db/index.js
src/domain/article_domain.js -> dist/domain/article_domain.js
src/domain/category_domain.js -> dist/domain/category_domain.js
src/eureka/index.js -> dist/eureka/index.js
src/middleware/response_handle.js -> dist/middleware/response_handle.js
src/model/article_day_summary_model.js -> dist/model/article_day_summary_model.js
src/model/article_model.js -> dist/model/article_model.js
src/model/category_model.js -> dist/model/category_model.js
src/mq/MQServer.js -> dist/mq/MQServer.js
src/mq/UpalogsSendMsg.js -> dist/mq/UpalogsSendMsg.js
src/repository/article_day_summary_repository.js -> dist/repository/article_day_summary_repository.js
src/repository/article_repository.js -> dist/repository/article_repository.js
src/repository/category_repository.js -> dist/repository/category_repository.js
src/swagger/api.js -> dist/swagger/api.js
src/swagger/index.js -> dist/swagger/index.js
src/util/index.js -> dist/util/index.js

啟動 node dist/app.js

pan@ubuntu18:~/disk/panyanan/project/website_node$ node dist/app.js 
加載local環境的配置文件成功
sequelize deprecated The logging-option should be either a function or false. Default: console.log node_modules/sequelize/lib/sequelize.js:193:13
Executing (default): SELECT 1+1 AS result
connect MQ queues: {"queueNames":["q.upa_logs_node"],"connectOption":{"vhost":"OuterHost","hostname":"192.168.10.200","port":5672,"username":"admin","password":"123456"}}
registered with eureka:  NTDWebsit/192.168.10.49:8989
eureka注冊成功
koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md dist/app.js:59:9
app started at port 8989

ok 以上就是在node服務中使用babel轉碼的嘗試,babel中的配置及插件很多.設置起來也很麻煩,需要耐心的閱讀官方文檔,及前輩們的博客,總結一下基本概念.

  • babel-core 是babel的核心
  • babel-preset-env 是針對環境設置不同的轉碼規則
  • babel-polyfill,用於轉碼es6的api,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(比如Object.assign)都不會轉碼。babel 默認只轉換語法 如() => {}
  • babe-runtime可以做到按需轉碼,減少轉碼后的代碼體積
  • 利用useBuiltIns選項,可以不必在代碼中require(bable-polyfill)
  • 通過提前build的方式可以提高性能,相比之下 babel-node則很重,內存使用率很高
  • babel6/bable7的使用有很大不同,無論是.babelrc配置還是插件

PM2

pm2 基礎命令可以看看官方文檔
這里說一下與babel相關的小坑,如果采用上面的build的方式是沒有任何問題的,只需要修改配置文件的目錄為轉碼之后的啟動文件 apps.config.js

pm2 start apps.config.js 啟動
如果設置env 則需要加上參數如 pm2 start apps.config.js --env prod
則process.env.NODE_ENV == 'production'

module.exports = {
  apps : [{
    name: 'websit_node',
    script: './dist/app.js',
    args: 'one two',
    instances: 1,
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    env: {
      NODE_ENV: 'local'
    },
    env_dev: {
      NODE_ENV: 'development'
    },
    env_pred: {
      NODE_ENV: 'pred'
    },
    env_prod: {
      NODE_ENV: 'production'
    }
  }],
};

如果采用babel-node方式啟動,則需要增加解釋器配置

module.exports = {
  apps : [{
    name: 'websit_node',
    script: './src/app.js',
    args: 'one two',
    instances: 1,
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    interpreter: 'node_modules/babel-cli/bin/babel-node.js',
    env: {
      NODE_ENV: 'local'
    },
    env_dev: {
      NODE_ENV: 'development'
    },
    env_pred: {
      NODE_ENV: 'pred'
    },
    env_prod: {
      NODE_ENV: 'production'
    }
  }],
};

注意:

  • script字段則是未轉碼的項目入口文件,
  • interpreter字段,使用babe-node作為編譯器執行script指定的入口文件,
  • babel-node啟動的方式在pm2中不支持集群模式,就是說instances字段只能寫1,而提前build的方式則沒有這個限制.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM