GameWith Developer Blog

GameWith のエンジニア、デザイナーが技術について日々発信していきます。

ダッシュボードの新機能開発にVue.jsを導入した背景と苦労したこと #GameWith #TechWith

こんにちは!サーバサイドエンジニアのkuromokaです!

こちらの記事でもあったように、GameWithのリプレイス開発ではVue.jsを使っています。 tech.gamewith.co.jp

今回はリプレイスではなく、GameWithの社員の方が使っているダッシュボードの新機能開発に、Vue.jsを導入した背景と苦労したことについて、お話します。

Vue.jsを導入した背景

GameWithのダッシュボードは社員の方しか見れない画面で、フロント側は次のような技術が使われています。

  • Bootstrap v2.0.3
  • jQuery v1.8.3

それぞれのリリース日を調べてみたら、Bootstrap v2.0.3は2012年の4月*1、jQuery v1.8.3は2012年の11月*2のようです。

2020年の今となってはかなり昔のバージョンを使っているのですが、裏側の画面のためにフロント側で凝った画面にする機会があまりなく、苦労さは感じつつ開発はしていました。

ただダッシュボードが使い辛いことでの作業効率が下がっているという話はたびたび聞いていて、今回もそういった作業効率を改善するための新機能開発でした。

今回の新機能はかなり根本的な改善を行うための機能だったため、フロントの改修も大幅に必要な見込みになりました。

開発チームでも相談して、この開発を今のフロント環境でやるのはちょっと辛いなということになりました。 あとはダッシュボードなので比較的新しい技術を取り入れやすいというのもありました。

そういった経緯で、今回はVue.jsを採用することにしました。具体的には次のような技術を使いました。

  • Vue.js v2.6.11
  • Composition API
    • Vue.js3系に備えて採用。v2系のため@vue/composition-api を導入
  • BootstrapVue
    • Bootstrap v4ベースのコンポーネントを、Vueコンポーネントとしてコーディングするため
  • Vue CLI
  • TypeScript
  • Jest
  • Go(バックエンドAPI)
    • Vue.jsからは基本的にGoのAPI経由で、データの取得や更新を行う

Vue.jsの導入で苦労したこと

今回の新機能開発に関しては、開発環境が整ってからはVue.jsの恩恵も受けながらスムーズに開発できたので、新しい環境にして良かったと思っています。*3

ただVue.jsの導入までが、既存プロジェクトへ導入するような事例があまり見つからないのと、私自身もそこまでVue.jsに詳しいわけではなかったので結構苦労しました。

細かいところを含めればもっと紹介したいのですが長くなってしまうので、今回は「既存プロジェクトへのVue.jsの導入で苦労したこと」について、3点紹介します。

1. Vue.jsのインストールからビルドまで

Vue.js公式ドキュメントには、CDN・NPM・Vue CLIでのインストールが紹介されています。最初は一番手軽なCDNにしようとも思ったのですが、今後規模が大きくなることやビルド設定が最初から入っていることもあり「Vue CLI」でインストールをしました。 jp.vuejs.org

ダッシュボードの画面はPHPで動いています。PHPのプロジェクト内に、Vue CLIで「frontend」プロジェクトを作りました。

$ cd ${DASHBOARD_APP_PATH}
$ vue create frontend


Vue CLI v4.1.1
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Linter, Unit
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Pick a linter / formatter config: Basic
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

Vue CLIはビルド設定が最初から入っているため、$ npm run build するだけで、ビルド結果が出力されるのはすごく楽でした。

ただそのままだとVue CLIで作った、「frontend」プロジェクト内にビルド結果が出力されます。公開フォルダにはしていないため、PHPから参照することができません。

そのためアセットの公開フォルダに対して、ビルド結果が出力されるように、vue.config.jsファイル*4を作って設定を調整しました。

具体的には、次のようにoutputDirassetsDir を調整しました(いろいろな事情がありVue CLIのプロジェクトが深くなっているので、こんな相対パスになっています)。

module.exports = {  
  outputDir: '../../../../../public/', 
  assetsDir: './assets/frontend/',
}

