nuxtにtypescriptを入れたnuxtプロジェクトにて、古くなったパッケージの更新を行った後に遭遇したメモリエラーの記録です。実際は、node_modulesをbackアップしてnode_modules_bakのようなディレクトリを作成していたというチョンボなのですが、そのとき@nuxt/typescript-buildについて調べたので、そのときの内容を共有しようと思います。

環境について

バージョンアップ後の主要モジュールのバージョンは以下の通りです。

  • nuxt@2.12.2
  • typescript@3.8.3
  • @nuxt/typescript-build@1.0.2

発生していた現象

yarn buildを行うと90%前後まで進んでしばらくすると、下記のようなエラーログが出力されます。

<--- Last few GCs --->

[89792:0x108008000]    54574 ms: Scavenge 2044.1 (2051.1) -> 2042.7 (2051.3) MB, 2.2 / 0.0 ms  (average mu = 0.219, current mu = 0.104) allocation failure
[89792:0x108008000]    54580 ms: Scavenge 2044.4 (2051.3) -> 2043.0 (2051.6) MB, 2.3 / 0.0 ms  (average mu = 0.219, current mu = 0.104) allocation failure
[89792:0x108008000]    54588 ms: Scavenge 2044.6 (2051.6) -> 2043.2 (2056.3) MB, 2.7 / 0.0 ms  (average mu = 0.219, current mu = 0.104) allocation failure


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x100950919]
    1: StubFrame [pc: 0x1008fc271]
Security context: 0x1269d26c08d1 <JSObject>
    2: slice [0x1269d26ceba9](this=0x1269a3522fe9 <JSArray[14]>,1)
    3: parseNodeModuleFromPath(aka parseNodeModuleFromPath) [0x1269d9d1a9e9] [/Users/kawashima/work/app-swing-by/closb/web-ui/cloud-gen-wui/node_modules/typescript/lib/typescript.js:~30223] [pc=0xe0405f03469](this=0x126998e804b1 <undefined>,0x1269a3522d49 <Obje...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Writing Node.js report to file: report.20200813.101626.89792.0.001.json
Node.js report completed
 1: 0x100080c68 node::Abort() [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]
 2: 0x100080dec node::errors::TryCatchScope::~TryCatchScope() [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]
 3: 0x100185167 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]
 4: 0x100185103 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]
 5: 0x10030b2f5 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]
 6: 0x10030c9c4 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]
 7: 0x100309837 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]
 8: 0x1003077fd v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]
 9: 0x100312fba v8::internal::Heap::AllocateRawWithLightRetry(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/kawashima/.nodebrew/node/v12.16.1/bin/node]

✔ Client
  Compiled successfully in 56.76s

✔ Server
  Compiled successfully in 20.71s

調査してみると、ビルドの中でtypescriptの型チェックが実行されていることがわかりました。
nuxt.config.jsは、下記のような設定になっています。 

  /*
  ** Nuxt.js dev-modules
  */
  buildModules: [
    '@nuxtjs/vuetify',
    '@nuxt/typescript-build',
    'nuxt-typed-vuex'
  ],

ビルドには、@nuxt/typescript-buildを利用しています。nuxt typescriptにModule optionsが記載されていますが、ビルド時の型チェックを無効にする方法は、typeCheckfalseを設定してます。typecCheckは、オブジェクトか真偽値(object | boolean)で定義されています。objectについては、fork-ts-checker-webpack-pluginに定義されているのでそちらを参照してください。

    buildModules: [
      '@nuxtjs/vuetify',
      ['@nuxt/typescript-build', {
        typeCheck: false
      }],
      'nuxt-typed-vuex'
    ],

エラーログにある「ERROR Issues checking service aborted - probably out of memory. Check the memoryLimit option in the ForkTsCheckerWebpackPlugin configuration.」の部分に注目し、メモリ上限についても確認してみます。

メモリ上限について

メモリ上限の割当には、nodeのオプションを利用する方法とfork-ts-checker-webpack-pluginのオプションを利用する方法があります。 

nuxt.config.jsfork-ts-checker-webpack-pluginのオプションを渡すには、下記に記載します。memoryLimitは、MBで指定します。

〜省略〜
      ['@nuxt/typescript-build', {
       typeCheck: {
         async: true,
         typescript: {
           enable: true,
           memoryLimit: 16384,
         },
〜省略〜

memoryLimitのデフォルト値は、2048MBです。fork-ts-checker-webpack-plugin/src/typescript-reporter/TypeScriptReporterで定義されています。

node -v8オプション

--max_old_space_sizeオプションで指定できます。v8オプションは他にも便利なもの例えば、--gc_intervalなどもあるので調べてみると面白いと思います。

おわりに

今回は、チョンボから色々ビルド処理の流れなどを追ってメモリ上限などについても調べました。今後、プロジェクトが肥大化するとビルドプロセスを見直した高速化なども取り組んだ内容なども共有していこうと思ってますので、楽しみにしていて下さい。