お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
言語::TypeScriptNode.js

TSでprocess.exit()をラップしたカスタムexitを作った時に静的解析のフローが壊れたので、その対策。
因みにこの制御フローのことをControl Flow Analysisと呼ぶらしい。TS系の文書ではCFAと略されていることが多い模様。

問題事例

通常のprocess.exit()例の7-8行目のように次の行から先がデッドコードになって欲しいが、上手くいかないので、これを上手くいくようにする。

カスタムexitのコード例 通常のprocess.exit()例
カスタムexitのコード例
静的解析のエディタ表示例

確認環境

Env Ver
TypeScript 4.8.4

サンプルコード

オブジェクトでラップして、カスタムexit関数の戻り値をneverで指定してやると上手くいくようになる。
因みにこれTypeScriptの仕様らしく、上手くやる方法はあんまりなさそう。
実はアロー関数ではなくfunctionを使えば解決したりするが、それはなんか嫌なので…

example.ts

type ErrorPayload = {
  message: string;
  code: number;
};

type ExampleExit = {
  exit: (err: ErrorPayload) => never;
};

const exit = (err: ErrorPayload) => {
  process.exit(err.code);
};

export const Example: ExampleExit = { exit };

implements.ts

import { Example } from './example';

Example.exit({ message: 'exit', code: 1 });
console.log(1);

関連記事

投稿日:
言語::CSS

レスポンシブにdisplayを切り替えるCSSを書いててハマったので備忘録。

今回は例として画面幅に応じて表示する項目数を変動させるCSSを書いてみます。media queryとnth-childを使って表示数を切り替えていく感じです。

イメージとしてはこんな感じ。

SP View PC View
SPビュー
PCビュー

上手くいかないケース

このコードでは画面幅を変えても項目数に変化がありません。理由としてはnth-child(n + 4)display: none;が900pxでも保持されたままだからです。試しにdisplay: none;font-weight: bold;とかに変えてみると良くわかります。

デモページ

.example li:nth-child(n + 4) {
    display: none;
}

@media screen and (min-width: 900px) {
    .example li:nth-child(n + 6) {
        display: none;
    }
}

上手くいくケース

以下のコードではnth-childで非表示にしている部分を900pxの時に表示指定にすることで3項目表示と5項目表示が切り替わるようになっています。そりゃ指定してなければ表示されないよねっていう単純な話ですね…。

デモページ

.example li:nth-child(n + 4) {
    display: none;
}

@media screen and (min-width: 900px) {
    /** 明示的に表示させる */
    .example li:nth-child(n + 4) {
        display: list-item;
    }

    .example li:nth-child(n + 6) {
        display: none;
    }
}

条件分岐でコンポーネントの出し分けをしている時に正しくコンポーネントが出ているかどうかに使えるやつ
UIロジックのリグレッションテストで使える
分岐結果の出力を見てるだけなのでテストとして壊れづらく、運用しやすいと考えている

確認環境

Next.jsで確認してるけど素のReactでも同じだと思う

Env Ver
@swc/core 1.2.133
@swc/jest 0.2.17
jest 27.4.7
next 12.0.8
react 17.0.2
react-dom 17.0.2
react-test-renderer 17.0.2
typescript 4.5.4

テスト対象

テストのためにコンポーネントを細かくexportすると名前空間が汚染されるのが悩み…

type BaseProps = {
  id: string;
};

type SwitchExampleProps = BaseProps & {
  display: 'Foo' | 'Bar';
};

export const Foo = (props: BaseProps) => {
  return (
    <div id={props.id}>
      <p>Foo</p>
    </div>
  );
};

export const Bar = (props: BaseProps) => {
  return (
    <div id={props.id}>
      <p>Bar</p>
    </div>
  );
};

export const SwitchExample = (props: SwitchExampleProps) => {
  if (props.display === 'Foo') {
    return <Foo id={props.id} />;
  } else {
    return <Bar id={props.id} />;
  }
};

テストコード

