VSCodeCon JP の内幕

~ カンファレンス LP について~

2021/11/01

VSCodeCon JP プレイベント

jiyuujin

  • 複雑なUIを作るのが好きです
    • React/Next/Vue/Nuxt/Scala/Swift
  • スタッフとして色々と参画中
    • FlutterKaigi 2021
    • JAWS DAYS 2021 個人スポンサー
    • Flutter Japan User Group (Osaka)
    • PWA night
    • v-kansai / kansai.ts
  • プロフィールサイト
    • https://yuma-kitamura.nekohack.me
  • 技術ブログ
    • https://webneko.dev

VSCodeCon JP

  • https://vscodejp.github.io/conf2021/ja/
  • https://vscodejp.github.io/conf2021/en/

今年の VSCodeCon 実は

  • 今年で 6 年目を迎える VS Code Conference JP 2021 で初めてカンファレンスウェブサイトを製作した
    • スタッフ投票の結果 Happy Extensions をコンセプトとして採用している

VSCode のブランドカラー

  • VSCodeCon ウェブサイトに VSCode のブランドカラー 3 色全てを織り交ぜた
  • .vscode/settings.json でテーマカラーも設定した
{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "eslint.lintTask.enable": true,
  "peacock.color": "#007acc",
  "workbench.colorCustomizations": {
    "activityBar.activeBackground": "#007acc",
    "activityBar.activeBorder": "#ee90bb",
    "activityBar.background": "#007acc",
    "activityBar.foreground": "#e7e7e7",
    "activityBar.inactiveForeground": "#e7e7e799",
    "activityBarBadge.background": "#ee90bb",
    "activityBarBadge.foreground": "#15202b",
    "editorGroup.border": "#007acc",
    "panel.border": "#007acc",
    "sash.hoverBorder": "#007acc",
    "sideBar.border": "#0065a9",
    "statusBar.background": "#0098ff",
    "statusBar.foreground": "#e7e7e7",
    "statusBarItem.hoverBackground": "#007acc",
    "statusBarItem.remoteBackground": "#0065a9",
    "statusBarItem.remoteForeground": "#e7e7e7",
    "titleBar.activeBackground": "#0065a9",
    "titleBar.activeForeground": "#e7e7e7",
    "titleBar.inactiveBackground": "#1857a499",
    "titleBar.inactiveForeground": "#e7e7e799"
  }
}

見栄えが変わる

技術スタック

Deploy to

Github Pages

ざっくりこの 3 点

  • Github Pages へデプロイする
    • Next.js の静的サイト化を行う
  • React フレームワークのひとつ Next.js の採用
    • i18next を使って国際化 (EN/JA) に対応する
    • Context とその Provider を使って Light/Dark 双方に対応する

Github Pages へデプロイ

  • vscodejp.github.io というドメインで公開する方針の下 Github Pages へデプロイすることになった
    • next build と next export を合わせて進めることで、静的 HTML が生成される
  • Github Pages 固有の事象に対処する
    • _ から始まるファイルが 404 となってしまう問題
jobs:
  build-deploy:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [12.x]

    steps:
      - uses: actions/checkout@master

      - name: Use Node.js
        uses: actions/setup-node@master
        with:
          node-version: '12.x'

      - name: Transpile
        run: |
          npm install
          npm run build
        env:
          CI: true
          URL_PREFIX: conf2021
          GITHUB_PAGES: true

      - name: Export
        run: |
          npm run export
          touch out/.nojekyll

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v2.8.0
        env:
          ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
          PUBLISH_BRANCH: gh-pages
          PUBLISH_DIR: ./out

国際化対応に i18next を使う

  • 唐突ながらハマりポイントは next-18next が静的サイト用に使えないこと
    • Github issue が立てられていました
  • useRouter を使うことでルートパスに言語ごとのパスへリダイレクトするよう設定する
    • リダイレクトされた先でタイムテーブルなど具体的なコンテンツを配置する

Dynamic Routes を利用

  • 言語別にルーティングを準備する
    • ルーティングパスとして pages/[lang].tsx を準備する
    • getStaticPaths / getStatisProps を使うことで事前に想定している言語を paths / props として返す
      • 今回は英語と日本語を返す
export async function getStaticPaths() {
  return {
    paths: languages.map((lang) => {
      return { params: { lang: lang } }
    }),
    fallback: false,
  }
}

export async function getStaticProps({ params }) {
  return {
    props: {
      language: languages.includes(params.lang) ? params.lang : defaultLanguage,
    },
  }
}

強制リダイレクトさせる

  • ルートで各言語に応じたパスにアクセスさせる
    • pages/index.tsx から強制リダイレクトさせる
    • next/router の useRouter を使うことでユーザが入力したパスを判定する
      • en/ja が入力された際各言語に応じたパスを返す
import React from 'react'
import { useRouter } from 'next/router'
import i18next from 'i18next'

export default function Home() {
  const router = useRouter()

  React.useEffect(() => {
    const { pathname } = router
    if (pathname == '/') {
      router.push('/' + i18next.language.substring(0, 2))
    }
  })

  return null
}

テーマを Context に保存

  • Context は共通に使えるデータストア
    • 一般的に言われているのは props のバケツリレーを避けるため
    • 今回のテーマ保存はとある特定のコンポーネントに限定しないので、可能な限り Context という形式で管理した方が良さそう、という判断から
  • テーマを Union 型で定義する
    • colorMode: ColorMode = 'light' | 'dark'
    • 保存したテーマを localStorage に保存する

Provider を登録する

  • Context とその Provider を使ってテーマを保存する
    • 事前に Light/Dark 双方で使う用の CSS variables を読み込む
    • --initial-color-mode という名前の下で今のテーマを保存する
  • クライアントでページがロードされた時に読み込む
    • pages/_app.tsx で Provider を読み込む
type ColorTheme = {
  colorMode: 'light' | 'dark'
  changeColorMode: (cm: 'light' | 'dark') => void
}

export const ColorThemeContext = createContext<ColorTheme>(null)

export const ColorThemeProvider: FC = ({ children }) => {
  const [colorMode, setColorMode] = useState(undefined)
  useEffect(() => {
    const root = window.document.documentElement
    const initialColorValue = root.style.getPropertyValue('--initial-color-mode')
    setColorMode(initialColorValue)
  }, [])

  const changeColorMode = (mode: string) => {
    setColorMode(mode)

    window.localStorage.setItem('color-mode', mode)

    const root = window.document.documentElement
    root.style.setProperty('--initial-color-mode', mode)
    root.style.setProperty(
      '--color-text',
      mode === 'light' ? themeColors.light.textColor : themeColors.dark.textColor,
    )
    root.style.setProperty(
      '--color-background',
      mode === 'light' ? themeColors.light.backgroundColor : themeColors.dark.backgroundColor,
    )
  }
  return (
    <ColorThemeContext.Provider value={{ colorMode, changeColorMode }}>
      {children}
    </ColorThemeContext.Provider>
  )
}

コントリビュート歓迎

https://github.com/vscodejp/conf2021

最後にこれだけは!

  • VSCodeCon JP 今年のテーマは Happy Extensions
  • VSCode で自分仕様にカスタマイズできる
    • テーマカラーを設定できる
  • Next.js SG 化
    • next build と next export を合わせてビルドする
    • Dark/Light 双方へ対応するには Context
    • 国際化対応は注意が必要です

Thank you..🙇‍♀️

Made with Slides.com