じまろぐ

めめ

React + Typescriptプロジェクトでplugin-styled-componentsを使うときの設定

  • styled-components使ってる
  • env !== "production" のときにクラス名にファイル名が入るようにしたい
  • babel-plugin-styled-componentsがある
  • TypeScriptだとこのプラグインは効かない
    • ts-loaderでトランスパイルしてるから
  • storybookでも使いたい

という感じで、ts-loaderを使ってるのでTypeScriptプロジェクトの場合は typescript-plugin-styled-components を使う必要がある。babelでやってる場合は babel-plugin-styled-components で大丈夫なはず。

設定

webpack.config.js で ts-loaderのoptionを設定する。

const path = require("path");
const createStyledComponentsTransformer = require("typescript-plugin-styled-components")
  .default;
const styledComponentsTransformer = createStyledComponentsTransformer({
  displayName: process.env.NODE_ENV !== "production",
  getDisplayName(filename, bindingName) {
    // コンポーネントのパスがクラス名に入るように
    return path.relative(__dirname, filename);
  }
});

module.exports = {
  // 省略
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: "ts-loader",
        options: {
          onlyCompileBundledFiles: true,
          getCustomTransformers: () => ({
            before: [styledComponentsTransformer]
          })
        }
      }
    ]
  },
  // 省略
};

storybookで使う

"@storybook/preset-typescript" を使ってる前提

.storybook/main.js

const path = require('path');
const createStyledComponentsTransformer = require("typescript-plugin-styled-components")
  .default;
const styledComponentsTransformer = createStyledComponentsTransformer({
  getDisplayName(filename, bindingName) {
    // コンポーネントのパスがクラス名に入るように
    return path.relative(path.resolve(__dirname, "../") ,filename)
  }
});
module.exports = {
  stories: [
    '../src/**/*.stories.tsx'
  ],
  addons: ['@storybook/addon-actions/register','@storybook/addon-actions', {
    name: "@storybook/preset-typescript",
    options: {
      tsLoaderOptions: {
        transpileOnly: true,
        getCustomTransformers: () => ({
          before: [styledComponentsTransformer]
        })
      },
      include: /\.tsx?$/
    }
  }]
};

でクラス名にファイルのパスが入るようになった。

サイボウズに転職して1ヶ月たちました

TL;DR

  • ピクセルグリッドからサイボウズに転職しました
  • 社会性を取り戻すための戦いです
  • いい感じにやってます

f:id:nakajmg:20200201173914j:plain

2019年10月末にピクセルグリッド社を退職しました。

辞めたときは特に次が決まってたわけではないですが、のんびりしながら次を探しました。

そして2020年1月からサイボウズ株式会社で働き始めました。

サイボウズについては後ろの方で。

ピクセルグリッドでやってたこと

在籍期間は約6年で、自分のキャリアの中では最長です。最短はDMMの7ヶ月。

ピクセルグリッドはフロントエンドに特化している会社で、主な業務はクライアントワークです。 自分は入社当時から退職するまで、ひたすらJavaScriptでSPAを作っていました。入社当時はBackbone.jsがメインだった記憶。

Vueが出てからはVueを採用することが多かったです。Vue関連のことをいろいろと発信していましたが、Vueにこだわっているわけではないので、Reactも使っていましたし、最後の仕事はGatsby.jsでWebサイトの作り直しとか、いろいろやっていました。

ピクセルグリッドの環境

各メンバーがそれぞれ何かに強い人ばかりだったので、勉強になることが多かったです。 自社の技術系メディアCodeGridを運営していて、ここでいろいろな技術についての文章を書いていました。

6年で100本の記事。

app.codegrid.net

この経験のおかげで技術文書を書くスキルがつけられたと思います。

すこし前ですが技術書典にも参加して、Vueの本を書きました。

この本は商業版も出してもらえて、自費出版分と合わせて合計1000部ほど売れました。購入してくれた方、ありがとうございます 。

フルリモート

ピクセルグリッドの基本的な働き方はリモートワークです。オフィスはありますが、週に1回行くか行かないかくらいでした。

nakajmg.hatenablog.com

nakajmg.hatenablog.com

この記事を書いたのは3年前くらいなので、リモートワークについての考えは今はだいぶ変わっています。

出社とリモートとどっちがいいとかじゃなく、いろいろな要因に合わせて自由に選択できたらいいよね、という感じです。

転職した理由

個人的な要因がほとんどです。

クライアントワークに少しだけ飽きていたという面は少なからずありますが、慣れが進みすぎて、可処分時間を増やすためにサクッといい感じに作りきる、みたいな働き方になっている節がありました。 ほそぼそと個人プロジェクトこそやっていたものの、技術的な意欲は年々減少していっていたように思います。