react-testing-libraryの.toHaveAttribute().toHaveDisplayValue()を書き連ねるより圧倒的に楽で保守性も良いと思う

import TestRenderer from 'react-test-renderer';
import { Bar, Foo, SwitchExample } from './SwitchExample';

type TestCase = {
  name: string;
  param: Parameters<typeof SwitchExample>[0];
  actual: JSX.Element;
};

describe('SwitchExample', () => {
  const testCaseItems: TestCase[] = [
    {
      name: 'Foo',
      param: {
        id: 'hoge',
        display: 'Foo',
      },
      actual: <Foo id={'hoge'} />,
    },
    {
      name: 'Bar',
      param: {
        id: 'piyo',
        display: 'Bar',
      },
      actual: <Bar id={'piyo'} />,
    },
  ];

  testCaseItems.forEach((item) => {
    // eslint-disable-next-line jest/valid-title
    it(`switched condition ${item.name}`, () => {
      const result = TestRenderer.create(
        <SwitchExample id={item.param.id} display={item.param.display} />
      );
      const actual = TestRenderer.create(<>{item.actual}</>);

      expect(result.toJSON()).toStrictEqual(actual.toJSON());
    });
  });
});

参考記事

投稿日:
ジャンル::サイト運営言語::Markdown

Markdownを使って快適にブログを書きたくない?書きたいですよね?そう、書きたい!
ではどうすればいいか?というのをこれから書いていきます。
JAMStackを使ってGitHub PagesとNext.js SSGでMarkdownブログを作ろう!みたいな人はブラウザバックをオススメします。

技術選定

  • JAMStack
  • はてなブログ
  • WordPress

JAMStack

まずJAMStackは真っ先に除外します。ブログを書きたいのであってブログを作りたいわけではないからです。

またSSGだとクライアントサイドのレンダリングコストが重く、リッチなブログにしようとすると負荷がしんどい気がしています。恐らくSEO対策的にもCSRを妥協して極限までSSGしていないと厳しいのではないでしょうか?

はてなブログ

カスタマイズがすんごくだるい上に、真面目にやろうとするとクライアントサイドでHTMLをゴリゴリ書き換えたり、orderなどのハックに近いCSSを多用して擬似的に要素を移動させたりする必要があり、レイアウトを組むのが非常に面倒です。

エディタもしょぼいしカテゴリはないし(はてブロのカテゴリは実質的にタグなので)年会費が高い割に出来ることの制限が強い…。あんまSEOも強くなかったし、試しに使ってみたものの流入が激減…正直個人的にこれはですね。

WordPress

多分こいつが一番現実的な選択肢です。WP Githuber MDを使うことで不自由なくMarkdownを扱うことが出来ると思います。但し内蔵のPrism.jsはなんかいい感じに動いてくれないケースがあり、その場合はカスタマイズが必要です。

カスタマイズについてもプラグインやテーマが豊富にあり、改造も容易なのでローコストでリッチなものが実現しやすいと思います。またセルフホストなのでデータの取り回しの自由が効きやすいのも大きなポイントですね。

CMSは色々使ってきましたが、なんだかんだブログはWordPressが一番だなって思います。SEO対策もGoogle謹製のやつがあるし、特に何もしなくてもある程度なんとかなるのは強みだと思います。

カスタマイズ法

CSS

使っているテーマと整合性が取れるようにいい感じにします。私は Dracula for Prism.js を改造して使いました。

JS

私の場合は次のコードをヘッダタグの中に足して対処しました。特に内容の説明はしませんが、行番号とコピーボタンが出るようにしています。

