點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Webpack Loader 將 GraphQL Query 獨立出來

Sam Xiao's Avatar 2019-12-22

雖然 Vue 允許我們在 ECMAScript 內以 String 定義 GraphQL Query,但實務上 Query 會相當複雜,比較好的方式是拆成獨立的 *.graphql 方便維護。

Version

macOS Catalina 10.15.2
WebStorm 2019.3.1
Node 12.14.0
Vue CLI 4.1.1
Vue 2.6.10
Vue Apollo 3.0.0-beta.11

Vue Apollo

/src/App.vue

<template>
  <div>
    <ul>
      <li v-for="(item, index) in books" :key="index">
        {{ item.title }}:{{ item.price }}
      </li>
    </ul>
  </div>
</template>

<script>
import gql from 'graphql-tag';

let query = gql(`
  query {
    books {
      title
      price
    }
  }
`)

export default {
  name: 'app',
  apollo: {
    books: {
      query
    }
  }
}
</script>

12 行

import gql from 'graphql-tag';

let query = gql(`
  query {
    books {
      title
      price
    }
  }
`)

傳統寫法需先 import gql(),然後使用 gql() 將 string 轉成 GraphQL AST。

這種寫法有幾個缺點:

  • 實務上 query 會很龐大,僅使用單一 string 難以維護
  • GraphQL 畢竟是獨立語言,藏在 ECMAScript 內稍嫌不妥
  • 須在 runtime 將 string 轉成 GraphQL AST,稍微影響速度

比較好的方式是藉由 graphql-tag Webpack loader,將 GraphQL query 獨立成 *.graphql,在 Webpack bundle 階段將 string 轉成 GraphQL AST。

Webpack Loader

/src/App.vue

<template>
  <div>
    <ul>
      <li v-for="(item, index) in books" :key="index">
        {{ item.title }}:{{ item.price }}
      </li>
    </ul>
  </div>
</template>

<script>
import query from './graphql/books.graphql'

export default {
  name: 'app',
  apollo: {
    books: {
      query
    }
  }
}
</script>

12 行

import query from './graphql/books.graphql'

books query 寫在獨立的 books.graphql 內 import 進來,可自行取其名稱。

14 行

export default {
  name: 'app',
  apollo: {
    books: {
      query
    }
  }
}

定義 books smart query,可直接使用 import 進來的 query,不必再透過 gql() 將 string 轉成 GraphQL AST。

GraphQL Query

/src/graphql/books.graphql

query {
  books {
    title
    price
  }
}

books query 獨立成 books.graphql,除了方便維護外,還可直接在 WebStorm 內測試結果。

webpack001

Q:為什麼 Vue 不必使用 gql() 將 string 轉成 GraphQL AST 就能執行呢 ?

module.exports = {
  chainWebpack: config => {
    config.module
      .rule('graphql')
      .test(/\.graphql$/)
      .use('graphql-tag/loader')
        .loader('graphql-tag/loader')
        .end()
  }
}

其實 Vue Apollo 有另外設定 graphql-tag Webpack loader,在 bundle 階段將 string 轉成 GraphQL AST,因此我們 import 後即可使用。

Start Development Server

$ yarn serve

使用 yarn serve 啟動 Webpack dev server,graphql-tag Webpack loader 會將 import string 轉成 GraphQL AST。

webpack003

Build Docker Image

$ yarn docker:build
$ yarn docker:up

使用 yarn docker:build 命令 Babel 轉譯與 Webpack 打包,最後包成 Docker image。

webpack004

Browser

webpack002

可成功執行 Vue。

Conclusion

  • 使用 Webpack Loader 最大優點是將 GraphQL query 獨立成 *.graphql,適合大型專案使用,也能避免 runtime 使用 gql 轉譯成 GraphQL AST 造成效能耗損
  • Vue Apollo 已經將 Webpack loader 整好,可直接使用
  • 實務上建議一個 GraphQL query 使用一個檔案即可

Sample Code

完整範例可在我的 GitHub 上找到

Reference

Apollo Docs, Loading queries with Webpack
Vue CLI, Adding a New Loader
Apollographql, graphql-tag