gooberでtailwindcssを使うヘ(^o^)ノ

前の記事でNext.jsでgooberを導入してみました

murajun1978.hatenadiary.com

今回はgooberでtailwindcssを使ってみます

Next.jsにtailwindのセットアップしていきましょう

$ npm install @tailwindcssinjs/macro @tailwindcss/ui tailwindcss
$ npm install -D @babel/core babel-plugin-macros
// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme');

module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['Inter var', ...defaultTheme.fontFamily.sans],
      },
    },
  },
  variants: {},
  plugins: [require('@tailwindcss/ui')],
};
// babel.config.js
module.exports = {
  presets: ['next/babel'],
  plugins: ['macros'],
};

これでsetupはOKです

んじゃ、使ってみましょう

// src/pages/index.tsx
import { NextPage } from 'next';
import { styled } from 'goober';
import tw from '@tailwindcssinjs/macro';

const styles = {
  button: tw`
    relative
    w-64 min-w-full
    flex justify-center
    py-2 px-4
    border border-transparent
    text-sm leading-5 font-medium
    rounded-md
    text-white
    bg-teal-600
    hover:bg-teal-500
    focus[outline-none border-teal-700 shadow-outline-teal]
    active:bg-teal-700
    transition duration-150 ease-in-out
  `,
};

const Button = styled('button')(() => styles.button);

const Home: NextPage = () => <Button>button</Button>;

f:id:murajun1978:20200704093804p:plain

動かして確認するとわかると思いますが、一部のスタイルがあたっていないと思います

backgrand-colorですね

理由はtailwindcssinjs/macroではcros-browser対応するためにfallbacksというsyntaxを使っています

{
  ...
  backgroundColor: ["#047481", "rgba(4, 116, 129, var(--bg-opacity))"]
  ...
}

tailwindcssinjs/macroの出力は👆のように配列になってます

これがgooberにはわからないんですね

解決方法はtailwindcssinjs/macroのREADMEに書いてあります

github.com

tailwindcssinjsのpluginで出力フォーマットを変更できるみたいです!

CSSのStringで出力するpluginを導入してみましょう

// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme');

module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['Inter var', ...defaultTheme.fontFamily.sans],
      },
    },
  },
  variants: {},
  plugins: [require('@tailwindcss/ui')],
  tailwindcssinjs: { // ここ追加
    plugins: [require('@tailwindcssinjs/macro/lib/plugins/cssString').default],
  },
};

f:id:murajun1978:20200704093731p:plain

スタイルがあたりました!

Enjoy goober + tailwindcss ヘ(^o^)ノ

Next.jsでgooberを使ってみるヘ(^o^)ノ

はじめに

gooberというcss-in-jsのパッケージがあります

github.com

使い勝手はstyled-componentsとか、emotionなんかと同じです

ただ、パッケージのファイルサイズがびっくりの1KBです😆

このサイズは魅力的なので、Next.jsで使ってみましょう

Installation

$ npm install goober@next

最新がほしいのでnextバージョンを指定しました

Using with Next.js

コンポーネントを作成します

// components/HeadingTitle.tsx
import { styled } from 'goober';

export const HeadingTitle = styled('h1')`
  color: blue;
`;

Homeページで使ってみます 

// pages/index.tsx
import { NextPage } from 'next';
import { HeadingTitle } from '../components/HeadingTitle';

const Home: NextPage = () => (
  <HeadingTitle>Welcome goober with Next.js</HeadingTitle>
);

export default Home;

んじゃ、確認。。。あれ、rerenderエラーが。。。

Next.jsはpre-renderがデフォルトなので、SSR用の設定しないといけないみたいです

// pages/_app.tsx
import { createElement } from 'react';
import { setup } from 'goober';

const App = ({ Component, pageProps }) => {
  setup(createElement); // setup goober for SSR

  return (
    <Component {...pageProps} />
  );
};

export default App;

あらためて、動作確認

<head>
  ...
  <style id="_goober"> .go2445103859{color:blue;}</style>
</head>
<body>
  ...
  <h1 class="go2445103859">Welcome goober with Next.js</h1>
  ...
</body>

ちゃんとstyleがあたってますね 👍

まとめ

めちゃ簡単にNext.jsに導入できました

これで更にファイルサイズを小さく抑えることができそうですね

Enjoy goober ヘ(^o^)ノ

Prisma2で指定できるIDのType

