blog.unresolved.xyzblog.unresolved.xyz

LLM時代におけるソフトウェア開発について思うこと

LLM(大規模言語モデル)がソフトウェア開発の現場に浸透してきて、「開発がつまらなくなった」という声を耳にすることがあります。本当にそうなのか、自分なりの考えをまとめてみたいと思います。

Table of contents

LLMはソフトウェア開発をつまらなくしたのか?

「つまらなくなった」と感じる人と、そうでない人それぞれがいると思います。

そして、僕はむしろソフトウェア開発が非常に楽しくなった、と感じる側です。

過程を目的にする人と、目的のための手段として捉える人

エンジニアリングの楽しみ方には、大きく分けて二通りあるのではないでしょうか。

一つは、過程そのものを目的にしている人です。コードを書くこと、デバッグで原因を突き止めること、設計を考えること、そういった行為そのものが楽しい。手を動かして、頭を使って、何かが形になっていくプロセスに没入する喜びがある。

もう一つは、目的のための手段として捉えている人です。プロダクトを作る、問題を解決する、価値を届けることが目的で、コードを書くのはそのための手段。早く正確に届けられれば、手段は何でもよい。

LLMは後者にとっては強力なツールです。やりたいことの実現が早くなるし、ボイラープレートや定型的な処理は任せられる。一方で前者にとっては、「自分がやりたかったこと」をAIに任せる形になり、達成感や没入感がほとんどなくなってしまうというのは想像に難くないと思います。

以前書いた「労働と仕事」の話にも通じる部分があると思います。働くことがそれ自体を目的とした純粋な行為であってほしい、という気持ちを持っている人にとっては、LLM時代の開発は少し物足りなく感じるのかもしれません。

これからも価値のあるソフトウェアエンジニアであるために

LLM時代において価値のあるソフトウェアエンジニアであるためには何が重要なのかを考える機会も増えました。

改めて言うまでもなく、コードを書く量ではなく、何を作るか・なぜ作るかを決める力がより重要になると思います。つまり、指示を出す側になることです。

文脈の理解、要件の言語化、優先順位づけ。技術的負債をどう扱うか、アーキテクチャをどう設計するか。こういった判断は、AIに丸投げしにくい領域です。ここで適切な判断ができるかどうかが、これからのエンジニアの価値に直結するのではないでしょうか。

ソフトウェアは一度作るとサービス終了までメンテナンスコストが伴います。人員が採用しづらいテックスタックを採用してしまっていれば採用のコストもあがりますし、ドメインの複雑度の許容量を見誤れば人間の認知負荷やバグの発生率に影響します。

これらは一般的にはテックリードなどのポジションの人が「最終的に自分で責任を取れる」という前提で意思決定してきた領域なのではないかと考えています。

これらを考えていた結果、僕は最近「ソフトウェアエンジニア」という言葉より「ビジネスパーソン」という言葉を使うことが多くなりました。

指示を出す先という観点でのAIと人間の差異

ほんの数ヶ月前までは、AIと人間それぞれに指示を出す際の違いとして、「AIには明確に指示しなければならず、人間には曖昧な指示が許容される」というふうに考えていたことがありました。

しかし最近はほとんどこれが気にならないほどにLLMが進化してきたと感じます。

「作業の成果」という観点で今まだ残っている差異があるとすれば、人間へ指示を出した場合は稀に期待した成果を超えてくることがある、という点でしょうか。

しかしこれも、AIが近いうちに実現可能になるでしょうし、指示者の能力にも影響する指標であるため、AIという文脈だけで論じるのは難しいと思っています。

それでも、何を作りたいか、何が欲しいかを言語化する力は、AIに限らず人間にも指示を出す際に重要なので、これからも価値が下がることはないと思います。

まとめ

LLMがソフトウェア開発をつまらなくしたかどうかは、エンジニアリングの楽しみ方の違いによる部分が大きいと思います。過程そのものを目的にしている人にとっては、確かに物足りなく感じることもあるかもしれません。

一方で、これからは「指示を出す」「何を作るか決める」力がより重要になります。そのための訓練として、言語化する力、要件を定義する力、Issue を書く力が、これまで以上に価値を持つ時代になってきているのではないかと思います。

Node.js(NestJS)のビルドパフォーマンスを改善する

NestJSで構築している担当プロダクトのビルドが地味に遅くなっているのは薄々気づいていたのですが、ついにデプロイ時にOOM Killされる事態になったので本腰を上げて調べてみました。

tsc でトランスパイルの効率を調べる

tsc はトランスパイルするだけでなく、解析をする機能もいくつかついていて、今回はそれにだいぶお世話になりました。

extendedDiagnostics

generateTrace

extendedDiagnostics による解析

まず1つ目の extendedDiagnostics はトランスパイルの内訳を時間や行数として出力してくれるもので、このような数値になりました。

一般的な数値がわからなかったのでAIに食わせてみると、このような見解でした。

| 指標 | 値 | コメント | | --- | --- | --- | | Memory used: | 約2GB(2035800K) | 通常 Nest アプリの tsc では 400〜800MB 程度。明らかに高い。 | | Lines of Definitions: | 2,212,971 行 | 明らかに外部ライブラリ or 型定義が大量。→ node_modules/@types や SDK類の影響が濃厚。 | | Identifiers: | 2,286,631 | 通常数十万程度。TypeScript の型システムが相当な負荷に。 | | Symbols: | 1,440,909 | 同上。依存型の解決コストが大きい。 | | Types: | 148,758 | 高め。ジェネリクス + DTO/Entity の組み合わせが複雑かも。 | | Instantiations: | 692,686 | 非常に多い。型推論が深く入り込んでいる可能性大。 |

確かにメモリ2GBは使いすぎですし、型定義も異様に多いのが気になるところです。

すぐに思いついたのが、依存している外部APIのOpenAPI定義からSDKを作って利用していたので、おそらくこれがBarrelで不要なコードを読み込ませてしまっていたのではないか、というものです。

SDKは Hey API で作成していたので、依存していた6つのAPIそれぞれを利用しているパスのみSDKを生成するようにした結果がこちらです。

ざっと比べるとこのような感じです。 メモリは半分以下になり、型定義は3分の1ほどに減りました。

generateTrace による解析

generateTrace は extendedDiagnostics と同じように tsc のオプションで、これをつけるとトレース情報をファイルとして出力してくれます。

詳細は末尾に記載する記事に任せますが、だいたいこのような実行方法です。

出力されたファイルはChromeの chrome://tracing/ に食わせるとそれぞれのプロセスを可視化してくれます。

Refs

TypeScript プロジェクトのコンパイル時間を改善してみた話

PostgreSQLで検証を無効にしてFKを設定する方法

既存テーブルにFKを追加しようとしたときにDBに負荷がかかるのを避けたいので、検証なしのFKを張る方法をメモします。

こんな感じで NOT VALID をつけておけばよいです。

検証がずっと無効だと困るので、別途検証を有効にします。

テーブルのON DELETE、ON UPDATEの確認

参考

PostgreSQL: Documentation: 17: 51.13. pg_constraint

sql - How to know if a foreign key has cascade on delete clause - Stack Overflow

VitestでTypeScriptのトランスパイルエラーをエラーにしてほしい問題

Next.js + Vitestの構成で、テストファイル内で型エラーが起きてもテストがグリーンになってしまったので困りました。

JestはしてくれるのになぜVitestはしてくれないのか・・・と思ったら、タイムリーなIssueがありました。

Does not report TypeScript compilation errors · Issue #4295 · vitest-dev/vitest

結論

自分で型チェックしましょう。

Vitest導入覚書き

Turborepo環境に配置したNext.jsにVitestを入れようとして結構詰まったので、いろいろメモしておきます。

Next.js公式のサンプル

公式にもサンプルが配置されています。

next.js/examples/with-vitest at canary · vercel/next.js

コードを見た限りだとtesting-library/jest-domが有効にされていないように見えるので、matcherが使えない気がします。

testing-library/jest-domがVitestをサポート

このPRでサポートされました。

feat!: local types, supporting jest, @jest/globals, vitest by jgoz · Pull Request #511 · testing-library/jest-dom

v6.0.0のリリースに入ったようなので、比較的最近導入されたもののようです。

Release v6.0.0 · testing-library/jest-dom

これによって、これまでは vitest.setup.ts などで

のようにしていたのが、

だけで良くなりました。

導入した所感

比較的新しめのライブラリなので、ネット上にある情報がほとんど参考になりませんでした。

とはいえJestよりはTypeScriptネイティブな感じがありますし、Viteから派生しただけあってESM標準に作られているのが良かったです。

また、不要なライブラリをほとんど導入しなくて良いので、Jestよりはだいぶスマートな印象です。

とはいえ、JestはNext.jsが公式に next/jest というパッケージでサポートしている(next.js/examples/with-jest)ので、エコシステム的にはJestに軍配が上がるかなという印象です。

参考にさせていただきました

Vitest × testing-library雑めも

Yupで文字列のBool値をBoolean型に変換する方法

こんな簡単なことに15分くらい詰まりました。

NestJS + PrismaでSQLをログに出す方法

以下のようにします。

参考にさせていただきました

NestJS で Prisma の発行するクエリを出力する

class-validatorで特定の場合のみValidationしないようにする方法

例えば IsDateString を使いたいけれど空文字やnullを許容したい場合などです。

以下のように ValidateIf で制御できるようです。

https://github.com/typestack/class-validator#conditional-validation

Next.jsでもdrop_consoleしたい場合の設定方法

webpackでいう drop_console をNext.jsでもやりたい場合です。

next.config.jsにこのように設定します。

NestJSで@Injectable({ scope: Scope.REQUEST })にするとテストが落ちる問題

リクエストごとにスコープを切ってほしいサービスクラスを作ろうとしたら、テストが以下のエラーで落ちるようになりました。

とりあえず言うことを聞いて

のように直したら通りました。

@nrwl/expoでeas buildしようとしてかなり躓いたので供養します

最近Nx + NestJS + React Nativeで開発していて、Classic BuildからEAS Buildに移行しようとしたらとても躓いたので書いておきます。

idb/build/index.cjs is not computed

1つ目はこちらです。

metroがデフォルトだと .cjs を読めないので、 metro.config.js に

を追記すれば解決します。

全体はおそらくこのような形になります。

https://bytemeta.vip/repo/firebase/firebase-js-sdk/issues/6253

リンクが見れなくなったかもしれません・・・

Invalid bitcode version

2つ目がこちらです。

これはXcodeのバージョンに差異があると発生します。

eas.json に

のように設定すれば通ります。

https://github.com/expo/eas-cli/issues/1079

React NativeのBlobがJSのBlobに準拠していない問題について

TypeError: Network request failed when fetching a file:// uri · Issue #2402 · expo/expo

これはとてもエッジケースではないかという気がしますが、ファイルアップロードなどでBlobが必要になる場面は結構あり、気軽に踏み抜いてしまいました。

ワークアラウンドとしてはコメントに上がっている通りXHRを使ってBlobを取得すればなんとかなります。

ちなみにCommunityでも議題に上がってはいますが、放置されています。

Fix Blob Compatibility · Issue #109 · react-native-community/discussions-and-proposals

Issueを書くときに考えていること

最近Issueがわかりづらいなあと思うことが多くて、以下のTweetに感化されて自分が普段Issueを書くときに考えていることをまとめてみたいなと思いました。

ここでいうIssueはOSSのものではなく、仕事でプロダクト開発をするという体のものを指しています。

タイトルにはWhoとWhat、可能ならWhereを入れる

「CSVエクスポートできるようにする」のようなタイトルではなく「ユーザーは注文一覧画面から注文をCSVエクスポートできる」のように「ActorはWhatができる」のようにストーリーベースで書くようにしています。

