blog.unresolved.xyz

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よりはTSネイティブな感じがあるのと、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

何もしてないのに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

認証周りむずすぎてつらい。

何回目はわからんけど16personalitiesをやったらISFJ型だった

なんか定期的にパーソナリティテスト何型?って聞かれるけど絶対覚えてられないのでメモっておこうと思った。

“擁護者”型の性格 (ISFJ) | 16Personalities

Daisuke Tsuji - Turbulent Defender (ISFJ-T) | 16Personalities

良いことばっかかいてあるけど当てはまってないところ結構あるぞ・・・?

TypeScriptのmapped typeまじで記法わからん

Creating a mapped type | Learn TypeScript

脳みその記憶容量が足りなくて辛い

React Hook Formのresetメソッドでnumber型のフィールドをリセットするいい方法がわからん

こうやってるんだけど何がスマートなの・・・?

useForm - reset | React Hook Form - Simple React forms validation

JSの文字列 -> 整数変換はNestJSのgeneratorから学んだ

Nest.jsの nest g res xxx をするとこんなコントローラが生まれるんだけど、この +id なに・・・?って思ってたらどうやらHTTPパラメタで渡ってきた文字列のIDを整数にするためにやってるぽかった。

一昔前に "1" | 0 ってやるのが一番パフォーマンスが良いと教えてもらったことがあるけど、今はこういうやり方があるんだなあという学び。

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

tsconfigのbaseUrlとeslintを共存させる

tsconfigにbaseUrlを設定しているとeslintがコケることがある。

1回設定したら終わりだしメモらなくていいでしょ〜って思ってたけど5回ぐらいググってるのでこっちにメモっとく。

eslint-import-resolver-typescriptの導入とresolverの設定をする

ようはimport記法でtsファイルを解決できてないらしい。

して、

したら消えます。

refs

[import/no-unresolved] when using with typescript "baseUrl" and "paths" option #1485

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

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

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

Next.jsはAPIエントリポイントがでたときに「え〜そんなフルスタックになっちゃうの?」って気持ちがあった。

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

あとAPIエントリポイントがあるとプロキシとしても使えるので、バックエンドサーバを隠蔽することもできるし、HTTPヘッダにAuthorizationを埋め込んだりってこともできるのでめちゃくちゃ便利に使えてる。

Railsは1PJでGraphQL APIとして使ってるんだけど、正直これもTSで書いたほうが書きやすいのでそのうち捨てそうだなあという感じ。

慣れてるから書きやすいっていうのはあるし、何でも揃ってるから楽ではあるんだけど、やっぱりその分融通がきかなかったりはするので今後も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のスタックで個人PJを進めてるんだけど、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.

binnstubが変わってるぽいので最新のもので再生成。

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の文法に則っているわけだし、もしプラグインが死んでも自分で作れる or 誰かが作る可能性が高いと思う。

そもそも、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してくれる。