Web猫ブログ
CakePHPにVue導入 - サービス設計を考える
CakePHPにVue導入 - サービス設計を考える
09月 17日

PHP側でVueをレンダリングするまで

最近はCakePHPにVue導入するお仕事を進めてます。既に一部リリース済ながら、既存のような新規案件。先日 その導入編について書かせていただきました、良ければ確認してみてください。

CakePHPにVue導入 - インスタンスを作成しよう

サービス設計を考える

いよいよ型を入れるぞ! ということでまずは .eslintrc.js での初期設定ですが、私も黄金比率 (とまではいかないですけど) お決まりを知りたく、まずは以下参考にさせていただきました。

@typescript-eslint ことはじめ

module.exports = {
    extends: [
        'plugin:vue/essential',
        'plugin:prettier/recommended',
        '@vue/typescript'
    ],
    plugins: ['@typescript-eslint']
    parserOptions: {
        sourceType: 'module',
        parser: '@typescript-eslint/parser'
    }
}

ESLint + Prettierの組み合わせに加えPRでのレビューより eslint-config-standard も継承することにしました。少しばかり細々としたルールの記述が減ったような気がし、よりメンテし易くなったと思います。

  • eslint-config-standard
  • eslint-plugin-node
  • eslint-plugin-prettier
  • eslint-plugin-promise
  • eslint-plugin-standard

これを踏まえて、下記を中心に型安全を追求します。

  1. エンドポイントを interface で定義
  2. ロジックを services で管理
  3. その他最初は (分かんなかったら) Anyで対応

エンドポイントを interface で定義

サーバサイドとの通信を安全に完結させるため。

export default class SummaryService {
    public async fetchSummary(
        ids: string[],
        person: string,
        createdAt: string
    ): Promise<SummaryEndpoint> {
        const params = getParams(ids, person, createdAt)
        const res = await axios.get(`/summary?${params}`)
        return res.data
    }
}

通信処理を一つの module として切り分け、必要に応じてこの module をインポートして返却値を厳密に管理します。

ロジックを services で管理

今回画面全体でデータを管理する必要は無く vuex を一切採用していません (今後採用するつもりはありません) 強いて言えば、 Vue.observable をアカウントステータスを管理していることにのみ使っている点ですが、今回は話が長くなるためまた後日共有させてください..🙏

上記のように非同期通信を最大限利用して、ローカルステートに加工済データを管理。

mounted() {
    Promise.all([
        this.fetchSummaryA(),
        this.fetchSummaryB(),
        this.fetchSummaryC(),
        this.fetchSummaryD()
    ])
}

テーブルやグラフチャート用にデータを加工する訳ですが、必要に応じて props を渡します。

親コンポーネントから孫コンポーネントのように 2世代以上を超えて引数を渡すといったことの無いような設計を堅持しています。

最初はAnyで対応

おいおい自力で型定義を書ければ良いでしょう。

基本的にエンドポイントの型定義を書けると、特にプラグインをインストールしない限り問題無いと思います。今回トーストUIを別途入れていますが、流石に自力で型定義を書かなければいけません。

declare module "vue-toasted" {
    import Vue, { PluginFunction } from "vue";
    function install(): PluginFunction<any>;
    export interface VueToasted {
        show(message: string): void;
    }
}

コンポーネントで既存のCSSと競合..!?

実際にコンポーネントでは services にアクセスするための加工済データをローカルステートとして管理。こうしたコンポーネント化を進めるに当たって新たに導入検討を進めていた bootstrap-vue の存在。

想定と比べて深刻 (かも)

ボタンの背景色が表示されない、モーダルが動かない事象が発生。 Vue CLI内では Scoped CSS を採用、それはあくまで Vue Component内の話。既存のCSSはグローバルに書かれており、競合が発生するのも納得。良くも悪くも新規ではなく既存案件であることを痛感した場面の一つでした。

CSSのベタ書きに変更。今回は一例にモーダルを自作コンポーネント化しました。

<atoms-button
    ref="branchSelectButton"
    :text="title"
    @handleClick="displayModal"
></atoms-button>
<div v-if="showModal === true">
    <div class="modal-mask" @click.self="showModal = false">
        <div :style="modalWrapperStyle">
            <div class="modal-container">

            </div>
        </div>
    </div>
</div>

基本的な考え方としてボタンをタップした時に showModal フラグを true にする一方で、マスク領域をタップすると showModal フラグを false にしています。

最後に、

今回は上記の内容に加え v-model を使わないと言った、気付きを中心に v-kansai #10 でも喋らせていただいてます。

小さなことから改善してる話

今後も必要に応じて共有していきたいと思います。

コメントを残す

タイトル
メールアドレス
詳細

あわせてよみたい..

-----