タイトルから「完了した状態」をわかるようにする、という言い方がわかりやすいかもしれません。

本文は長くしない、議論は入れない

個人的な経験上、本文は空っぽだったり議論がだらっと書いてあったりすることが多かったです。

ただ、空っぽならまだしも議論が書いてあると結論がわからないですし、リーディングコストがかかるのでできれば避けたいと思っています。

そのIssueを完遂(タイトルの状態を満たす)するのに必要な情報かどうか、というのを考えているという表現が正しいかもしれません。

経緯はSlackであったり口頭の議事がドキュメンテーションツールにあると思うので、本文の末尾にリンクとして貼ったりすることが多いです。

本文にWhyを入れる

本文はIssueを担当する人が背景を知ることで盲目的に作業するのではない、つまりモチベーションを持ってもらうために、Whyを入れるようにしています。

例えばこのような感じです。

本文にHowを入れる

WhyでそのIssueの目的がわかっても、実際に何をどう作ればいいのかというところが詰まっていないので、どういう実現をすればいいのかをHowとして記載します。

ここはタイトルと情報が重複することがありますが、タイトルに情報が多いほうがIssue一覧から詳細に行かずにゴールが見えるメリットを優先しています。

Howは難しいところで、例えば

一覧にペジネーションがある場合は表示されているものだけを出すのか

処理が高負荷になる可能性がある場合はどう考慮するか

など、起票者だけでは拾いきれない、決めきれないことがあったりするので、あまり時間をかけて書ききらずに最低限を書いてスクラムチームでともに作り切るのがいいのではないか、というのが現段階の個人的な解という感じです。

参考

技術力の向上に、issueをちゃんと書けるになる訓練をするのが良いのではと思った - Magnolia Tech

NativeBaseのFabがBottomTab(React Navigation)にかぶってしまう問題の解決方法

BottomTabのheightは useBottomTabBarHeight で取得できるので、このような形で回避できます。

Nest.js + CodeFirst GraphQLでschema.gqlが生成できない問題

このようなバージョンで動きませんでした。

graphql v16とは相性が悪いようです

一旦ダウングレードすれば動きました。

@nestjs/graphql@9.1.1 not compatible with GraphQL@16 · Issue #8551 · nestjs/nest

javascript - NestJS - Expected undefined to be a GraphQL schema - Stack Overflow

AirPlay Receiverが5000番ポートが取ってしまう問題

macOS Montereyからでしょうか。

AirPlay Receiverというもののチェックを外せばすぐに開放されます。

Why is Control Center on Monterey … | Apple Developer Forums

7000番なども取られるようです。

「勢いのあるスタートアップ」を敬遠しちゃう気持ちとか働く理由とか2021年の振り返りとか

今年は約半年くらいずっと転職活動をしていた1年でした。

大変なこともあれば学ぶこともあったり、古い友人に会える機会も増えてそれなりに彩りのある1年間だったような気がします。

そんな中で色んなことを考えたり悩んだりしたので、忘れないように今の気持ちを書き留めておきたいと思います。

Table of contents

「勢いのあるスタートアップ」を敬遠しちゃう気持ち

今回の転職活動は必ず体験入社をさせてもらっているのですが、色んな会社を見させてもらっているうちに表題のような気持ちを持っていることに気づきました。

「小さいチームが好きだからでしょ」といえばそれまでなのですが、なんだかただの天の邪鬼のような気もするのでもうちょっと掘り下げてみたいと思います。

勢いがあるとどんな良いことがあるのでしょうか?

そもそもなんで「勢いがある」ことを売りにするのかを考えてみたのですが、多分こんなところでしょうか?

調達などが終わっていい条件が提示できる

イケてる組織に居るというブランドを得られる

優秀な人と働ける可能性が高い

それなりの未来が保証される = すぐに倒産する可能性が低い

ワンチャンIPOまで居られる

文化がある程度醸成されている

ラダーがある程度決まっていていきあたりばったりな条件にならない

勢いがある会社に惹かれないのはなぜでしょうか?

自分でまとめておいて「結構いいところばかりだな・・・」と思ったりもしたのですが、それでも敬遠しているのはなぜかというのも分析しておきたいと思います。

すでに勢いがあるならもうそのまま頑張ったらいいじゃん、という気持ち

ある程度不確実性が排除された後であることが多そうなので、1リソース以上の貢献の場が少なそう

勢いがある状態まで持っていくフェーズのほうが好き

カオスな中であーでもないこーでもないとワイワイやっているほうが好き

というところでしょうか。

長いこと転職活動を続けて「小さいチームが好き」というのはほぼ間違いないということがわかってきたのですが、そこにつながるものがある気はします。

結局のところ問題ばかりの組織で、その問題に対してチームで立ち向かうのが好きという人間性はありそうだなと思いました。

イケてる = 問題過多の状態は解消したのでアクセルを踏むだけと言ってほぼ間違いないと思いますので、惹かれない最大の理由はそこなのかなと思います。

なぜ働くのか

もう1つたくさん考えたトピックがこれです。

新卒の頃は生きていくためのお金を稼がないと死んでしまうので、「働く理由」なんてものは考えなくても簡単に手に入っていました。

ですが、欲求段階説でいう「安全の欲求」を超えたあたりで「これ以上働くのはなんでだっけ」といった疑問が出てくるのは結構必然的なのかなとも思います。

実際これは結構深刻に悩んだりして、心療内科に行って相談したりもしました。

その時のアドバイスは、「30代前半はやりたいこと、やるべきことを再確認し始める時期だから、その悩みは健全」という話でした。

どうせなら何かしらの病気のお墨付きが欲しかったなあとも思ったりしました。

仕事なんか生きがいにするな

そんな中読んだこの本がすごく参考になりました。(アフィリンクではないです)

Amazon.co.jp: 仕事なんか生きがいにするな 生きる意味を再び考える (幻冬舎新書) eBook : 泉谷閑示: 本

タイトルはちょっとミスリードしている感じはありますが、すごくいい本でした。

同じ悩みを持っている方がいたら薦めたいです。

「中年期の危機」の若年齢化

この本によれば、ユングが3つの精神的危機というものを提唱しているそうです。

それは「青年期の危機」、「中年期の危機」、「老年期の危機」というものです。

青年期の危機は「職業選択や家庭を持つといった社会的自己実現の苦悩」という「人生の出発に近いフェーズ」に関する苦悩を指していて、元は20代から30代ごろまでに表れるものとされています。

中年期の危機は社会的存在としての役割を果たしたのちに湧き上がる苦悩で、「自分らしく生きられているだろうか」、「これまでの延長線として人生を歩んでいいのだろうか」、「生きる上での使命はなにか」といった人間としての在り方に関する苦悩を指して、これは40代から50代に表れるものとされています。

が、本著によれば昨今はこの「中年期の危機」が20代あたりまで若年化してきているのでは、という指摘をしていて、これは僕の悩みと完全に一致していると思いました。

夏目漱石の「それから」の代助に学ぶ仕事に対する姿勢

僕は読書家ではないのでこの「それから」という本を読んだことがないのですが、この代助の仕事に対する向き合い方はとても参考になりましたし腹落ちもしました。(ちなみに即購入して積ん読しています)

この代助は父親から「世のため人のために仕事をしろ」と日常的に言われているのですが、代助はその説教に対して「その利他的に見せかけた動機は結局のところ自身のモチベーションにするための利己的なものでしかない」と心の中で批判し、結局のところ聞き流して「幼稚」と表現するほど見下しています。

後に友人との対話で「金に不自由してないから働く気にならないんだ」という指摘に「働くなら生活以上の働きでなくちゃ名誉にならない、食うための職業は誠実にはできない」と返します。

これは本著で言及されているハンナ・アーレントの指摘と同じで、「仕事」と「労働」を分けた考え方としてとても的を射ていると思います。

本著では代助の心情を「働くことがそれ自体を目的とした純粋な行為であってほしかった」と表現していて、そこにはすごく共感させられました。

つまり僕の悩みの本質も、「労働ではなく仕事がしたい」ということなのかもしれません。

2022年

エンジニアリングに留まらず、情熱を持って取り組める仕事がしたいですね。

react-markdownで目次(Table of Contents)を表示させます

Hackyなことをしなければいけないのかなと思いましたが、ちゃんとremark/rehypeのプラグインを渡せるようになっていました。

HタグにIDを追加する

これを使うだけです。

rehypejs/rehype-slug: plugin to add id attributes to headings

目次を表示させる

https://github.com/remarkjs/react-markdown/blob/8e07e9c3ed740977d6922a6d58e5113f1c09a0c2/test/test.jsx#L1175

上記を参考に remarkPlugins を設定して、本文に以下のように Table of contents という見出しを設定すればそこに目次が配置されます。

Pluginに引数を渡したい

https://github.com/remarkjs/react-markdown#use-a-plugin-with-options

これでいけます。

型があるとライブラリの仕様を追いやすくていいですね・・・!

yupでnumber型バリデーションで空文字を許容する方法

漏れがあるかもしれませんが、ひとまずこれで動きました。

yupでnumberだけどnullも許す感じでバリデーションしたいとき - 青いやつの進捗日記。

Number but allow empty string · Issue #298 · jquense/yup

Nxに入門したので覚書します

Nx: Smart, Extensible Build Framework

用語の整理

ワークスペース

そのプロジェクト全体のこと

ワークスペースの中にAPIやWebなど複数のアプリケーションが配置されます

アプリケーション

そのプロジェクトに必要なAPIやWebといった単位のソースコード群のこと

今回のゴール

バックエンドAPIとフロントエンドをぞれぞれNest.js、Next.jsで軽く動くところまでやります

generateコマンドでコンポーネントか何かを作ってみます

ワークスペースを作る

とりあえずAPIから作ります、Nest.jsです。

実行が終わるとこんな感じでワークスペース名のディレクトリができます。

この apps の中に見慣れたNest.jsのファイル群が配置されています。

Next.jsのコード群を追加する

ドキュメントはここです。

@nrwl/next:application - Nx

@nrwl/next を使いたいので依存性に追加します。

インストールできたらgenerateコマンドでアプリケーションを追加します、 web という命名にしておきます。

apps/web に見慣れたものが追加されました!

e2eは何でしょうか?一旦置いておきます。

とりあえず起動してみる

npx nx serve [application] で起動できる模様です、まずはAPIから。

できてそうです。

webも起動してみます。

できましたが・・・見た目がいまいちです・・・

Screen Shot 2021-12-03 at 8.56.40

まあいいでしょう。

コンポーネントをgenerateしてみる

ドキュメントはここです、Next.js用のコンポーネントジェネレーターがあります。

@nrwl/next:component - Nx

ちなみに --dry-run フラグでドライランができます、便利です。

--project を指定しないと nx.json で指定されているデフォルトプロジェクトの api 側に作ってしまうので注意が必要です。

specもできるのがいいですね!ファイル名がアッパーキャメルではないのがちょっと気になります・・・

コンポーネントのtsxはこんな感じで、 React.FC<HeaderProps> になっていないのが少し気になるところです。

specはこのようになっています。

便利すぎて感動しました。

とりあえずバックエンド、フロントエンドがそれぞれ動いたのでここまでにします。

また進めていくと無限に躓きそうですが、肌感はわかったのでよしとします!

所感

全体的に便利でした、気になったのはこの辺りです。

nxを経由していろんなこと(起動など諸々)をやるのは、いらない依存が増えるという見方もできるかなと思いました

generator、カスタマイズしたくなったら面倒そうだなと思いました

カスタマイズするよりhygenなどにしてしまったほうがいいのでしょうか?

とはいえ思っていたより便利で満足です、generatorもデフォルトのまま使えそうですし、プロダクションで使ってみたいところです。

次はデプロイまでやってみようかなと思います。

参考になりそうなリンク