最後に公開フォルダに出力するようにしたビルドファイルを、PHPから読み込むようにしました。

<script src="/assets/frontend/js/app.js"></script>

2. カレントパスによるコンポーネントの切り替え

見ているページのカレントパスでVueコンポーネントを切り替えるために、「vue-router」を使いました。 router.vuejs.org

初期化時に追加していなかったので$ vue add routerで後から追加しました。このコマンドでvue-routerのインストールとサンプル用のルーティング設定まで一通りやってくれます。

Vue CLIはデフォルト設定だと #appの要素にApp.vueがマウントされる設定になっています。今回App.vue<router-view/>を追加して、この部分をvue-routerで切り替えるようにしました。

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

PHPからは、Vueコンポーネントを表示したい箇所に#appを書きます。あとはvue-routerのルーティング設定を調整すれば、カレントパスによって#appの部分が切り替わるようになります。

<div id="wrap">
  <div id="app"></div>
</div>

3. ホットリロードで開発する

今回一番苦労した点です。

Vue CLIには最初からホットリロードが有効な開発サーバが$ npm run serveで起動できるようになっています。
ただ今回は「PHPの一部分をVue.jsにした環境で、Vue.jsの部分だけホットリロード」するような挙動にしたかったので、そのままでは開発サーバが使えませんでした。

そのためしばらくは$ npm run buildで毎回ビルドして確認していましたが面倒で開発効率が悪いので、なんとかホットリロードを使えないか調べてみました。

調べていく中で、vue.config.jsdevServer.proxyという、設定が使えそうなことが分かりました。この設定を使うと開発サーバの特定パスへリクエストがあったときに、別サーバにプロキシさせてリクエストすることができるようになります。 cli.vuejs.org

一部省略していますが、実際に設定したvue.config.jsは次のような感じです。http://php-local-server/はPHPのローカル開発サーバです。/なので全てのリクエストをPHPにプロキシさせています。

