FrankenPHPでサクッとWordPressの開発環境を作る

FrankenPHPは先日v1.0がリリースされたばかりの、PHPとWebサーバがセットになったDockerイメージです。

ちょうどローカルでWordPressを動かしたいタイミングがあったので試してみました

基本的にはdunglas/frankenphp-wordpressにひな形があるのでこれを参考にします。

まずはDockerfile。
ほぼひな形通りですが、PHP8.3以上の環境だとImagickのビルドでコケるので、今回は明示的に sha-2eabec8-php8.2 を指定しています。

FROM dunglas/frankenphp:sha-2eabec8-php8.2

# install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions)
RUN install-php-extensions \
    bcmath \
    exif \
    gd \
    intl \
    mysqli \
    zip \
    imagick \
    opcache

COPY --from=wordpress /usr/local/etc/php/conf.d/* /usr/local/etc/php/conf.d/
COPY --from=wordpress /usr/local/bin/docker-entrypoint.sh /usr/local/bin/
COPY --from=wordpress --chown=root:root /usr/src/wordpress /app/public

VOLUME /app/public

RUN sed -i \
    -e 's/\[ "$1" = '\''php-fpm'\'' \]/\[\[ "$1" == frankenphp* \]\]/g' \
    -e 's/php-fpm/frankenphp/g' \
    -e 's#/usr/src/wordpress#/app/public#g' \
    /usr/local/bin/docker-entrypoint.sh

ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile"]

docker-compose.ymlはそのままでも大丈夫そうだけど、好みの問題で下記のようにしました

version: '3.1'

services:

  wordpress:
    build: .
    ports:
      - 80:80
      - 443:443
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: docker
      WORDPRESS_DB_PASSWORD: docker
      WORDPRESS_DB_NAME: dbname
    volumes:
      - ./:/app/public

  db:
    image: mysql
    environment:
      MYSQL_DATABASE: dbname
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    ports:
      - 3306:3306

上記2ファイルをドキュメントルートの階層に置いて、起動すればlocalhostでアクセスできました。

docker compose up

ウェブサイトでSVGを配置して、cssでドロップシャドウを付ける話

以前の投稿では、SVGの色をcssを使って変更する方法についてお話ししました。今回は、SVGに影(ドロップシャドウ)を追加する方法に焦点を当てたいと思います。

divにドロップシャドウを付ける場合は、以下のようにcssのfilterプロパティでdrop-shadow関数を使用することができます。

.divShape {
  display: block;
  width: 500px;
  height: 500px;
  background: #222;
  filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4)); 
}

前回のカスタムシェイプの場合、この方法ではドロップシャドウが適用できません。

この場合、擬似要素を使用します。::before擬似要素をカスタムシェイプに適用し、その親であるdivにドロップシャドウを追加します。

このようにすることで、カスタムシェイプのdivにドロップシャドウを効果的に付けることができます。

.svgShape {
  position: relative;
  width: 606px;
  height: 514px;
  filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4)); 
}

.svgShape::before {
  display: block;
  height: 100%;
  content: "";
  background: linear-gradient(45deg, black, transparent);
  mask-size: contain;
  mask-image: url('/img/sample.svg');   
}

ウェブサイトでSVGを配置して、cssで色を変更する話

SVGをウェブページに追加する最も簡単な方法は、<svg>タグをインラインで直接記述するか、<img>要素を追加してsrc属性でSVG画像を参照することです。
SVGファイル直接に使用すると、SVGの色を変えたい時は少しややこしいです。(編集ソフトを使用して、書き直す必要があります。)
(<img> 要素を使用してインポートした場合、CSSだけで色を変更することはできません。)

単色を変えたい場合:
css実装例:

#svgID path{   
  fill: red; 
}

このようにすればcssでpath要素の色を簡単に変更できるだと思いますが、グラデーションをかけたい場合はSVGファイル自体を修正しなければなりません。そこでもう一つの方法を紹介します。

DIV要素をカスタムシェイプに:

SVGインラインで直接記述するより、DIV要素の形をSVGにすれば、色々カスタマイズができます。今回は外部SVGを参照して、cssで色をグラデーションにします。

divといえば、多くの人のイメージには長方形や正方形しかありません。しかしdivを他の形にすることができます。この時はmask-imageを使います。
(単純にdivの形を変えたい場合はclip-pathも出来ますが、今回の主旨と違いますので詳細は割愛させていただきます)

HTML実装例:
<div class=”svgShape”></div>
css実装例:
(widthとheightはsvgのサイズに合わせてください)

.svgShape {
  width: 500px; 
  height: 500px;
  background: linear-gradient(45deg, black, transparent);
  mask-image: url('/img/sample.svg');
}


このように実装すれば、divはsvgの形に変えられ、色はcssでカスタマイズできます。
実装例:

refrence:

https://developer.mozilla.org/ja/docs/Web/CSS/mask-image

Figmaでアイコン等をSlotで管理してみる

Figmaでデザイン制作する際に、
1つのアイコンを様々な大きさで使う場面があるとします。

これをVariantsでまとめておくとこんなかんじになります。

3サイズを8つの絵柄で作ると合計24個。ちょっと多い。

これをもっとスマートにまとめる
「FigmaのSlotでコンポーネントを管理する方法」があるらしく、
これを使うとコンポーネント置き場がすっきり綺麗になるそうです。

↑こんな感じ。8つの絵柄だけでOK

なので試しにやってみたぞ、というお話です。

Slotってなに?

そもそもSlotって? Figmaの機能かな?と思ってたのですが、どうやらそうではない様子。空のコンポーネントを作り、その中に入るインスタンス要素を入れ替えているようです。

参考にした動画とFigmaファイルです↓

https://www.figma.com/community/file/969234311094210750

(この動画ではカードレイアウトで解説されています)

やってみよう

1. Slotコンポーネントをつくる

まずインスタンスを入れる空のSlotコンポーネントをつくります。

長方形ツールで縦横16pxの図形を製作し、Slotという名前を付け
右クリック→「コンポーネントの作成」からコンポーネント化します。

コンポーネント化したら、もう一度選択して右クリック→「オートレイアウトの追加」を選択。右側のオートレイアウトプロパティより上下の間隔やパディングを全て0にします。

※わかりやすいようにピンクの点線で囲んでいます。

2. Slotの複数サイズ展開をつくる

デザイン内でアイコンを使用する場面を想定して、様々なサイズ展開を作ります。
今回はS(16px)M(32px)L(64px)の3種類にします。

先程製作したSlotをアセットから複製しサイズを変え、
「IconArea / S」「IconArea / M」「IconArea / L」とそれぞれ名前を付け、コンポーネント化。
コンポーネント化したら、製作した3つのIconAreaを選択して
右メニューよりVariantコンポーネントにします。

Valiantについては過去に記事を書いてますので合わせてお読みくださいhttps://blog.nasbi.jp/design/figma_variants/

3. アイコンを準備する

実際に表示したいSVGアイコンを用意し、
それぞれに「Icon / アイコン名」の名前を付けてから
コンポーネント化→まとめてVariantコンポーネントにします。

アイコンサイズは48pxにしています。

これで準備完了です。

インスタンスを置き換えてみよう

準備ができたら、あとはアセットからIconAreaを呼び出し、
IconArea / L を選択→「インスタンスの入れ替え」からアイコンを選ぶと…
アイコンがIconArea / L の大きさに可変し、インスタンスの入れ替えができました👏

ここで一つ上のIconAreaの方を選んで
「インスタンスの入れ替え」を選択しても、可変されないので注意です

普通の32pxの四角いコンポーネントを作り、インスタンスの入れ替えをしても
可変されず、元のアイコンの大きさ(48px)になってしまいます。

Slotを使うと可変されるけど…
ただのコンポーネントだと可変されず元の大きさになってしまう


Slotを使った管理方法は、
アイコンの数が多くなってしまう場合に有効なやりかたのひとつだとおもいます。
皆様も良きFigmaライフをお送りください。

LINE公式アカウントの消せないリッチメニューを消す方法

LINE公式アカウントのチャンネルを運用するには、LINE Official Account Manager(以下 Account Manager)を使う方法とサードパーティーや独自開発をしたアプリケーションを介してLINE Messaging API(以下 Messaging API)を利用する方法があります。
リッチメニューの仕様として、Account Managerで作成したリッチメニューをMessaging APIで操作したり、Messaging APIで作成したリッチメニューをAccount Managerで操作したりすることはできません。

ここで問題になるのが、リッチメニューの表示優先順位です。

ドキュメントによると(1. が最優先)

  1. Messaging APIで設定するユーザー単位のリッチメニュー
  2. Messaging APIで設定するデフォルトのリッチメニュー
  3. Account Managerで設定するデフォルトのリッチメニュー

という順で表示されるのですが、1. や 2. が設定されていると、Account Managerでリッチメニューを作成してもユーザーに表示されませんが、前述の通りAcocunt ManagerからはMessaging APIで作成したリッチメニューを削除することができません。

この場合Messaging APIを利用してリッチメニューを削除する必要がありますが、意外と簡単に削除することができます。

流れとしては

  • チャンネルアクセストークンを用意する
  • リッチメニューIDを取得する
  • リッチメニューIDを指定して削除する

の3段階です。

チャンネルアクセストークンを用意する

Messaging APIを利用するにはチャンネルアクセストークンが必要です。

チャンネルアクセストークンは LINE Developers のコンソール の「チャンネル設定」から確認することができます。

チャンネルアクセストークンがない場合は、Account Managerの右端の「設定」→左メニューの「Messaging API」のページのチャンネルID(Channel ID)とチャンネルシークレット(Channel secret)を確認できます。

そして、短期のチャネルアクセストークンを発行するAPIからチャンネルアクセストークンを発行できます。

リッチメニューIDを取得する

リッチメニューの配列を取得するAPIでMessaging APIで作成したリッチメニューのIDを取得できます。

{
  "richmenus": [
    {
      "richMenuId": "{richMenuId}", // <- これがリッチメニューID
      "name": "Nice rich menu",
      "size": {
        "width": 2500,
        "height": 1686
      },
      "chatBarText": "Tap to open",
      "selected": false,
      "areas": [
        {
          "bounds": {
            "x": 0,
            "y": 0,
            "width": 2500,
            "height": 1686
          },
          "action": {
            "type": "postback",
            "data": "action=buy&itemid=123"
          }
        }
      ]
    }
  ]
}

リッチメニューを削除する

リッチメニューを削除するAPIに先程取得したリッチメニューIDを指定して削除します。

このAPIを叩くことで「Messaging APIで設定するユーザー単位のリッチメニュー」や「Messaging APIで設定するデフォルトのリッチメニュー」も削除することができるので、Account Managerで設定したリッチメニューをユーザーに表示させることができます。

まとめ

Messaging APIが使えると、LINE公式アカウントのチャンネルをより深くカスタマイズできるようになりますが、相応の専門知識が必要です。

もしMessaging APIでお困りごとがあれば、弊社お問い合わせフォームから気軽にご相談ください。

ColimaのDocker内で `composer install` に失敗する問題の解決

M1やM2などのArm Macで、かつ Colima でDockerを使っている場合、Docker環境内で composer install でするとコケる事がある。
厄介なのは、コケたりコケなかったりColimaごと固まったり非常に不安定なことがある。
その場合恐らく、デフォルトの qemu 環境で立ち上がっていると思われるので、一旦VM環境を削除した後に

colima start --vm-type vz --vz-rosetta --mount-type virtiofs

のようにVZ環境で作り直すとうまくいく。

Virtualization.framework(vz)はMac OS 13から利用できる仮想環境のAPIで、I/Oも早くなるらしい。

aspidaのRestClientで多重送信を抑制する

OpenAPIでAPIが定義されているプロジェクトにおいて @aspida/fetch を使ってRestClientを生成・利用しています。

とあるGETリクエストを複数のコンポーネントからほぼ同時に呼び出す必要があり、リクエストの回数を1回にまとめたい状況がありました。
これをaspidaでやろうと思ったときにちょっと思ったようにできなかったのでメモ。

最初にやろうとした実装は、aspidaに渡すfetchをラップする方法。

const promises = {};
function customFetch(url, option) {
if (option.method === 'GET') {
const key = `GET__${url}`;
if (!promises[key]) {
promises[key] = fetch(url, option);
}
return promises[key];
} else {
return fetch(url, option);
}
}

promiseを再利用したいわけですが、こうすると、ResponseのStreamが使用済みなのでエラーになります。そりゃそうだ。

Response.clone() で複製してから使えばよいわけですが、aspidaの生成するtsコードで Response.json() を実行してしまうので、外からcloneを挟むようなことは無理そう…

色々考えた結果、こうなりました

const promises = {};
function dedupe(api, option) {
const key = `GET__${api.$path(option)}`;
if (!promises[key]) {
promises[key] = api.$get(option);
}
return promises[key];
}

使う側では

const result = await client.path.to.hoge.$get({ query: { fuga: 'piyo' } });

これを、

const result = await dedupe(client.path.to.hoge, { query: { fuga: 'piyo' } });

こうする。

関数で囲わなければいけなくなったのがちょっとスマートじゃないですが、まあ重複排除したいところだけ使えてポータブルな関数になったので良いということにしよう。

Google Publisher Tag のよくあるエラー

googletag.openConsole() で表示される警告文の意味と主な対処方法の自分メモ

用語

GPT: Google Publisher Tag
GAM: Google Ad Manager

ドキュメント

⚠️ 広告ユニットが取得されませんでした

何が起きているか

defineSlotは行われたが、displayやrefreshを行っておらず、広告リクエストが走っていない状態

対処方法

displayやrefreshを実行する。

googletag.display('div-id');
googletag.pubads().refresh([slot]);

disableInitialLoad() が利用されている場合は、displayでは広告リクエストが走らなくなるのでrefreshを使う。

⚠️ 広告ユニットが埋められませんでした

何が起きているか

配信条件に一致する広告申込情報が見つからずに広告を埋められなかった

対処方法

GAMで該当の広告ユニットと広告申込情報の配信設定やターゲティングを見直す

CSSのfont-synthesisとtext-renderingが原因でAndroidで太字にならない

Viteで新規にプロジェクトを作るとapp.cssに font-synthesistext-rendering が指定されています。

:root {
  ...
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  ...
}

これらのプロパティがあると、 Android Chrome で見たときにfont-weightで700以上を指定しても太字にならない場合があります。

font-synthesis は、フォントに太字やイタリックの字体が含まれていない場合にブラウザが合成してよいかどうかを制御するもの。

text-rendering は、合字やカーニングの処理を行うか否かを制御し、読みやすさと速度のどちらを優先するか決めることができます。

これら2つの両方もしくはどちらかと、おそらく font-family によるフォント指定の組み合わせによって太字書体が使える環境にも関わらず太字にならないことがあるようです。

基本的に欧文フォントのためのプロパティなので、日本語環境では、少なくとも現段階では使わないほうが無難なようです。

Web Designing 2022年12月号にインタビューが掲載されました

2022年10月18日にマイナビ出版さんより発売された「Web Designing 2022年12月号」に菅沼のインタビューを掲載していただきました。

12月号はJavaScriptフレームワーク特集ですが、その中の「モダンフロントエンド開発技術の使い分けと現場の実情」というコーナーで、「普段どういう目線でフレームワークを選定しているのか?」「VueやReactなどを使う際に気をつけるべきこと」など、鼎談形式で話をさせていただきました
技術の深い話ではなく、フレームワークを使うと何が変わるのか、といった内容が主なので、現役のエンジニアよりはディレクターに向けた内容になっています

出版社サイトはこちら:
https://book.mynavi.jp/ec/products/detail/id=132319

ご興味があればぜひご覧ください!