【フロントエンド、バックエンドを一つのリポジトリで管理】monorepoを実現できるNxをさわってみた | DevelopersIO

とても詳細に書かれていて良さそうでした、ちゃんと読んでいませんが困ったら読もうと思います

nextjs-auth0のgetAccessTokenでOpaque TokenではなくJWTがほしい場合はAUTH0_AUDIENCEを設定しないといけない

これは本当に数週間詰まって大変でした。

AUTH0_AUDIENCE を設定しなくても認証は疎通してしまうのですが、この設定の有無で返ってくるトークンがどちらになるか切り替わるようです。

Why is my access token not a JWT? (Opaque Token) - Auth0 Community

認証周りは難しすぎて辛いです。

prisma-replがとても便利でした

egoist/prisma-repl: REPL for Prisma databases.

普段プライベート開発ではTSばかり使っていて、バックエンドのDB周りはprismaに任せているのですが、どうしてもrails consoleみたいなものが欲しくなってしまって困っていました。

prisma-repl はいい感じに全部ロードしてくれて db 変数が使えるようになるREPLツールで、導入もとても簡単でいい感じです。

prisma studioとも一旦お別れかもしれません・・・。

Chakra UIのuseBreakpointValueでProps全体を柔軟に扱う方法

Chakraのサンプルにある

だと柔軟性が伝わらないのですが、結局のところブレークポイント単位に特定の定義した値を返すことができるので、このような形でPropsをまとめて定義することもできて便利です。

無理のあるレスポンシブ対応をしたいとき(しないほうが良いですが)に活躍したりします。

useBreakpointValue - Chakra UI

Material-UIで配列を複数のTextFieldに分割して処理する方法

React Hook Form - Array Fields - CodeSandbox

例によってポートフォリオをリニューアルしました

Daisuke Tsuji's portfolio

もともとcreate-react-appで作ったものを1年ぐらい前にNext.jsに置き換えたのですが、その後メンテしていなかったですし、コンテンツ管理もコードベタ書きでつらかったので一気に置き換えました。

6時間ぐらいかかりました。

技術スタック

Next.js

GraphCMS

リニューアル前はJS上にJSONでコンテンツを持っていたのですが、さすがにメンテしづらいですしGraphCMS使ってみたかったですし、最近作った自分用サービスもあったからコンテンツ追加したいし、ということが重なったのでいいタイミングになりました。

GraphCMSがとてもよかったです

Headless CMSは個人的に気に入っているソリューションなのですが、今は群雄割拠の時代すぎてどれを選ぶかがとても困る状態になっています。

https://headlesscms.org/

同時にGraphQLは個人的にとても気に入っていて、さらに深入りしていきたい気持ちもあったのでそこに特化しているGraphCMSを選びました。

あと気になっていたのはこの辺りです。

https://www.sanity.io/

https://strapi.io/

GraphCMS、使ってみた感想としてはとてもシンプルでいいです!

ただのHTTPベースのAPIで認証もbearer tokenなので、Contentfulみたいにライブラリが使いづらいということもないですし、ブログもGraphCMSにしておけばよかったという気持ちです。

Railsにhologramを導入してスタイルガイドを運用できるようにする方法

正直それなりにデザインスキルが高く、かつデザイナーさんたちがテクニカルスキルが高い組織でないとスタイルガイドの運用は結構難しいと思うのですが、ちょうど現職ですでに導入されていたレガシーな自前スタイルガイド機構があったので、負債化したそれをhologramに置き換えました。

trulia/hologram

Screen Shot 2020-07-17 at 10.25.42

hologramのここが良い

hologramはCSS上にコメント形式でMarkdownとマジックコードコメントを書くことで「実際の表示」と「コードの例」をそれぞれドキュメント化してくれるRuby製のツールです。

Screen Shot 2020-07-17 at 9.41.17

普通に自前で作ろうとすると「コードの例」を載せるのがとても難しいので、それをやってもらうにはやはりライブラリを使ったほうが楽です。

また、「CSS上にコメント形式で記載する」ことで、「そのCSSがドキュメント化される」のと「ガイドに掲載されているのか」がCSSを見るだけでわかるようになります。

自前で作るとなると基本的にはCSSとHTMLは分離されてしまうことが多いと思いますので、これがCSS単品で完結するのはとても大きな強みだと思います。

hologramをRailsに乗せる

とはいえRailsはコンパイル後のCSSにハッシュダイジェストをつけてくれてしまうので、実はhologramをRailsに乗せるのは結構難しいです。

本来は「hologram -> 生成されたCSSを読むHTMLを吐き出す」という流れにしたいのですが、生成されたCSSのファイル名を取得する方法がhologram自体にはないので、そこは自前で書くしかありません。

方法1: styleguide用scssを自前コンパイルしてそのCSSから app/javascripts/ 配下の元CSSを読ませる

この方法ならコンパイル後のCSSを知らなくても、コンパイル前を読み込んで自前でコンパイルさせてしまえるのでhologramでも使えるようになります。

hologram自体にもstyleguide用のCSSは必要なので、それをSassで運用するようにしてかつ元のCSSも読ませるようにすればスマートに解決します。

方法2: manifest.json を読んでCSSを埋め込めるようにする

自分は方法1を選んだのでこれが実際できるのかはわかりませんが、理論的にはできそうでしょうか?

Railsは public/packs 配下に元ファイルとコンパイル後のファイルのマッピングを持ったjsonを吐き出すので、それを読み込んでコンパイル後のファイル名を取得してしまえばhologramに埋め込むことも可能かもしれません。

hologram導入で躓いたところ

意外と簡単にいけるだろうと思ったのですが、思った以上に躓いて半日ぐらいかかったのでメモしておきたいと思います。きっとまたやらかします。