module.exports = {  
  host: '0.0.0.0', 
  port: 9000,   
  proxy: {   
    '/': {  
      target: 'http://php-local-server/',  
      secure: false,   
      cookieDomainRewrite: 'localhost',        
    },
}

PHPではサーバ変数の$_SERVER['HTTP_X_FORWARDED_HOST']でプロキシ時のホスト名を取ることができます。
この値を見てlocalhost:9000の場合にhttp://localhost:9000からのパスで、ビルドファイルを読み込むようにしました。

<script src="http://localhost:9000/assets/frontend/js/app.js"></script>

ここまで設定すれば、

  • $ npm run serveで、Vue CLIの開発サーバを起動
  • http://localhost:9000/vue-js-pathで、Vue.jsを使っているページを見る
    (PHPのhttp://php-local-server/vue-js-pathがプロキシ経由で表示される)
  • Vueコンポーネントを更新するとビルドが走って、Vue.jsの部分だけ自動でリロードされる

という感じで開発ができるようになって毎回のビルドが不要になりました!これで当初目指した「PHPの一部分をVue.jsにした環境で、Vue.jsの部分だけホットリロード」を実現することができました。

まとめ

今回はダッシュボードの新機能開発に伴う、「Vue.jsを導入した背景」と「Vue.jsの導入で苦労したこと」をお伝えしました。

記事で紹介した「frontend」プロジェクトは、今は「GameWithのリプレイスについて vol.2 ~Web Components を Vue で書いたら最高だった編~ #GameWith #TechWith - GameWith Developer Blog」で紹介した「GameWithDesignSystem」のように別システム化をして、PHPのプロジェクトから独立して開発できる環境に改善をしています。

今回の内容が同じような悩みの人に対して、少しでも参考になる情報だったら嬉しいです!

終わりに

GameWithのDeveloper向けTwitterアカウントを開設しました。

技術やブログの更新情報などを発信するので良かったらフォロー宜しくお願いします!

https://twitter.com/gamewith_devtwitter.com

*1:https://blog.getbootstrap.com/2012/04/24/bootstrap-2-0-3-released/

*2:https://blog.jquery.com/2012/11/13/jquery-1-8-3-released/

*3:Composition APIだけは苦労したのですが、RFCを見たりGitHubでコード検索をしたりして、書き方に慣れていくようにしました

*4:https://cli.vuejs.org/config/ 今回このファイルを触る機会が多かったので、とても参考になったページです

iOSのViewが画面上に表示されたことを判定する実装方法 #GameWith #TechWith

こんにちは、iOSエンジニアの chuymaster です!

最近とある案件で、ユーザーが特定のViewを見たかどうかを計測しました。iOSエンジニア向けに、その実装方法について紹介したいと思います。

目次

背景

弊社は、設置したバナーの効果測定のため、ユーザーが何人バナーを見て、何人クリックしたかというデータを集計しています。

広告用語でいうと、クリック率(CTR)に当たる数字を集計して、分析しています。

それに基づいて、どういうバナーが効果が良いのかの実験が日々行われていますが、iOSアプリではそのようなことができませんでした。

要件

元々各バナーのクリックイベントは記録していますが、インプレッション(表示)イベントを記録していなかったので、CTRを測定できませんでした。

今回はインプレッションを記録する実装を下記の「統合トップ」画面で行いました。

f:id:gwchai:20200526150111p:plain:w300
統合トップ画面

インプレッションの定義は様々ですが、Googleアドマネージャーの定義に従いました。

Google アド マネージャーでは、業界基準に沿った方法でモバイルアプリ インプレッションがカウントされます。つまり、デバイスの画面に広告クリエイティブが 1 ピクセル以上表示されると、モバイルアプリ インプレッションが 1 回カウントされるという仕組みです。

実装要件に置き換えると、対象Viewが画面上に1pxでも表示されればインプレッションイベントを送ることになります。

実装

下記が対象画面の構成になります。

f:id:gwchai:20200526183630p:plain
インプレッションを判定したい箇所

見ての通り、インプレッションを判定したい箇所は3種類あって、かなり深い層にあります。 インプレッションログ送信の実装要件はこのようになります。

  1. UIScrollViewの中のUIViewが画面内に表示された際
  2. スクロールが無効なUICollectionViewの中にある、UICollectionViewCellが画面内に表示された際
  3. 横スクロールが有効なUICollectionViewの中にある、UICollectionViewCellが画面内に表示された際

基本的な実装コード

stackoverflow.com

上記のスレを参考に、scrollViewDidScroll(_:) 時に、スクロールして見える bounds と対象の UIViewboundsintersects(_:) したら、インプレッションログを送信します。

しかし、Viewが複数階層でネストされている対象画面では、そのまま UIViewboundsUIView が交差しているかどうかを判定すると、ローカル座標が返されて間違った判定になってしまいます。そこで登場するのが convert(_:to:) 関数です。

view.convert(bounds, to: UIScreen.main.coordinateSpace)

これで画面上の空間での座標に変換できます。詳しくはこちらを読んでみてください。 https://developer.apple.com/documentation/uikit/uicoordinatespacedeveloper.apple.com

①UIViewが画面上に表示されたことを判定するコード

完成したコードがこちらです。

func detectImpressions(scrollView: UIScrollView, view: UIView) {

        // スクロールした位置で見えているフレームの位置を計算する
        let currentVisibleFrame = CGRect(x: scrollView.contentOffset.x,
                                         y: scrollView.contentOffset.y,
                                         width: scrollView.frame.size.width,
                                         height: scrollView.frame.size.height)

        // 見えているフレームの位置を、画面上の位置に変換する
        let currentVisibleFrameInMainSpace = scrollView.convert(currentVisibleFrame, to: UIScreen.main.coordinateSpace)

        // Imp計測対象Viewのフレームの位置を、画面上の位置に変換する
        let viewFrameInMainSpace = view.convert(view.bounds, to: UIScreen.main.coordinateSpace)

        // 重なりを判定する
        if viewFrameInMainSpace.intersects(currentVisibleFrameInMainSpace)
         {
            // インプレッションログを送信する
         }
    }

スクロールして見えたフレームと、対象Viewのフレームを UIScreen.main.coordinateSpace 空間の座標に変換して、画面上に見えているかどうかを判定します。 あとは scrollViewDidScroll(_:) で呼び出せば良いです。

これで、要件①UIScrollViewの中のUIViewが画面内に表示された際の判定処理が実現できました。

②UICollectionViewのUICollectionViewCellが表示されたことを判定するコード

UICollectionView の場合は、中のセルのフレームを見て判定する必要があります。

stackoverflow.com

上記の回答を参考に、今見えているセルの indexPath.row を返す関数を実装しました。

   func getVisibleRows(currentVisibleFrameInMainSpace: CGRect, collectionView: UICollectionView) -> [Int] {
        var visibleRows = [Int]()

        let visibleIndexPaths: [IndexPath] = collectionView.indexPathsForVisibleItems
        for indexPath in visibleIndexPaths {
            guard let cell = collectionView.cellForItem(at: indexPath) else { continue }

            // 画面描画位置の重ねで表示されたかどうかを判定する
            let cellRect = cell.contentView.convert(cell.contentView.bounds, to: UIScreen.main.coordinateSpace)
            if currentVisibleFrameInMainSpace.intersects(cellRect) {
                visibleRows.append(indexPath.row)
            }
        }
        return visibleRows
    }

引数に①の関数で取得した画面上のフレーム座標を渡して、各セルの座標と比較して画面上に見えているかどうかを判定します。

collectionView.indexPathsForVisibleItems がそのまま使えない理由は、今回の実装では、全てのセルを最初から展開して描画させているため、すべてのセルの indexPath が返却されるからです。

これにより、要件②スクロールが無効なUICollectionViewの中にある、UICollectionViewCellが画面内に表示された際の判定処理が可能になります。

要件③横スクロールが有効なUICollectionViewの中にある、UICollectionViewCellが画面内に表示された際のも同じコードでできますが、scrollViewDidScroll(_:)delegateUICollectionView に変える必要があるので、ご注意ください。

スクロールが有効なUICollectionViewなので、 collectionView:willDisplayCell:forItemAtIndexPath: は一見使えるように見えますが、実際はユーザーが見えない場所で呼び出されることがあるので、使わない方が良いです。

注意点

初回表示時の判定

scrollViewDidScroll(_:) で判定処理を入れているので、画面ロード後、ユーザーの操作なしだと判定処理が走りません。

そのため、画面ロード後に明示的に判定する必要があります。

GameWithアプリでは RxSwift を使っているので、scrollView.rx.contentOffsetSubscribe して初期状態でも判定させることができました。

判定タイミング

この方法は、画面上の描画後の座標を元に、2つのフレームが交差したかどうかを判定しています。

そのため、描画完了前に判定してしまうと正しい座標になりません。

判定がおかしいなぁと思ったら

  1. view.layoutIfNeeded() で描画させる
  2. DispatchQueue.main.async 内で判定処理を呼ぶ

のどちらかを試してみてください

重複除外

scrollViewDidScroll(_:) で表示判定をしているので、イベントが何回も送られます。 一度送ったイベントを送らないように除外する必要があります。

最後に

この実装でかなり時間がかかったので、同じ課題に当たるiOSエンジニアの方に少しでも役に立ったら幸いです!

GameWithのDeveloper向けTwitterアカウントがあります。

ブログの更新情報などを発信するので良かったらフォローしてください!!

twitter.com

サスティナブルな社内LT #GameWith #TechWith

サスティナブルな社内LT

こんにちは! コミュニティではごーと呼ばれている只野です。

前回社内LTを続けるコツについて、ブログに書きました!

tech.gamewith.co.jp

今回はオフィスで開催していた社内LTをオンライン開催に変更をしていった経緯について書いていきたいと思います!

サスティナブルな社内 LT とは

私たちは、社内 LT を GamWith の開発組織における文化形成の手段として行ってきました。LT を行う機会が増えると、個性を共有できるようになり、個性の集まりが GameWith 特有の文化として根付いていくことが期待できます。 この取組みが長いスパンで行われることを sustain(持続する)とable(〜できる)からなる言葉と重ねて、「サスティナブルな社内LT」 と考えています。

社内LTの変化

1. オフィスで開催していた時期

以前書いたブログにもある通り、毎週金曜日の19:15 ~ 19:45 に社内 LT を開催していました!

この時期については上記のブログに詳しく書いてありますので、そちらをご参照ください。

2. 出社組とリモート組が混ざっていた時期

LTの発表は出社組が zoom でオフィスから社内LTを配信しリモートしているメンバーも視聴していました。

3. フルリモートになった初期

2の時期は在宅勤務の推奨となっていましたが、3/30(月)に発表のあったとおり弊社はフルリモートへ移行しました。

gamewith.co.jp

フルリモートに移行して1ヶ月ほどは社内 LT を開催していませんでした。

フルリモートという環境の大きな変化もあり、社内 LT の開催方法などについて考える余裕があまりなかったのが正直なところです。

4. フルリモート後の復活

4/17(金)に社内 LT を復活させ、今日まで毎週開催しています。

全員がフルリモートの環境に徐々になれてきたため、復活させました。

全員フルリモートなので、逆に社内 LT はやりやすいのでは?と気づきました。

プロセス

時間帯は毎週金曜日の19:30 ~ 20:00に行っています!

以前までは2,3人が10分程度LTを行っていましたが、現在は4人が5分程度 LT を行っています。

人数と時間を変更した理由としては、以前までは質疑応答や感想を話したりとコミュニケーションの時間を取っていました。 しかし、オンラインで双方向のやり取りが難しいと思い、視聴者にはマイクをオフにしてもらい配信形式のような形にしました。 また、視聴者が飽きないように短い LT にして発表者の人数を増やしました。

オンラインになったので無音の時間ができるだけ無いように、テンポの良いファシリを心がけています。

オフィスで開催していたときは写真を撮っていましたが、オンライン開催では社内 LT の配信を録画し編集しています。 編集で無音をカットした動画は、テンポが良くとても見やすいです。

最初の方は録画した映像を iMovie を使い手動で編集していたが、とても大変でした😭 現在は vrew というツールを利用して自動で編集をしています!

vrew.voyagerx.com

オフィスで開催していたときより発表者の人数が増えた分、時間通り30分で終わらせるために多めにバッファを取っています。

視聴者は Slack のスレッドにコメントをしています。 最初は画面にコメントが流れるツールを使っていたが、準備が大変で今の形に落ち着きました。

LTが5分になり発表者の準備もそこまで時間がかからないので、発表者の準備が以前と比べて楽になりました。

告知は週の前半で1回お知らせをして、開催時間の少し前に再度お知らせをしています。

f:id:tiwu:20200521190555p:plain

全員参加しているチャンネルで告知をしているので、頻繁に @here をしないように告知の回数は最小限にしています。

効果

オンライン開催になったので席が少し遠かった人も発表をしたり、視聴者として参加するようになりました!

オンライン化により可能性が広がった事で、今後外部との合同 LT なども検討しています。 弊社と共に LT を開催したい場合などは、是非 @gamewith_dev まで気軽にご連絡ください!

フルリモートになり曜日の感覚が薄まっていったが、毎週金曜日の19:30に開催をしているので、少しずつ曜日の感覚を取り戻してきたのではないかと思います。

またフルリモートになって他チームの人の顔を見る機会が以前よりも減ったので、この社内 LT で他チームの人の顔が見れることもオンライン化のメリットだなと感じました。

オンラインになったので、作業中の BGM として社内 LT を聞くこともできますし、参加するスタイルはより自由になっています。

まとめ

以前のブログで社内 LT を続けるのに特に苦労はなかったと書いたのですが、上記の通りフルリモートになった際に一ヶ月ほど社内 LT の開催を停止してしまう時期がありました。

ですが、いざ再開してみると意外と問題なくオンライン社内 LT が実施できることがわかりました。

この数ヶ月で日々の MTG などの通常業務もフルリモート体制に移行したこともあり、自分達が思いの外オンライン環境に適応していたことがわかりました。

これからもサスティナブルな社内 LT をやっていきたいと思います!

最後に

GameWithのDeveloper向けTwitterアカウントも開設しました。

ブログの更新情報などを発信するので良かったらフォロー宜しくお願いします!

twitter.com

GameWithのリプレイスについて vol.2 ~Web Components を Vue で書いたら最高だった編~ #GameWith #TechWith

はじめに

こんにちは!Incremental Stream Team の@53able, @inosy22, @nog です!

前回のブログでは Gamewith で行っているリプレイスの概要について紹介しました。

tech.gamewith.co.jp

今回は Web Components を Vueで開発するための、システム( GameWithDesignSystem)を開発したので紹介したいと思います。

GameWithDesignSystem とは?

Vue で実装したコンポーネントを Web Components として配布をし、どんなプロジェクトでも利用できるコンポーネントを提供するシステムです。

実際に GameWith では下記のスクショのようにカウントダウンをする広告をGameWithDesignSystemで開発しました。

f:id:tiwu:20200416194434p:plain

GDS の目指す世界

  1. どんなプロジェクトでも簡単に利用できるHTMLコンポーネントの提供

  2. 将来的にデザイナーも UI/UX 改善に利用できるようにしたい

  3. 将来的にエコシステムを OSS として公開したい

作った背景

課題

リプレイスでは、Nuxt.js (Vue.js) を採用しています。

現在は BFF(Backends For Frontends)で Nuxt.js を動かして、SSRのみ行っています。(クライアントで Nuxt.js が動いているわけではありません)

リプレイスは段階的に行う計画のため、上記の対応によって既存のJSは後ほどまとめてリプレイスする予定でした。

しかし、既存のJSの部分的リプレイスを実施する必要が出てきました。

既存コードと新規コードを共存させる場合は、jQuery による DOM 操作と Vue で扱う仮想 DOM との相性が良いとは言えず、部分的にクライアントで Vue を取り入れるのは難しい状態でした。

部分的リプレイスの要件

  • 既存の jQuery で書かれている JS をモダンに実装
  • 将来的には完全な形で BFF にリプレイスする見込み
  • 既存のJSを Nuxt.js + TypeScript で実装し、BFFへ移行時に再利用
  • 既存のJSからの仮想 DOM の破壊を防ぐ

解決案

  • 仮想 DOM を破壊しない、ShadowDOM を採用
  • ShadowDOM を利用するために、Web Components を採用
  • SFC(Single File Component)を実装したあとに、Web Components へビルドできる環境

これまでリプレイスの BFF は Nuxt.js + TypeScript で実装してきていたので、技術的に要求されるギャップはなかったです。

また、SFCで実装してあれば、将来的にBFF(Nuxt.js)で再利用も可能です。

さらに、リプレイスチームだけでなく他のチームでも利用できるようにするため、リプレイスチームのプロジェクトに依存しない構成にしました。

技術構成

利用技術

  • Vue
  • VueCLI
  • @vue/web-component-wrapper
  • TypeScript
  • Storybook

@vue/web-component-wrapper

Vue コンポーネント をカスタム要素(Web Components)としてラップして登録します。

Vue 公式のラッパーです。

Composition API や Props や Vueの Life cycle method などの基本的な機能は、 Web Components にビルド後に問題なく動作します。

不要な Web Components のカスタム要素を生成しないようにするために、コンポーネント名は、prefix に _ で対応しました。Scss の仕組みを参考にしました。

vue-cli-service build --modern --target wc-async --inline-vue --name gds --dest 'dist/public' 'src/components/**/[!_]*.vue'"

@vue/web-component-wrapper

Storybook とどう連携するか

初期は、Storybook を導入していませんでした。

作成した Vue コンポーネントは App.vue に追加し、VueCLI の serve 機能を利用してブラウザに表示して確認しデバッグを行っていました。

しかし、そのままだと手間がかかる上に、リリースして実際に利用される Web Components での動作を常時確認したいので、カスタム要素を Storybook 上で管理できるようにしました。

Storybook では、利用するときに SFC をビルドしたコードを import する必要があります。

最初は新しいコンポーネントを追加する都度、該当するコードの import 文を書き換えてましたが、手間がかかっていたので下記コードでカスタム要素をすべてインポートするように自動化しました。

const fs = require("fs");
const scriptPath = "./dist/private";

// ファイル一覧からimportの文を作る
const makeIndexContent = files => {
  let content = "";
  files.forEach(item => {
    if (!item.endsWith(".min.js")) return;
    content += `import "./${item}";\n`;
  });
  return content;
};

// 非公開も含む全コンポーネントのindex.jsを作成
fs.readdir(scriptPath, (err, files) => {
  if (err) throw err;
  const content = makeIndexContent(files);
  fs.writeFile(`${scriptPath}/index.js`, content, err => {
    // eslint-disable-next-line no-console
    if (err !== null) console.log(err);
  });
});

コンポーネント開発をストレスなくやるために

  • stylelint-config-rational-order をStylelint に組み込んで、css プロパティの並び順を一律自動整形しています。

  • SFC を新規実装するときに、コマンドによってテンプレートからファイルを生成するようにして最低限必要なコードが揃っている状態から実装始められるようにしています。

リリースフロー

ビルドされたJSファイルをS3にアップロードします。

アップロード先は package.json の version を元にパスを切ることで、ブラウザキャシュのバグを防ぎ、カナリアリリースを実現させています。

利用したいバージョンのパスを指定して <script> タグで読み込むことによって、定義された Web Components のカスタム要素を利用できます。

利用する Web Components のJSだけが部分ロードされるので、コンポーネントの量が増えても問題ありません。

f:id:tiwu:20200416194503j:plain

苦労した点

  • ShadowRoot 内で document.* が使えずクッキーなどが取得できませんでした。

  • ビルドの監視や、 hot reload など行いたかったが、まだ対応できてないです。毎回全てのSFCをビルドしているので、確認まで数秒時間がかかってしまいますし、ビルド実行を自動化できてないです。

感想

SFC から Web Components へビルドし、利用できる方になるまでの過程で煩雑な作業をひとつひとつ解決してきており、 コンポーネント実装以外の工程は、設けているコマンドを実行することでまかなえるようしています。

初めてGDSを触る人にも易しい構成になっていきています。

独立したシステムで SFC を開発とテストすることは、配備される環境で考慮することが少なくて済むので、コアロジックに集中ができます。

しかし、SFC は Vue.js を前提に実装できることから容易にたくさんの仕様を詰め込んでしまうことが可能です。

コンポーネントの粒度は考慮する必要があります。

ただし、粒度が大きいコンポーネントを作ってしまっても、今回は TypeScript で実装しているので、後で分割するときにコードの整合性はコントロールしやすいと感じました。

レガシーな環境でも、モダンなコードで実装されたコンポーネントを追加できるので、今後は開発するのに継続的な効果が期待できそうです!

最後に

GDS の開発環境は、将来的には公開して利用できる様にしていきたいと考えているのでご期待下さい。

また、GameWith にイケてるコンポーネントがこれからたくさん作られていくので、ぜひ探してみてください!

GameWithのDeveloper向けTwitterアカウントも開設しました。
もくもく会の告知やブログの更新情報などを発信するので良かったらフォロー宜しくお願いします!

twitter.com

GameWith iOS もくもく会 #20 開催しました #GameWith #TechWith #gamewith_moku2

こんにちは!
GameWithのiOSエンジニアのkyamです。
2月20日(木)にGameWith主催で第20回目のもくもく会を開催しました!

GameWith iOS もくもく会 #20

https://gamewith.connpass.com/event/166701/

前回のiOSの開催が9月だったので5ヶ月振りの開催となりました。
今回は社内1人、社外2人の計3人が集まってくれました!

当日の流れ

f:id:keeetaka:20190930141449p:plain

最初にお知らせ、次に自己紹介と今日の作業内容を発表して、軽食を挟みながら2時間程もくもくし、最後に進捗の発表という流れで開催しました!

進捗発表

以下がメンバーの取り組んだ内容です。

  • 個人アプリの開発環境整備
  • 個人アプリ(日記アプリ)のUIPageViewを使ったUIの実装
  • 個人アプリにFirebaseを使ったPush通知の実装

といった風に全員が個人アプリに関する取り組みでした!
今回は人数も少なかったため開発中のアプリについての雑談や知見共有など密なコミュニケーションも終了後に行われました。

以下はお知らせになります!

お知らせ1

GameWith iOSもくもく会参加者用のslackワークスペースを作成しました!

作業中に気軽に質問などを投げることができ、誰でも返答できるようにし、参加者にとって勉強会自体の効率をよりあげたり、勉強会前後のコミュニケーションを高めたいという意図からです。 またちょっとした事務連絡などもSlackで行えるようにしました。

既に6人の方が参加してくれました!

お知らせ2

GameWithのDeveloper向けTwitterアカウントを開設しています。
もくもく会の告知やブログの更新情報などを発信しているので良かったらフォロー宜しくお願いします!

twitter.com

最後に

参加していただいた皆様ありがとうございました!
3月以降も基本的に毎月開催していく予定なので、興味のある方は是非参加してください。

GameWith フロントエンド もくもく会 #19 開催しました #GameWith #TechWith #gamewith_moku2

GameWith のエンジニアの tiwu です。

1月30日(木)にGameWith主催で2020年最初の第19回目のもくもく会を開催しました!

GameWith フロントエンド もくもく会 #19

gamewith.connpass.com

新年1発目のテーマは僕自身が関心を高く持っているフロントエンドを採用しました。

もくもく会は社内1人、社外5人の合計6人で開催しました!

f:id:tiwu:20190329134140p:plain

もくもく会は最初にお知らせ、次に自己紹介と今日のもくもく内容を発表して、もくもくし、最後に進捗発表という流れで開催しました!

2時間ほどもくもくしたら本日の進捗の発表をしました!

  • web components で作られた 格闘ゲーム便利ツールにフレーム比較機能を追加
  • Chart.js を利用したグラフの表示
  • python + django で作られた Web アプリのコードリーディング
  • Udemy で Vue.js の勉強
  • gulp + jQuery で作られたポートフォリオを Vue.js に置き換え&Netlify で公開
  • Vue.js + TS で Web アプリを作成

といった様々なテーマの取り組みのもくもく会でした!

最後に

参加していただいた皆様ありがとうございました!

今年もよろしくおねがいします!!

GameWithのDeveloper向けTwitterアカウントを開設しました。

もくもく会の告知やブログの更新情報などを発信するので良かったらフォロー宜しくお願いします!

twitter.com

PHPerKaigi 2020 にスポンサーとして協賛します #GameWith #TechWith #phperkaigi

こんにちは。GameWith のエンジニアの tiwu です。

この度、2/09, 10, 11 に開催されるPHPerKaigi 2020 に協賛をさせていただきます!!!

PHPerKaigi 2020

phperkaigi.jp

PHPerKaigi は去年も開催されており、弊社は去年の PHPerKaigi も協賛させていただきました!

tech.gamewith.co.jp

今年もとても楽しみにしています!

PHPer チャレンジ

去年も開催された PHPer チャレンジが今年も開催されます!

blog.phperkaigi.jp

PHPerチャレンジとは

PHPerチャレンジは会場内外に隠された「PHPerトークン」を探しだし、イベントサイトに入力して得られたスコアを競う企画です。 PHPerトークンは「記号の# + 任意の文字列」の形をしています。

PHPer トークン

弊社もこの PHPer チャレンジに参加しており、このブログのどこかに、 PHPer トークンを仕込みました!!!!

頑張って見つけてみてください🙏

最後に

GameWith では一緒に働く仲間を募集中です!

毎月もくもく会なども開催しているので、気軽に連絡ください!

recruit.gamewith.co.jp

ツイッターアカウントを開設しました!

ブログ更新情報や、イベントの開催など告知していきます!

twitter.com