とあるサービスの開発をしているとchart.jsで生成したグラフをOGP画像にする必要が出て、Vercelならサーバレス関数を無料でデプロイできると知り試したのですが、謎のエラーが発生して困っていました。
その回避策(?)をとりあえず見つけたのでメモ書き程度に書きます。
version
canvas: 2.6.1
chartjs-node-canvas: ^3.2.0
chart.js: ^3.5.0
発生してたエラー
ERROR Unhandled Promise Rejection
{
"errorType":"Runtime.UnhandledPromiseRejection",
"errorMessage":"Error: Cannot find module 'canvas'\n
Require stack:\n
- /var/task/node_modules/chartjs-node-canvas/dist/freshRequire.js\n
- - /var/task/node_modules/chartjs-node-canvas/dist/legacy.js\n
- - /var/task/node_modules/chartjs-node-canvas/dist/index.js\n
- - /var/task/api/index.js","reason":{"errorType":"Error","errorMessage":"Cannot find module 'canvas'\n
- Require stack:\n- /var/task/node_modules/chartjs-node-canvas/dist/freshRequire.js\n
- - /var/task/node_modules/chartjs-node-canvas/dist/legacy.js\n
- - /var/task/node_modules/chartjs-node-canvas/dist/index.js\n
- - /var/task/api/index.js",
- "code":"MODULE_NOT_FOUND",
- "requireStack":[
- "/var/task/node_modules/chartjs-node-canvas/dist/freshRequire.js",
- "/var/task/node_modules/chartjs-node-canvas/dist/legacy.js",
- "/var/task/node_modules/chartjs-node-canvas/dist/index.js",
- "/var/task/api/index.js"],
- "stack":[
- "Error: Cannot find module 'canvas'","Require stack:",
- "- /var/task/node_modules/chartjs-node-canvas/dist/freshRequire.js",
- "- /var/task/node_modules/chartjs-node-canvas/dist/legacy.js",
- "- /var/task/node_modules/chartjs-node-canvas/dist/index.js",
- "- /var/task/api/index.js",
- " at Function.Module._resolveFilename (internal/modules/cjs/loader.js:902:15)",
- " at Function.resolve (internal/modules/cjs/helpers.js:98:19)",
- " at Object.exports.freshRequire (/var/task/node_modules/chartjs-node-canvas/dist/freshRequire.js:6:34)",
- " at new ChartJSNodeCanvas (/var/task/node_modules/chartjs-node-canvas/dist/new.js:23:39)",
- " at module.exports (/var/task/api/index.js:14:31)",
- " at Server.<anonymous> (/var/task/___vc/__helpers.js:813:19)",
- " at Server.emit (events.js:375:28)",
- " at parserOnIncoming (_http_server.js:897:12)",
- " at HTTPParser.parserOnHeadersComplete (_http_common.js:126:17)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: Error: Cannot find module 'canvas'",
- "Require stack:",
- "- /var/task/node_modules/chartjs-node-canvas/dist/freshRequire.js",
- "- /var/task/node_modules/chartjs-node-canvas/dist/legacy.js",
- "- /var/task/node_modules/chartjs-node-canvas/dist/index.js",
- "- /var/task/api/index.js",
- " at process.<anonymous> (/var/runtime/index.js:35:15)",
- " at process.emit (events.js:387:35)",
- " at processPromiseRejections (internal/process/promises.js:245:33)",
- " at processTicksAndRejections (internal/process/task_queues.js:96:32)"]}
Unknown application error occurred
もちろんcanvasモジュールはpacakge.jsonに記述されていましたが、存在しないと言われてしまいました。
回避策
次のrequire('canvas')を加える(使わなくても必要)
const { ChartJSNodeCanvas } = require('chartjs-node-canvas');
const canvas = require('canvas'); // ポイント
package.jsonのvercel-buildを設定する。
"scripts": {
"vercel-build": "yum install libuuid-devel libmount-devel && cp /lib64/{libuuid,libmount,libblkid}.so.1 node_modules/canvas/build/Release/"
}
これだけでグラフは表示されましたが、文字が表示されなかったのでフォントの登録が必要です。
フォントの登録はREADMEに書いてあったChartJS.defaults.global.defaultFontFamily
では動かなかったので、chart.jsの公式ドキュメントを確認してChartJS.defaults.font.family
にしました。
サンプルレポジトリ
https://github.com/karintou8710/vercel-chartjs-node-canvas
なぜこれで動いたの?
全くわからないです...
エラーメッセージに書いてある/var/task/node_moduleの中身を**require('canvas')**を加えない場合と比較したところ、加えない場合はcanvasとその依存関係にあるモジュールがインストールされていませんでした。
vercelの最適化が関係しているのか?と最初は考えたのですが、そもそもpackage.jsonに書いてあるのにインストールされないのは不思議です。
もし理由が分かる方がいればぜひコメントで教えて頂きたいです。