退職の半年前くらいからこれじゃいかんな〜と思いはじめて、環境を変えるか〜となりました。

社会性の喪失

元々が出不精なので、リモートと合わせてどんどん外に出なくなっていっていたのも理由の一つです。 一度も家を出ない週もざらにあり、人との話し方も忘れかけてました。

週に1回以上は勉強会に出ていましたがほぼ行かなくなり、妻以外の人間との接触機会がほとんどなかったです。

このままだとこの先どこかで働き続けるの無理になりそう、と思うようになりました。

副業を始めた

ちょうど1年前くらいから副業をはじめました。

転職してコミットできる量は減りましたが、ROXXさんには今でも継続してお手伝いさせてもらっています。

nakajmg.hatenablog.com

副業始めたてのころは副業先のオフィスに出向いて作業したりと、リハビリみたいなことをしてました。 また自社サービスを運用・改善していくという体験ができたので、クライアントワーク以外のイメージもだいぶつかめました。 そしてこの時期から「出社イケるんじゃね?」と思うようになっていきました。

サイボウズ

フロントエンドエキスパートチームの存在を認知したことが、サイボウズに興味を持ったきっかけだったと思います。

blog.cybozu.io

自分のやりたいこと&キャリア的にフロントエンドを続けていきたいと思っていたので、フロントエンド専門でやるようなチームがあるということにワクワクしたのを覚えています。

サイボウズのエンジニアとはつながりを持っていなかったので、サイボウズに勤めている元同僚の奥さんにコンタクトを取ってチームにつないでもらいました。

面接とか

カジュアル面談をしてもらったあとにフォームから応募して、面接3回を経て内定を頂きました。

面接ではいろんな人とお話しました。多拠点の人とzoomでつないで面接したのが印象的でした。 3回目ではエラい人が出てきたりもしました。

サイボウズの環境

働き方という面でとにかく進んでるな、というのが第一印象。 フルリモートからオフィスに出社するスタイルに変わることへの不安がそれなりにあったんですが、初週には払拭されてました。 自分で自分の働き方を宣言する、そしてそれが滅多なことがない限り受け入れられる。

cybozushiki.cybozu.co.jp

会社の規模のわりにめちゃくちゃ自由で働きやすく、この風土を作るのにいろいろあったんだろうなぁと先人に感謝する日々です。

サイボウズでの仕事

フロントエンドエキスパートチームという、特定のプロダクトに所属しない形でフロントエンド領域の支援をするチームにいます。

プロダクトにそこそこの歴史があるので、アーキテクチャを刷新する基盤作りなどの支援をやっています。

サイボウズではなにごともモブですすめるのが主流で、とにかく寄ってたかって課題を倒していく感じです。助かる。

今はClosureをReact + TypeScriptで置き換えるやつをやっています。

社会性と社交性

サイボウズの人たちは、大体の人が落ち着いていて余裕がある感じです。 巻き込み力が高い人が多く、チーム以外の人たちとも自然に交流の機会ができてます。感謝。 部活動もあり、自分は運動系の部活動に参加したりしてます。フットサル初めてやった。

入社1ヶ月にして社会性も社交性もかなり取り戻した感覚があります。自分でもびっくりするくらい人と交流しています。

1月はほぼフルでオフィスに出社しました。リモートワークも可能ですが、最初の方はできるだけ物理出社に寄せないと思ってやりました。 オフィスが自宅から近いのもありますが、オフィス内の環境が良く、ストレスなく働けているので、リモートに寄せなくてもやっていけそうだなという手応えがあります。

いい感じに続けられそうです。

おわりに

前職がめちゃくちゃ自由だったのでどうなるかな〜と思ってましたが、同じくらい自由に楽しく働けてます。

誰にでもオススメってわけではないですが、ライフステージの変化とかで思うことがあったり、今の働き方に疑問を持ってるような人にはいいのかもな〜と思います。 気が向いたら応募してみてください(自分に人事権はない)。

cybozu.co.jp

⭐🍠 https://www.amazon.jp/hz/wishlist/ls/1XOSM113L3K5O

2019年 買ってよかった家電・家具

今年は7月に引っ越しをした。

そのタイミングでこれまでツギハギしてきた家具たちを全部捨てて心機一転、統一感のある部屋を作ろうと決意。

家具家電での出費はなかなかのものだったけど、「良いものを長く使っていきましょう」という合意が夫婦間で取れたので、結果的にすごく満足度も高く、妻も自分も今の家が大好きという状態になれた。

全部乗せるとすごい数なので、生活してる上で「買ってよかったな〜」とちょくちょく思うやつをピックアップして紹介。

プロジェクタ

