Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Datapiaのフロントエンドについて

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for danny danny
November 12, 2020

 Datapiaのフロントエンドについて

Avatar for danny

danny

November 12, 2020
Tweet

More Decks by danny

Other Decks in Programming

Transcript

  1. Datapiaについて
 3 • フロントエンドがReactでバックエン ドがRuby on Rails • ログインページでログインした後は Single

    Page Application構成 • フロントエンドの規模感 ◦ およそ3万4千桁 (TypeScript, TSX) ◦ React Component数は373
  2. 構成
 フロントエンド • TypeScript • React • Redux ◦ React

    Redux ◦ TypeScript FSA Reducers • React Router • styled-components • Apollo Client バックエンド • Ruby on Rails (GraphQL API Server)
  3. Railsでwebpackを使う
 Webpackerを使わない理由 • フロントエンドエンジニアじゃなくても扱えるように整備された状態で使えるのはメ リットたが、その反面細かい部分まで調整したい場合はいじりずらい ◦ webpackの設定ファイルと書き方が違う ◦ webpackのあの設定、Webpackerだとどう設定するのかを調べないと分からない webpack-assets-pipleline

    • webpackで生成したファイルのハッシュ値付きのURLが入ったmanifest.jsonを生成で きる ◦ Railsでassets precompileする必要がなくなる ◦ Railsでもwebpackを使って開発できるようになる 参考 • https://infinum.com/the-capsized-eight/squeezing-webpack-into-backend-fram eworks 5
  4. Babelの設定
 6 "presets": [ [ "@babel/preset-env", { "targets": { "chrome":

    "75", "firefox": "68", "edge": "18" }, "useBuiltIns": "usage", "corejs": 3 } ], "@babel/preset-react", "@babel/preset-typescript" ] useBuildIns usage • 対応ブラウザのバージョンを定義して おくと、その定義をみて自動で必要な polyfillのみを使ってビルドされる
  5. ESLintで禁止してるもの
 import/no-default-export • 任意の名前でインポートできるので後から名前を変えたり、使われてる箇所をさがすときに大変な ため no-restricted-syntax • TSEnumDeclaration ◦ 後から入ったエンジニアがenumかUnion型どっち使うのか混乱しないように

    • TSInterfaceDeclaration ◦ 後から入ったエンジニアがtypeとinterfaceどっち使うのか混乱しないように ◦ interfaceは既存の定義されてる名前のまま拡張できるので公開するライブラリで使う方針 • ForInStatement, ForOfStatement, VariableDeclaration[kind='let'] ◦ 副作用が起きない書き方によせるため • LabeledStatement ◦ go to使われるとコード読みづらくなるため • WithStatement ◦ withで省略されると出どころが追いづらくなってコードが読みづらくなるため 参考 • https://github.com/airbnb/javascript/blob/master/packages/eslint-config-airbnb-base /rules/style.js#L339-L357 7
  6. 例外通知
 8 componentDidCatch(error: Error, errorInfo: ErrorInfo): void { Sentry.withScope((scope) =>

    { scope.setExtras(errorInfo as any) Sentry.captureException(error) }) this.setState({ hasError: true }) } React Error Boundaryで補足した例外 をSentryに送る • Redux Storeの中身をsentryに送信 するような実装はしない ◦ 送ったほうがデバックはしやすくな るが、Redux Storeはバックエンド のAPIからユーザーの情報が入って いて、内容によっては外部のサービ スに送ってはまずいものが含まれて ることがあるため
  7. React Hooksの使い方
 9 const history = useHistory() const { id

    } = useParams<{ id: string }>() const { currentOrganization, currentUser, user } = useSelector((state: RootState) => ({ currentOrganization: state.organization.currentOrganization, currentUser: state.user.currentUser, user: state.user.user, })) const dispatch = useDispatch() useEffect(() => { dispatch(actions.user.fetchUser({ id })) }, [id]) APIで取得した値をRedux Storeから取り出 して表示する • useHistory • useParams • useSelector • useDispatch
  8. バックエンドとの通信
 12 function errorLink(): ApolloLink { return onError((response: any) =>

    { if (response.networkError && response.networkError.statusCode === 401) { location.href = '/users/sign_in' } }) } Apollo Client • GraphQLクライアント SPA特有の問題 • ログインセッションが切れた状態で画 面を操作するとなにも反応がなくなっ てしまう ◦ ApploLinkでonErrorをハンドリングし てログインページにローケーション