Prisma2で指定可能なIDのTypeはドキュメントに書いてあります

www.prisma.io

// integerでautoincrementする
model User {
  id Int  @id @default(autoincrement())
  name String
}

{
  id: 1,
  name: "murajun1978"
}

// cuidを使う
model User {
  id String @id @default(cuid())
  name String
}

{
  id: "ckbnw8uvi0000aloy4biot7rc",
  name: "murajun1978"
}

// uuidを使う
model User {
  id String @id @default(uuid())
  name String
}

{
  id: "dd85a66b-95b0-498f-b188-aafee97facc9",
  name: "murajun1978"
}

Prisma2は、十分productionで使えるレベルではあると思います

絶賛、RailsからNext.js + GraphQL + Prisma2へリプレイス中

Enjoy Prisma2 ヘ(^o^)ノ

CloudflareのImage Resizingを使ってプレースホルダ画像として表示する

はじめに

Next.jsではpre-renderがデフォルトです。

pre-renderとは、server side renderingとclient side renderingの中間的な存在。(雑な説明です

みなさんはMediumってブログを見たことありますか?

Mediumの記事は画像がピンぼけして、すこしたってからきれいな画像に差し替わりますよね?あんな感じです。

解像度のあらーい画像(数バイト)をしゅっとダウンロードして、それをピンぼけ状態で表示します。

んで、裏ではOriginをダウンロードしていて、完了したときに差し替えるって仕組みです。

これを実現するためには、プレースホルダ用の画像とoriginの両方の画像が必要になります。

いちいち、両方の画像を用意するのは面倒ですよね?ね?

そこでCloudflareのImage Resizingです。

Image Resizing

ビジネスプラン以上にアップグレードして、ぽちっとするだけで利用可能になります。

f:id:murajun1978:20200610214144p:plain

実際に試してみましょう。

画像のURLがこんなだとします。

https://www.murajun1978.dev/images/profile_image.jpeg

f:id:murajun1978:20200610214504p:plain

小さくてみにくいですが、8.3kbの画像です。

これくらい小さいと気にはなりませんが、もっと解像度を下げて小さくしてみましょう。

URLはこんな感じになります。

https://www.murajun1978.dev/cdn-cgi/image/width=5,height=5,quality=5/images/profile_image.jpeg

f:id:murajun1978:20200610221312p:plain

画像は小さくて見えないですよね。。。

↑のオプションを設定しましたところ、875bまで小さくなりました。

ちなみにWebPにも対応してます。

詳しい使い方はこちらを参考にしてください。

まとめ

Reactのsuspenseとかを使うと簡単に実装できますよ。

pre-render時は、CSSのopacityを0.5とかに設定して、画像をぼかして表示します。

で、Origin画像のダウンロードが完了したら、Origin画像が表示されます。

ちょー楽勝ですね!

料金ですが、ビジネスプランは$200/月です。

ビジネスプランでImage Resizingを使う場合、10万リクエストまでは追加料金なしで利用できます。

10万リクエストを超えるたびに$10かかります。

ま、個人のサイトに$200/月はちょっとお高い気もしますが、Image Resizingだけではなく、その他の機能ももりもりついてきます。

前回紹介したWorkersでも利用できるますよ。

Cloudflareをフル活用して、いい感じに手を抜きたい人は、ビジネスプランにアップグレードしてみては?

Enjoy Cloudflare Image Resizing ヘ(^o^)ノ

Next.jsをCloudflare workersから配信したい! Part 2

はじめに

Part 1では workder.devにデプロイするところまでやったよね

murajun1978.hatenadiary.com

Part2ではproductionにデプロイして、KVを使ってみましょう

Productionデプロイ

productionにデプロイする前にやることがあります。

それはAレコードの登録です。

例えば、"www.murajun1978.dev"へのリクエストをworkersに託すって設定をしないといけない。

でも、こんなのは5秒で終わる(反映するまでに5分以上かかるときがあります)

CloudflareのDNSにAレコードを追加します!

こんな感じ

f:id:murajun1978:20200608235714p:plain

次にデプロイ設定をwrangler.tomlに追記します。

ここでちょっと気をつけてほしいこと

デプロイでローカル環境で実行することはほぼないですよね?だいたいはCIでデプロイします。

CIでデプロイするってことは、GitHubなんかにデプロイするってことですよね?

そこにAPI Tokenをコミットすると。。。ね。。。

はい、wranglerには環境変数が用意されています。こちらを使うのが推奨というか、使おうね

僕はDokcerを使ってるので↓のように設定しました

# docker-compose.yml

version: '3.8'
services:
  node:
    build: .
    volumes:
      - .:/home/app
    ports:
      - 3000:3000
    env_file:
      - wrangler.env
# wrangler.env
CF_API_TOKEN=<YOUR API TOKEN>
CF_ACCOUNT_ID=<YOUR ACCOUNT ID>
CF_ZONE_ID=<YOUR ZONE ID>

んで、gitignoreにwrangler.envを追加しときましょー

CIにも↑の環境変数を設定すればOKです。

これで安心!

さ、productionの設定を追記しよう

# wrangler.toml

name = "dev-site"
type = "webpack"
workers_dev = true
route = ""

[site]
bucket = "./out"
entry-point = "workers-site"

[env.production] # プロダクション用の設定
route = "www.murajun1978.dev/*"

routeを追加するだけです!

この設定で、www.murajun1978.dev/のすべてのリクエストがworkersに転送されます

Productionデプロイ

$ npx wrangler publish --env production

やばい、簡単すぎる。。。

Cloudflareで確認するとこんな感じ

f:id:murajun1978:20200609001043p:plain

f:id:murajun1978:20200609001129p:plain

これでProductionにデプロイできました。

ここでちょっとKVを見てみましょ

f:id:murajun1978:20200609001341p:plain

ファイル名がKEYになってて、値にはファイルのHTMLやJS、CSSなんかが格納されています。

デプロイ時に、KVにKEY ファイル名 値: HTMLやJSを格納して、Edge serverから参照できるようにしているってことですね。

なので、アクセスするたびに、workersのアクセスカウントが++されていきますw

そう、HTML、JS、CSSファイルにアクセスするたびにねw

金額はささいなものなので、気にはなりませんが(少なくとも僕は)、完全無料でブログを公開したい、もしくはもっと手抜きしたい場合は、NetlifyVercelを使うって選択になりそうですね.。

GitHub連携できるのも敷居が一気にさがります。

KVにcurrent versionを設定する

これ、やろうと思ったのですが、なんか微妙だったので僕は見送りました。

切り戻したいときはrevertすればいいかなと、とはいえKVに値をセットしてみましょ(とりあえず

まずは、KVのnamespaceを設定する必要があります

# wrangler.toml

kv-namespaces = [ 
  { binding = "CONTROL", id = <YOUR KV ID>}
]

[env.production]
route = <YOUR ROUTE>

kv-namespaces = [ 
  { binding = "CONTROL", id = <YOUR PRODUCTION KV ID>}
]

KV IDってのは↓です

f:id:murajun1978:20200609003540p:plain

んじゃ、KVにセットしてみましょう

$ npx wrangler kv:key put --binding=CONTROL "putting test" "test"

f:id:murajun1978:20200609004341p:plain

はい、登録できましたね!

まとめ

Cloudflare workersを2記事にまとめてみました。

マジで簡単。

ちなみに、悶絶雑なページをlighthouseで計測してみました!

f:id:murajun1978:20200609005844p:plain

Next.js + Preactなら楽勝で100Pointsですよw

近々、ブログもこちらに移行する予定です

おそらく、Vercelを使うことになると思います。

次はCloudflareのImage Resizingを使ってみようかなー

サイトはVercelから配信して、画像はS3やCloud Storageにアップロードしたものを、Cloudflareから配信するって感じです。

pre-renderするときに、画質を落としてぼかした画像を表示しておいて、裏でダウンロードが完了したら、ちゃんとした画像に差し替えるって感じですかね。(Mediumと同じやつです

こうご期待w

Enjoy Cloudflare workers ヘ(^o^)ノ

Next.jsをCloudflare workersから配信したい! Part 1

みなさま、Cloudflare workersってご存じですか?

workers.cloudflare.com

90カ国 200都市のデータセンターで動いてるEdge serverです。

service workerのEdge server版ってとこです。

S3やCloud StorageのファイルをCDN経由で配信?

ま、それも悪くないですが、Edge serverでパッと処理してシュッと返してあげましょ!S3もCloud Storageも不要です(ヤッタ

Edge serverだから、クライアントの一番近いところで動いているので、爆速でHTMLをreponseを返すことができます。

キャッシュコントロールも可能なので、さらに爆速!Preactで更にドン!

そんな誘惑にこころ動かされたので試してみます。

注意!Workers Sitesを使うので、Cloudflare workersの有料プランである必要があります💰($5/月)

ではやってみましょう💨

Next.js

$ npx create-next-app

以上

wrangler

Cloudflare workersのCLIです。

github.com

インストール

$ npm install -D @cloudflare/wrangler

初期設定

CloudflareのアカウントIDとゾーンIDとAPI Tokenが必要です。

アカウントIDとゾーンIDは、Cloudflareのダッシュボードに表示されてるのでメモ。

API Tokenはworkers用のトークンを作成します。

こちらもダッシュボードに"API トークンを取得"ってリンクがあるので、そこからAPIトークンを作成します。

$ npx wrangler config

Enter API Token:

さきほど作成したAPI Tokenを入力して終了でっす。

Siteの作成

workers siteを作成します。

$ npx wrangler init --site hello-next-worker

workers-siteってディレクトリとwrangler.tomlが作成されたはずです。

name = "hello-next-worker"
type = "webpack"
account_id = <あなたのアカウトID>
workers_dev = true
route = ""
zone_id = <あなたのゾーンID>

[site]
bucket = "./out"
entry-point = "workers-site"

account_id, zoon_idを設定します。

bucketにはNext.jsのbuildディレクトリを指定します。

これでwranglerの設定は完了です。簡単!

ビルド

Next.jsでbuildします📦

$ npx next build
$ npx next export

Publish

workers devにpublishします。ProductionへのpublishはPart 2で。

$ npx wrangler publish

これで、https://hello-next-worker.<あなたのドメイン>.workers.dev にpublishできるはずです🎉

まとめ

以上で、Next.jsのbuildしたファイルをCloudflare workers siteにpublishして、Edge serverから配信することができました!

どうでしょう?簡単でしたよね?

Part 2では、ProductionへのpublishとKVを使って、前のバージョンに切り戻したりしてみます。

Enjoy Cloudflare workers ヘ(^o^)ノ

Traefikでdocker-composeのポート重複を解決する

昨日のDockerCon LiveのセッションでTraefikの存在を知ってしまったので、ちょっと試してみました😄

github.com

同一プロジェクト、または複数のプロジェクト間でportがかぶってちょっとずつ変えているなどなど

例) App1では3000ポートをApp2でも3000ポートを使っている

僕もいままでは、App2を4000ポートに変更して対応していました

"Simplify All the Things with Docker Compose" @mikesir87 さんのセッションを見て面白かったので試してみます

Thanks a lot, mikesir87👍

docker.events.cube365.net

github.com

僕のサンプルアプリ

github.com

ちょっと調子のってDenoで書いてみましたw

1つのプロジェクトにApp1とApp2のサーバが3000ポートでサーバが立ってます

これをTraefikを使ってProxyしてみます

サンプルコードをみてもらったら、一目瞭然なので詳しい説明はしませんが(しないのかよ!)

ハマったこと

僕がちょっとハマったことを書いておきます

僕の開発環境はLinux + Rootless dockerです

Rootless dockerがちょっとハマりました。。。

公式ドキュメントのサンプルとかでは、80番ポートでProxyしてるのですが、Rootless dockerはrootユーザで起動してないので、 localhostの80番ポートが使えなかったです😭

なので、僕のサンプルコードでは3000番ポートをリッスンするようにしてます

あとは、socketファイルのパスが違うことですね、DOCKER_HOSTを確認してくださいね

$ echo $DOCKER_HOST
unix:///run/user/1000/docker.sock

動作確認

コンテナを起動します

$ docker-compose up -d

app1.localhost:3000にアクセスしてみます

f:id:murajun1978:20200529154714p:plain

app2.localhost:3000にもアクセスしてみます

f:id:murajun1978:20200529154805p:plain

まとめ

どうでしょうか、めちゃ簡単にProxyできましたね👏

同一プロジェクトでは旨味はありませんが、プロジェクトをまたがる場合は重宝しそうです

プロジェクトをまたぐ場合は、Traefikをdeamonで動作させて、Traefikのnetworkをexportしておけばいいと思います

各プロジェクトでは、このネットワークに接続することで、Proxyできるようになります

もうポートを気にする必要はない!

Enjoy Traefik ヘ(^o^)ノ