コメントは /* doc じゃだめ、 /*doc のようにスペースは入れない

これで30分ぐらい動かなくて悩みました。

hologramのコードを読めばわかったのかもしれませんが、何回やってもHTMLが生成されなくて適当に触りまくっていたら直りました。

SCSSの自前コンパイルとファイルウォッチ

スタイルガイドを作るとなると、ガイドだけではなくてデザインの確認にも使いたかったので、開発サーバを起動してstyleguideのテンプレートと実CSSファイルの変更を検知 & 再ビルドをさせたいと考えていました。

この辺はSCSSのコンパイルは sass を使っていたので、ついでに paulmillr/chokidar を入れてファイルの変更検知をさせることで解決しました。

終わりに

hologram、結構古いライブラリの割にJSXの対応などが入っていてちゃんとメンテされているのだなという印象がありました(最終更新は3年前ですが)。

本来はフロントを分離してstorybookなどを使いたいのですが、レガシーシステムなのでそういうわけにもいかず、少し泥臭くてもこういった小さい改善で今後もなんとかしていきたいという気持ちです。

ブログをGatsbyJSからNext.jsへ変更しました

GatsbyJSにはずっと不満を感じていたのですが、先週ついに限界が来て、一気に置き換えることにしました。

構成

かなり昔、このブログはHugo + ローカルのMarkdownで運営していたのですが、ローカルのMarkdownを編集するのが大変でContentfulへ移行した経緯があり、以下のような構成になっていました。

As-Is

コンテンツ管理: contentful

ホスティング: Netlify

ビルド: GatsbyJS

Netlifyはホスティングサービスとしてはとても良いのですが、dependabotなどで依存性を頻繁に更新しているとビルドの上限に達してしまうことがあり、少し不便に感じていました。

特にGatsbyJSは依存性が増えすぎる傾向があるため、なおさらそのデメリットを大きく感じていたように思います。

To-Be

コンテンツ管理: contentful

ホスティング: Vercel

ビルド: Next.js

このような構成で、Next.jsのStatic Optimizationを利用してビルドしています。ホスティングもNext.jsにあわせてVercelに移行しました。

Netlifyを使っているのはもうポートフォリオだけなので、この際ポートフォリオもVercelに移行しようかという気持ちが出てきています。中身はNext.jsですし。

contentfulも正直なところAPI設計がそれほど好みではなく、GraphCMSなどのほうが良かったのかもしれないという気持ちはあります。

ただ、この移行コストは非常に高いので一旦は見送りました。GraphCMSに移行しても同じ問題を抱える可能性は捨てきれませんでしたし。

最近の個人開発とNext.js

最近はブログやポートフォリオを含めて個人でメンテしているプロジェクトが4つほどNext.jsで動いており、ようやくRailsからの脱却が本格的にできてきたなという気持ちがあります。

Next.jsはAPIエントリポイントが出たときに「そんなフルスタックになってしまうのか」という気持ちがありました。

ただ、よく考えてみるとRailsに対して抱いていたフルスタックへの嫌悪感は「フロントエンドの描画をコントローラに依存して行っている」ところだったので、Next.jsのようにレンダリングがReactでできていて、バックエンドとの疎通をAjaxで行える(SPAを維持できる)のであれば、APIエントリポイントは問題にはならないという結論に行き着きました。

またAPIエントリポイントがあるとプロキシとしても使えるので、バックエンドサーバを隠蔽することもできますし、HTTPヘッダにAuthorizationを埋め込むこともできるので、非常に便利に使えています。

Railsは1プロジェクトでGraphQL APIとして使っているのですが、正直これもTypeScriptで書いたほうが書きやすいので、そのうち移行しそうだなという感じです。

慣れているから書きやすいというのはありますし、何でも揃っているから楽ではあるのですが、やはりその分融通がきかなかったりするので、今後もRails脱却は進めていきたいところです。

Jest実行時にReferenceError: fetch is not definedが出る問題

知りませんでした。

fetch is not available in Node, which is where Jest is running your tests. Is it an experimental browser technology.

You will need to polyfill the behaviour if you want to make actual http calls, or mock fetch to simulate network requests.

https://github.com/facebook/jest/issues/2071#issuecomment-259709487

yarn add -D whatwg-fetch して

jest.setup.js に

fetch undefined when running tests with jest

MissingAPIError: indexedDB API missingの解決方法

初めてIndexedDBを使ったのですが、Jestが落ちるようになってしまったので直しました。メモしておきます。

議論はここでされています。

Puppeteer, Jest, Unhandled rejection: MissingAPIError: indexedDB API not found

これを使えば解決できます。

dumbmatter / fakeIndexedDB

jest.setup.jsなどに

を入れるだけです。

stylelintでセレクタ名にキャメルケースを強要する方法

Reactを書くときはクラス名もローワーキャメルケースがいいなと思ってLintを設定しようとしたら色々手間取ったのでメモしておきます。

stylelintのセレクタ命名は selector-class-pattern で設定できます。

公式にも汎用的な正規表現の定義が載っているので、それを参考にすればOKです。

https://stylelint.io/user-guide/rules/regex

Heroku + Rails(Sprockets4.0.1)でassets:precompileがエラーする問題

dependabotのオートマージで夜中にデプロイ失敗したよというメッセージが発生しました。

以下で解決できました。

https://stackoverflow.com/questions/62208867/rails-deployment-to-heroku-nomethoderror-undefined-method-for-nilnilclass

https://github.com/rails/sprockets/issues/683

Hygenで大文字小文字の制御をする方法

最近Next.js + TypeScript + GraphQLのスタックで個人プロジェクトを進めているのですが、Railsと違ってコードジェネレータがないのが辛かったのでHygenを使ってみたときの些細なメモです。

Hygenでのパラメタの先頭大文字や小文字化

結論としてはここに全部のヘルパーが載っています。

https://www.hygen.io/templates/#helpers-and-inflections

Reactだとファイル名やコンポーネント名をアッパーキャメルケースにしたり、変数名はローワーキャメルケースにしたりするので、適宜Helpersを使い分ければよさそうです。

Hygenは簡単に使えてしまうのでDocumentをちゃんと読まなかったのですが、テンプレートの章は目を通して損はなさそうです。

https://www.hygen.io/templates

拡張もできるようです。

https://www.hygen.io/extensibility/#helpers

rmagickで画像を一括リサイズする方法

前回に続いてローカルの作業自動化で何回か使ったので、見失わないようにメモしておきます。

記事にしなくてもTILで十分ですね。

参考にさせていただきました

https://rmagick.github.io/resize_to_fill.rb.html

rmagickで画像合成をするときにradiusをかける方法

最近やけに画像合成をサーバサイドでやることがあるのですが、角丸の画像合成ってできるのかなと気になったので調べました。できたのでメモしておきます。

rmagickを用いた角丸画像合成の実装

完全に動かしたコードのコピペですが、このような感じです。ビジネス的な命名だったところは雑に直したので動かなくなっているかもしれません。

rounded メソッドに対象の画像とサイズ、角丸の大きさを渡して、上から角丸になるように生成した画像を重ね合わせて合成した画像インスタンスを返しています。

新しい画像インスタンスを作っているので元のインスタンスは変わらないことに注意してください(なので代入しています)。

ほとんど後述するSOFのコードのコピペです。

参考にさせていただきました

http://www.imagemagick.org/Usage/thumbnails/#rounded

https://stackoverflow.com/questions/2716457/rmagick-rounded-corners

request specでもcssでマッチさせる方法

例えばcanonicalやmetaタグに正しい値が出力されていることもテストしたい場合などです。

system/feature specを使えば簡単ですが、request specのほうがパフォーマンスが良いです。

Capybara.stringのhas_css?メソッドを使う

metaタグ、head内要素など見えないタグの場合

参考にさせていただきました

Capybaraでドキュメント・メタデータが出力されていることを確認したい | feedforce Engineers' blog

HerokuのPostgreSQLのプランを変更するときの移行手順メモ

いつも忘れて本当に困るのでメモしておきます。

定期バックアップの設定

参考にさせていただきました

https://qiita.com/takecian/items/e37bc5d2d753f600e7e6

webpacker3系の依存しているwebpack-dev-server2系がCVE-2018-14732脆弱性に引っかかるのでwebpacker4.0.0.rc.2を使うようにしました

GitHubのSecurity AlertをOnにしていたら以下のようなAlertがあがってきました。

CVE-2018-14732 More information low severity Vulnerable versions: < 3.1.11 Patched version: 3.1.11 An issue was discovered in lib/Server.js in webpack-dev-server before 3.1.11. Attackers are able to steal developer's code because the origin of requests is not checked by the WebSocket server, which is used for HMR (Hot Module Replacement). Anyone can receive the HMR message sent by the WebSocket server via a ws://127.0.0.1:8080/ connection from any origin.

https://nvd.nist.gov/vuln/detail/CVE-2018-14732

webpacker3系はwebpack3系のラッパーで、webpack3系はwebpack-dev-server2系に依存しています。そして、webpack-dev-server2系に関する脆弱性のようです。

気持ち的にはさっさとwebpack4系にしたかったので、webpacker4系の安定版を待たずにRCの4系を使ってみようと思います。

CHANGELOGはここです。

https://github.com/rails/webpacker/blob/master/CHANGELOG.md

Upgrade to webpacker v4.0.0.rc.2

とりあえずサクッとバージョンだけあげます。

Gemfile

package.json

Reinstall binstubs

binstubが変わっているようなので最新のもので再生成します。

Regenerate configuration files

後で書きますが、babelやpostcssの設定ファイルのフォーマットが変わっているのでこちらも再生成します。

breakingなchanges(気になったものだけ)

今使っている3.5系からの差分をCHANGELOG見ながら読みましたが、このくらいでしょうか。

postcss-next is replaced with postcss-preset-env

さよなら・・・。@applyが仕様から落ちたのは本当に痛いです。なので一旦、postcss-nextを使い続けるようにしました。

そのうち外します。

Separate CSS extraction from build environment

エントリポイントであるJSから呼んだCSSをファイル展開せず、分割されたままheadに動的に埋め込むようにしたということでしょうか。

https://github.com/rails/webpacker/pull/1625

webpacker.ymlに以下の記載をすることで設定ができるようです。

trueにすればこれまでと同じ挙動をする模様です。

.babelrcと.postcssrcのフォーマットがJSに

babel.config.jsとpostcss.config.jsになりました。

https://github.com/rails/webpacker/pull/1822/files

余談

webpacker4系になれば少しは薄いラッパーになるのかなと思っていましたが、そうでもないようです。

webpackを自分で入れる運用にするべきか迷っていましたが、その気持ちが強くなりました。

2018年の振り返り、2019年からLang-8社に入社します

久々に書く記事が年末の振り返りかよ・・・という感じですが・・・。

というわけであっという間に1年が終わってしまいました。

今年はフリーランスやら技術顧問やらいろいろやりましたが、まあ前に進めたいい年だったのではないかと思います。

毎年やっているわけではないのですが、振り返りくらいしてみようと思います。

フリーランスとして1年過ごしました

これまでジョブホッパーとしていろんな会社で色んな経験をさせてもらいました。

とてつもない幸運の持ち主なのでだいたいどの会社も居心地がよく、ホップしたのは本当に不義理なことをしてしまったと思います。

でもおかげで幅広い経験をさせてもらえましたし、確実に糧になりましたし、僕自身は感謝しています。いつか恩返しもしたいです。

というわけでホップしまくった結果、2018年(正確には2017年12月)からフリーランスとして仕事をしていました。

誰もがイメージするキラキラした感じのはたらき方ではなく普通にフルコミットで仕事しまくっていましたが、別に食えなかったり実質ニートになったり死んだりもしませんでした。

フリーランスになってどうだったかというと、まあお金には余裕ができました。税金でどれくらい持っていかれるか次第ではありますが。

お金が増えても幸福度はあがらないという記事を見ますが、意外とそうでもなく、今のところはある程度比例してあがっています。

仕事もありがたいことに途切れることなく、次の仕事を探さなきゃいけないという強迫観念もありません。

実際のところフリーランスになるのはそんなに難しくないなとも思いました。

スカウトが来たときに「業務委託でいいですか?」と言ってしまえばそれで晴れてフリーランスなんだということに気づきました。

エンジニアは今、空前絶後の売り手市場ですから、もしなりたい人はさくっとなってみるといいと思います。

手続きも大変だとよく聞きますが、僕はそんなに大変ではありませんでした。周りにそういうのに詳しい人が数人いたというのもあったと思いますが。

この辺りのお話が聞きたい方はなんでも話しますのでぜひ聞いてほしいです。

技術顧問というはたらき方

僕は12月現在で4、5社並行して仕事をさせてもらっていて、そのうち1社は技術顧問として小さなチームに対してアドバイスをしたりしています。

技術顧問という言葉はかっこよすぎてあまり使いたくないのですが、昨今はそもそもそういうポジションも必要ですしやっている人はアピールしていったほうがよいのでは?という流れもあるようなので、せっかくですし僕の例をまとめてみたいと思います。

技術顧問というはたらき方はきっと千差万別で、人や会社によって全く違うのが現状だと思います。

僕がやっているのはだいたい次のことで、ほとんどリモートでやっています。

全体設計

命名のアドバイスやルールぎめ

コードレビュー

難しい機能のベース実装と引き継ぎ

非エンジニアとの対話

新しい技術トレンドやニュースの共有

自分が得た知見や失敗の共有

採用のフォロー

たまに飲み会で話を聞く

ポジショントークになってしまいますが、少人数のチームには技術顧問という立ち位置の人間がいることの恩恵はとても大きいのではないかと思います。

よくエンジニアが口にする言葉として「技術的負債」というものがありますが、まずこれを作らないようにすることや、タスクに対して大きな手戻りがないように進め方をアドバイスしたり、テストの書き方やLintの設定、依存性の管理、インフラの設計や監視、アラートの設定など、経験がものをいうポイントでのアドバイスはチームのヘルスケアとして確実に貢献すると思います。

システム開発は考えるべきことが本当に多くて、これを経営者に寄り添いつつエンジニアの味方として考えられる存在がいると、確実にシステムの寿命が伸びます。

ありがちな話に、外注が作ったシステムが運用できなくて内製にしたいけど採ったエンジニアがつらい思いをする、というものがありますが、そういった場面も防げます。

会社と同じで、システムは作って終わりではなく、維持しなければ意味がありません。そういった部分で問題が顕在化した結果、技術顧問という立場の人間が必要とされる時代になったのだと思います。

ちなみにこれは顧問をやる方の恩恵もあって、やはりそれでチームが良くなったり開発体験を良くしてあげられると本当に嬉しいです。

若手が育つのを見られるのも嬉しいですし、エンジニア界隈全体に少しは貢献できているのではないか、と思えたりもします。

なのでそういう話が来たらぜひ一度受けてみるといいと思います。

というわけで、Rails関係でそういう感じの人間がほしい会社さんがあればやりますよ。スタートアップでエンジニア1、2人規模がいいですね。

プライベートの方

まあぼちぼちという感じです。

ゲームしたり個人開発したり本を読んだり引っ越したり、特につらいことはなく過ごした一年でした。

個人開発の方は1つちゃんとリリースして、もう1つリリースしたいけど時間がなくて何もできていないものがあったりします。

個人でプロダクトを持つというのは技術研鑽、運用のスキル、コスト管理、監視、ディレクション、デザイン、モチベーション管理、あらゆる面でいい経験になります。

実際に個人開発しようとしたとき、まず抵抗があるのはデザインスキルなどだと思いますが、別に、自分のブログを自分で運営する、くらいでいいと思います。

自分ひとりである程度全体が見られるようになると本当にできることの幅が広がります。

もちろん躓きますが、その経験はきっと仕事でも活かせます。エンジニアとしてやってよかったと思うことの1つです。

あと、フリーランスになってから、仕事でもプライベートでも、良くも悪くも自分本位な生き方をするようになったなと思いました。

時間がなければ仕事は断りますし、お金が悪くても断りますし、言いづらいことも言わなきゃいけない場面が増えました。

これはまあ長期的に見れば大人として生きていく上で必要なスキルだったのかなと思います。個人的には結構手に入れてよかったスキルだと思っています。

思えばフリーランスとして複数社ではたらいたことで、そこで関わった人とプライベートで飲みに行ったりする機会が増えました。

これまでもなかったわけではないのですが、それ以上に交流が大きく広がったのは今思えばフリーランスというはたらき方のメリットなのかと思います。

現場を離れたあとでも繋がれるのはありがたいですし、困ったときにはぜひお手伝いしたいと思える相手がいるのはエンジニアとして生きていく上での貢献感につながります。

正社員だとそういう意味で幅の広がりに欠けるのが寂しいところだったりするかもしれません。

Lang-8社に入社することになりました

フリーランスとしてフラフラしまくっていたら年末間際に拾ってもらいました。

正社員は全く考えていなかったのですが、フリーランスでやっていくぞ!という気概があったわけでもないので、まあいいかということでさくっと決めました。

Lang-8社自体はもともと知っていて、なんだか難易度高そうなサービスをやっているなあ、作るの大変そう、くらいの認識はありました。

もともとはCTOの八木@sys1yagiさんから声をかけてもらって業務委託で入っていたのですが、社員になってほしいという話と、まあ長く居たい気持ちはあるなというのがマッチしたので入社の流れとなりました。

まあ、英語の勉強をしている身でもありましたし。(サボりまくりですが)

入社は1月なので厳密にはまだ業務委託なのですが、Railsの開発者としてHiNativeの面倒を見ています。

設計やら何やらで改善点は多くありますが、それでもテストが書いてあったり、つらい時期でも丁寧に育てられてきたサービスなのだろうと思っています。

技術的に最適化すべきポイント(技術的負債とは言いたくない)は多々ありますが、それはこれから率先して直していきたいですし、それ以上にサービスを成長させるためにコミットしたいと思います。

というわけで次は長く腰を据えるつもりだという表明も込めてここで報告とさせていただきます!

あと語学勉強中の方はぜひ使ってみてください。

HiNative | 全ての外国語学習者のためのQ&Aサービス。

ユーザテストも募集していますよ、気軽に声かけてくださいね。

2019年はこれをやります

10月頃まではとにかく仕事しない生活をしようと努力してきたのですが、なかなか思うようにいかず、結局仕事漬けの1年になってしまいました。

なんだかんだ12月になってみると、2019年はちゃんとプロダクトにコミットしたいな〜という気持ちになってしまったので、まあそれはLang-8社で頑張ろうかと思います。

というわけでエンジニアとして頑張るという曖昧なのが1つです。

もう1つはお金のことをちゃんと考えたいと思っています。

具体的に言うと資産運用で、ずっとこれまでもやってみたかったのですが、なかなかイメージがわかず、それがようやくなんとなくやれそうな具合の余裕が出たので挑戦したいです。

最後の目標はQOLを今よりあげることです。

これは年内ずっと言っていたのですが、人生の意味はよくわかりませんがQOLを上げるのは間違いなく正しくて、そのためにはお金をある程度使うべき(むしろ使わなければいけない)ということに気づき始めました。

なので来年は今以上にそういった生きやすさとか、過ごしやすさを重視して生活を改善していきたいです。

締まらない感じになってしまいましたが、2019年も自分の人生最優先で頑張ります。

良いお年を。

GitHubのレポジトリをsshでyarn addする方法

これは詰まったのでメモしておきます。

package.jsonのmainにCSSを指定できるのは初めて知りました。

Scrapbox、esa、kibelaあたりのドキュメンテーションツールを検討比較したのでまとめます

最近フリーランスとして技術顧問業を少しだけ始めたので、組織づくりのためにいろいろツールを決めようとしたのですが、思っていたより難しかったのでメモしておきます。

2018年9月現在の定番どころはだいたい検討できたのではないかと思います。

要件

できれば無料、安く済ませたい

検索機能が強いほうがいい

下書きやスライドモードなど高機能さは不要、むしろ無いほうがいい

カテゴライズはできてほしい

Markdownで書きたい

日記や日報のような使い方ではなく、あくまでWikiのような使い方にしたい

esa - A document sharing service for motivated teams

1人500円/月。

自分が今お手伝いしている会社さんだと、一番多いのがesaです。

個人的にはそれほど不満はなく、思考停止でこれにしてしまってもいいかなと思えるくらいに満足しています。

気になるところ

最近動作が遅い?

サイドバーの動作が遅いのが辛いです・・・

WIPはなくていい

導線設計がちょっと使いづらい

階層設計が難しく、だいたい破綻します

Scrapbox - Realtime Knowledge Base - Capture ideas in context

ビジネスの場合は1人1,000円/月。

最近話題のScrapboxです。気になっていたので今回まず導入して使ってみました。

他のドキュメンテーションツールと違って共同編集がとても強く、MTGのアジェンダ等の管理はとてもしやすかったです。

完成度の高さゆえに、アジェンダ上で議論ができてしまうレベルだったので、それはそれで・・・という感じはありました。(運用次第ですが)

ページ同士がリンクしやすくなるのは本当に便利でよくできていて、これはドキュメントが増えていっても破綻しないだろうなという体験でした。

これのおかげで、ちゃんとしたドキュメントを作りたいときも、とりあえず書き捨てたいときも使えるサービスになっていると思います。

気になったところ

やはりMarkdownが使えないのは辛いです

markdownはデカイ文字を書くのに便利 - 橋本商会

上記にあるとおりで、大きい文字を書くためにMarkdownを使っているので、それが書きづらいのはやはり体験として良いものではありませんでした

文書の構造化がしたいわけではなく、ここからちょっと違う話になるぞ、というのを1ドキュメント内で区切りたいときに使いたいのです

Kibela - a new communication tool to fuel the team

5人まで無料。

Kibelaも実際に使ったことがあるサービスです。

WikiとBlogで別れていて、使用体験としてはesaと変わらない感じです。

無料で5人まで利用可能なのがとても魅力的です。

気になったところ

デザインが発展途上でしょうか

全体的に整っていない感じがあります

ドキュメントを読んでいて気になってしまいます

個人的にBlogとWikiは別れていなくていいかなと思います・・・

使い方に困ってしまいます

ダッシュボード?トップページがただ情報が羅列されているだけなので、少し物足りない感じがしてしまいます

Notion – The all-in-one workspace for your notes, tasks, wikis, and databases.

ストレージの容量制限はあるが人数無制限で無料。

Twitterで流れてきて知りました。

ドキュメンテーション特化ではなく、タスク管理や簡単なデータ管理もできる模様です。

これは今回は採用しませんでしたが、いずれ使ってみたいです。

marchily | 仕事見える、チームちかづく

1人800円/月。

最近出てきたサービスでしょうか。

デザインがとてもかわいいです。ちゃんとWebまでやれるデザイナーさんが携わっているのだろうなという感じです。

実際に使っているわけではないのですが、金額の面で採用しませんでした。

気になったところ

「タスク管理にアソビの要素を!」はあまり同意できないかもしれません・・・

バッジやタスクのような機能もあるようですが、今回はシンプルにドキュメンテーションがしたかったので要件に合いませんでした

情報共有ツール DocBase(ドックベース ) | ストレスフリーなドキュメント共有ツール

3人まで900円/月。

これはまったく知らなかったのですが、意外とよくできていそうで驚きました。なんとなく雰囲気的に大手企業向けなのかなと思いました。

デザインも良さそうで、テンプレートが作れたり機能的にもほとんど不満なく使えるのではないかという感じです。

今回はお金の面で利用しませんでした。

参考にさせていただきました

ブラウザ上でいつでもどこでもメモが書けるサービスの個人的比較 #webサービス - mimemo

ポートフォリオをちょっとメンテしました

ずっと放置していたポートフォリオをメンテしました。

Portfolio - Daisuke Tsuji

依存性を整理しました

prop-typesなどを勉強がてら入れていましたが、ただのペライチには不釣合いだったので削除しました。

加えてstyled-componentsに移行したりもしました。

ついでに以下の対応もやりました。

CircleCIでyarn upgradeとかbundle updateをやってプルリクを作ってもらう - unresolved

構造のリファクタ

無駄にコンポーネント化されていたりしたので、フラットな感じに変えました。

ちょっとメンテせずに戻ってきたときにとてもわかりづらかったので、おそらく良い構造ではなかったのだと思います。

404対応

ポートフォリオはGitHubのWebHookでNetlifyにデプロイされるようになっているのですが、create-react-appで作ったものをそのまま載せると、どんなURLでも200になってしまいます。

そのため、リダイレクトの設定をこのようにしました。

public/_redirects

雑ですね。

内容の更新

個人プロジェクトやフリーになってからの経歴が載せられていなかったので追加しました。

あとは無駄な情報を削ったり、もろもろ整理しました。

CircleCIでyarn upgradeやbundle updateを実行してプルリクを作ってもらう方法

本当にライフチェンジングなので、やっていない方はぜひ試してみてください。

有志が以下のような素晴らしいツールを公開してくれているので、これらをありがたく使わせていただきましょう。

masutaka/circleci-bundle-update-pr: Create PullRequest of bundle update in CircleCI

taichi/ci-yarn-upgrade: Keep NPM dependencies up-to-date with CI, providing version-to-version diff for each library

CircleCIで依存ライブラリのアップデートを回す

自分はこのようなconfig.ymlを使っています。

CircleCI上のcronはUTCで回るので、日本だとAM9時に処理が実行されます。

サービスにやらせるならこちら

おそらく王道はこのあたりでしょうか。

Dependabot - Automated Dependency Updates

renovatebot/renovate: Automated dependency updates. Flexible, so you don't need to be.

Greenkeeper | Automate your npm dependency management

どちらもセルフホスティングできるはずなので、費用をかけたくない場合は自分で立ててしまえば済むと思います。

エンジニアは技術ブログをどこで運用するのがいいのか問題

もう移行は終わってしまいましたが、最近いろいろ考えることが多かったのでまとめてみます。

何を決めるべきなのか

そもそも選択肢が多いのが悪いです。

よくあるパターンとメリット・デメリットはこのあたりでしょうか。

どこかのプラットフォームを使う場合

メリット

画像の圧縮はだいたいやってくれるはず

管理コストがない

ドメインが強いかも

デメリット

融通がきかないかも

HTMLが汚いかも(とはいえ自分で書いても汚いですが)

自作する場合

メリット

いくらでも融通がきく

1プロダクトになる

デメリット

インフラが面倒

お金がかかるかも

メンテが面倒

何を目的にするのか

そもそもブログとは何なのでしょうか。

ブランディング

個人メモ

ブログ自体がサンドボックス

具体的にどんな手段があるのか

おそらくこのあたりです。

Medium

Hatena Blog

Hugo

GatsbyJS

Contentful

Contentfulは広告で知ったのですが、そのときからとても良いなと思っていて、これを機に使ってみたい気持ちがあります。

ただ管理画面がとても難しいです。

やっぱり自分で作りたい

楽したい気持ちもありますが、自分で作りたい気持ちもあります。

GatsbyJS + Netlify

なんだかんだ触ってみたいGatsbyJS

Contentfulと連携させれば画像圧縮もうまくやれるのでは

これにしましょう。新しいものをやりたいです

Hugo + GitHub Pages

Hugoはまだまだ勢いがありますし、枯れているようで枯れていません

最近追えていなかったのも心残りでした

ただ飽きた感はあります

GitHub PagesもHTTPS対応したのでもうNetlifyはいい気がします。ポートフォリオだけそちらで

CircleCIで自動デプロイの環境を作りましょう

デザインをゼロから真面目に作ります

ポートフォリオもなんとかしなければ問題

本当に404の対応などもできていなくてひどいです

メンテしなければなりません

なのでポートフォリオは別でやります

Nuxt.jsでも使おうかなと思います

ブログをGatsbyJS + Contentful + Netlifyで作り直したので今日はGatsby記念日です

SPAがいいねと君が言ったから7月6日はGatsby記念日。ざっと3日くらいおうちで頑張って移行しました。

スタックはこちらです。

GatsbyJS

Contentful: Content Infrastructure for Digital Teams

Netlify: All-in-one platform for automating modern web projects.

HugoからGatsbyJSへ

Hugoが嫌いになったわけではありません。

開発も盛んで気がつけばバージョンが倍くらい上がっていたりするような活発さで、ちょっとついていけなかったりもしましたが、とてもお世話になったプロダクトでした。

ただ、静的サイトジェネレータ自体の運用に少し疲れてしまいました・・・。

Markdownをファイル生成して書いてコミットして・・・というのはとても楽なのですが、日付やカテゴリをファイル内で管理するのが辛くなってきたのが正直なところです。

JSONを手でいじっているときと似た辛さがあります。

静的サイトジェネレータのここが辛かった

思えばいろいろと辛い場面はあった気がします。

GatsbyJSも静的サイトジェネレータではあるのですが、融通の利きやすさ(Contentfulなどコンテンツソースが選び放題)という意味で以下の辛さがだいたい解決できるのではないかと思っています。

Frontmattersの管理

画像の配置の手間、リサイズや最適化

画像をディレクトリに入れてマークダウンにパスを書いて・・・というのが辛いです

静的資材の管理、webpack等との共存

HugoもHugoで変更監視をしていてwebpackにもやらせると仲良くできなかったりしました

Ignoreしたり調整すればなんとかなると思います

(Hugoに限る話ですが)Goのテンプレートの書きづらさ、エラー原因特定のしづらさ

どれも頑張ればなんとかできることですし、実際なんとかしている人も多いと思いますが、個人的に限界が来てしまいました。

バックエンドのContentful、フロントエンドのGatsbyJS

もうバックエンドは手元で管理するのをやめて、Contentfulに載せることにしました。

Conntentfulは知ったときから気になっていたHeadless CMSというたぐいのサービスで、データ構造とデータ自体の管理だけやってあとはAPI(GraphQL)で配信するという感じのものです。

これは絶対に有用ですし、これからの時代で活躍する場面があるだろうと思っていたのですが、なかなかその場面が見いだせずにここまで来てしまいました。出遅れてしまいました。

これが従来より楽になるかはもう少し運営しないとわかりませんが、物は試しということで。

とにかくGetting Started

まずこれを読みます。

GatsbyJS and Contentful in five minutes

package.jsonを見るとyarn devで動きそうなので叩いてみますが、このようなエラーが出たので、

gatsby-config.jsを見ながらこのような修正をしてみます。

これで通るようになるのですが、実際にContentfulに設定されている構造とサンプルのGraphQLのリクエストがミスマッチを起こしてエラーするので、そのあたりを適宜調整します。

GraphQLは初めてで全然わかりませんでしたが、読めばなんとなくわかるのですごいです。

カスタマイズ

Next.jsと同様、examplesがたくさん用意されているので疎通だけならほとんど詰まることはありませんでした。

gatsby/examples at master · gatsbyjs/gatsby

こういうのは本当に助かります。

とはいえReact自体の知識がなさすぎるのとGatsbyJSの土地勘がないので、細かい部分までやろうとすると結構詰まった場面は多かったです。

いらないファイルを消したりstyled-componentsに置き換えたり、地道な作業もありました。

デプロイの自動化、WebHookによるデプロイ

Hugoを使っているときはコンテンツの管理とブログ自体のソースを一緒にしていたのですが、今回はGitHub上にブログのソース、コンテンツはContentfulという形で切り分けることができました。

そのためmaster pushをするとNetlifyが受け取ってリビルドしてくれるのですが、Contentful側でコンテンツを変えた場合はリビルドされないので、ContentfulのWebHookとNetlifyのWebHookをつなげてあげれば自動デプロイの環境が簡単に作れます。

今後もPostCSSを使っていく上でどうしていくべきかを考えてみました

この記事は酔っ払いながら書いているので正しくない可能性があります。

Railsをwebpacker + PostCSSに移行してそれなりにコードを書いてみましたが、ちょっと思うところや考えなければいけないことがあったのでまとめてみます。

[Rails5.1.3] Asset Pipeline + SCSSからwebpacker + PostCSSに移行してみるか by 42 Design Work

PostCSSのリスク

PostCSSはとても面白い仕組みで、この仕組みを使っているだけでわくわくしてしまうようなものなのですが、組織で使うなら色々考えなければいけない部分もあるなと思います。

独自に進みすぎるリスク

まず誰もが感じるのはこれだと思います。

PostCSSはプラグイン形式でいろいろな機能を追加していけるので、ビュッフェ感覚で気軽にプラグインを追加できてしまいます。

これはまさに秘伝のタレを作るようなもので、導入した本人はよくても、周りの人はそのルールを知ることが難しいですし、結局文法が分離してしまうリスクになってしまうと思います。

過多になりすぎるリスク

webpackerではPostCSSのプラグインとして、デフォルトで以下の2個が入っています。

postcss-smart-import

postcss-cssnext

これはまあいい落とし所だと思っていて、ギリギリ最低限のものに見えます。

webpack側のローダーにはsass-loaderがあるので、Railsから移行する上でスムーズにいけるように、と考えられているのだと思います。

が、cssnextはちょっとプラグインが過多で、いきなり全部把握するのはちょっと難しいです。 CSS4に準拠しているという意味ではまあ妥当なのでしょうが、個人的にいきなりcssnextを使うのはいいかなと思ったので使っていません。

cssnextを使うか、cssnextのサブセットを構築するのが安全なのでは

というわけで、ここまで書いたようなことを感じたのもあって、先日書いた記事からPostCSSの構成をだいぶアップデートしました。

どういう考えでどういうアップデートをしたのかをまとめてみます。

Sassを実現しようとしない、cssnextで使われていないプラグインは使わない

とはいえcssnextは重要な指標になると思っていて、進むべき方向として参考にするには十分な存在だと思っています。 とても安易でもはや自分で判断したものではないのですが・・・。

cssnextは結局はプラグインの集まりなので、ここに使われているプラグインはある程度信用していいと思います。

CSS4の文法に則っていますし、もしプラグインが死んでも自分で作れる、あるいは誰かが作る可能性が高いと思います。

そもそも、Sassの機能を使いたいならPostCSSに移行すべきではありません。

postcss-simple-varsを捨てる

これがとても大変でした。

変数なんてあちこちで使っていますし、記法が結構変な感じで変わるので置換もちょっと面倒で・・・。

これまでは

と書いていたのを、

と書くようにします。ちなみにスコープが使えるようになります。私は使っていませんが。

追記: スコープは未実装でした。

置換したコマンドはちょっとどれだったか覚えていませんが、これでしょうか・・・。

動かなかったらすみません。

postcss-nestingに乗り換える

私はなぜかpostcss-nestedを使っていたのですが、postcss-nestingに切り替えました。

これによって以下が、

こう書かなければいけなくなりました。

これは置換する方法がわからなかったので、1個1個手で修正しました・・・。 まだCSSのファイルが40くらいだったので、軽い痛みで済みました。

なぜわざわざ大変な方に行ったのかと言うと、これもやはりCSS4の仕様に追従するためです。 中途半端にSassの機能を引きずりたくなかったので。

extendを捨てる

まあこれもSassで好きな機能だったのですが、やめました。 postcss-applyを使えばだいたい同じことができます。

こう書いていたものが、

こうなります。

カレントセレクタはどうなのでしょう、使えないと思います。

mixinは残しました

これはちょっとどうしようもありませんでした。

他に代替的な仕様がないのか探したのですが見つからなくて・・・。

grepで除去できるものは使っても良いルール

最終的に、cssnextにないけど残したプラグインは以下の2個です。

postcss-hexrgba

postcss-mixins

これらは最悪やめるときがきても、grepで引っ掛けられるからいいかなと思います。

今使っている.postcssrc.yml

わからなくなったらplaygroundへ。

cssnext Playground

以上です。

[Rails5.1.3] Sass(SCSS)からwebpacker + PostCSSに移行してみます

私は結構Asset Pipelineの仕組みが好きなので特にやめたいという意識はないのですが、 個人プロジェクトですし新しいものを実際に使ってみる経験というのも大切かなと思いました。

あと、私のプロジェクトは依存性の解決だけをyarnがやっていて、yarnで落としている3rd Party系アセットをAsset Pipelineで運用していくやり方に限界を感じていました。

CSSとその他フォントファイル等が共存しているパッケージなどです。

移行前の状態

現状はそれなりにRailsの基本的な状態です。私はあまり色んなものをゴテゴテと入れないタイプなので。

rails (5.1.3)

アセット系はすべてAsset Pipelineで処理

依存性に関してはyarnでやりたかったのでwebpacker:installは済んでいます

でもwebpackerは使っていません

目指すところ

「移行すること」を目的にしてしまうのはあまりにもナンセンスなので、移行後に目指すところと守るべきラインを決めます。

そもそも、現状の環境に困っているわけではないですし・・・。

.scssで書いているものを全部移行して、PostCSS on webpackerで処理できるようにする

scss-lintをやめて、stylelintに移行する

Autoprefixerは今でも使うのが常識らしいので入れます(勝手にいらないものと思っていました・・・。)

Set Up Your Build Tools | Tools for Web Developers | Google Developers

守るべきライン

CSSに関する部分だけなので、とりあえず以下だけにしました。

ファイルサイズは極端に増やさない(Autoprefixerなしの状態で)

処理時間は極端に増やさない(Asset Pipelineは移行後も生きるので、webpackの頑張り分が多少増える気がします)

FontAwesome等の3rd Party系アセットも、きちんとダイジェスト付きで配信する

開発環境は悪化させない(主にwebpack-dev-serverまわりのこと)

Roadieはちゃんと動くようにする(HTMLメールを使っているので)

これが守れないならmasterブランチにマージしません。

私はCSSが大きくなるのがとても嫌なタイプなので・・・。とはいえ少しくらい増えるのはOKとします。 10KBとか増えるならNGです。

移行前作業 - 現状での出力されるファイルサイズと処理時間を計測

そんなに大きいプロジェクトでもないので、言うほどでもないかと思います。 FontAwesomeが幅を取っているかもしれませんね・・・。

ビルド

ファイルサイズ

処理時間の計測はこれでいいのでしょうか。こういうのは詳しくないので誰か教えてください・・・。

移行作業その1 - PostCSSが動くようにする

webpackerは標準設定があるので、まずそれを把握するためにとりあえずREADMEに目を通します。

rails/webpacker: Use Webpack to manage app-like JavaScript modules in Rails

あれ!PostCSS - Auto-Prefixerって書いてありますね・・・。Autoprefixer、デフォルトで有効ということでしょうか・・・?

追記: cssnextに標準でAutoprefixerが入っているからです。

application.cssを作成

こういったもののディレクトリ構成はデファクトみたいなのがあると思いますが、私はこうしました。

application.jsはこうです。

CSSの中身は移行したものではなく、PostCSSを使っていない暫定の記述だけです。とりあえず疎通が見たかったので。

HTMLからの呼び出しはstylesheet_pack_tagを使えばいけるようなのですが、この記事に書いてもしょうがない作業なので割愛します。

PostCSSがちゃんと動くかを見る

application.cssの中身をPostCSSぽくして、ちゃんと動くかを見てみたいので、 まず、webpackerのCSSに対するローダーがデフォルトでどのようになっているかを確認してみます。

設定はここでしょうか。

webpacker/style.js at master · rails/webpacker

逆から読むのでしたっけ?これは以下の順番で処理してくれるということなのでしょうか。webpackの設定ファイルの見方がいまいちわかりません・・・。

sass-loader

postcss-loader

css-loader

あれ、sassも読めるのでしょうか・・・。まあどちらにせよ、PostCSSのローダーは入っているようなのでこのまま行ってみましょう。

PostCSSの設定はルートに.postcssrc.ymlを置けばいいみたいですね。

webpackerのインストール直後はこんな感じで配置されるようです。

smart-importが入っているので、importが使えるかを見てみます。

app/javascript/stylesheets/modulesディレクトリを作って、test.cssを作ってみます。

application.cssはこんな感じです。

bin/webpackを実行すると・・・、

うまくいっているようです!

移行作業その2 - とりあえずCSSを移行して処理してみる

とりあえずどかっとファイル移動しただけでどうなるかを見てみます。SCSSの拡張子もそのままです。

ああ、まあエラーしたので、章をわけて1個ずつ対応します。

smart-importでglob展開はできない

globでのimportはできないようです。過去にpostcss-importプラグインがサポートしていたようですが、外されたようです。

Remove glob support · postcss/postcss-import@1fbeca6

postcss-easy-importというプラグインでできるようですが、まあここで増やすのもどうかな・・・という気もするので、1個1個importするように書き換えました。

TrySound/postcss-easy-import: PostCSS plugin to inline @import rules content with extra features

この対応だけしたら、普通にbin/webpackは通るようになりました。

FontAwesomeを読めるようにする

これまではGemで読んでいたので、ダイジェストもいい感じにやってくれていました。 webpacker経由でうまいことダイジェストも解決する方法を知らないので、ここで解決してしまいます。

application.cssには

CSSだとフォントファイルにダイジェストがつかなかったりするかな?と思ったら、なぜか読み込むだけでうまくいきました・・・。

これは何かのローダーがやってくれているのでしょうね。ちょっとその辺は追っていませんが、すごいですね・・・。

移行間作業 - 出力されるファイルサイズと処理時間を計測

とりあえずビルドは通ったので、ここでちょっと計測してみます。 変数展開とかが全然できていないはずなので、まだ完成ではないですが・・・。

ビルド

ファイルサイズ

比較

あれ!致命的なほど遅くなりました!source mapも出してしまっているからでしょうか・・・。

移行作業その3 - webpackerの設定をちゃんとする & 足りないプラグインを入れる

このままでは失敗に終わってしまいます!足りないプラグインを足しながら設定を見直します。

全然知識がないのでとりあえず調べてみます。

build performance

devtool: "eval" has the best performance, but it only maps to compiled source code per module. In many cases this is good enough. (Hint: combine it with output.pathinfo: true.)

なるほど。source mapは一旦いいでしょう。

source mapを出さないようにしてみる

む、むしろ遅くなりました・・・。

SCSSをやめる

source mapの設定はいったんデフォルトに戻して、違う原因を探します。

application.scssを削っていったら改善されたので、どうやら@importの数か、純粋に処理しているファイル量に応じて遅くなっているようです・・・。 SCSSをそのまま移行したのがだめだったのでしょうか?

90548ms!

とりあえずSCSSをCSSに変えてみます。 拡張子を変えて、処理できるようにいくつかプラグインを追加します。

.postcssrc.ymlにも追加します。

.postcssrc.ymlは記述の順番がシビアみたいです。とりあえず上の状態では動きました・・・。

mixinについてはちょっと記述の修正が必要でした。

これで実行してみると・・・。

おお!10分の1になりました!

assets:precompileは・・・。

比較

まだ移行前より遅いですが、だいぶよくなりました!もうちょっと頑張れば超えられるかもしれません・・・。一旦は許容範囲ということにしましょう。

ちなみにsource mapを出さないようにしてみると・・・?

全然速くなりません!やり方が違うのでしょうか・・・。

ファイルサイズは変わっていなさそうです。これはいいですね。

他に参考にした資料です。

Optimising build performance, initial: 40s, incremental: 6s · Issue #1574 · webpack/webpack

移行作業その4 - 開発環境でのスタイルシートの更新監視

webpackでCSSを処理するようになったので、これまでのようにrails sしていれば一緒に処理される、ということがなくなりました。

(追記 : これは処理されるみたいです。ただ常駐しないので毎回webpackが立ち上がって・・・という感じの挙動で遅かったです。)

bin/webpack-dev-serverをrails sと並行して起動する必要があるので、公式も推奨しているForemanを使ってプロセス管理をします。

開発環境はシンプルに保ちたいので、この工程が入るなら導入しなくてもいいかなと思うくらいのハードルでした・・・。

webpacker/env.md at master · rails/webpacker

とりあえずProcfileを作ります。ローカル用に分けたかったので、Procfile.localにしました。

Foreman自体も入れましょう。

あとは実行するだけです。

移行後作業 - プラグインの設定とめぼしいプラグインを入れる

さて、ここらへんで今後の運用も考えて、PostCSSにはどんなプラグインがあって、どんなものを入れたいかを考えてみようと思います。 導入しないにしても、知っておく必要はあると思いますので。

とりあえず移行しました!だけだとただのやってみた記事になりますし、そもそももったいないので。

以下から探せるのですが、

PostCSS.parts | A searchable catalog of PostCSS plugins

一覧性が悪かったので、以下をざっと眺めてみました。

postcss/plugins.md at master · postcss/postcss

CSS4のものなどは見ていて面白いですね。

Autoprefixer

まずは目的の1つであったAutoprefixerからです。

どのブラウザを対象にするかのジャッジがちょっと難しいらしいですね。 デフォルトだと結構バッサリと切り捨てるようなので、一旦そのままにしてあとでちゃんとドキュメントを読んでみようと思います。

hexrgba

これは私が普段とてもよく使うので入れなければいけませんでした。忘れていました。

seaneking/postcss-hexrgba: PostCSS plugin that adds shorthand hex methods to rgba() values

rgba(0, 0, 0, .5)みたいなものを、rgba(#000, .5)みたいに書けるようにするものです。

lazyimagecss

画像のサイズを自動的にwidth、heightに設定してくれるものです。これはすごいですね!

Jeff2Ma/postcss-lazyimagecss: A PostCSS plugin that generates images's CSS width & height properties automatically.

導入はしませんでしたが覚えておきます。

移行後作業 - stylelintを入れる

stylelint

これはどちらにしろ入れる方針だったので、最後にやってしまいます。

CLIでも動くようにできるみたいですが、せっかくなのでPostCSSの処理に組み込んでしまいます。

私はCSSのlintはsmacssのソート順になっていることだけをチェックできていれば満足なので、以下の設定を使います。

cahamilton/stylelint-config-property-sort-order-smacss: Stylelint config for Property Sort Ordering based on the SMACSS methodology

.stylelintrc.ymlはこのようになります。

stylefmtというものを使えばauto correctもできるみたいなので、今度やってみます。

まとめ

長くなったので整理します。

移行前後の処理時間

約30秒も遅くなってしまいました。悔しいですが妥協します。

移行前後のファイルサイズ

これはAutoprefixerも入った状態のものです。1KB増えました。許容範囲です。

最終的なpackage.json

最終的な.postcssrc.yml

stylelintはこのプロセスに入れてしまうとnode_modulesが処理されてしまって除外の仕方がわからなかったので、CLIでやるようにしました・・・。

エディタ上では効くので、まあCIで弾ければいいかなと思います。

書かなかったけど詰まったところ

@import "any/styles.css"のように拡張子をつけないと変数周りの処理がうまくいきませんでした(css以外の処理が入ってしまう?)

@define-mixin、@mixinの引数には括弧を付けてはだめみたいです(エラーしてとても詰まりました!)

postcss-extendではプレースホルダーセレクタの中でカレント(&)が参照できなかったので、mixinにしました

画像を参照したいときは、url(asset_path())で持ってきたところを普通にurl()にすれば見れるようになります。パスは~images/xxx.jpgみたいな感じです。

今後

せっかくなので、JSと画像系アセットもwebpack側に寄せようかなと思います。 そうすればAsset Pipelineがいらなくなるので、少しは速くなるかもしれません・・・。

Docker上のDebianイメージ(ruby/2.3.3-slim)で日本語が打てない問題の解決方法

Docker Composeはいいですよね。 とても手軽に使えますし、慣れたらもう戻れない魅力があります。

自分の開発環境はcomposeで構築していて、Railsが載っているWeb用イメージはRubyの公式Dockerイメージをベースに使っているのですが、 これだとDocker上で日本語が受け付けなくて何かと困ることが多いです。

元のDockerfileは以下で、FROM debian:jessieでわかるようにdebianが使われています。

ruby/Dockerfile at 7a3e1295bbc840c350fc37d406692301b27f4e86 · docker-library/ruby

debianのロケール設定はUbuntuともちょっと違ったりして、調べて出てくる情報だと全然解決できなかったりします。 そして毎回この問題で困っている自分も嫌なので、備忘録として残しておきたいと思います。

ちなみに結論からいうと、自分の場合の解決方法はこちらでした。

なぜ日本語を受け付けないのか

いろいろ調べてみるとロケールの設定によるもののようです。 この辺りは少し難しいのであまり理解できていませんが、そのうちちゃんと勉強したいところです。

docker の ubuntu イメージで日本語が入力できない件 - しゅんログ

Docker1.11 / Ubuntu14.04 でコンテナの bash から日本語入力できない時 - Qiita

Docker+Ubuntuで日本語入力できないのを解決した - nocorica

Docker: Bash で日本語入力を扱う - Sarabande.jp

だいたいは言語のパッケージを入れて、ロケールを設定すればいけるという説明なのですが、 Debianだと少し勝手が違ったり、そもそもそれでは直らなかったりします。

Language Pack

Ubuntuだとこのような形で、言語パックが導入できるようです。

これがDebianだとこうなります。

まあこれが原因ではなかったのですが、UbuntuとDebianでこのような些細な違いがあったりするのだなと。

日本語を打てるようにする

散々探し回ったのに、この記事で完璧に説明されていました・・・。

たぶんLANG設定をすればうまくいきます

FROM ruby:2.2.3 ENV LANG C.UTF-8

Docker Compose でローカルの Rails 開発環境を作る - Qiita

うまくいきました。

結局のところロケールってどう使われているのか

OSの動作をどういう言語で行うかを設定するものなのだろう、くらいの認識です。

Linux では Locale を使ってユーザーがどの言語を使うか定義します。また、locale は使われる文字セットも定義するので、あなたの使っている言語が非 ASCII 文字を含んでいる場合、正しい locale を設定することは特に重要になります。

ロケール - ArchWiki

ではlocaleコマンドで表示される変数はどういう意味を持っているのかというと、

このような意味があるようです。

|環境変数|意味| |:----|:----| |LC_CTYPE|文字の分類および大文字/小文字の変換。| |LC_NUMERIC|小数区切り文字 (または基数文字)、千の区切り文字、およびグループ化を指定します。| |LC_TIME|月の名前、曜日、一般的な完全表示や短縮表示など、日付や時刻の書式を指定します。| |LC_MONETARY|ロケールの通貨記号、千の区切り文字、符号の位置、小数点以下の桁数など、通貨の書式を指定します。| |LC_COLLATE|ロケールの照合順序および正規表現の定義を指定します。| |LC_MESSAGES|ロケールのローカライズメッセージの記述言語、および肯定と否定の応答 (yes と no の文字列と表現) を指定します。|

ロケール(locale)まとめ - Qiita

利用可能なロケールを確認 / 追加する

言語によっては最初から利用可能だったり、そうでなかったりするようです。 利用可能なロケールはlocale -aで確認できます。

Debian系の場合は、/etc/locale.genに書いてあるロケールのコメントアウトを解除してlocale-genコマンドを実行することで有効にできるとのことです。

参考にさせていただきました

Docker Compose でローカルの Rails 開発環境を作る - Qiita

Docker / rails console で日本語入力できない問題 · GitHub

ロケール(locale)まとめ - Qiita

ロケール - ArchWiki

Hugoのテーマを何個か作ったので知見をまとめてみます

Hugoは静的サイトジェネレータの中でもだいぶ柔軟性のあるツールだと思います。

ただ、その分気をつけなければいけないことがあったり、実現する方法が分かりづらかったりすることが多いので、 そういった点をまとめてみます。

テーマの作成

まずはテーマを作ります。 この章では、テーマを作るための環境の作り方を解説します。

HugoBasicExampleをcloneしましょう

HugoにはHugoBasicExampleという、サンプルの記事や基本的な機能を使ったテスト用レポジトリが用意されています。

spf13/HugoBasicExample: Example site to use with Hugo & Hugo Themes

Hugoのテーマづくりは、このレポジトリのcloneから始まります。

hugo new theme

次にテーマの雛形を作ります。 Hugoにはテーマの雛形を作り上げるコマンドがあります。

hugo newコマンドは、新しくサイトを作るときやページを作るときにも使われます。 とにかく、何か新しいものを作るときに使われるコマンドで、テーマを作るときもこれを使います。

cloneしたHugoBasicExampleのルートディレクトリでコマンドを実行すれば、./themes/XXXXに雛形が作られます。

後述するthemes.gohugo.ioに載せてもらうために必要なファイルも揃っているので、0からファイルを作るよりこのコマンドを使うのが賢明だと思います。

ページの構造とテーマファイルの基礎的な構造を理解する

Hugoのページ構造はだいたい次の通りです。

HomePage

list

single

taxonomies

terms

404.html

で、hugo newで作られるテーマファイルの構成は次の通りです。

実は、この雛形には足りないものや要らないものもあります。 それはおいおい自分の好きなように足したり消したりすれば大丈夫です。

テンプレートファイルと対象ページの紐付けを理解する

テンプレートファイルと対象ページの紐付けは、実は少しややこしいです。

なぜかというと、Hugoは対象のテンプレートを特定の順番で走査する仕組みになっていて、 ページごとに細かくデザインを変えたり、全体で1つのテンプレートに統一したりと、融通が効くようになっています。

listページを例に具体的な構造を示すとこうなります。

Hugo - Content List Template

上から順に、最初に見つかったテンプレートを採用します。 つまり、最終的に/themes/THEME/layouts/_default/list.htmlまですべて見つからなければ、何も描画されません。

オーバーライドの仕組みを理解する

Hugoの最も便利な仕組みの1つとして、テンプレートファイルは./themesとルート直下のものでそれぞれ用意できるような仕様があります。

つまり、themesにおいたテーマファイルをユーザが独自にオーバーライドできるようになっています。

先の例にあげたlistで言えば、/layoutsと/themesで同じファイルを走査しているのがわかります。

例えば、ユーザがあなたのテーマを使ってくれたとします。

そのまま使えばあなたがデザインしたとおりに描画されますが、対象のテンプレートファイルと同じ名前をルートディレクトリに配置することで、 そのファイルだけを独自に変更することができます。

ここで大事なのは、これはテンプレートファイルに限った話ではなく、CSSや画像などの静的ファイルにも同じことが言えるということです。

これをうまく利用することで、ユーザが豊富なバリエーションで使うことができるテーマを作ることができます。

何から手をつけるか

ここまでで、Hugoのテーマづくりにおける基礎的な解説はできたと思います。

しかし、実際に手をつけるとなるとどこから着手していいかわからなくなると思います。 というわけで、自分がテーマを作るときの作業順序をまとめてみます。

./layouts/index.htmlの削除

Hugoは./layouts/index.htmlがなければ、./layouts/_default/list.htmlが採用されます。

自分は複雑な構造にするのが嫌なので、まず./layouts/index.htmlを消してしまいます。

トップとそれ以外の記事一覧で表示を変えたい場合は、if文と.IsHomeでなんとかします。

トップと一覧が大幅に乖離する場合は、ちゃんと分けたほうが良いです。

./layouts/_default/baseof.htmlの作成

後述するblock templatesを使うため、baseof.htmlを作ります。 ここでHTMLに必要な<!DOCTYPE html>やmetaタグの配置、ヘッダとフッタのマークアップとデザインをします。

Hugo - Block Templates

./layouts/_default/list.htmlの作成

次にlist.htmlを作ります。 前述したとおり、Hugoは./layouts/index.htmlがなければ、./layouts/_default/list.htmlが採用されます。

このタイミングで、トップページのマークアップとデザインを終わらせます。

./layouts/_default/li.htmlの作成

Hugoは断片的なパーツ、例えば一覧表示用の記事など、使い回しをする素材を切り出すことを推奨しています。

これはPageが持つ.Renderを使って実現します。

Hugo - Hugo Template Functions

./layouts/_default/list.htmlには最新記事の一覧を表示する場合がほとんどであるため、 ./layouts/_default/list.htmlで作った記事1つ1つをli.htmlに切り出します。

./layouts/_default/single.htmlの作成

次に記事詳細を作ってしまいます。 これはここまでで説明したものとなんら変わりないので、特筆なしです。

./layouts/_default/terms.htmlの作成

次にtermsのページを作ります。 このページは質素になりがちなので、デザインが難しいです。

./layouts/404.htmlの作成

忘れがちなのが404.htmlです。 ちゃんと作っておかないと空白のページが作られます。

気をつけたほうがいいこと

ここまでで基本的なテーマを作れるまでの説明をしました。 しかし、これだけだときっとハマるであろう落とし穴がいくつかあります。

相対パスは避ける

画像や静的資材の参照には相対パスを使ってはいけません。これはHTML上にあらわれるあらゆるファイルすべてに言えます。

ユーザはドメインのルートであなたのテーマを使うとは限りません。 例えばthemes.gohugo.ioがいい例です。

Hugo Themes Site

各テーマのデモはサブディレクトリで構成されます。 つまり、相対パスを使ってしまうと参照が壊れてデザインが崩れます。

{{ .Site.BaseURL}}を使って絶対参照で構築するべきです。

マジックナンバーは避ける

よくあるのが、Taxonomyに使われる値をべた書きしてしまうものです。 categoriesやtagsなど。

これをマジックナンバーで書いてしまうと、ユーザが独自にTaxonomyを定義できません。 Hugoは.Site.Taxonomiesで定義されたTaxonomyをすべて取得できるので、できるだけ柔軟に使えるようにしましょう。

Hugo - Displaying Taxonomies

Hugo側でcategoriesとtagsはデファクトのようなスタンスを取っているので、それを理解した上でべた書きするのはありだと思います。

必要最低限の機能を付ける

サイトを作る上で、誰もが使いたいであろう機能があります。 そういった機能はできるだけつけたほうが良いです。

GoogleAnalytics

代表的なものがGoogleAnalyticsです。 Hugoはconfig.tomlにGoogleAnalyticsのUserAgentを記述できるようになっています。

この値が設定されていればGoogleAnalyticsのタグを配置するべきですし、 設定されていないなら出すべきではありません。

そういったときにはwithが便利に働きます。

Conditionals | Hugo - Go Template Primer

GoogleAnalyticsのタグは_internal/google_analytics.htmlという内部テンプレートが用意されています。 自分で書くよりもこれを呼び出してしまえば、値の設定、未設定の判定もやってくれます。

Hugo - Analytics in Hugo

Disqus

静的サイトのコメント機能でもっとも有名なDisqusです。 これもGoogleAnalyticsと同様、変数名が決まっています。

Hugo - Comments in Hugo

DisqusもGoogleAnalytics同様、内部テンプレートが用意されているので、それを呼び出すのが良いです。

Generator

HugoはHugoのコミュニティを成長させるために、metaタグにgeneratorを明記することを推奨しています。

generatorは{{ .Hugo.Generator }}でタグとともに出力されます。 ユーザに影響をあたえるものではありませんが、Hugoの発展のためにできるかぎり入れてあげたいところです。

generator-meta-tag | Hugo - Creating a Theme

Share button

シェアボタンも、基本的にはどのサイトにも必要になります。 これは国によって使われるサービスやSNSが異なるため、可変にできるとなお良いです。

また、シェア自体いらないという場合もあるため、config.tomlで表示、非表示が切り替えられたり、 記事単位に.Paramsで切り替えられたりすると良いと思います。

よりよいテーマにするために

ここまでで、必要最低限なものが揃ったテーマを作るための説明はできたと思います。 次は少し発展させて、ユーザが柔軟にテーマを使うための機能を作ります。

Menuを可変にする

だいたいのWebサイトには、メニューが配置されます。 HugoにはMenusという機能があり、これを使うこともできます。

Hugo - Menus

ただ、実際にこれを使ってMenuを形成している人は少なそうな印象です。 そのため、config.tomlなどで設定できるようにしているテーマが多く見られます。

自分がもっとも適切と思える形で実装し、READMEで設定の仕方を説明すると良いです。

Shortcodesを用意する

Wordpressやその他のブログシステムにはShortcodesというとても便利な機能があります。

もちろんHugoにもありますので、基本的なものはテーマ側で用意しておくと良いです。

Hugo - Shortcodes

これはマークダウン内で定型的なHTMLを差し込むことができるものです。 例えば、画像やiframe、Twitterの埋め込みなどは、毎回HTMLを書くよりも手軽に呼び出せるようにしたかったりします。

テーマが用意するShortcodesとしては、画像の埋め込みと右寄せ、左寄せくらいを提供できると良いです。 機能を作ったら、README.mdに使い方を書いておきます。

custom.cssを作っておく

ユーザが独自に、デザイン的なオーバーライドをしたい場合があります。

styles.css1つ用意しておけば、ユーザがまるまるHugoのルートディレクトリにコピーしてオーバーライドすることもできますが、 全体をコピーしないといけなくなります。

そういったときのため、custom.cssという空っぽのスタイルシートを用意して読み込ませておくと良いです。 ユーザは必要な場合のみcustom.cssを作ればいいですし、そうでないなら空っぽのまま使われるだけです。

テーマのバージョンアップをしたときも、影響を少なくすることができます。

言語を超えて拡張性をもたせる

Hugoは全世界のあらゆる国で使われています。 テーマもできるだけ、特定の国に依存しないようにします。

DateFormatを可変にする

まず言えるのが、日付の形式です。

日本は2016/01/01といった形式ですが、世界では違います。 これはできるだけ、柔軟に変えられると良いです。

例えば、config.tomlに次のように設定できるようにします。

テンプレートファイルでは次のように描画します。

フォントを可変にする

英語圏ではHelveticaやArialなどでいいフォントも、国によってはそうとも言えません。

これもDateFormatと同じように、config.tomlなどで設定できると良いです。 custom.cssを用意する方法でも良いですが、フォントだけのためにファイルを作らせるよりは、設定で変えられると親切だと思います。

開発における発展的なノウハウ

ここでは、テーマを作る上でのさらに発展的なノウハウについてまとめます。

block templatesを使いたい

すでに登場しましたが、Hugoはblock templatesという機能が使えます。

Hugo - Block Templates

これはベースとなるテンプレートと子となるテンプレートを用意できる機能で、 HTMLの共通的な部分をベーステンプレートに切り出すことができます。

しかし、このHugoの機能には現在バグがあり、時折Golangのエラーメッセージを吐いてクラッシュします。

この記事を書いている今も、かなりの回数クラッシュしています。

おそらく記事生成をgoroutineで回していて、その中でmapへの不適切なアクセスが走っているのだと思います。 そのうち直ると思いますが、気になる方はblock templates自体を使わないほうが良いです。

Concurrent map read and write error in template handling · Issue #2224 · spf13/hugo

Issueもあがっていますが、再現できていないようです。

AMP対応をしたい

AMP対応は制約がいくつか付くだけなので、そこまで難しい実装ではありません。

おそらく一番困るのがスタイルシートの導入だと思います。 自分は./layouts/partials/styles.cssにスタイルを配置して、次のようにしてインラインCSSとして描画しています。

themes.gohugo.ioに載せてもらう

テーマを作ったら、Hugoのテーマポータルであるthemes.gohugo.ioに載せてもらうための手順を進めます。

Hugo Themes Site

theme.tomlを書く

まず、theme.tomlを書く必要があります。 これはhugo newで雛形が作られているので、それにそって書けば大丈夫です。

基本的な説明は、Hugoのテーマ用レポジトリのREADMEにあります。

spf13/hugoThemes: All Themes Hugo

スクリーンショットを撮る

themes.gohugo.ioに表示されるサムネイルが2つの異なるサイズで必要になります。

Thumbnail should be 900×600 in pixels

Screenshot should be 1500×1000 in pixels

Media must be located in:

[ThemeDir]/images/screenshot.png

[ThemeDir]/images/tn.png

一番映えるページでスクリーンショットを撮り、配置します。

README.mdを書く

README.mdはユーザにもっとも近いドキュメントになります。 ここにはできるかぎり親切な情報を載せたほうが良いです。

例えば次のようなものです。

Screenshots

Features

config.toml example

frontmatter example

Shortcodes example

必要であれば、画像も使って説明をします。

GitHubにIssueをあげる

ここまでできたら、自分のテーマレポジトリをHugoのテーマ用レポジトリにIssueとして連絡すれば大丈夫です。

spf13/hugoThemes: All Themes Hugo

コントリビューターの方が確認して、修正すべきポイントがあればIssueをあげてくれますし、 問題なければ取り込んでCloseしてくれます。