部屋の壁が広くなったのでプロジェクタのスクリーンにできそうだなと思い購入。ダイニングテーブルの横に置いて動画ながしたりしてる。

  • 超短焦点なので壁際に置けて邪魔にならない
  • 移動も楽で使い勝手がよい
  • 明るさは微妙
    • 昼間はカーテンを閉めないとよく見えない
    • 部屋の照明が白系だと夜でも使いづらそう

家にお客さんが来たときにBGMとしてYouTubeとかで自動再生しておくと「あ、懐かしい〜」みたいな会話も生まれてよいですね。

テレビ

4Kモニタでもよかったんだけど、大きさを求めるとコスパよくない感じなのでテレビにした。

LGのテレビ用OSが乗っていて、YouTubeとかNetflixとかアプリが入れられてリモコンで一発起動できるのが使いやすい。

以前はテレビにPCをつないで視聴していたので体験が良くなった。

あとOSにアプデが入ってAirPlayに対応したので、macから画面を飛ばせるようになって大変便利。画質も十分。

(自分が購入した時より5万くらい値が下がってるので買い時かも)

スピーカー

BOSE SOUNDBAR 700 ワイヤレスサウンドバー Amazon Alexa搭載 ボーズブラック

BOSE SOUNDBAR 700 ワイヤレスサウンドバー Amazon Alexa搭載 ボーズブラック

  • 出版社/メーカー: BOSE(ボーズ)
  • 発売日: 2018/10/11
  • メディア: エレクトロニクス

テレビにつないでる。

AirPlayにも対応してるので、リビングで音楽聴きたいときにも使える。

リアスピーカーとウーハーもつけたけど、ご近所迷惑になりそうだったのでウーハーは外した(悲しい)。

音はめっちゃいい。

BOSE HOME SPEAKER 300 スマートスピーカー Amazon Alexa搭載 ラックスシルバー

BOSE HOME SPEAKER 300 スマートスピーカー Amazon Alexa搭載 ラックスシルバー

  • 出版社/メーカー: BOSE(ボーズ)
  • 発売日: 2019/08/22
  • メディア: エレクトロニクス

仕事部屋用に。

これもAirPlayに対応してるので便利。

低音な結構効いててこの大きさのわりにパワフルな感じ。

ヘルシオ

うちは料理をほとんどしないので冷食とか惣菜とかお弁当を温める用。

蒸気で温めるやつは時間かかるけど美味しく温められてよい感じ。

ダイニングテーブル

www.low-ya.com

はじめてのダイニングテーブル。

仕事机以外に椅子に座りながらPC開ける場所が欲しかったので。ベンチが物理的にも心理的にも座りやすい。

横に並んでご飯が食べられるのもよい感じ。

www.dinos.co.jp

仕事部屋(兼ゲーム部屋)の飾り棚として。

立体物のグッズをディスプレイするのにとてもよい。

そのた

滑らないハンガー。

Tシャツがよれないし、コートとかも滑らないので大変使いやすい。

脚立

椅子とかに乗るの危ないので。

見た目がいいのでリビングにインテリアとして置いてる。

収納用。

経験上、中身が見えない収納はそのまま使われず存在がないものになるので透明なやつに。

ちょうどいいサイズかつ重ねられるので使いやすい。

おわりに

家具家電はだいたい揃ったので、来年はインテリアとかディスプレイとか力を入れたい。

Vueでsvgファイルをいい感じに扱う

svgtemplateにコピペする暗黒時代の終わりを告げる

vue-svg-loader を使う

github.com

vue-svg-loaderを使うとsvgファイルをvueコンポーネントとして扱えるようになる

<template>
    <a href="https://github.com/vuejs/vue">
      <VueLogo />
      Vue
    </a>
</template>
<script>
import VueLogo from './public/vue.svg';

export default {
  name: 'Example',
  components: {
    VueLogo,
  },
};
</script>

Nuxtで使うときは nuxt.config.jsbuild.extend でloaderを設定

ドキュメント: https://github.com/visualfanatic/vue-svg-loader/#basic-configuration

export default {
  build: {
    extend(config) {
      const svgRule = config.module.rules.find(rule => rule.test.test('.svg'));
      svgRule.test = /\.(png|jpe?g|gif|webp)$/i

      config.module.rules.push({
        test: /\.svg$/,
        loader: 'vue-svg-loader',
      })
    },
  },
}

これでsvgファイルをコンポーネントとして好きに使える

動的なパス指定でsvgを読み込むコンポーネントを作る

svgの数だけ import して components に登録するのもめんどうなのでsvg読み込むvueコンポーネントを作る

<template>
  <component :is="svg"/>
</template>

<script>
export default {
  name: "SVGElement",
  props: {
    name: {
      type: String,
    },
  },
  computed: {
    svg() {
      return () => import(`~/assets/img/${this.name}.svg`)
    }
  }
}
</script>

