フィーチャーフラグ

Gutenberg プロジェクトのフェーズ2を開始するにあたってはコード変更のリリースコントロールを改良する必要がありました。フェーズ2以降で開発された新しい機能は Gutenberg プラグインとしてリリースする一方、改良やバグの修正は引き続きコアリリースに反映しなければなりません。

こうした処理技術は「フィーチャーフラグ」として知られています。

process.env.GUTENBERG_PHASE の導入

process.env.GUTENBERG_PHASE はフェーズ番号を示す環境変数です。コードをプラグインとしてビルドする際、この変数を 2 にセットします。コアとしてビルドする際には 1 にセットします。

基本的な使用方法

フェーズ2の関数や定数は次の3項構文を使用してエクスポートしてください。

function myPhaseTwoFeature() {
    // implementation
}

export const phaseTwoFeature = process.env.GUTENBERG_PHASE === 2 ? myPhaseTwoFeature : undefined;

フェーズ1の環境で phaseTwoFeature のエクスポートは undefined になります。

フェーズ2の機能をインポートし呼び出す場合はエラーを避けるため、関数呼び出しを if 文でラップしてください。

import { phaseTwoFeature } from '@wordpress/foo';

if ( process.env.GUTENBERG_PHASE === 2) {
    phaseTwoFeature();
}

動作原理

webpack のビルド時、すべての process.env.GUTENBERG_PHASE は webpack の define プラグイン を使用して置き換えられます。

次のようなコードがある場合

if ( process.env.GUTENBERG_PHASE === 2 ) {
    phaseTwoFeature();
}

コードベースをプラグインとしてビルドすると、変数は数値リテラル 2 で置き換えられます。

if ( 2 === 2 ) {
    phaseTwoFeature();
}

if 文内部のコードは、2 === 2 が true と評価されるため、Gutenberg プラグイン内部で実行されます。

コアでは、process.env.GUTENBERG_PHASE 変数は 1 で置換されるため、ビルドされたコードは以下のようになります。

if ( 1 === 2 ) {
    phaseTwoFeature();
}

1 === 2 は false と評価されるため、フェーズ2の機能はコア内部では実行されません。

呼ばれないコードの削除

本番リリース用にコードをビルドする場合、webpack はコードをミニファイ (縮小化) し、可能な限り不要な JavaScript のコードを削除しようとします。その中の1つが「呼ばれないコードの削除」です。

次のコードに出会うと webpack は周りの if 文は不要と判断します。

if ( 2 === 2 ) {
    phaseTwoFeature();
}

条件は常に true と評価されるため、if 文を削除し、中の実行部分のみを残すことができます。

phaseTwoFeature();

同様にコアのビルドの場合、次の if 文の条件は常に false と解決されます。

if ( 1 === 2 ) {
    phaseTwoFeature();
}

ミニファイプロセスは内容を含む if 文全体を削除します。これでフェーズ2のコードは、コア用にビルドされた JavaScript に含まれません。

FAQ

なぜ process.env.GUTENBERG_PHASE の比較には === や !== のみを使うべきなのですか ? >>=<<= ではいけないのですか ?

これは process.env.GUTENBERG_PHASE が undefined の場合の JavaScript 演算子 >< の振る舞いのための制限です。WordPress npm パッケージのサードパーティユーザーも同様です。process.env.GUTENBERG_PHASE < 2 も process.env.GUTENBERG_PHASE > 1 も false と解決されます。if ( process.env.GUTENBERG_PHASE > 1 ) と書いて、続く if 文内部のフェーズ2のコードの実行を避けるつもりなら、これは false と評価されるため意図したとおりに動作します。

しかし次のコードは予想したとおりに動作しません。

function myPhaseTwoFeature() {
    if ( process.env.GUTENBERG_PHASE < 2 ) {
        return;
    }

    // implementation of phase 2 feature
}

このコードはフェーズ2の機能の実行を避けるため、その前で return しています。しかし if の条件は false と解決されるため、その前の return は通らず、フェーズ2の機能が誤って呼び出されます。

なぜ GUTENBERG_PHASE 関連の評価結果を変数に割り当てるべきではないのですか ? たとえば const isMyFeatureActive = process.env.GUTENBERG_PHASE === 2 ではいけないのですか ?

webpack のミニファイが呼ばれないコードを削除できるよう、コードに複雑性を持ち込まないようにするためです。詳細については上の「 呼ばれないコードの削除」セクションを参照してください。

最終更新日: