Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

Rollupは循環参照をうまくさばけないことがある

Rollupでは、循環参照していてもビルドしてくれます。しかし、子クラスが2つ以上になると意図した通りにビルドしてくれません。

このケースでは、ビルド自体は通るのですが、エラーが起きるコードが出力されます。ビルドは通ってしまうので、落とし穴に気づきにくくかなり厄介です。

コード

実際のコードがこちら

// main.js
import C from './C.js';
import {A} from './A.js';

import {B} from './B.js';
export {A, B, C};
// B.js
import {A} from './A.js';
import C from './C.js';
export class B {
  a() {
    return new A();
  }
}
// A.js
import {B} from './B.js';
export class A extends B {}
// C.js
import {B} from './B.js';
export default class C extends B {};

このように、AとCがBを継承している構造をRollupは正しくビルドしてくれません。

ES2015のクラスでは、extendsしたいクラスはextendsの宣言より前に宣言されていなければなりません。そのため、BがAとCよりも前に宣言されていなければいけません。しかし、RollupはどうやってもBを前に出してくれません。

この問題は子が1つのケースでは起こりません。そのため、AかCどちらか一方のみにすれば、Bが先にきてくれます。

解決方法は?

この問題、 現段階ではあきらめるほかありません。 main.jsにA.js、B.js、C.jsすべて書き出せば解決できます。

この循環参照の問題はちょうどHandling of circular dependenciesというIssueにて議論中です。今後のアップデートに期待しましょう。