この例だと src/assets/img/ の中から name で指定したファイル名のsvgを読み込める。 ~/assets/img/${this.name}.svg の部分は自分の環境と使い方に合わせてお好きなように

使う側はこんな感じ

<template>
  <div>
    <SVGElement name="bars"/>
  </div>
<template>

<script>
import SVGElement from "~/elements/SVGElement"
export default {
  name: "ProjectsPage",
  components: { SVGElement },
}
</script>

これがVueでsvgを扱う体験の一番いいやつ、と思う

GridsomeでGraphCMSのデータを使う

gridsome.server.js

const axios = require('axios')

module.exports = function (api) {
  api.loadSource(async ({ addContentType }) => {
    const res = await axios.get(process.env.GRIDSOME_GRAPHCMS_ENDPOINT, {
      params: {
        query: `query {
          posts {
            id
            title
            slug
            date
            cover {
              thumbnail: url(transformation: {
                image: {
                  resize: {
                    width: 200
                    height: 200
                    fit: crop
                  }
                }
              })
              url
            }
            tags {
              name
            }
            category {
              name
            }
            body {
              html
            }
          }
        }`
      },
      headers:
        {
          Authorization: process.env.GRIDSOME_GRAPHCMS_TOKEN
        }
    })
    const {posts} = res.data.data
    if (posts) {
      const contentType = addContentType({
        typeName: 'Posts',
        route: '/posts/:slug'
      })
      posts.forEach(post => {
        contentType.addNode(post)
      })
    }
  })
}

addNode に追加したやつから自動でschemaを作ってくれて page-query とかから取得できるようになる。

axiosでGraphCMSのデータ取得

API Explorerでこんなクエリで取得するやつ

{
  posts {
    title
  }
}

jsから

const endPoint = "https://api-apeast.graphcms.com/v1/xxxxxxxxxxxxxx/master"
const authToken = "xxxxxxxxxxxx"
const res = await axios.get(endPoint, {
  params: {
    query: `query {
      posts {
        title
      }
    }`
  },
  headers:
    {
      Authorization: authToken
    }
})
console.log(res.data)

※ フロントから叩く場合はfunctionsとかかませてtokenは環境変数で。

Nuxtプロジェクト内で使われてないコンポーネントを探す

  • プロジェクトが進むと役目を終えた使わないコンポーネントが出てくる
  • 放置していくとどれが使っててどれが使ってないかわからなくなってくる
  • 使わなくなったコンポーネントの代わりに作られたコンポーネントの名前が似てると最悪みがある
    • 「このコンポーネントだろう」と思って変更してみたら「残念!そっちじゃありません!」みたいなやつ
  • 使わなくなったタイミングで削除するのがベストだけどそうもいかないのが現実

という感じで、使われなくなったコンポーネントを削除したい。

使われなくなったコンポーネントを見つける

webpackのプラグインでビルド時に使われていないコンポーネントが探せる。

unused-files-webpack-pluginを使って一覧を出す

github.com

nuxt.config.jsbuild.plugins に追記する。

const { UnusedFilesWebpackPlugin } = require('unused-files-webpack-plugin')

export default {
  // 省略
  build: {
    plugins: [
      new UnusedFilesWebpackPlugin({
        patterns: ['src/**/*.vue', 'src/**/*.js']
      })
    ],
  }
}

patterns はビルド時に使われてないファイルをフィルターするオプション。

['src/**/*.vue', 'src/**/*.js'] を指定すると、 src/ ディレクトリ内でビルド時に使われてない .vue.js ファイルが一覧で出力されるようになる。

build の実行

nuxt build を実行すると、次のような出力が得られる。

...

Entrypoint app [big] = aaa5230fc2fc8d2d7264.js a4af7f6bc00ce5633bbf.js b2deabd0e786c068c1e3.js 9d7368b9e3e8d6ddd2a4.js

WARNING in 
UnusedFilesWebpackPlugin found some unused files:
src/components/lp/AppFooter.vue
src/components/lp/ShareButtons.vue
src/components/lp/SocialLinks.vue
src/components/organisms/AppFooter.vue
src/components/organisms/AppPage.vue
src/modules/generate_route.js

...

ここに出てきたファイルを ビルド時に使われてない = 不要 とみなして削除。

実際は使ってないけど import されてるファイルは出てこない

使わなくなったけど、使われているコンポーネントから import されてる場合、使われてないファイルとしてはでてこない。

たとえば次のような場合

<script>
import AppFooter from '~/components/lp/AppFooter'
export default {
  layout: 'lp'
}
</script>

AppFooter は使われてないけど import しているコンポーネントが使われているのでunusedではなくなる。ESLintなりでチェックして潰していきましょう

Nuxtプロジェクトじゃなくても

unused-files-webpack-pluginは名前の通りただのwebpackのプラグインなので、webpackでビルドしてるプロジェクトなら使えます