Closed3

GitHubの草をNuxtでThree.jsを使って生やしたい

nac-39nac-39

GitHub GraphQL APIをNuxtからurqlを使って叩く

こちらの記事を見るとgraphql-request が軽量で良さそうだが、エラーが出て使えなかったのでurqlというライブラリを使う
https://zenn.dev/youcangg/articles/4b1a47af9a42d8#graphql-request

urqlのドキュメントはとても丁寧なのでこれ見れば大丈夫
https://formidable.com/open-source/urql/docs/basics/vue/#context-options

  • urql導入
yarn add @urql/vue graphql
# or
npm install --save @urql/vue graphql

最小構成

クライアント側にGitHubのトークンを渡したくないので、サーバー側でGitHubのAPIを叩く仕様にする

plugins/github.server.ts
import { Client, cacheExchange, fetchExchange } from "@urql/core"

export default defineNuxtPlugin(async () => {
  const urql = new Client({
    url: "https://api.github.com/graphql",
    exchanges: [cacheExchange, fetchExchange],
    fetchOptions: () => {
      const token = process.env.GITHUB_TOKEN
      return {
        headers: { authorization: token ? `Bearer ${token}` : "" },
      }
    }
  })
  const { data } = await urql.query(`
  query {
    viewer {
      login
    }
  }
  `, {}).toPromise()
  return {
    provide: {
      github: data
    },
  }
})
composables/github.ts
export const useGitHub = () => {
    const { $github } = useNuxtApp()
    const github = useState('github', () => $github)
    return github
}
pages/kusa.vue
<template>
  <ClientOnly>
    {{ kusa }}
  </ClientOnly>
</template>
<script setup lang="ts">
  const kusa = useGitHub()
</script>

実行結果

あとはクエリを草を取得するものに変えれば良い。


これを自分で設定するのが面倒なら、このパッケージ使うのもありかも(Nuxt3には対応してないっぽい…?)

https://github.com/lindsaykwardell/nuxt-github-api


(余談)graphql-request使おうとしたら起こったエラーはこれ↓
https://github.com/jasonkuhrt/graphql-request/issues/519
raphql-request: https://github.com/jasonkuhrt/graphql-request

GitHub APIの仕様について

  • トークンはClasicの方を使う

注: GraphQL API の認証には personal access token (classic)、GitHub App、または OAuth App を作成する必要があります。 GraphQL API は fine-grained personal access token を使った認証をサポートしていません。
https://docs.github.com/ja/enterprise-cloud@latest/graphql/guides/forming-calls-with-graphql

nac-39nac-39

NuxtサイトにThree.jsを導入する

この記事を参考にして進めてみる。composablesにthree.jsのコードを置いて、.vueから呼び出して使う方針らしい。

https://zenn.dev/tsukiyama3/articles/f42b95f88a72b5

  • three.js導入
yarn add @types/three three

参考記事をめちゃめちゃ参考にさせてもらいながら、こんな感じに

types/GitHub.ts
// 命名もうちょっと良いのあったやろ…
export type KusaWeek = {
    contributionDays: {
        date: string,
        weekDay: number,
        color: string,
        contributionCount: number,
    }[]
}
pages/kusa.vue
<template>
  <div ref="container" class="w-full h-80">
    <ClientOnly>
      <GitHubKusa
        :weeks="kusa.user.contributionsCollection.contributionCalendar.weeks"
        :clientWidth="clientWidth"
        :clientHeight="clientHeight"
      />
    </ClientOnly>
  </div>
</template>
<script setup lang="ts">
  const kusa = useGitHub()
  const container = ref<HTMLElement | null>(null)
  const { clientHeight, clientWidth } = useWindowSize(container)
</script>
components/GitHubKusa.vue
<template>
  <div ref="container"></div>
</template>
<script setup lang="ts">
  import { KusaWeek } from "~/types/GitHub"

  const props = defineProps<{
    weeks: KusaWeek[]
    clientWidth: number
    clientHeight: number
  }>()
  const container: Ref<HTMLElement | null> = ref(null)
  onMounted(() => {
    if(!props.weeks) return
    const { init } = useKusa(
      container,
      props.clientWidth,
      props.clientHeight,
      props.weeks
    )
    init()
  })
</script>
composables/kusa.tsのkusa生成部分
    const kusaMesh = (week: KusaWeek) => {
        const group = new Group()
        for (let i = 0; i < week.contributionDays.length; i++) {
            const height = week.contributionDays[i].contributionCount
            const geometry = new BoxGeometry(10, height, 10)
            const material = new MeshBasicMaterial({ color: week.contributionDays[i].color})
            const cube = new Mesh(geometry, material)
            cube.position.set(i * 15, height / 2, 0)
            group.add(cube)
        }
        return group
    }
composables/kusa.tsのkusa作成部分2
        // 草作成
        const kusa = new Group()
        for (let i = 0; i < weeks.length; i++) {
            const weekMesh = kusaMesh(weeks[i])
            weekMesh.position.set(0, 0, i * 21)
            kusa.add(weekMesh)
        }
        kusa.position.set(-5, 0, -(weeks.length * 21 / 2))

こんな感じ

nac-39nac-39

開発環境

% node -v
v16.19.1
% yarn -v
1.22.19
% lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.2 LTS
Release:        22.04
Codename:       jammy
このスクラップは2023/05/07にクローズされました