🌊

Vue Fes Japan Online 2022 ティザーの裏側

Vue Fes Japan Online 2022 ウェブサイトのリードを担当させていただいた経験と、そのついでに Nuxt 3 の話題も触れさせていただきます。

By jiyuujin at

#NuxtBridge
#Vue
#VueFes
#Advent-Calendar
Vue Fes Japan Online 2022 ティザーの裏側をはてなブックマークに追加

Vue Fes Japan Online 2022

https://vuefes.jp/2022

今回私自身は、公式ウェブサイト の初期ローンチを始め、技術のリードをメインに取り組ませていただきました。

結果的に初期ローンチで緻密な設計を行え、以後度重なる機能追加を経るも全体の体裁は整えられたものと考えています。

ちなみに、今回携わったチーム全体の 面々 を確認できます。

先日の kazu_pon さんが書かれたブログ記事にも、同じ画像が挿入されています。

https://note.com/kazu_pon/n/nc9926a474c03

数字で見る Vue Fes Japan Online 2022

リリース回数は 28 回、2 月に製作を開始した後、めでたく初期ローンチを 4 月 11 日に迎え 745 回のコミットを経ました。その内、前半の一部については Vue.js 日本ユーザーグループの公式 Twitter アカウントや Slack で公表させていただいております。

具体的には、下記 CHANGELOG をご確認いただければ幸いです。

初期ローンチを果たした 4 月 11 日から 11 月 11 日まで、7 か月間のデータを計測してみました。

ページビューは累計 20,000 を超えました。

  • ユーザー 14,000+ 名
  • セッション 24,000+ 件

閲覧者の利用 OS は、以下の通りとなります。

  • macOS 36%
  • iOS 30%
  • Windows 21%
  • Android 9%
  • Others (Linux) 4%

Web 開発者として気になるのは、閲覧者の Web ブラウザの比率でしょうか。

  • Chrome 64%
  • Safari (in-app 含む) 30%
  • Edge 3%
  • Firefox 2%
  • Others (Android Webview, etc) 1%

これらの数字を振り返ってみるだけでも大変勉強になりますが、この Advent Calendar では実際どうやって Vue Fes Japan Online 2022 のウェブサイトを運営してきたのか書かせていただきます。

キーワードで見る Vue Fes Japan Online 2022

今回のキーワードについて、下記キーワードが挙げられます。

捕捉事項は 2 点あります。ひとつは GSAP について Vue Fes Japan 2019 の ウェブサイト より基本的なアニメーションロジックを引き継いでいます。

使用の前提として、クライアントサイドでアニメーションを動作させるのを考慮する必要があります。

<client-only>
  <!-- GSAP アニメーション -->
</client-only>

大きく 6 つの形状に分けて、それぞれの形状から構成されるコンポーネントの下でアニメーションのロジックを書いています。

まずは、円形から構成されるコンポーネントのアニメーションを見ていきます。

円形から構成されるコンポーネント。
shape implementation
/components/shapes/HeadCircle.vue
1 つの三角形から構成されるコンポーネント。

ここでは Triangle と命名しています。

shape implementation
/components/shapes/HeadTriangle.vue
2 つの三角形から構成されるコンポーネント。

ここでは Slash と命名しています。

shape implementation
/components/shapes/HeadSlash.vue
4 つの三角形から構成されるコンポーネント。

ここでは Cross と命名しています。

shape implementation
/components/shapes/HeadCross.vue
四角形 (長方形) から構成されるコンポーネント。

ここでは Horizontal と命名しています。

shape implementation
/components/shapes/HeadHorizontal.vue
静的画像 (`***.jpg`) から構成されるコンポーネント。

ここでは Photo と命名しています。

/components/shapes/HeadPhoto.vue

こうして得られた各形状について、詳細なアニメーションロジックを useAnimationParts() フックへ書いていきます。

それぞれの図形を生成する際に、図形の切り替えと比べて duration を多めにとってアニメーションを実現させるようにします。

const PARTS_FADE_TIME = 0.2

// 図形の切り替え
gsap.to(refs, {
  attr: { ...attr },
  ease: Power2.easeOut,
  duration: PARTS_FADE_TIME,
})
const PARTS_CREATE_TIME = 0.6

// 図形の生成
gsap.to(refs, {
  attr: { ...attr },
  ease: Power2.easeOut,
  duration: PARTS_CREATE_TIME,
})

そして Vue 公式の提供するライフサイクルメソッド onMounted()onBeforeUnmount() を利用することで、アニメーションを制御させています。

export default {
  setup(props, context: SetupContext) {
    const { createAnimation, fadeAnimation, transformPosition } = useAnimationParts()

    const KEY_FRAME = [0, 60]
    const transform = transformPosition(props)

    const createAnimations = () => {
      setTimeout(() => {
        createAnimation(context.refs.shape, { r: KEY_FRAME[1] })
      }, 0)
    }

    const fadeAnimations = () => {
      fadeAnimation(context.refs.shape, { r: KEY_FRAME[0] })
    }

    onMounted(() => {
      createAnimations()
    })

    onBeforeUnmount(() => {
      fadeAnimations()
    })

    return { transform }
  },
}

それぞれのフックの詳細については、GitHub をご確認いただくとして。

Vue 3 では、下に示すようにアニメーションロジックをカスタムフック化できます。

こうしたロジックをコンポーネントの責務より外して管理させることができます。

<video controls playsinline width="100%" autoplay loop muted="true" type="video/mp4" src="https://i.imgur.com/SxgEI3W.mp4">
Sorry, your browser doesn't support embedded videos.
</video>

他方、Headless CMS のひとつとして今年の 4 月に正式ローンチしたばかりの Newt を使わせていただいています。

こちらは Newt 側で作成したスペースの UID と、CDN API のトークンを読み込む必要があります。

import { defineNuxtConfig } from '@nuxt/bridge'

export default defineNuxtConfig({
  publicRuntimeConfig: {
    newtCdnToken: process.env.NUXT_NEWT_CDN_TOKEN,
    newtSpaceUid: process.env.NUXT_NEWT_SPACE_UID,
  },
})

その上で、newt-client-jscreateClient を利用します。

useRuntimeConfig#app よりアクセスできます。

import { useRuntimeConfig } from '#app'
import { createClient } from 'newt-client-js'

export const createNewtClient = () => {
  const $config = useRuntimeConfig()
  return createClient({
    spaceUid: $config.spaceUid,
    token: $config.accessToken,
    apiType: 'cdn',
  })
}

作成済みインスタンスから client.getContents<T>({ appUid, query }) の API を利用して、指定のクエリに所属するデータへアクセスできます。

const fetchContent = (query?: Query) =>
  createNewtClient().getContents <
  T >
  { appUid, ...options, query }.then((contents) => {
    return contents.items
  })

ここまで来るとフロントエンドの描画となりますが、これより先は割愛させていただきます。

最後に

今回、初めて Vue Fes コアスタッフのひとりとして参画させていただきました。その中でウェブサイトのリードを担当させていただき、全体としてほんとうに貴重な経験をさせていただいた思いを抱いています。

知見発信の促進や、地方の Vue.js コミュニティの再興など、この 3 年余りの期間で失ってしまった文化を取り戻さなければいけないという使命も感じたりしています。

来たる Vue Fes Japan 2023 (仮称) でも引き続きコアスタッフのひとりとして、微力ながらお手伝いさせていただければ (余程の差し込み等無ければ) と前向きに考えています。

Vue Fes Japan Online 2022 ティザーの裏側をはてなブックマークに追加