<script src="https://unpkg.com/prismjs@1.28.0/components/prism-core.min.js"></script>
<script src="https://unpkg.com/prismjs@1.28.0/plugins/autoloader/prism-autoloader.min.js"></script>
<script src="https://unpkg.com/prismjs@1.28.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
<script src="https://unpkg.com/prismjs@1.28.0/plugins/toolbar/prism-toolbar.min.js"></script>
<script src="https://unpkg.com/prismjs@1.28.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
<script>
  document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('pre > code').forEach((codeEl) => {
      codeEl.className = codeEl.className === '' ? 'language-none' : codeEl.className;
      codeEl.className = codeEl.className.replace(/^sh$/, 'shell');
      codeEl.parentNode.className = 'line-numbers';
    });

    window.Prism.highlightAll();
  });
</script>

VSCodeでは出来たことがPhpStormだと上手く出来なかったので、その解消法です
Remote Developmentに慣れてるとハマりやすいと思います
PhpStormに類似の機能は多分ないです

PhpStorm編

確認環境

一応Apacheの上に乗っかったLaravelで確認してますがそこらへんの環境情報は端折ってます

Env Ver
Windows 11 Pro
PhpStorm 2021.3.2
Docker 20.10.11
docker-compose 1.29.2
PHP 8.1.1
Xdebug 3.1.3

Dockerfile

PHPが入ってるDockerfileに以下を追記
出来ることならヒアドキュメントで書きたい

RUN pecl install xdebug
RUN docker-php-ext-enable xdebug
RUN echo "zend_extension=xdebug" > /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.mode=develop,coverage,debug,trace" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.start_with_request=trigger" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.trigger_value=StartProfileForMe" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

Dockerの設定

適当にDockerを追加してコンテナとローカルのパスをマッピング

20220412031939.png

PHPインタプリタの設定

CLIインタプリタをDockerに向けて設定します
パスマッピングは勝手にやってくれた気がする

20220412031948.png

デバッグ

HTTPリクエスト

受話器みたいなところを押してcurlなりPOSTMANなりブラウザなりにXDEBUG_TRIGGER=StartProfileForMeというCookieを刺してリクエストするとブレークにかかります
初回だけパスマッピングを構成するダイアログが出てくるのでよしなに処理します

20220412031956.png

PHPUnit

デバッグ構成を作ってデバッグするだけ

20220412032006.png

おまけのVSCode編

VSCodeだとネイティブに動くのでDockerの存在を考えなくて済むのは楽ですが、IDEとしての性能はPHP Intelephenseに課金してもPhpStormには劣るので微妙なところ(静的解析に問題がある

確認環境

PhpStormと被る部分は端折ってます

Env Ver
VSCode 1.64.2
ms-vscode-remote.remote-containers 0.217.4
robberphex.php-debug 1.14.0

Dockerfile

PHPが入ってるDockerfileに以下を追記
PhpStormとの違いはxdebug.client_hostが不要なところです
(PhpStormでもCLI Debugだとなくていけるっぽいのでややこしい)

RUN pecl install xdebug
RUN docker-php-ext-enable xdebug
RUN echo "zend_extension=xdebug" > /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.mode=develop,coverage,debug,trace" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.start_with_request=trigger" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.trigger_value=StartProfileForMe" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

launch.json

  • Listen for Xdebug
    • HTTPリクエスト用
  • PHPUnit
    • PHPUnit用
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        },
        {
            "name": "PHPUnit",
            "type": "php",
            "request": "launch",
            "program": "${workspaceFolder}/vendor/phpunit/phpunit/phpunit",
            "args": ["${file}"],
            "env": {
                "XDEBUG_TRIGGER": "StartProfileForMe"
            },
            "port": 9003
        }
    ]
}

デバッグ

PHPのいるコンテナにAttach Visual Studio CodeしてF5押せばデバッグできます

あとがき

個人的に操作感はVSCodeの方が好みなので使えるならVSCodeでいきたいのですが、今の所PhpStormには敵わないという感じなのが悲しい
まぁJS/TS用のエディタみたいなもんだし仕方がないですね…
ただGitのGUI周りはVSCodeが圧倒的に好みなので、Git操作するときだけVSCode使ってたりはします
しかしPhpStormとVSCodeを共存させるのはxdebug.client_hostの向きの関係で微妙な感じですね…