<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>nove-b</title><description>A coder-ready Astro blog theme with 59 of your favorite color schemes to choose from</description><link>https://blog.nove-b.dev</link><item><title>GithubActionを使用してエックスサーバーにデプロイする</title><link>https://blog.nove-b.dev/posts/github-action-wordpress-deploy</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/github-action-wordpress-deploy</guid><content:encoded>&lt;h2&gt;FTPでファイルをアップロードするのが面倒くさい&lt;/h2&gt;
&lt;p&gt;今まで多くの人がそうであるように、&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;サイト作成&lt;/li&gt;
&lt;li&gt;Githubに最新バージョンをプッシュ&lt;/li&gt;
&lt;li&gt;FileZillaをしようしてサーバーにデプロイ&lt;/li&gt;
&lt;li&gt;修正&lt;/li&gt;
&lt;li&gt;Githubに最新バージョンをプッシュ&lt;/li&gt;
&lt;li&gt;FileZillaをしようしてサーバーにデプロイ&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;というフローを踏んでサイトを運用してきた。&lt;/p&gt;
&lt;p&gt;が、これが面倒でしかたない。&lt;/p&gt;
&lt;p&gt;どうせGithubにあげたものをデプロイするのであれば、プッシュと同時にデプロイができればいいのに…！&lt;/p&gt;
&lt;h2&gt;レンタルサーバーでもできるのか？&lt;/h2&gt;
&lt;p&gt;Firebase Hosting、Netlify ...、などを使えばできることは知っている。&lt;/p&gt;
&lt;p&gt;しかしレンタルサーバーでもできるのか？&lt;/p&gt;
&lt;p&gt;正直レンタルサーバーは上記サーバーに比べて劣るイメージがある。&lt;/p&gt;
&lt;h3&gt;エックスサーバーで簡単にできた&lt;/h3&gt;
&lt;p&gt;まずはエックスサーバー万歳三唱🙌🙌🙌&lt;/p&gt;
&lt;p&gt;本サイトはエックスサーバーを作っているのだが、エックスサーバーならGithub
Actionと連携できることを知った。&lt;/p&gt;
&lt;p&gt;これで今までのフローとストレスと労力が半減された。&lt;/p&gt;
&lt;p&gt;さらには常に最新バージョンがデプロイされるという先祖返りの危機もなくなった。&lt;/p&gt;
&lt;p&gt;最後にエックスサーバー万歳三唱🙌🙌🙌&lt;/p&gt;
&lt;p&gt;[sc name=&quot;exserver_all_unlimited&quot; ][/sc]&lt;/p&gt;
&lt;h2&gt;どうやって実現するのか&lt;/h2&gt;
&lt;p&gt;すごく簡単なので、特に考えすぎずに実行してほしい。&lt;/p&gt;
&lt;h3&gt;エックスサーバー側の設定&lt;/h3&gt;
&lt;p&gt;特にないけれど、エックスサーバーのサーバーパネルで&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ftpサーバのホスト&lt;/li&gt;
&lt;li&gt;ftpサーバのアカウント名&lt;/li&gt;
&lt;li&gt;ftpサーバのパスワード&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;を確認してメモをしておく。&lt;/p&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://www.xserver.ne.jp/manual/man_ftp_setting.php&quot;&gt;FTPソフトの設定 | レンタルサーバーならエックスサーバー&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Github側の設定&lt;/h3&gt;
&lt;p&gt;対象リポジトリのSettings &amp;gt; Secrets に下記情報を入力する。&lt;/p&gt;
&lt;p&gt;FTP_PASSWORD → ftpサーバのホスト&lt;/p&gt;
&lt;p&gt;FTP_SERVER → ftpサーバのアカウント名&lt;/p&gt;
&lt;p&gt;FTP_USERNAME → ftpサーバのパスワード&lt;/p&gt;
&lt;h3&gt;deploy.ymlの作成&lt;/h3&gt;
&lt;p&gt;対象リポジトリ直下に.github/workflows/ディレクトリを作成し、その下にdeploy.ymlファイルを設置する。&lt;/p&gt;
&lt;p&gt;そこに下記情報を入力すれば完了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;on:
push:
branches:
- main
name: Deploy
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@2.0.0
env:
FTP_SERVER: ${{ secrets.FTP_SERVER }}
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
LOCAL_DIR: ./
REMOTE_DIR: /デプロイ対象のサイト/public_html/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;あとはmainブランチにプッシュする、ただそれだけでサイト運営が嘘のように楽になる。&lt;/p&gt;
&lt;p&gt;ぜひ、試してみてはどうでしょうか。&lt;/p&gt;
&lt;p&gt;エックスサーバーができるので、当然他のレンタルサーバーでもできるのかもしれないが、上記方法はエックスサーバーでの方法になるので、悪しからず。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavaScriptを使用してWordpressの投稿に目次を挿入する</title><link>https://blog.nove-b.dev/posts/javascript-wordpress-insert-toc</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/javascript-wordpress-insert-toc</guid><content:encoded>&lt;h2&gt;記事に目次をつけよう&lt;/h2&gt;
&lt;p&gt;目次があれば、結末まですぐに飛ぶことができる。&lt;/p&gt;
&lt;p&gt;時間に追われる現代人にはなくてはならない機能である。&lt;/p&gt;
&lt;p&gt;そこで本サイトに目次を導入した。&lt;/p&gt;
&lt;h3&gt;プラグインは使いたくないよう&lt;/h3&gt;
&lt;p&gt;個人的にプラグインには頼りたくない。&lt;/p&gt;
&lt;p&gt;理由はシンプルで楽しくないからである。&lt;/p&gt;
&lt;p&gt;どうせ作るなら自分自身の力で作成したい。&lt;/p&gt;
&lt;p&gt;なので今回も自作した。&lt;/p&gt;
&lt;h2&gt;目次を挿入するための考え方&lt;/h2&gt;
&lt;p&gt;やりたいことはページが開かれた時に記事に目次を挿入する。&lt;/p&gt;
&lt;p&gt;で、対象はh2タグとh3タグとする。&lt;/p&gt;
&lt;p&gt;つまり、記事内にh2タグとh3タグがあるかを判定し、あればそれに対応する目次を挿入する。&lt;/p&gt;
&lt;h2&gt;実現コードはこちら&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// 目次を生成
let secondIdCount = 1
let ThirdIdCount = 1
const headingSecond = document.querySelector(&apos;.article-detail&apos;)?.querySelectorAll(&apos;h2&apos;)
const headingThird = document.querySelector(&apos;.article-detail&apos;)?.querySelectorAll(&apos;h3&apos;)
if (headingSecond !== undefined || headingThird !== undefined) {

    headingSecond.forEach(el =&amp;gt; {
        el.id = `tocSecond-${secondIdCount}`
        secondIdCount++
    });
    headingThird.forEach(el =&amp;gt; {
        el.id = `tocThird-${ThirdIdCount}`
        ThirdIdCount++
    });

    const target = document.querySelectorAll(`[id^=&apos;toc&apos;]`)

    const insertTarget = document.querySelector(&apos;.article-table-of-contents-insert&apos;)
    if (target.length === 0) {
        document.querySelector(&apos;.article-table-of-contents&apos;).style.display = &apos;none&apos;
    } else {
        target.forEach((el) =&amp;gt; {
            if (el.nodeName === &apos;H2&apos;) {
                insertTarget.insertAdjacentHTML(&apos;beforeend&apos;, `&amp;lt;p class=&quot;second&quot; onclick=&quot;smoothScroll(&apos;${el.id}&apos;)&quot;&amp;gt;${el.innerText}&amp;lt;/p&amp;gt;`)
            } else {
                insertTarget.insertAdjacentHTML(&apos;beforeend&apos;, `&amp;lt;p class=&quot;third&quot; onclick=&quot;smoothScroll(&apos;${el.id}&apos;)&quot;&amp;gt;${el.innerText}&amp;lt;/p&amp;gt;`)
            }
        });
    }
}

// スムーススクール
const smoothScroll = (el) =&amp;gt; {
    const box = document.querySelector(&apos;.content&apos;)
    const scrollY = box.scrollTop
    const target = document.getElementById(el).getBoundingClientRect().top
    const headerHight = document.getElementById(&apos;header&apos;).clientHeight
    box.scrollTo({
        top: target - headerHight + scrollY,
        behavior: &apos;smooth&apos;
    })
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前提として記事内に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;article-table-of-contents&quot;&amp;gt;
  &amp;lt;p class=&quot;title&quot;&amp;gt;目次&amp;lt;/p&amp;gt;
  &amp;lt;div class=&quot;article-table-of-contents-insert&quot;&amp;gt;


  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という要素を書いておく必要がある。&lt;/p&gt;
&lt;h2&gt;実現コードを書き下してみる&lt;/h2&gt;
&lt;h3&gt;事前に必要な情報を定義する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// 目次を生成
let secondIdCount = 1
let ThirdIdCount = 1
const headingSecond = document.querySelector(&apos;.article-detail&apos;)?.querySelectorAll(&apos;h2&apos;)
const headingThird = document.querySelector(&apos;.article-detail&apos;)?.querySelectorAll(&apos;h3&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずは諸々定義する。&lt;/p&gt;
&lt;p&gt;IDに連番を振るので、基準の数字。&lt;/p&gt;
&lt;p&gt;記事内にある、h2タグとh3タグ。&lt;/p&gt;
&lt;h3&gt;連番IDを付与する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;headingSecond.forEach(el =&amp;gt; {
    el.id = `tocSecond-${secondIdCount}`
    secondIdCount++
});
headingThird.forEach(el =&amp;gt; {
    el.id = `tocThird-${ThirdIdCount}`
    ThirdIdCount++
});

const target = document.querySelectorAll(`[id^=&apos;toc&apos;]`)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;事前に定義した情報をもとにh2タグh3タグに連番IDを振る。&lt;/p&gt;
&lt;p&gt;IDを振った要素を取得する。&lt;/p&gt;
&lt;h3&gt;対象を目次に挿入していく&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const insertTarget = document.querySelector(&apos;.article-table-of-contents-insert&apos;)
if (target.length === 0) {
    document.querySelector(&apos;.article-table-of-contents&apos;).style.display = &apos;none&apos;
} else {
    target.forEach((el) =&amp;gt; {
        if (el.nodeName === &apos;H2&apos;) {
            insertTarget.insertAdjacentHTML(&apos;beforeend&apos;, `&amp;lt;p class=&quot;second&quot; onclick=&quot;smoothScroll(&apos;${el.id}&apos;)&quot;&amp;gt;${el.innerText}&amp;lt;/p&amp;gt;`)
        } else {
            insertTarget.insertAdjacentHTML(&apos;beforeend&apos;, `&amp;lt;p class=&quot;third&quot; onclick=&quot;smoothScroll(&apos;${el.id}&apos;)&quot;&amp;gt;${el.innerText}&amp;lt;/p&amp;gt;`)
        }
    });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まず、挿入する要素を取得する。&lt;/p&gt;
&lt;p&gt;次に先ほど取得したtagertが、H2であればh2に紐づくHTMLを。&lt;/p&gt;
&lt;p&gt;H3であればh3に紐づくHTMLをどんどん挿入していく。&lt;/p&gt;
&lt;h3&gt;クリック時に対象要素にスクールする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// スムーススクール
const smoothScroll = (el) =&amp;gt; {
    const box = document.querySelector(&apos;.content&apos;)
    const scrollY = box.scrollTop
    const target = document.getElementById(el).getBoundingClientRect().top
    const headerHight = document.getElementById(&apos;header&apos;).clientHeight
    box.scrollTo({
        top: target - headerHight + scrollY,
        behavior: &apos;smooth&apos;
    })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記はヘッダーの高さを取得しているので、そこは適宜変更してほしい。&lt;/p&gt;
&lt;h2&gt;技術を書く技術がない&lt;/h2&gt;
&lt;p&gt;うーん。&lt;/p&gt;
&lt;p&gt;色々書いたが、うまく伝えられない。&lt;/p&gt;
&lt;p&gt;考え方さえわかれば難しくないと思うので、挑戦してみてほしい。&lt;/p&gt;
&lt;p&gt;わからなければコメントを残してもらえれば個人的に解説をするので、どんどんコメントしてください。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Wordpressのタグをチェックボックスに変更して管理を楽にする</title><link>https://blog.nove-b.dev/posts/wordpress-tags-to-checkboxes</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/wordpress-tags-to-checkboxes</guid><content:encoded>&lt;h2&gt;Wordpressのタグがひっちゃかめっちゃかになった過去&lt;/h2&gt;
&lt;p&gt;かつて、タグに翻弄されていたことがある。&lt;/p&gt;
&lt;p&gt;カテゴリはチェックボックスで過去に設定したカテゴリを投稿画面で見ることができるのだが、タグはなぜかそれができない。&lt;/p&gt;
&lt;p&gt;例えば、「HTML」と過去に投稿したことがあったのだが、次に書くときは「html」と書いてしまうかもしれない。&lt;/p&gt;
&lt;p&gt;その時点で2つは別になってしまうのである。&lt;/p&gt;
&lt;p&gt;そこでタグもチェックボックスにしようと思いついた。&lt;/p&gt;
&lt;h2&gt;タグをチェックボックスにする実現コードはこちら&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;//タグをチェックボックス表示に
function re_register_post_tag_taxonomy()
{
  global $wp_rewrite;
  $rewrite = array(
    &apos;slug&apos; =&amp;gt; get_option(&apos;tag_base&apos;) ? get_option(&apos;tag_base&apos;) : &apos;tag&apos;,
    &apos;with_front&apos; =&amp;gt; !get_option(&apos;tag_base&apos;) || $wp_rewrite-&amp;gt;using_index_permalinks(),
    &apos;ep_mask&apos; =&amp;gt; EP_TAGS,
  );


  $labels = array(
    &apos;name&apos; =&amp;gt; _x(&apos;Tags&apos;, &apos;taxonomy general name&apos;),
    &apos;singular_name&apos; =&amp;gt; _x(&apos;Tag&apos;, &apos;taxonomy singular name&apos;),
    &apos;search_items&apos; =&amp;gt; __(&apos;Search Tags&apos;),
    &apos;popular_items&apos; =&amp;gt; __(&apos;Popular Tags&apos;),
    &apos;all_items&apos; =&amp;gt; __(&apos;All Tags&apos;),
    &apos;parent_item&apos; =&amp;gt; null,
    &apos;parent_item_colon&apos; =&amp;gt; null,
    &apos;edit_item&apos; =&amp;gt; __(&apos;Edit Tag&apos;),
    &apos;view_item&apos; =&amp;gt; __(&apos;View Tag&apos;),
    &apos;update_item&apos; =&amp;gt; __(&apos;Update Tag&apos;),
    &apos;add_new_item&apos; =&amp;gt; __(&apos;Add New Tag&apos;),
    &apos;new_item_name&apos; =&amp;gt; __(&apos;New Tag Name&apos;),
    &apos;separate_items_with_commas&apos; =&amp;gt; __(&apos;Separate tags with commas&apos;),
    &apos;add_or_remove_items&apos; =&amp;gt; __(&apos;Add or remove tags&apos;),
    &apos;choose_from_most_used&apos; =&amp;gt; __(&apos;Choose from the most used tags&apos;),
    &apos;not_found&apos; =&amp;gt; __(&apos;No tags found.&apos;)
  );


  register_taxonomy(&apos;post_tag&apos;, &apos;post&apos;, array(
    &apos;hierarchical&apos; =&amp;gt; true,
    &apos;query_var&apos; =&amp;gt; &apos;tag&apos;,
    &apos;rewrite&apos; =&amp;gt; $rewrite,
    &apos;public&apos; =&amp;gt; true,
    &apos;show_ui&apos; =&amp;gt; true,
    &apos;show_admin_column&apos; =&amp;gt; true,
    &apos;_builtin&apos; =&amp;gt; true,
    &apos;labels&apos; =&amp;gt; $labels
  ));
}
add_action(&apos;init&apos;, &apos;re_register_post_tag_taxonomy&apos;, 1);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これが全コード。&lt;/p&gt;
&lt;p&gt;これをfunction.php に書けばタグがチェックボックスになり、管理が簡単になる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>何が面倒って、アイキャッチ画像を設定するほど面倒なことはない</title><link>https://blog.nove-b.dev/posts/wordpress-featured-image-setup</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/wordpress-featured-image-setup</guid><content:encoded>&lt;h2&gt;ブログ更新ってめんどくさい&lt;/h2&gt;
&lt;p&gt;ブログ更新は面倒くさい。&lt;/p&gt;
&lt;p&gt;そんなこと分かり切っている。&lt;/p&gt;
&lt;p&gt;なかでも面倒なことの1つにアイキャッチ画像の選定がある。&lt;/p&gt;
&lt;p&gt;面倒なことを楽にできるのがエンジニアの特権だ。&lt;/p&gt;
&lt;p&gt;ということでアイキャッチ画像を簡単に作れるようにした。&lt;/p&gt;
&lt;h2&gt;作成されるアイキャッチ画像&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/intoroduction.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;本ツールを作成できるアイキャッチ画像はこんな感じ。&lt;/p&gt;
&lt;p&gt;「本ツールを作成できるアイキャッチ画像」の部分を簡単に変更できる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/intoroduction.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;作成するうえでの考え方&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;JavaScriptのCanvasに背景画像を描画する&lt;/li&gt;
&lt;li&gt;その上にCanvas で文字を書く&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;作成したコード&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&quot;creatEyeCatch&quot;&amp;gt;
    &amp;lt;div class=&quot;input&quot;&amp;gt;
      &amp;lt;input type=&quot;text&quot; id=&quot;input&quot; placeholder=&quot;記事タイトルを記入する&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;canvas class=&quot;canvas&quot; id=&quot;canvas--background&quot; width=&quot;788px&quot; height=&quot;486px&quot;&amp;gt;&amp;lt;/canvas&amp;gt;
    &amp;lt;div class=&quot;operation&quot;&amp;gt;
      &amp;lt;button id=&quot;deleteTitle&quot;&amp;gt;タイトルを削除&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  // var
  const deleteTitle = document.getElementById(&apos;deleteTitle&apos;)


  // 背景CANVASの作成
  const canvasGround = document.getElementById(&apos;canvas--background&apos;)
  const ctxGround = canvasGround.getContext(&apos;2d&apos;)
  const nove = new Image();
  nove.src = &apos;画像のパス&apos;;
  ctxGround.drawImage(nove, 0, 0, canvasGround.width, canvasGround.height);


  // 入力されたタイトルを描画する関数
  const drawFont = (el) =&amp;gt; {
    ctxGround.font = &apos;32px Noto Sans JP&apos;;
    ctxGround.fillStyle = &apos;#000000&apos;;
    const x = (canvasGround.width - ctxGround.measureText(el).width) / 2
    const y = (canvasGround.height + 32 / 2) / 2 + 40
    ctxGround.fillText(el, x, y, 708);
  }


  // テキストが入力確定で出力
  const input = document.getElementById(&apos;input&apos;)
  input.addEventListener(&apos;change&apos;, () =&amp;gt; {
    drawFont(input.value)
    clearCanvas()
    window.setTimeout(() =&amp;gt; {
      drawFont(input.value)
    }, 500)
  })


  // テキストの削除
  deleteTitle.addEventListener(&apos;click&apos;, () =&amp;gt; {
    clearCanvas()
    input.value = &apos;&apos;
  })


  const clearCanvas = () =&amp;gt; {
    ctxGround.clearRect(0, 0, canvasGround.width, canvasGround.height);
    nove.src = &apos;画像のパス&apos;;
    ctxGround.drawImage(nove, 0, 0, canvasGround.width, canvasGround.height);


  }
  // タイトルの文字量をチェック
  input.addEventListener(&apos;input&apos;, () =&amp;gt; {
    if (input.value.length &amp;gt; 21) {
      alert(&apos;今はまだ、タイトルは20文字以内にしてください。&apos;)
    }
  })
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;基本的にコメントアウトを残したので、それ通りに作れば特に難しい点もないと思う。&lt;/p&gt;
&lt;h2&gt;投稿画面にリンクを張る&lt;/h2&gt;
&lt;p&gt;最後に作成したツールに飛ぶためのリンクを投稿画面に貼る。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_action(&apos;admin_footer-post-new.php&apos;, &apos;add_custom_text&apos;);
add_action(&apos;admin_footer-post.php&apos;, &apos;add_custom_text&apos;);
function add_custom_text()
{
?&amp;gt;
  &amp;lt;script&amp;gt;
    const selectEyeCatch = document.getElementById(&apos;postimagediv&apos;)
    selectEyeCatch.insertAdjacentHTML(&apos;afterend&apos;, &apos;&amp;lt;p class=&quot;creatEyeCatch&quot;&amp;gt;&amp;lt;a href=&quot;URL&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&amp;gt;nove のアイキャッチを生成する&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&apos;);
  &amp;lt;/script&amp;gt;
&amp;lt;?php
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これですこしブログ更新を楽にできる。&lt;/p&gt;
&lt;p&gt;わからない部分はコメントに残してもらえれば解説します。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>アドセンスでサブドメインが使用できなかったので、ルートから301リダイレクトして対処した</title><link>https://blog.nove-b.dev/posts/301-redirect-for-adsense-subdomain</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/301-redirect-for-adsense-subdomain</guid><content:encoded>&lt;h2&gt;アドセンスに申し込む&lt;/h2&gt;
&lt;p&gt;記事も10記事たまったので、いったんダメ元でアドセンスに申し込もうと思い立った。&lt;/p&gt;
&lt;p&gt;過去に1年間続いたブログではそれなりにアドセンスからの収入があった。&lt;/p&gt;
&lt;p&gt;当時は本の感想ブログで、本なんて売れないし、アフェリエイトよりも効率良くアドセンスは収入があったので、なんとしても入れたい。&lt;/p&gt;
&lt;h3&gt;サブドメインが使用できません&lt;/h3&gt;
&lt;p&gt;で、よし、いざ、と腰を上げると、&lt;strong&gt;なんとサブドメインが使用できない&lt;/strong&gt;とのこと。&lt;/p&gt;
&lt;p&gt;本サイトは何を隠そうサブドメインなので、腰を上げた瞬間に座り込んだ。&lt;/p&gt;
&lt;p&gt;ブログはサブドメインと言った自分の計画性のなさにうんざりする。&lt;/p&gt;
&lt;p&gt;が、なんとしてもアドセンスやりたい。&lt;/p&gt;
&lt;p&gt;そこで実現のために２つの方法を考えた。&lt;/p&gt;
&lt;h2&gt;アドセンスをサブドメインで申請する２つの方法&lt;/h2&gt;
&lt;h3&gt;ルートドメインで新規構築&lt;/h3&gt;
&lt;p&gt;１つはルートドメインでサイトを構築する。&lt;/p&gt;
&lt;p&gt;現状はロゴが真ん中にあるだけのサイトになっている。&lt;/p&gt;
&lt;p&gt;アドセンスの審査は厳しいので、それだと落ちるに違いない。&lt;/p&gt;
&lt;p&gt;落ちないようにするために、それなりのサイトを作成する必要がある。&lt;/p&gt;
&lt;p&gt;当然、自身の労力もかかれば、時間もかかるので、この方法は現実的じゃない。&lt;/p&gt;
&lt;h3&gt;301リダイレクト&lt;/h3&gt;
&lt;p&gt;２つ目はルートドメインからサブドメインに301リダイレクトをする方法。&lt;/p&gt;
&lt;p&gt;301リダイレクトとは「サーバー側の永続的なリダイレクト」のことで、Google曰く、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;検索エンジンの結果に表示されるページの URL を変更する必要がある場合は、可能な限りサーバー側の永続的なリダイレクトを使用することをおすすめします。これは、Google 検索とユーザーを確実に正しいページに導くための最善の方法です。ステータス コード 301 と 308 は、ページが別の場所に完全に移転したことを意味します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;つまり、Googleはリダイレクト先を見てくれるようになる。&lt;/p&gt;
&lt;p&gt;これの方が簡単かつシンプルなので、こちらの方法を採用することにした。&lt;/p&gt;
&lt;h2&gt;301リダイレクトを使用しサブドメインでアドセンス申請&lt;/h2&gt;
&lt;p&gt;301リダイレクトは .htaccess をいじる必要がある。&lt;/p&gt;
&lt;p&gt;でも本ブログで使用しているエックスサーバーでなら管理画面で簡単にできるので、そちらを使用することにした。&lt;/p&gt;
&lt;h3&gt;リダイレクトが繰り返し行われました&lt;/h3&gt;
&lt;p&gt;作業は簡単でサーバーパネル &amp;gt; サイト転送設定 &amp;gt; ドメインを選択 &amp;gt; リダイレクト設定追加 &amp;gt; リダイレクト先を追加するだけなのだが、実行すると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;********でリダイレクトが繰り返し行われました。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;というエラーがでた。&lt;/p&gt;
&lt;p&gt;なぜ、という思いで調べてみると&lt;a href=&quot;https://www.xserver.ne.jp/manual/man_server_transfer.php&quot;&gt;サイト転送設定（リダイレクト設定） | レンタルサーバーならエックスサーバー&lt;/a&gt;に答えが書かれていた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;指定のURLへリダイレクト設定が可能です。&lt;/p&gt;
&lt;p&gt;※サブドメインを含む、同一ドメインのURLにはリダイレクト設定はできません。 同一ドメイン内でリダイレクト設定を行う場合は、.htaccessファイルで設定してください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;なるほど、エックスサーバーは本当に親切でありがたい。&lt;/p&gt;
&lt;p&gt;どうせなら設定できるようにしてくれるともっとありがたいのだが、現状で相当親切にしてもらているのでそんなことは言えません。&lt;/p&gt;
&lt;p&gt;とても親切なので、広告リンクを貼ってあげる。&lt;/p&gt;
&lt;p&gt;[sc name=&quot;exserver_all_unlimited&quot; ][/sc]&lt;/p&gt;
&lt;h3&gt;.htaccessをエックスサーバーの管理画面で編集する&lt;/h3&gt;
&lt;p&gt;話を元に戻して――、ということで .htaccessをいじることに。&lt;/p&gt;
&lt;p&gt;ただこれもFTPとか使うことなくエックスサーバーなら簡単にできる。&lt;/p&gt;
&lt;p&gt;サーバーパネル &amp;gt; .htaccess編集 &amp;gt; ドメインを選択 &amp;gt;
.htaccess編集 で下記コードを記入し保存。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RewriteEngine On
RewriteRule (.*) 遷移先のURL [R=301,L]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでやっとアドセンスに申請することができた。&lt;/p&gt;
&lt;p&gt;広告プレビューを見ると無事に本サイトのトップ画面が表示されているので、めでたし、めでたし。&lt;/p&gt;
&lt;h3&gt;後は、祈る。ただ祈る。&lt;/h3&gt;
&lt;p&gt;あとは祈るだけ、愛は祈りだ、僕は祈る、なんて「&lt;a href=&quot;https://www.amazon.co.jp/gp/product/4062760819/ref=as_li_tl?ie=UTF8&amp;amp;camp=247&amp;amp;creative=1211&amp;amp;creativeASIN=4062760819&amp;amp;linkCode=as2&amp;amp;tag=nove0822-22&amp;amp;linkId=aabb6496afdea4fc13d8a4b52609eb34&quot;&gt;好き好き大好き超愛してる。&lt;/a&gt;」の舞城王太郎じゃないけど私は祈る。&lt;/p&gt;
&lt;p&gt;Googleへの愛は誰よりもある。&lt;/p&gt;
&lt;p&gt;ピクセルだって使ってる。&lt;/p&gt;
&lt;p&gt;Googleさん、そういうことなので、どうぞよろしく。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>クラシックエディタでリンク挿入ボタンがうまく機能していなかったので、原因を調査した</title><link>https://blog.nove-b.dev/posts/classic-editor-link-button-issue</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/classic-editor-link-button-issue</guid><content:encoded>&lt;h2&gt;クラシックエディタのリンク挿入ボタンがうまく機能していない&lt;/h2&gt;
&lt;p&gt;公開から少し経ち、ブログを投稿する機会が増えるにつれ、気が付き始めたことがある。クラシックエディタのリンク挿入機能がうまく機能していないという点が、その１つ。&lt;/p&gt;
&lt;p&gt;調べてみるとクラシックエディタがうまく機能しなくなるバグはよくあることらしい。&lt;/p&gt;
&lt;h3&gt;プラグインが原因？&lt;/h3&gt;
&lt;p&gt;調査結果によると多くはプラグインを起因とするものらしく、特定のプラグインを無効化すれば直ったという声をよく見た。&lt;/p&gt;
&lt;p&gt;しかし、こういう事態に備えて、プラグインを最小限に抑えている。 とは言え入れていないわけではないので、ひとつひとつ無効化してテストしてみた。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Classic Editor&lt;/strong&gt;
無効化したが効果が見られず。 というより、そもそもこのプラグインを無効化したら意味がない。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Highlighting Code Block&lt;/strong&gt;
エンジニアの味方。 ブログでコードを簡単に見せることができるプラグイン。 無効化したが効果が見られず。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XML Sitemaps&lt;/strong&gt;
動的にサイトマップを作成してくれるプラグイン。 無効化したが効果が見られず。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;結果、&lt;strong&gt;原因はプラグインではない&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;functions.phpにいけない記述があるのかしら。&lt;/p&gt;
&lt;p&gt;ということで、functions.phpをまるっと削除してみたところ、正常に稼働した。&lt;/p&gt;
&lt;p&gt;細分化してエラーの原因を探すと、どうやらビジュアルエディターにcssを当てる記述が悪さをしているとのこと。&lt;/p&gt;
&lt;p&gt;書かれたソースがこちら。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 投稿ページにスタイルを充てる
function wpdocs_theme_add_editor_styles()
{
add_editor_style(&apos;パス&apos;);
}
add_action(&apos;admin_init&apos;, &apos;wpdocs_theme_add_editor_styles&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;もしやエディタを読み込む関数が非推奨になったのかしらなんて思い、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_editor_style(&apos;パス&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;シンプルに記述方法を変えてみたが、変わらず正常に稼働しない。&lt;/p&gt;
&lt;h3&gt;ついに、原因解明&lt;/h3&gt;
&lt;p&gt;まさかと思いつつ、ということで読み込んでいるcssの内容をまるっと削除すると、正常に稼働。&lt;/p&gt;
&lt;p&gt;そこでトライ＆エラーと消しては確認を繰り返すとついに発見。&lt;/p&gt;
&lt;p&gt;原因はaタグに指定された「display: contents ;」...!&lt;/p&gt;
&lt;p&gt;確かシンプルにリンクにアイコンをつけたくて記述した箇所だが、現状はもう使用してない不要な箇所。&lt;/p&gt;
&lt;p&gt;自身が使うエディタのみだから削除を忘れていた。&lt;/p&gt;
&lt;p&gt;そして&lt;strong&gt;原因はまさかのCSS&lt;/strong&gt;だった。&lt;/p&gt;
&lt;h2&gt;無駄な記述は自身の首を絞める&lt;/h2&gt;
&lt;p&gt;今回の教訓として心に刻むことにした。&lt;/p&gt;
&lt;p&gt;せっかくなので、&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;display: contents ; 理解を深める&lt;/li&gt;
&lt;li&gt;表示のスタイルとエディターのスタイルを一元管理する&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;上記２つを課題として自らに課すことにした。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【解決】助けて&amp;#x203c;「検出 - インデックス未登録」とか文句言ってGoogleがなかなかインデックスしてくれないの&amp;#x1f631;</title><link>https://blog.nove-b.dev/posts/google-indexing-issue-solved</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/google-indexing-issue-solved</guid><content:encoded>&lt;h2&gt;Googleのクローラーが来ない&lt;/h2&gt;
&lt;p&gt;ブログを始めたのが 2021年11月23日 で現在（2021年12月6日）24個のURLを持つサイトになった。&lt;/p&gt;
&lt;p&gt;友人とふたりで特に縛りなく、楽しく更新しているので、割といいペースで記事投稿ができるいると思うのだが、アクセスが伸びない。&lt;/p&gt;
&lt;p&gt;原因はわかりきっている。&lt;/p&gt;
&lt;p&gt;Googleのクローラーが来てくれないのである。&lt;/p&gt;
&lt;h3&gt;「検出 - インデックス未登録」&lt;/h3&gt;
&lt;p&gt;サーチコンソールで確認すると「検出 - インデックス未登録」のURLが24件、ずらっと並んでいる。&lt;/p&gt;
&lt;p&gt;つまり、すべてのURLが「検出 - インデックス未登録」とのことらしい。&lt;/p&gt;
&lt;p&gt;さて、「検出 - インデックス未登録」とはいったいなんなのか。&lt;/p&gt;
&lt;p&gt;答えは、クローラーがサイトマップ(sitemap.xmlやfeedなど)やリンクを通してページの存在を把握しているが、インデックスはまだしていないというステータスのこと。&lt;/p&gt;
&lt;p&gt;前述したが、クロール待ちとのこと。&lt;/p&gt;
&lt;h3&gt;「クロール済み-インデックス未登録」とは似て非なる&lt;/h3&gt;
&lt;p&gt;同じような状況で「クロール済み-インデックス未登録」という状態もある。&lt;/p&gt;
&lt;p&gt;こちらも似たようなステータスだが、実は全く異なるステータスで、クローラーが内容を見た上で「インデックスしない」と判断された状態のことをいう。&lt;/p&gt;
&lt;p&gt;「価値なし」という烙印を押されたページのことである。&lt;/p&gt;
&lt;p&gt;このことを知り、少しほっとしたが、とはいえ、クロールが来ないのは困る。&lt;/p&gt;
&lt;p&gt;誰かに読まれたく、ブログを書いているのである。&lt;/p&gt;
&lt;p&gt;小説家になれない私たちはネット世界の片隅でこそこそとブログを書くしか、表現の場がないのである。&lt;/p&gt;
&lt;p&gt;ちなみに本ブログを共有している ふたみくんはいまだに小説家を夢見ているらしい……、&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/133/&quot;&gt;小説新人賞に応募するまでの道のり　～新人賞の選び方～&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;実をいえば私もまだ夢を見ているが、そのことは別記事で語ることにする。&lt;/p&gt;
&lt;p&gt;話をもとに戻して続ける。&lt;/p&gt;
&lt;h2&gt;Googlebotがストライキ中だ！&lt;/h2&gt;
&lt;p&gt;調べてみると、どうやらこの状況（検出 - インデックス未登録）良く見られるようで、一説によると2021年5月のアップデートで何らかの事象が起きたのではないか、とのこと。&lt;/p&gt;
&lt;p&gt;5月から情報が出回り始め、11月には多くのサイトでその影響を受けることになったらしい。&lt;/p&gt;
&lt;p&gt;https://twitter.com/Seolyzer_io/status/1460255741860847633&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;訳：&lt;/strong&gt;
&lt;em&gt;Googlebotがストライキ中だ！ Googlebotは11月11日午後6時以降、多くの大規模サイトでクロール活動を大幅に縮小している。これは議論が必要だ！&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;なんて、ツイートが出回るほど。&lt;/p&gt;
&lt;p&gt;さらに、Googleのジュン・ミューラー氏もこの現象を認め、現在調査をしているとのこと。&lt;/p&gt;
&lt;p&gt;ブログによっては、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;クロールは17日遅くから戻りつつあるよう&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;と書いてあったが、定かではない。&lt;/p&gt;
&lt;p&gt;現にこのブログにはまだ来ない。&lt;/p&gt;
&lt;p&gt;つまり、現状世界的なクローラー不足だと思われる。&lt;/p&gt;
&lt;p&gt;私たちはただ待つしかない。待つしかない。&lt;/p&gt;
&lt;h2&gt;12月10日 現在（謎が深まる）&lt;/h2&gt;
&lt;p&gt;変わらず、「検出 - インデックス未登録」のまま。&lt;/p&gt;
&lt;p&gt;唯一の変更は記事数が増えたので対象URLが27件になったことだけで、当然追加されたURLだって「検出 - インデックス未登録」になってしまっている。&lt;/p&gt;
&lt;p&gt;徐々にindexされ始めているというが、ストライキ中に登録した記事は再クロール対象外だろうが。&lt;/p&gt;
&lt;p&gt;あるいは公開後、間もないのでクロールの優先順位が低いのか。&lt;/p&gt;
&lt;p&gt;この現象に気が付き、今日まで、毎日のようにリクエストしてきたが、意味がないようだ。&lt;/p&gt;
&lt;h3&gt;初手サブドメインに問題があった？&lt;/h3&gt;
&lt;p&gt;サーチコンソールだが、サブドメインでの細かいデータを見たかったので、URL プレフィックスで登録した。&lt;/p&gt;
&lt;p&gt;その後、ドメインプロパティでも同様に登録した。&lt;/p&gt;
&lt;p&gt;で、ドメインプロパティの方を見るとどうやらクローラーが訪れてきているようである。&lt;/p&gt;
&lt;p&gt;本サイトはトップドメインも「https://media.nove-web.com」にサーバーリダイレクトしているので、そこに来ているのであればクローラーは認識しているってこと？&lt;/p&gt;
&lt;p&gt;リダイレクトするからいいやと思ってindex.htmlに何も書かなかったせいか、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;重複しています。ユーザーにより、正規ページとして選択されていません&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;というエラーが出ていた。&lt;/p&gt;
&lt;p&gt;そこで、リダイレクトもとにcanonicalをしていして再送信してみることにした。&lt;/p&gt;
&lt;p&gt;さて、結果はどうなることか。&lt;/p&gt;
&lt;p&gt;引き続き調査する。&lt;/p&gt;
&lt;h2&gt;12月11日現在（調査中）&lt;/h2&gt;
&lt;p&gt;色々と考えてみた。&lt;/p&gt;
&lt;p&gt;整理していくと、&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;サブドメインでサーチコンソールに登録&lt;/li&gt;
&lt;li&gt;ドメインプロパティでサーチコンソールに登録&lt;/li&gt;
&lt;li&gt;ドメインプロパティにはクローラーが訪問した？&lt;/li&gt;
&lt;li&gt;トップドメインをサブドメインにサーバーリダイレクト&lt;/li&gt;
&lt;li&gt;以降トップドメインにもクローラーがこない&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;つまり、サブドメインの本サイトに問題があるのかもしれない。&lt;/p&gt;
&lt;p&gt;というわけで、色々調査。&lt;/p&gt;
&lt;p&gt;本サイトで怪しい部分と言えば人気記事のコード。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/ranking/&quot;&gt;人気記事一覧&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;人気記事はPV数を集計して出しているが、サーバー側でbotのPVはいれない処理をしている。&lt;/p&gt;
&lt;p&gt;唯一ここが、botに対してアクションをしていると思っていた、－－、が、もしかするもっと重大な問題が含まれているのかもしれない。&lt;/p&gt;
&lt;p&gt;というのも本サイトだが、bing では検索結果が表示されるのである。&lt;/p&gt;
&lt;p&gt;流石、Microsoft、surface早く欲しい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bing.com/search?q=%E9%99%B0%E7%BF%B3%E7%A4%BC%E8%AE%83%E3%80%80%E5%AE%B6%E4%BD%9C%E3%82%8A+nove&amp;amp;qs=n&amp;amp;form=QBRE&amp;amp;sp=-1&amp;amp;pq=%E9%99%B0%E7%BF%B3%E7%A4%BC%E8%AE%83+%E5%AE%B6%E4%BD%9C%E3%82%8Anove&amp;amp;sc=0-12&amp;amp;sk=&amp;amp;cvid=A3354A72E4F848D3A5DDA6F6C57BFAE8&quot;&gt;bing &amp;gt; 陰翳礼讃　家作り nove&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;こんな感じで。&lt;/p&gt;
&lt;p&gt;ありがたいことだが、bingのユーザーは３％なので、やっぱりGoogleでヒットしたい。&lt;/p&gt;
&lt;h3&gt;bing webmaster tool が最強にわかりやすい&lt;/h3&gt;
&lt;p&gt;そこで、bing のウェブマスターツールに登録してみた。&lt;/p&gt;
&lt;p&gt;これがなかなか優秀で、非常にわかりやすい。&lt;/p&gt;
&lt;p&gt;実際に調査した結果は、&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Meta Description タグがありません&lt;/li&gt;
&lt;li&gt;画像がない場合の Alt 属性&lt;/li&gt;
&lt;li&gt;Meta robots タグに制限付きのロボット ディレクティブが含まれています&lt;/li&gt;
&lt;li&gt;タイトルが長すぎます&lt;/li&gt;
&lt;li&gt;Meta Description が長すぎるか短すぎます&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;という警告とエラーがあった。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Meta Description タグがありません&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;これはURL一覧を見た感じ、タグページとかのことを言っているので優先度は低い。&lt;/p&gt;
&lt;p&gt;まあ、いずれ潰すかくらいの感覚でいい気がする。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;画像がない場合の Alt 属性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;これはアイキャッチ画像にalt 属性を入れていないことが問題のよう。&lt;/p&gt;
&lt;p&gt;これはすぐに直せるので、修正をすることにする。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Meta robots タグに制限付きのロボット ディレクティブが含まれています&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;これは非常に怪しい。&lt;/p&gt;
&lt;p&gt;が、URLを見た感じ、こちらもタグページに適用されている。&lt;/p&gt;
&lt;p&gt;これは正しい挙動である。&lt;/p&gt;
&lt;p&gt;これが正解だったらシンプルで嬉しかったのに。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;タイトルが長すぎます&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;これもまあ、そこまで気にすることないと思われる。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Meta Description が長すぎるか短すぎます&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;こちらも同様で、特に気にすることないと思われる。&lt;/p&gt;
&lt;p&gt;分かりやすく解説してくれたが、どうにも問題の核のような箇所は見つからない。&lt;/p&gt;
&lt;h3&gt;今できる修正は？&lt;/h3&gt;
&lt;p&gt;つまり今できることは&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;人気記事一覧のコードからbot除外の記述を削除（bing でインデックスされていることを考えると原因じゃない気もするが...）&lt;/li&gt;
&lt;li&gt;アイキャッチ画像にalt属性を入れる。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;くらいだろうか。&lt;/p&gt;
&lt;p&gt;とりあえずそれで様子を見ることにする。&lt;/p&gt;
&lt;h2&gt;12月12日現在（インデックスされる！）&lt;/h2&gt;
&lt;p&gt;起きて、サーチコンソールを見ると昨日までとは全く違う結果に、「検出 - インデックス未登録」が０件になっているのである。&lt;/p&gt;
&lt;p&gt;もしや、クローラーが来てくれた？&lt;/p&gt;
&lt;p&gt;ただそれであれば有効も１件以上になっているはずなのだが、なぜか０で、謎が深まる。&lt;/p&gt;
&lt;p&gt;で、実際にはどうなのだろうか。&lt;/p&gt;
&lt;p&gt;まだ検索最適化できていないので、検索にヒットするワードはないと思われる。&lt;/p&gt;
&lt;p&gt;そこで「ウェブ制作を手掛ける&quot;nove&quot;のオウンドメディアになります。 特にこだわりなく、有益なものから無益なことまで、徒然なるままに書いていきます。」という本サイトのキャチコピーで検索してみた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.google.com/search?q=%E3%82%A6%E3%82%A7%E3%83%96%E5%88%B6%E4%BD%9C%E3%82%92%E6%89%8B%E6%8E%9B%E3%81%91%E3%82%8B%22nove%22%E3%81%AE%E3%82%AA%E3%82%A6%E3%83%B3%E3%83%89%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82+%E7%89%B9%E3%81%AB%E3%81%93%E3%81%A0%E3%82%8F%E3%82%8A%E3%81%AA%E3%81%8F%E3%80%81%E6%9C%89%E7%9B%8A%E3%81%AA%E3%82%82%E3%81%AE%E3%81%8B%E3%82%89%E7%84%A1%E7%9B%8A%E3%81%AA%E3%81%93%E3%81%A8%E3%81%BE%E3%81%A7%E3%80%81%E5%BE%92%E7%84%B6%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%BE%E3%81%AB%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%84%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82&amp;amp;oq=%E3%82%A6%E3%82%A7%E3%83%96%E5%88%B6%E4%BD%9C%E3%82%92%E6%89%8B%E6%8E%9B%E3%81%91%E3%82%8B%22nove%22%E3%81%AE%E3%82%AA%E3%82%A6%E3%83%B3%E3%83%89%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82+%E7%89%B9%E3%81%AB%E3%81%93%E3%81%A0%E3%82%8F%E3%82%8A%E3%81%AA%E3%81%8F%E3%80%81%E6%9C%89%E7%9B%8A%E3%81%AA%E3%82%82%E3%81%AE%E3%81%8B%E3%82%89%E7%84%A1%E7%9B%8A%E3%81%AA%E3%81%93%E3%81%A8%E3%81%BE%E3%81%A7%E3%80%81%E5%BE%92%E7%84%B6%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%BE%E3%81%AB%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%84%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82&amp;amp;aqs=chrome..69i57.456j0j1&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&quot;&gt;結果を見る&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;結果は無事にトップに検索されている👍&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/serch_result.png&quot; alt=&quot;nove の検索結果&quot; /&gt;&lt;/p&gt;
&lt;p&gt;これでやっと土俵に立てる。&lt;/p&gt;
&lt;p&gt;あとは記事を検索される記事を書いていくだけである。&lt;/p&gt;
&lt;h2&gt;結果、何が良かったのか？ 何だったのか？&lt;/h2&gt;
&lt;p&gt;まず、何だったかについてだが、これはクローラーの減少である。&lt;/p&gt;
&lt;p&gt;で何が良かったのかだが、これは特に何も良くなかった。&lt;/p&gt;
&lt;p&gt;というより何もしてないし、何もする必要がなかったのではないかと思われる。&lt;/p&gt;
&lt;p&gt;つまり、世界的なクローラー減少により、本サイトはなかなかインデックスされなかったが、時間が経つにつれ、徐々にクローラーが訪れるようになってくれたというだけである。&lt;/p&gt;
&lt;p&gt;まあ、いうなれば記事を更新しているのが良かったのかもしれない。&lt;/p&gt;
&lt;p&gt;サイトが特別なエラーを吐いていないのであれば、クローラーは必ずやってくるので、焦らず待つのが一番ということに落ち着いてみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>サブドメインでアドセンスに申請したので、実況中継する。</title><link>https://blog.nove-b.dev/posts/live-broadcasting-adsense-on-subdomain</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/live-broadcasting-adsense-on-subdomain</guid><content:encoded>&lt;h2&gt;おっかなびっくりアドセンス申請&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/194/&quot;&gt;アドセンスでサブドメインが使用できなかったので、ルートから301リダイレクトして対処した&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;先日お伝えした通り、本ブログもアドセンスに申請を出した。&lt;/p&gt;
&lt;p&gt;アドセンスの申請はなかなかハードルが高く、落ちるか、受かるかわからない。&lt;/p&gt;
&lt;p&gt;そこで、どのような状況で審査に出し、どういった経緯で、どういう結果になったか記しておく。&lt;/p&gt;
&lt;h3&gt;申し込んだときの状況は？&lt;/h3&gt;
&lt;p&gt;実際に申し込み時の状況を記載しておく。&lt;/p&gt;
&lt;p&gt;サイト開設：2021年11/23（土）&lt;/p&gt;
&lt;p&gt;申請日：2021年12/04（土）&lt;/p&gt;
&lt;p&gt;申請時の記事数：11記事&lt;/p&gt;
&lt;h3&gt;アドセンスに受かる必須条件&lt;/h3&gt;
&lt;p&gt;ちなみにアドセンス申請条件として下記が言われている。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;独自ドメインの利用が必須&lt;/li&gt;
&lt;li&gt;総記事数は最低でも10本以上&lt;/li&gt;
&lt;li&gt;１記事あたりの文字数は、1000文字以上&lt;/li&gt;
&lt;li&gt;1日に100PV程度が必要&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;実際は定かじゃないが、多くの記事で言及されているので、あながち間違いじゃないと思われる。&lt;/p&gt;
&lt;h3&gt;本ブログの条件通過具合&lt;/h3&gt;
&lt;p&gt;本ブログの状況を上記条件と照らし合わせてみる。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;独自ドメインの利用が必須&lt;/strong&gt;  →
ok（エックスサーバーの無料キャンペーンで取得済）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;総記事数は最低でも10本以上&lt;/strong&gt; → ok（11記事）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;１記事あたりの文字数は、1000文字以上&lt;/strong&gt;
→ ？（9/11で1000文字越え、平均：1649文字）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1日に100PV程度が必要&lt;/strong&gt; → ok（平均：122.5pv）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;軒並み基準は超えていると思われる。&lt;/p&gt;
&lt;p&gt;１点、文字数で超えていない記事もあるが平均で見ると余裕で超えている。&lt;/p&gt;
&lt;p&gt;さらに記事に関しては最大3682文字の記事まである。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/39/&quot;&gt;JavaScriptを使用してWordPressの投稿に目次を挿入する&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただ上記はコードも含まれているので、純粋な文字量で言えば、&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/83/&quot;&gt;転職で失敗しないために気を付けるポイントまとめ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上記記事が2321文字で最多、かつ実体験を通しての記事なので、それなりにユーザーのニーズに合っているだろう。&lt;/p&gt;
&lt;h3&gt;とはいえ不安は拭えない&lt;/h3&gt;
&lt;p&gt;ということで、基準はクリアしているのだが、不安な点もある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;心配なのがGoogleのクローラーがまだ本ブログに未訪問なこと。&lt;/li&gt;
&lt;li&gt;サイト開設から時間があまりたっていないこと。&lt;/li&gt;
&lt;li&gt;本ブログがサブドメインで運用されていること。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;の３点があげられる。&lt;/p&gt;
&lt;p&gt;上記の悩みは他記事でも書かせていただいた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/176/&quot;&gt;助けて‼「検出 – インデックス未登録」とか文句言ってGoogleがなかなかインデックスしてくれないの😱&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/194/&quot;&gt;アドセンスでサブドメインが使用できなかったので、ルートから301リダイレクトして対処した&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;さあ、果たして合格するか、否か。&lt;/p&gt;
&lt;p&gt;随時更新していく所存である。&lt;/p&gt;
&lt;h2&gt;12月11日（土曜日）１週間経過&lt;/h2&gt;
&lt;p&gt;音沙汰がない。&lt;/p&gt;
&lt;p&gt;どうしたことだろうか。&lt;/p&gt;
&lt;p&gt;登録時のメールには、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;チェックが完了すると、アカウント有効化の状況を記載したメールが届きます。通常、審査は数日で終了しますが、2 週間ほどかかる場合もあります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;と書いてある。&lt;/p&gt;
&lt;p&gt;つまり、数日で終わらない場合、何らかの問題がある可能性がある？&lt;/p&gt;
&lt;p&gt;まだインデックスも来ないし、それが影響しているのだろうか？&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/176/&quot;&gt;助けて‼「検出 – インデックス未登録」とか文句言ってGoogleがなかなかインデックスしてくれないの😱&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;12月12日無事にインデックスされたので、上記記事にその過程を付け加えた。&lt;/p&gt;
&lt;p&gt;つまり、以降の経過はインデックスは関係ないと思われる。&lt;/p&gt;
&lt;h2&gt;12月18日（土曜日）2週間経過&lt;/h2&gt;
&lt;p&gt;何の反応もない。&lt;/p&gt;
&lt;p&gt;インデックスだって、それなりにされてきた。&lt;/p&gt;
&lt;p&gt;が、連絡がこない。&lt;/p&gt;
&lt;p&gt;流石におかしいということで、お問い合わせフォームから連絡をしてみた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLSfbuzhIJYBxVD8u9sSka7a26-PGJBpF16jc6dOAVuM1GoC7lg/viewform&quot;&gt;AdSense 審査状況確認フォーム&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;こんなフォームがあるなんて知らなかった。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AdSense の審査の返答が 1 週間以上来ない場合や、非承認の理由が現状と異なる場合は、 大変お手数ですが以下のフォームよりご報告ください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;もう２週間もきていません。&lt;/p&gt;
&lt;p&gt;このフォームもっと早く知りたかった。&lt;/p&gt;
&lt;p&gt;待て、続報を！&lt;/p&gt;
&lt;h2&gt;12月19日（日曜日）結果が届く&lt;/h2&gt;
&lt;p&gt;さてフォームに送信したからか、翌日返信がきた。&lt;/p&gt;
&lt;p&gt;結果は&lt;strong&gt;不合格!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;審査結果はサイトが未完成とのこと。&lt;/p&gt;
&lt;p&gt;とはいえ、記事は20記事以上ある。&lt;/p&gt;
&lt;p&gt;じゃ何が悪いのか。&lt;/p&gt;
&lt;p&gt;考えみた結果、インデックスされている記事がすくないんじゃないか、という結論に至った。&lt;/p&gt;
&lt;p&gt;先日インデックスされたといったが、まだ除外されている記事の方がおおい。&lt;/p&gt;
&lt;p&gt;詳しく言うと有効が５つで、除外が23。&lt;/p&gt;
&lt;p&gt;つまりGoogleが検知している記事が５つしかないということなのかもしれない。&lt;/p&gt;
&lt;p&gt;ということで、有効記事を増やしていく。&lt;/p&gt;
&lt;p&gt;有効記事が20を超えた時に再申請する次第である。&lt;/p&gt;
&lt;h2&gt;12月30日（木曜日）結果が届く&lt;/h2&gt;
&lt;p&gt;結果は不合格。&lt;/p&gt;
&lt;p&gt;実は13記事で、いけるだろうと送っていた。&lt;/p&gt;
&lt;p&gt;落ちた理由は、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;コンテンツの有用性が低い&lt;/li&gt;
&lt;li&gt;作成中である。&lt;/li&gt;
&lt;li&gt;アラート、ナビゲーションなど、行動が目的で使用されている。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最後の、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;アラート、ナビゲーションなど、行動が目的で使用されている。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;はわからないけど、やっぱり記事数だろうか。&lt;/p&gt;
&lt;p&gt;あるいはコンタクトページがGoogleサービスを使用しているせい？&lt;/p&gt;
&lt;p&gt;Googleフォームはだめなのかしら。&lt;/p&gt;
&lt;p&gt;そこをはっきりさせるために、もう少しサイトのPVが伸びるのを記事数を増やしてから再トライする。&lt;/p&gt;
&lt;h2&gt;2022年10月13日（木曜日）合格🎉&lt;/h2&gt;
&lt;p&gt;申請してから10か月。&lt;/p&gt;
&lt;p&gt;たまに、審査リクエストをしたりしなかったり、で遂に合格しました。&lt;/p&gt;
&lt;p&gt;まあ、記事数も当然増えているが、正直インデックスされている記事数はそこまで増えてない。&lt;/p&gt;
&lt;p&gt;つまりこのブログは質が悪い......、まあ自分で言うことでもないけれど。&lt;/p&gt;
&lt;p&gt;じゃあ、なぜ審査が通ったのか🤔?&lt;/p&gt;
&lt;p&gt;考えられるのはひとつ。&lt;/p&gt;
&lt;h2&gt;アドセンスに合格するのはPV数に違いない&lt;/h2&gt;
&lt;p&gt;というのも10日くらい前、他に持っているブログを閉鎖するのでこちらのブログにリダイレクトした。&lt;/p&gt;
&lt;p&gt;そちらのブログのPV数は月600ある。&lt;/p&gt;
&lt;p&gt;まあ、プロブロガーには遠く及ばないが、２年間更新がないと思えば十分な気がする。&lt;/p&gt;
&lt;p&gt;で、そのブログからリダイレクトしてしばらくしたら合格した、さてどういうことか。&lt;/p&gt;
&lt;p&gt;ドメインパワー？&lt;/p&gt;
&lt;p&gt;いや、でもSEO的には上がっている気がしない。&lt;/p&gt;
&lt;p&gt;念のために調べてみたところ、100点中8.4点、うん、ドメインパワーは関係ない。&lt;/p&gt;
&lt;p&gt;であれば、PV数としか思えない。&lt;/p&gt;
&lt;p&gt;リダイレクトする前は１日３PVとかだったが、リダイレクトをしてからは30くらいに増えている。&lt;/p&gt;
&lt;p&gt;つまりそういうこと、アドセンス合格にはPV数がカギになる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>react でプロジェクトを作成する</title><link>https://blog.nove-b.dev/posts/create-react-project</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-react-project</guid><content:encoded>&lt;h2&gt;react をインストールする&lt;/h2&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://ja.reactjs.org/docs/create-a-new-react-app.html&quot;&gt;Create React App&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx create-react-app my-app-name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のコマンドで react が自動でインストールされる。&lt;/p&gt;
&lt;p&gt;※そんなことしないと思うが、「my-app-name」を「react」にすると怒られ、インストールできないので注意。私は何も考えずにそうして、無事に怒られた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd my-app-name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次にインストールしたディレクトリに移動する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、ローカルホスト（http://localhost:3000/）が開かれる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/react_start.png&quot; alt=&quot;reactの初期画面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;これだけで、reactのアプリが起動する。&lt;/p&gt;
&lt;p&gt;起動だけを考えるとvue より楽かもしれない、vueはいろいろと選択する必要があるので。&lt;/p&gt;
&lt;h3&gt;まずはソースを覗き見る&lt;/h3&gt;
&lt;p&gt;この時点で表示されているのは App.js のようで、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import logo from &apos;./logo.svg&apos;;
import &apos;./App.css&apos;;

function App() {
  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;header className=&quot;App-header&quot;&amp;gt;
        &amp;lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&amp;gt;
        &amp;lt;p&amp;gt;Edit &amp;lt;code&amp;gt;src/App.js&amp;lt;/code&amp;gt; and save to reload.&amp;lt;/p&amp;gt;
        &amp;lt;a
          className=&quot;App-link&quot;
          href=&quot;https://reactjs.org&quot;
          target=&quot;_blank&quot;
          rel=&quot;noopener noreferrer&quot;
        &amp;gt;Learn React&amp;lt;/a&amp;gt;
      &amp;lt;/header&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;該当ソースがこんな感じで、Javascriptを使用してhtmlを吐き出している？&lt;/p&gt;
&lt;p&gt;正直、ぱっと見だとvue のtemplate構文のほうが見やすい気がする。&lt;/p&gt;
&lt;p&gt;まあ、少しづつ、慣れていく。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>フォルダをツリー構成で綺麗に表示したい。vsCodeでtree コマンドがなくても表示できる</title><link>https://blog.nove-b.dev/posts/display-folder-structure-in-vscode</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/display-folder-structure-in-vscode</guid><content:encoded>&lt;h2&gt;treeコマンド&lt;/h2&gt;
&lt;p&gt;treeコマンドとは、フォルダ構成とかを綺麗に表示してくれるもの。&lt;/p&gt;
&lt;p&gt;実際に吐き出されるソースの見本は下記記事を参照。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/360/&quot;&gt;インストールしたreact のファイルを検分する&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;使い方は簡単で、コマンドを開き、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd 表示したいフォルダ
tree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、きれいに表示される。&lt;/p&gt;
&lt;p&gt;ちなみに、ファイル名まで表示したい場合は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tree /f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、実行する。&lt;/p&gt;
&lt;h3&gt;bash: tree: command not found&lt;/h3&gt;
&lt;p&gt;Windowsのコマンドなので（？）、vsCode 上で実行すると&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;bash: tree: command not found&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;というエラーができる。&lt;/p&gt;
&lt;p&gt;そういう時はコマンドに行けばいいのだが、どうしてもvsCodeでやりたい時は下記コマンドで実行可能となる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pwd;find . | sort | sed &apos;1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://qiita.com/Qsugi/items/aebd6e790a5928eb84fc&quot;&gt;Windowsファイルツリー構造の表示とテキスト保存&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://qiita.com/yone098@github/items/bba8a42de6b06e40983b&quot;&gt;tree コマンドが無い環境で tree コマンドを実現&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>インストールしたreact のファイルを検分する</title><link>https://blog.nove-b.dev/posts/explore-installed-react-files</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/explore-installed-react-files</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/312/&quot;&gt;前回にreactの環境構築をした&lt;/a&gt;ので、今回はインストールしたファイルを細かく見ていくことにする。&lt;/p&gt;
&lt;h2&gt;react app のファイル構成&lt;/h2&gt;
&lt;p&gt;最初にインストールした時点で存在しているフォルダは下記一覧。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;|--node_modules
| |--(抜粋)
|--public
| |--favicon.ico
| |--index.html
| |--logo192.png
| |--logo512.png
| |--manifest.json
| |--robots.txt
|--README.md
|--src
| |--App.css
| |--App.js
| |--App.test.js
| |--index.css
| |--index.js
| |--logo.svg
| |--reportWebVitals.js
| |--setupTests.js
|--.gitignore
|--package.json
|--README.md
|--yarn.lock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;node_modulesの中身は多すぎるので、抜粋した。&lt;/p&gt;
&lt;p&gt;どうやらこの中でも必要じゃないファイルがいくつかあるらしいので、残しておくべきファイルを整理する。&lt;/p&gt;
&lt;h3&gt;必要フォルダ構成&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;|--node_modules // 必要
| |--(抜粋)
|--public
| |--favicon.ico
| |--index.html // 必要
| |--logo192.png
| |--logo512.png
| |--manifest.json
| |--robots.txt
|--README.md
|--src
| |--App.css // 必要
| |--App.js // 必要
| |--App.test.js
| |--index.css
| |--index.js // 必要
| |--logo.svg
| |--reportWebVitals.js
| |--setupTests.js
|--.gitignore // 必要
|--package.json // 必要
|--README.md // 必要
|--yarn.lock // 必要
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;必要なフォルダ構成は上記の通り。&lt;/p&gt;
&lt;p&gt;それ以外は削除してフォルダ構成をクリーニングする。&lt;/p&gt;
&lt;p&gt;すると当然依存ファイルがなくなるので、下記エラーが吐き出される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./src/logo.svg
Error: ENOENT: no such file or directory, open &apos;C:\Users\kyoryu\Desktop\react-app\src\logo.svg&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;なので、依存関係をすべて解決すれば、再び、表示される。&lt;/p&gt;
&lt;p&gt;私は下記、参考書を参考に勉強したので、そこに詳しい依存関係解決後のコードがある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/gp/product/B08XWMVX76/ref=as_li_tl?ie=UTF8&amp;amp;camp=247&amp;amp;creative=1211&amp;amp;creativeASIN=B08XWMVX76&amp;amp;linkCode=as2&amp;amp;tag=nove0822-22&amp;amp;linkId=b66ad4511b3b4cab277de1fae53fe9a5&quot;&gt;はじめてつくるreact アプリ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;キンドルアンリミテッドで無料なので、自身で依存関係を解決できないのであれば、参考にしてください。&lt;/p&gt;
&lt;p&gt;[sc name=&quot;kindleunlimited_234x60&quot; ][/sc]&lt;/p&gt;
&lt;h2&gt;削除したものはなに？&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/gp/product/B08XWMVX76/ref=as_li_tl?ie=UTF8&amp;amp;camp=247&amp;amp;creative=1211&amp;amp;creativeASIN=B08XWMVX76&amp;amp;linkCode=as2&amp;amp;tag=nove0822-22&amp;amp;linkId=b66ad4511b3b4cab277de1fae53fe9a5&quot;&gt;はじめてつくるreact アプリ&lt;/a&gt;に従ってクリーニングした。&lt;/p&gt;
&lt;p&gt;さて、ここで気になるのは削除した依存関係と不要とされた記述はなんなのか、ということである。&lt;/p&gt;
&lt;p&gt;気にならないのであればそれでいいが、それもそれで今後が怖いので、一応調べておく。&lt;/p&gt;
&lt;p&gt;いじったのは App.js と index.js の２つ。&lt;/p&gt;
&lt;p&gt;App.jsに関しては、読み込んでいるreact のメインビジュアルを変更を削除しただけなので、特に問題はない。&lt;/p&gt;
&lt;p&gt;気になるのは index.js の方。&lt;/p&gt;
&lt;p&gt;削除したのは、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// import &apos;./index.css&apos;;
// import reportWebVitals from &apos;./reportWebVitals&apos;;
// &amp;lt;React.StrictMode&amp;gt;
// &amp;lt;/React.StrictMode &amp;gt;
// reportWebVitals();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;の５行で、１つ目はcss なので問題がない。&lt;/p&gt;
&lt;p&gt;それ以外である。&lt;/p&gt;
&lt;p&gt;残りの４つは２つに分けることができる。&lt;/p&gt;
&lt;h3&gt;reportWebVitals&lt;/h3&gt;
&lt;p&gt;まずは１つ目の「reportWebVitals」。&lt;/p&gt;
&lt;p&gt;こちらはimport で読み込み、関数を実行している？&lt;/p&gt;
&lt;p&gt;どうやらこれは「WebVitals計測ライブラリ」というものらしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://create-react-app.dev/docs/measuring-performance/&quot;&gt;reactの公式&lt;/a&gt;でも解説されている。&lt;/p&gt;
&lt;p&gt;使い方とかは下記が詳しいのでメモ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://qiita.com/ozaki25/items/6139cbc70cf988d1c870&quot;&gt;CreateReactAppにWebVitals計測ライブラリが入ったので試してみた&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;確かに必要はなさそうなので、最小限のアプリとかを作る場合は削除しても問題なさそうだが、まあ、試しに使ってもいいので、あえて削除する必要もないくらいの感覚。&lt;/p&gt;
&lt;h3&gt;React.StrictMode&lt;/h3&gt;
&lt;p&gt;最後が&amp;lt;React.StrictMode&amp;gt;という開始タグと&amp;lt;/React.StrictMode &amp;gt;という閉じタグ。&lt;/p&gt;
&lt;p&gt;こちらも公式にあったので、参照。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;StrictMode はアプリケーションの潜在的な問題点を洗い出すためのツールです。Fragment と同様に、StrictMode は目に見える UI を描画しません。StrictMode の子孫要素に対しては、付加的な検査および警告が動くようになります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;現状のコードを見ると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
document.getElementById(&apos;root&apos;)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;となっているので、アプリ全体の問題点を洗い出してくれるようになる。&lt;/p&gt;
&lt;p&gt;つまり、これはあったほうがいいのか？&lt;/p&gt;
&lt;p&gt;しかも本番環境には影響を与えないとのこと。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ja.reactjs.org/docs/strict-mode.html#gatsby-focus-wrapper&quot;&gt;strict モード&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;うーん、こちらは残したほうが良さそうなので、残しておく。&lt;/p&gt;
&lt;p&gt;次はやっとこさ、ソースをいじっていく。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>react を適当に触って確かめてみる。</title><link>https://blog.nove-b.dev/posts/explore-react-functionality</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/explore-react-functionality</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/360/&quot;&gt;前回、reactのファイルを検分した&lt;/a&gt;ので、今回は、適当に触ってみる。&lt;/p&gt;
&lt;h2&gt;それじゃ、適当に触ってみる&lt;/h2&gt;
&lt;h3&gt;App.js編&lt;/h3&gt;
&lt;p&gt;まず、前回インストール時の時から依存ファイルをクリーニングした。&lt;/p&gt;
&lt;p&gt;結果、非常にわかりやすくなった。&lt;/p&gt;
&lt;p&gt;ざっと見た感じ、HTML部分の特別な違いは、class が classNameになること...くらい？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import &apos;./App.css&apos;;

function App() {
  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;header className=&quot;App-header&quot;&amp;gt;
        &amp;lt;p&amp;gt;HTML部分の特別な違いは、class が classNameになること...くらいかしら&amp;lt;/p&amp;gt;
          &amp;lt;a
            className=&quot;App-link&quot;
            href=&quot;https://reactjs.org&quot;
            target=&quot;_blank&quot;
            rel=&quot;noopener noreferrer&quot;
          &amp;gt;Learn React&amp;lt;/a&amp;gt;
      &amp;lt;/header&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コードで保存すると、&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/className_change.png&quot; alt=&quot;react 変更分&quot; /&gt;&lt;/p&gt;
&lt;p&gt;のように表示される。&lt;/p&gt;
&lt;p&gt;ここまでは特別に難しくない。&lt;/p&gt;
&lt;h3&gt;App.css 編&lt;/h3&gt;
&lt;p&gt;次に、App.js の先頭に書かれている、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import &apos;./App.css&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を見ていく。&lt;/p&gt;
&lt;p&gt;こちらも特別難しいことはない。&lt;/p&gt;
&lt;p&gt;普通にcssを読みこんでいるだけなので、&lt;/p&gt;
&lt;p&gt;color: white; → color: red;&lt;/p&gt;
&lt;p&gt;にすればテストの色が変更される、&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/css_change.png&quot; alt=&quot;css変更画像&quot; /&gt;&lt;/p&gt;
&lt;p&gt;この画像通りに。&lt;/p&gt;
&lt;p&gt;特別難しいことはないが、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media (prefers-reduced-motion: no-preference)  {}
font-size: calc(10px + 2vmin);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;とか個人的に知らない使い方があったので、勉強になる気がする。&lt;/p&gt;
&lt;p&gt;てか、人のコードを見るのは勉強になる。&lt;/p&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://www.funnypro.net/blog/tech/2845.html&quot;&gt;意外と知らない？メディアクエリを使ってみよう。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://jajaaan.co.jp/web-production/frontend/css-vw-vh-vmin-vmax/&quot;&gt;【CSS】vw、vh、vmin、vmaxとは？基本的な使い方&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;index.js 編&lt;/h3&gt;
&lt;p&gt;最後に、前述した App.js を読み込んでいる index.js 、こいつが少しわからなかった。&lt;/p&gt;
&lt;p&gt;こちらはクリーニングした状態で下記のようになっている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React from &apos;react&apos;;
import ReactDOM from &apos;react-dom&apos;;
import App from &apos;./App&apos;;
import reportWebVitals from &apos;./reportWebVitals&apos;;

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById(&apos;root&apos;)
);

reportWebVitals();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;さて、これはなんなのだろうか。&lt;/p&gt;
&lt;p&gt;vue を良く触るので、vueで考えてみると、App.vue（？）あるいは、views 内ファイルのどれか（？）&lt;/p&gt;
&lt;p&gt;調べたところ、どうやらindex.js は、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Reactアプリを実行する際、一番最初に呼び出されるファイル&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;らしいので、App.vue に近いのだろうか。&lt;/p&gt;
&lt;p&gt;んー、わからないので、次で新規でページを作ってみて、index.jsの動きを確認してみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>javascriptでimportするときに { 中括弧 } をつける時とつかない時があって釈然としない</title><link>https://blog.nove-b.dev/posts/javascript-import-braces-issue</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/javascript-import-braces-issue</guid><content:encoded>&lt;h2&gt;defaultの有無&lt;/h2&gt;
&lt;p&gt;export default で書き出した値は、中括弧なしでimport できる。&lt;/p&gt;
&lt;p&gt;export で書き出した値は、中括弧ありでimport する。&lt;/p&gt;
&lt;p&gt;そしてさらに少しややこしくなるが、export で書き出した値は { xxx as yyy
} とすることで任意の変数名に変えることができる。&lt;/p&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://qiita.com/ozaki25/items/9723cb3c1c72845157d5&quot;&gt;ES2015のモジュール機能(import/export)&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;実際に動かしてみた&lt;/h3&gt;
&lt;p&gt;上記の参考とまんまだが、実際に動かしてみた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default &quot;uchida hyakken&quot;;
export const firstNaMe = &quot;hyakken&quot;;
export const lastName = &quot;uchida&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;import name, { firstNaMe, lastName } from &quot;./export&quot;;

console.log(&quot;name&quot;, name); // name uchida hyakken
console.log(&quot;firstNaMe&quot;, firstNaMe); // firstNaMe hyakken
console.log(&quot;lastName&quot;, lastName); // lastName uchida
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;iframe style=&quot;width: 100%; height: 500px; border: 0; border-radius: 4px; overflow: hidden;&quot; src=&quot;https://codesandbox.io/embed/wizardly-neumann-txkkz?fontsize=14&amp;amp;hidenavigation=1&amp;amp;theme=dark&quot; title=&quot;wizardly-neumann-txkkz&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;下に小さくあるconsole ボタンを押して見ていただければ成功していることが確認できる。&lt;/p&gt;
&lt;p&gt;うん、動かすことで理解が深まった。&lt;/p&gt;
&lt;p&gt;export / import を使いこなすことで、ファイル管理を楽にしていこう。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>エンジニアの成長のためには単語のコピペをやめたほうがいいんじゃないかという思い付き</title><link>https://blog.nove-b.dev/posts/stop-copy-pasting-for-engineer-growth</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/stop-copy-pasting-for-engineer-growth</guid><content:encoded>&lt;h2&gt;コピペは決して悪じゃない&lt;/h2&gt;
&lt;p&gt;エンジニアはとにかくコピペをするべきである、って新卒で入ったウェブ制作会社で言われたのは、もう6年も前。&lt;/p&gt;
&lt;p&gt;少しややこしい言い方をしたが、ロジックも含めてコピペをするわけじゃなくて、単語とかをコピペしろ、っていう意味で言われた。&lt;/p&gt;
&lt;p&gt;確かに、デバック中にスペルの抜けで動いてないことを知った時、エンジニアは皆、般若のような顔になる。&lt;/p&gt;
&lt;p&gt;つまりとても理にかなっている。&lt;/p&gt;
&lt;p&gt;理にかなっているので、実践してきた。&lt;/p&gt;
&lt;p&gt;例えば、event 時に実行する関数は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;対象の要素.addEventListener(種類, function() {
// 処理を記述
}, false);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というコードをクリップボードに保存して使う。&lt;/p&gt;
&lt;p&gt;これならスペルミスも生まれないし、時短にもなる。&lt;/p&gt;
&lt;p&gt;が、がしかし、である。&lt;/p&gt;
&lt;h3&gt;かっこいいエンジニアになりたい&lt;/h3&gt;
&lt;p&gt;最近、まあ、6年近くウェブに携わってきたので、後輩に教えることが多くなってきた。&lt;/p&gt;
&lt;p&gt;「わかりません」と呼ばれ、後輩の机に移動する。&lt;/p&gt;
&lt;p&gt;「あー、これね、こんなの簡単よ」ってどや顔し、いざパソコンと向き合った時、わかる、わかるのだが、スペルがわからない。&lt;/p&gt;
&lt;p&gt;「ごめんだけど、アドイベントリスナーってググってくれない？」&lt;/p&gt;
&lt;p&gt;「え、あどいべんとりすなー？」って後輩に聞き返される。&lt;/p&gt;
&lt;p&gt;なんて、恥ずかしい思いはしたくない。&lt;/p&gt;
&lt;p&gt;そう思うならコピペを辞めるのも手じゃなかろうか。&lt;/p&gt;
&lt;h2&gt;私はコピペを辞めました。&lt;/h2&gt;
&lt;p&gt;以来、だれのパソコンでもすらすらと日本語を書くように、というと言い過ぎだが、コードを書けるようになった。&lt;/p&gt;
&lt;p&gt;前述したが、コピペは全く悪じゃない。&lt;/p&gt;
&lt;p&gt;コピペエンジニアと言われている人たちがいるが、あれはロジックを理解せずに使っているエンジニアで、スペルミスを防ぐためにコピペをしているのはコピペエンジニアではない。&lt;/p&gt;
&lt;p&gt;ただ後輩の前でかっこつけたいのであれば、なるべく手を動かし書くべきだと思う。&lt;/p&gt;
&lt;p&gt;結果、たまに般若のような顔を後輩に見られることになるかもしれないが。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>react.jsが急に、突然インストールできなくなった</title><link>https://blog.nove-b.dev/posts/react-installation-issue</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/react-installation-issue</guid><content:encoded>&lt;p&gt;以前、reactをインストールする方法を書いたが、今日（2021年12月22日）急にインストールができなくなった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/312/&quot;&gt;react でプロジェクトを作成する&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;You are running `create-react-app` 4.0.3, which is behind the latest release (5.0.0).

We no longer support global installation of Create React App.

Please remove any global installs with one of the following commands:
- npm uninstall -g create-react-app
- yarn global remove create-react-app

The latest instructions for creating a new app can be found here:
https://create-react-app.dev/docs/getting-started/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出てくる。&lt;/p&gt;
&lt;p&gt;なにうえ、と調べるといくつかヒットした。&lt;/p&gt;
&lt;p&gt;キャッシュを消せとか、色々出てきたので、検索して試してみるといいと思われる、が。&lt;/p&gt;
&lt;p&gt;私にはどの方法もうまくいかなかった。&lt;/p&gt;
&lt;p&gt;で、結局うまくいったのは...下記の通り。&lt;/p&gt;
&lt;h2&gt;これが正解...？&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npx clear-npx-cache

C:\Users\{name}\AppData\Roaming\npm-cache 削除

npm init

npx create-react-app myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これが正解なのだろうか。&lt;/p&gt;
&lt;p&gt;情報をさらに調べてみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>特定のページでコメント投稿欄が非表示になっていたので、原因を調査してみた。</title><link>https://blog.nove-b.dev/posts/comment-section-hidden-issue-in-specific-page</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/comment-section-hidden-issue-in-specific-page</guid><content:encoded>&lt;h2&gt;コメント投稿機能が表示されない&lt;/h2&gt;
&lt;h3&gt;ブロガー朝のルーティン&lt;/h3&gt;
&lt;p&gt;朝起きてから自身の予約投稿した投稿が、無事に公開されているか確認する。&lt;/p&gt;
&lt;p&gt;そんなブロガーであり、目覚めの悪い私が驚き飛び起きたのには訳がある。&lt;/p&gt;
&lt;p&gt;コメント投稿欄が非公開になっていたからである。&lt;/p&gt;
&lt;p&gt;11月、機能追加したコメント投稿機能がうまく動作していなかったのかしら、と他ページを見てみたところ、どうやら問題なく表示されている。&lt;/p&gt;
&lt;p&gt;どうしてこのページだけ、投稿機能が動作しないのか。&lt;/p&gt;
&lt;h2&gt;長いバグ修正の旅に&lt;/h2&gt;
&lt;p&gt;長い長い、そして結論はいたってシンプルであったバグ修正の旅に出る。&lt;/p&gt;
&lt;p&gt;まずは同じ現象が起きているページを探してみる。&lt;/p&gt;
&lt;p&gt;結果、2ページが該当した。&lt;/p&gt;
&lt;p&gt;該当したのは下記ページ（現在は正常に動作中なので、コメントください）。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/194/&quot;&gt;アドセンスでサブドメインが使用できなかったので、ルートから301リダイレクトして対処した&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/128/&quot;&gt;nove月次報告書（2021年11月）-初月の収益を公開-&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この２つにはいくつかの共通点があった。&lt;/p&gt;
&lt;p&gt;ひとつは、カテゴリが「&lt;a href=&quot;https://media.nove-web.com/category/web/media/&quot;&gt;メディア&lt;/a&gt;」であるということ。&lt;/p&gt;
&lt;p&gt;ひとつは、今月機能追加で採用したショートコード管理プラグインが動作しているということ。&lt;/p&gt;
&lt;p&gt;そこでふたつの共通点を順に調査していくことに。&lt;/p&gt;
&lt;h3&gt;カテゴリが関係しているのか&lt;/h3&gt;
&lt;p&gt;まず、カテゴリについて実験してみる。&lt;/p&gt;
&lt;p&gt;他の記事をメディアカテゴリに移管する→投稿機能は無事に動作している。&lt;/p&gt;
&lt;p&gt;該当記事を他のカテゴリに移管する→投稿機能は変わらず表示されない。&lt;/p&gt;
&lt;p&gt;つまり、カテゴリは今回のバグに関係ない。&lt;/p&gt;
&lt;h3&gt;プラグインが関係しているのか&lt;/h3&gt;
&lt;p&gt;次にショートコード管理プラグインを疑ってみる。&lt;/p&gt;
&lt;p&gt;この時点で私は相当このプラグインを疑っていた。&lt;/p&gt;
&lt;p&gt;だからプラグインなんて採用するものじゃない、なんて悪態すらついていた。&lt;/p&gt;
&lt;p&gt;そんな心境でデバックを開始する。&lt;/p&gt;
&lt;p&gt;まずはプラグインを無効にしてみる→該当ページの投稿機能は変わらず表示されない。&lt;/p&gt;
&lt;p&gt;他の記事に上記プラグインを使用してショートコードを挿入する→投稿機能は無事に動作している。&lt;/p&gt;
&lt;p&gt;該当ページにあるショートコードの記述を削除してみる→投稿機能は変わらず表示されない。&lt;/p&gt;
&lt;p&gt;つまり、プラグインは問題ない。&lt;/p&gt;
&lt;p&gt;そもそも評価4.1かつ多くの人が使用しているプラグインを疑うくらいなら自身の作成したテーマを疑うべきである。&lt;/p&gt;
&lt;p&gt;というわけで、自作テーマを見返したが、どうにも原因となる部分は見つからない。&lt;/p&gt;
&lt;h2&gt;解決編&lt;/h2&gt;
&lt;p&gt;そこでいろいろ調べていると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ダッシュボード &amp;gt; 投稿 と移動し、 該当する投稿の「クイック編集」で「コメントを許可」にチェックを入れてみてください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という記述を見つけた。&lt;/p&gt;
&lt;p&gt;まさか、と思い上記手順で確認してみたところ、どうしてか知らないが、チェックが外れている。&lt;/p&gt;
&lt;p&gt;唖然としつつ、チェックをいれ、再度ページを見ると、無事にコメント機能が動いていた。&lt;/p&gt;
&lt;p&gt;また、つまらぬことに時間を割いてしまった、なんて内心解決にほっとしている気持ちを隠しつつ、ハードボイルドに言ってみたりする。&lt;/p&gt;
&lt;p&gt;共通点ある、なんてどっかの私立探偵のみたいなセリフは何も生み出さなかった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>サーチコンソールより優秀な「Bing Webmaster Tools」を使ってブログで検索上位を目指してみる</title><link>https://blog.nove-b.dev/posts/bing-webmaster-tools-vs-google-search-console</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/bing-webmaster-tools-vs-google-search-console</guid><content:encoded>&lt;p&gt;上位を目指してみるなんて言ってみたが、現状（12月11日）本サイトをGoogleに認識されていない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/176/&quot;&gt;助けて‼「検出 – インデックス未登録」とか文句言ってGoogleがなかなかインデックスしてくれないの😱&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;色々、調査中である（12月12日にインデックスされ解決した）。&lt;/p&gt;
&lt;p&gt;で、調査中において、MicrosoftのBing Webmaster
Toolsが非常に便利だったので、ぜひとも後世に残しておきたい。&lt;/p&gt;
&lt;h2&gt;Bing Webmaster Toolsとは？&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bing.com/webmaster/tools&quot;&gt;Bing Webmaster Tools&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bing Webmaster
Toolsアカウントを使用すると、検索最適化計画（SEO）を非常に簡単に開始できます。ウェブマスターツール内では、SEOセクションの下に、バックリンクの調査、キーワードの調査、サイトや個々のURLのSEOエラーの分析などのタスクに役立つツールのリストが表示されます。 SEOレポートは、アカウントで確認したドメインで隔週で自動的に実行されます。したがって、月に約2回、SEOで対処する必要のある項目に関する提案を含む最新のレポートが表示されます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;つまりbingの検索エンジンで上位に来るように色々調査できるというもの。&lt;/p&gt;
&lt;p&gt;つまりつまり、サーチコンソールのbing版というもの。&lt;/p&gt;
&lt;h3&gt;登録方法は割愛中&lt;/h3&gt;
&lt;p&gt;登録方法とかは別に難しいこともないので割愛する。&lt;/p&gt;
&lt;p&gt;１つアドバイスとすればサーチコンソールを先に登録したほうがいい。&lt;/p&gt;
&lt;p&gt;なぜかというと、Bing Webmaster
Toolsはサーチコンソールのデータを引き継ぐことができるのである。&lt;/p&gt;
&lt;p&gt;つまり、サーチコンソールに登録しておけばBing Webmaster
Toolsに登録するのが楽になる。&lt;/p&gt;
&lt;h3&gt;で、何が優秀なのか&lt;/h3&gt;
&lt;p&gt;話を戻すことにして、優秀な機能の１つとしてサイト スキャン機能がある。&lt;/p&gt;
&lt;p&gt;これはサイトのエラーや警告を通知してくれるのである。&lt;/p&gt;
&lt;p&gt;seo &amp;gt; サイト スキャン &amp;gt; 新しいスキャンを開始&lt;/p&gt;
&lt;p&gt;で、調査が始まる。&lt;/p&gt;
&lt;p&gt;後はメールで通知してくれるので、待つだけである。&lt;/p&gt;
&lt;p&gt;結果は非常にわかりやすい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Meta Description タグがありません&lt;/li&gt;
&lt;li&gt;画像がない場合の Alt 属性&lt;/li&gt;
&lt;li&gt;Meta robots タグに制限付きのロボット ディレクティブが含まれています&lt;/li&gt;
&lt;li&gt;タイトルが長すぎます&lt;/li&gt;
&lt;li&gt;Meta Description が長すぎるか短すぎます&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;こんなに具体的に教えてくれるので、修正もしやすい。&lt;/p&gt;
&lt;h3&gt;サーチコンソールとは違ってわかりやすい&lt;/h3&gt;
&lt;p&gt;サーチコンソールだとこうはいかない。&lt;/p&gt;
&lt;p&gt;サーチコンソールは漠然としたことしか教えてくれない。&lt;/p&gt;
&lt;p&gt;「検出 - インデックス未登録」みたいな感じで、どうしてそうなったのかを教えてくれないのである。&lt;/p&gt;
&lt;p&gt;それに比べて「Bing Webmaster Tools」は丁寧なこと、この上ない。&lt;/p&gt;
&lt;p&gt;もちろん、この丁寧に教えてくれるエラーを解消したところで、「検出 - インデックス未登録」が直るわけではないのだが、人間全くわからないよりはすこしでも分かっている方が、落ち着くのである。&lt;/p&gt;
&lt;p&gt;そういう意味でも「Bing Webmaster
Tools」は技術だけでなく、心にもいいツールであると言える。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>カスタムフィールドで改行が適用されないので、無理やり改行できるようにした。</title><link>https://blog.nove-b.dev/posts/custom-field-line-break-issue-solved</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/custom-field-line-break-issue-solved</guid><content:encoded>&lt;p&gt;本記事はリード文をカスタムフィールドで書いている。&lt;/p&gt;
&lt;p&gt;が、カスタムフィールドないでいくら改行しても改行が記事に反映されないので、調査、修正してみた。&lt;/p&gt;
&lt;p&gt;まず、そもそものコードは&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
  $item_lead = get_post_meta($post-&amp;gt;ID, &apos;item_lead&apos;, true);
  echo $item_lead;
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という形で吐き出していた。&lt;/p&gt;
&lt;p&gt;が、これだとcssは当たるが、改行が反映されない。&lt;/p&gt;
&lt;p&gt;どうやらこれは調べてみると仕様っぽい。&lt;/p&gt;
&lt;p&gt;コードによる解決方法が見つからなかったので、すこし無理やりだが、改行を判定し、pタグで囲むようにした。&lt;/p&gt;
&lt;p&gt;実際のコードは、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$values = explode(&quot;\n&quot;, get_post_meta($post-&amp;gt;ID, &apos;item_lead&apos;, true));
  foreach ($values as $value) {
    echo &quot;&amp;lt;p&amp;gt;&quot; . $value . &quot;&amp;lt;/p&amp;gt;\n&quot;;
  }
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という形に修正した。&lt;/p&gt;
&lt;p&gt;やっとこととしては、まずexplode()で取得した文字列を改行コードで分割する。&lt;/p&gt;
&lt;p&gt;分割した値を回し、pタグで囲っていく。&lt;/p&gt;
&lt;p&gt;ただそれだけ。&lt;/p&gt;
&lt;p&gt;少し無理やりかもしれないが、改行が反映されるようになった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>n の倍数で数値を丸める</title><link>https://blog.nove-b.dev/posts/round-to-n-multiple</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/round-to-n-multiple</guid><content:encoded>&lt;h2&gt;特定の倍数に数値をまとめたい。&lt;/h2&gt;
&lt;p&gt;なにをいっているのだろうと思われたかもしれないので、実例をどうぞ。&lt;/p&gt;
&lt;h3&gt;実例&lt;/h3&gt;
&lt;p&gt;ユーザーが数値を入れるインプットエリアがあるとする。&lt;/p&gt;
&lt;p&gt;ユーザーは任意の数字を入れることができる。&lt;/p&gt;
&lt;p&gt;その結果を10の倍数にまとめたい。&lt;/p&gt;
&lt;p&gt;つまり、24とユーザーが記入した場合は「20」が期待値になる。&lt;/p&gt;
&lt;p&gt;ということがやりたい。&lt;/p&gt;
&lt;h3&gt;実装方法&lt;/h3&gt;
&lt;p&gt;じゃ、どうするのか。&lt;/p&gt;
&lt;p&gt;まずは実装済みのものをどうぞ↓（うまくコンパイルできない時があるので、下の更新ボタンをクリックしてください）&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe style=&quot;width: 100%; height: 500px; border: 0; border-radius: 4px; overflow: hidden;&quot; src=&quot;https://codesandbox.io/embed/floral-field-fiof9?fontsize=14&amp;amp;hidenavigation=1&amp;amp;theme=dark&amp;amp;view=preview&quot; title=&quot;floral-field-fiof9&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;inputエリアに数字を入れていくと、5で10、14で10、15で20になっていることが確認できる。&lt;/p&gt;
&lt;p&gt;つまり24と入力すれば「20」が表示される、期待値通り。&lt;/p&gt;
&lt;h2&gt;特定の倍数に数値をまとめるコード&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;const changeNumber = () =&amp;gt; {
  const unit = 10;
  const el = Math.round(num.value);
  result.value = Math.round(el / unit) * unit;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;inputエリアのvalueが更新された時、&lt;/p&gt;
&lt;p&gt;まずはvalueを丸める。&lt;/p&gt;
&lt;p&gt;つまり、2は0、5は10になる。&lt;/p&gt;
&lt;p&gt;その値を最初に定義した値（丸めたい倍数）で計算する。&lt;/p&gt;
&lt;p&gt;実際に24が入力された時、&lt;/p&gt;
&lt;p&gt;24を丸めて20にする。&lt;/p&gt;
&lt;p&gt;その値を10で割って10でかける。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;20 / 10 * 10 = 20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;結果20になる。&lt;/p&gt;
&lt;p&gt;なんかこうやってみるともっと簡単な方法がある？&lt;/p&gt;
&lt;p&gt;まあ、期待値は取り出せたので、良しとする。&lt;/p&gt;
&lt;p&gt;理系の人、ぜひ教えてください。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>エンジニアのバイブル「リーダブルコード」をKindle Paperwhiteで読む</title><link>https://blog.nove-b.dev/posts/read-readable-code-on-kindle</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/read-readable-code-on-kindle</guid><content:encoded>&lt;h2&gt;Good Bye 紙の本、そして紙の本しか出さない作家さん&lt;/h2&gt;
&lt;p&gt;読書は専らKindle Paperwhiteで読む。&lt;/p&gt;
&lt;p&gt;「ひと昔前は本は紙でしょう、電子書籍？　いやいや風情も雰囲気もない。」&lt;/p&gt;
&lt;p&gt;なんて思っていたが、Kindle Paperwhiteを買ったらもう、紙に戻れなくなった。&lt;/p&gt;
&lt;p&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName(&quot;body&quot;)[0],e.appendChild(d))})(window,document,&quot;script&quot;,&quot;//dn.msmstatic.com/site/cardlink/bundle.js?20220329&quot;,&quot;msmaflink&quot;);msmaflink({&quot;n&quot;:&quot;Kindle Paperwhite (8GB) 6.8インチディスプレイ 色調調節ライト搭載 広告つき&quot;,&quot;b&quot;:&quot;Amazon&quot;,&quot;t&quot;:&quot;53-026459&quot;,&quot;d&quot;:&quot;https://m.media-amazon.com&quot;,&quot;c_p&quot;:&quot;/images/I&quot;,&quot;p&quot;:[&quot;/412W8Vob-EL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/61zydt1iBTL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/41iy0gIKgRL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/51OJb-0ZSZL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/41PThq9CjyL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/51WSWUkd0eL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/41kXf2RlNDL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;],&quot;u&quot;:{&quot;u&quot;:&quot;https://www.amazon.co.jp/dp/B08N41Y4Q2&quot;,&quot;t&quot;:&quot;amazon&quot;,&quot;r_v&quot;:&quot;&quot;},&quot;v&quot;:&quot;2.1&quot;,&quot;b_l&quot;:[{&quot;id&quot;:4,&quot;u_tx&quot;:&quot;Amazonで見る&quot;,&quot;u_bc&quot;:&quot;#f79256&quot;,&quot;u_url&quot;:&quot;https://www.amazon.co.jp/dp/B08N41Y4Q2&quot;,&quot;a_id&quot;:3112474,&quot;p_id&quot;:170,&quot;pl_id&quot;:27060,&quot;pc_id&quot;:185,&quot;s_n&quot;:&quot;amazon&quot;,&quot;u_so&quot;:1},{&quot;id&quot;:1,&quot;u_tx&quot;:&quot;楽天市場で見る&quot;,&quot;u_bc&quot;:&quot;#f76956&quot;,&quot;u_url&quot;:&quot;https://search.rakuten.co.jp/search/mall/Kindle%20Paperwhite%20(8GB)%206.8%E3%82%A4%E3%83%B3%E3%83%81%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4%20%E8%89%B2%E8%AA%BF%E8%AA%BF%E7%AF%80%E3%83%A9%E3%82%A4%E3%83%88%E6%90%AD%E8%BC%89%20%E5%BA%83%E5%91%8A%E3%81%A4%E3%81%8D/&quot;,&quot;a_id&quot;:3109755,&quot;p_id&quot;:54,&quot;pl_id&quot;:27059,&quot;pc_id&quot;:54,&quot;s_n&quot;:&quot;rakuten&quot;,&quot;u_so&quot;:2},{&quot;id&quot;:2,&quot;u_tx&quot;:&quot;Yahoo!ショッピングで見る&quot;,&quot;u_bc&quot;:&quot;#66a7ff&quot;,&quot;u_url&quot;:&quot;https://shopping.yahoo.co.jp/search?first=1\u0026p=Kindle%20Paperwhite%20(8GB)%206.8%E3%82%A4%E3%83%B3%E3%83%81%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4%20%E8%89%B2%E8%AA%BF%E8%AA%BF%E7%AF%80%E3%83%A9%E3%82%A4%E3%83%88%E6%90%AD%E8%BC%89%20%E5%BA%83%E5%91%8A%E3%81%A4%E3%81%8D&quot;,&quot;a_id&quot;:3109760,&quot;p_id&quot;:1225,&quot;pl_id&quot;:27061,&quot;pc_id&quot;:1925,&quot;s_n&quot;:&quot;yahoo&quot;,&quot;u_so&quot;:3}],&quot;eid&quot;:&quot;D4cJo&quot;,&quot;s&quot;:&quot;s&quot;});&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;リンク&lt;/p&gt;
&lt;p&gt;結果的に電子書籍を出していない作家は、私の中で読む術を失った。&lt;/p&gt;
&lt;p&gt;なにを思って電子書籍版を出さないのかわからないが、出さないことで少なくとも私のような人種からのリーチを失っていると作家には知ってほしいし、読みたいので電子書籍版を出して欲しい。&lt;/p&gt;
&lt;p&gt;とは言え、ただただ、電子書籍版を出せばいいというわけでもない。&lt;/p&gt;
&lt;p&gt;Kindle Paperwhiteで読みたいのである。&lt;/p&gt;
&lt;p&gt;で、やっとタイトルに繋がるのと同時に少し脱線する。&lt;/p&gt;
&lt;h2&gt;エンジニアのバイブル リーダーブルコード&lt;/h2&gt;
&lt;p&gt;リーダブルコードという本を知っているだろうか。&lt;/p&gt;
&lt;p&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName(&quot;body&quot;)[0],e.appendChild(d))})(window,document,&quot;script&quot;,&quot;//dn.msmstatic.com/site/cardlink/bundle.js?20220329&quot;,&quot;msmaflink&quot;);msmaflink({&quot;n&quot;:&quot;リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)&quot;,&quot;b&quot;:&quot;&quot;,&quot;t&quot;:&quot;&quot;,&quot;d&quot;:&quot;https://m.media-amazon.com&quot;,&quot;c_p&quot;:&quot;/images/I&quot;,&quot;p&quot;:[&quot;/51MgH8Jmr3L.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/41MjTupTFrL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/51xzvyKj6CL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/31IbgwvNCML.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/41Y2tAewYCL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/511jUNQR7XL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/51-9K4G3M9L.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;,&quot;/41ZfokYCDVL.&lt;em&gt;SL500&lt;/em&gt;.jpg&quot;],&quot;u&quot;:{&quot;u&quot;:&quot;https://www.amazon.co.jp/dp/4873115655&quot;,&quot;t&quot;:&quot;amazon&quot;,&quot;r_v&quot;:&quot;&quot;},&quot;v&quot;:&quot;2.1&quot;,&quot;b_l&quot;:[{&quot;id&quot;:4,&quot;u_tx&quot;:&quot;Amazonで見る&quot;,&quot;u_bc&quot;:&quot;#f79256&quot;,&quot;u_url&quot;:&quot;https://www.amazon.co.jp/dp/4873115655&quot;,&quot;a_id&quot;:3112474,&quot;p_id&quot;:170,&quot;pl_id&quot;:27060,&quot;pc_id&quot;:185,&quot;s_n&quot;:&quot;amazon&quot;,&quot;u_so&quot;:1},{&quot;id&quot;:1,&quot;u_tx&quot;:&quot;楽天市場で見る&quot;,&quot;u_bc&quot;:&quot;#f76956&quot;,&quot;u_url&quot;:&quot;https://search.rakuten.co.jp/search/mall/%E3%83%AA%E3%83%BC%E3%83%80%E3%83%96%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89%20%E2%80%95%E3%82%88%E3%82%8A%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%9F%E3%82%81%E3%81%AE%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E5%AE%9F%E8%B7%B5%E7%9A%84%E3%81%AA%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF%20(Theory%20in%20practice)/&quot;,&quot;a_id&quot;:3109755,&quot;p_id&quot;:54,&quot;pl_id&quot;:27059,&quot;pc_id&quot;:54,&quot;s_n&quot;:&quot;rakuten&quot;,&quot;u_so&quot;:2},{&quot;id&quot;:2,&quot;u_tx&quot;:&quot;Yahoo!ショッピングで見る&quot;,&quot;u_bc&quot;:&quot;#66a7ff&quot;,&quot;u_url&quot;:&quot;https://shopping.yahoo.co.jp/search?first=1\u0026p=%E3%83%AA%E3%83%BC%E3%83%80%E3%83%96%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89%20%E2%80%95%E3%82%88%E3%82%8A%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%9F%E3%82%81%E3%81%AE%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E5%AE%9F%E8%B7%B5%E7%9A%84%E3%81%AA%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF%20(Theory%20in%20practice)&quot;,&quot;a_id&quot;:3109760,&quot;p_id&quot;:1225,&quot;pl_id&quot;:27061,&quot;pc_id&quot;:1925,&quot;s_n&quot;:&quot;yahoo&quot;,&quot;u_so&quot;:3}],&quot;eid&quot;:&quot;31Yra&quot;,&quot;s&quot;:&quot;s&quot;});&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;リンク&lt;/p&gt;
&lt;p&gt;エンジニアであれば一度は聞いたことがあるかもしれない。&lt;/p&gt;
&lt;p&gt;それはそうで、なにせエンジニアのバイブルと言われているくらいである。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;美しいコードを見ると感動する。優れたコードは見た瞬間に何をしているかが伝わってくる。そういうコードは使うのが楽しいし、自分のコードもそうあるべきだと思わせてくれる。本書の目的は、君のコードを良くすることだ」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;初版は2012年6月23日でもう10年前の発行である。&lt;/p&gt;
&lt;p&gt;であるのだが、今でも根強い人気を誇っている。&lt;/p&gt;
&lt;p&gt;私もずっと読もうと思っていたが、なんとなく先延ばしにしてきた。&lt;/p&gt;
&lt;p&gt;そこで、このゴールデンウイークに重い腰を上げて読んで見ようと思い立った。&lt;/p&gt;
&lt;h3&gt;kindle版がない......?&lt;/h3&gt;
&lt;p&gt;がしかし、リーダブルコードは電子書籍版が存在するのが、kindle版が存在しないという稀有な例。&lt;/p&gt;
&lt;p&gt;そこでリーダブルコードをKindle Paperwhiteで読む方法を調べてみた。&lt;/p&gt;
&lt;h2&gt;エンジニア味方 オライリーの本をKindle Paperwhiteで読む&lt;/h2&gt;
&lt;h3&gt;公式オンラインショップで検索&lt;/h3&gt;
&lt;p&gt;まずはオライリー公式ホームページでリーダブルコードを検索する。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oreilly.co.jp/books/9784873115658/&quot;&gt;O&apos;Reilly Japan - リーダブルコード&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;公式オンラインショップで購入&lt;/h3&gt;
&lt;p&gt;次に、Ebook Storeで電子版を購入:価格2,112円をカートに入れ購入手続きに進む。&lt;/p&gt;
&lt;p&gt;その後、購入に際してPayPalのアカウントが必要になるので手順に従いアカウント登録をする必要がある。&lt;/p&gt;
&lt;p&gt;こういうのが面倒でkindleストアで一元管理しているのに......&lt;/p&gt;
&lt;p&gt;登録購入ができると、オライリーの本棚に購入した本（今回であればリーダブルコード）が表示される。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oreilly.co.jp/ebook/bookshelf&quot;&gt;O&apos;Reilly Japan Ebook Store - 購入済みの商品&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;インストール＆kindleにインポート&lt;/h3&gt;
&lt;p&gt;購入した本が表示されていることを確認できたら、ePubをインストールする。&lt;/p&gt;
&lt;p&gt;で、調べた情報によると、ePub版はkindleで対応できないとのこと。&lt;/p&gt;
&lt;p&gt;kindleで対応しているのはmobiファイルということで、ePubをmobiに変換する必要がある。&lt;/p&gt;
&lt;p&gt;今回はオンラインツールを使用し、mobiファイルに変更をした。&lt;/p&gt;
&lt;p&gt;できないようであればPDFファイルでも問題ないので、購入した本のPDF版をインストールする。&lt;/p&gt;
&lt;p&gt;やっとKindle Paperwhiteの出番である。&lt;/p&gt;
&lt;p&gt;まずはパソコンとKindle Paperwhiteを接続する。&lt;/p&gt;
&lt;p&gt;接続が完了するとkindleのフォルダが表示されると思うので、D:\documentsにインストールしたmobiファイル or
PDFファイルを置く。&lt;/p&gt;
&lt;p&gt;その際、mobiファイルは書籍情報が含まれているので、自動でタイトル補完をしてくれるがPDF版の場合は、ファイル名をタイトルにしたほうがわかりやすい。&lt;/p&gt;
&lt;p&gt;これでKindle Paperwhiteで読書する準備が完了した。&lt;/p&gt;
&lt;h2&gt;実読&lt;/h2&gt;
&lt;p&gt;さて、実読。&lt;/p&gt;
&lt;p&gt;ということで今回はmobi版とPDF版の両方をインストールした。&lt;/p&gt;
&lt;h3&gt;mobi vs PDF&lt;/h3&gt;
&lt;p&gt;PDF版は書籍のレイアウトをそのままに読めるので、特に違和感なく読むことができる。&lt;/p&gt;
&lt;p&gt;それに対しmobi版は本として再レイアウトしてくれるので、すこし崩れのようなものを感じる。&lt;/p&gt;
&lt;p&gt;が、本として読むことできるので、フォントサイズに調整等に対応できる。&lt;/p&gt;
&lt;p&gt;Kindle
Paperwhiteは画面サイズが大きいというわけではないので、mobi版の方が読みやすいかもしれない。&lt;/p&gt;
&lt;p&gt;それじゃ、リーダーブルコードを読み、良いコードライフ＆いい読書ライフを。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>エックスサーバーで作ったサブドメインをGoogle Hostingに適用する</title><link>https://blog.nove-b.dev/posts/apply-xserver-subdomain-to-google</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/apply-xserver-subdomain-to-google</guid><content:encoded>&lt;p&gt;エックスサーバーは非常に便利で50個のサブドメインを作成することができる。&lt;/p&gt;
&lt;p&gt;これは私みたいに飽き性でいろいろなものを作っては放置するタイプには非常に重宝する機能である。&lt;/p&gt;
&lt;p&gt;エックスサーバーが気になるのであれば下記リンクをどうぞ。&lt;/p&gt;
&lt;p&gt;[sc name=&quot;exserver_all_unlimited&quot; ][/sc]&lt;/p&gt;
&lt;p&gt;さてそしてまた、この機能を使用する機会がきた。&lt;/p&gt;
&lt;p&gt;今回はエックスサーバーのサブドメインをGoogle
Hostingに適用するというケースを行ったので、備忘録としてここに書いておく。&lt;/p&gt;
&lt;p&gt;サブドメインの取得の仕方は省力する。&lt;/p&gt;
&lt;p&gt;が、反映になかなか時間がかかるのが、エックスサーバーの玉に瑕。&lt;/p&gt;
&lt;h2&gt;firebase Consoleに行く&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://console.firebase.google.com/u/0/&quot;&gt;Firebase console&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;作成したドメインを入力する&lt;/h3&gt;
&lt;p&gt;まずはfirebase
ConsoleのHostingに移動し、カスタムドメインを追加ボタンをクリックする。&lt;/p&gt;
&lt;p&gt;するとドメイン名の入力を求められるので、エックスサーバーで作成したサブドメインを記入する。&lt;/p&gt;
&lt;p&gt;※「angular.nove-web.com を既存のウェブサイトにリダイレクトする」をチェック。&lt;/p&gt;
&lt;p&gt;リダイレクト先にはエックスサーバーで作成したサブドメインを記入する。&lt;/p&gt;
&lt;p&gt;次へをクリック。&lt;/p&gt;
&lt;h3&gt;所有権の確認&lt;/h3&gt;
&lt;p&gt;エックスサーバーのDNSレコード設定に進み、対象ドメインを選択する。&lt;/p&gt;
&lt;p&gt;次に「DNSレコード追加」タブに移動する。&lt;/p&gt;
&lt;p&gt;記入欄が現れるので、下記のように記入していく。&lt;/p&gt;
&lt;p&gt;ホスト名：作成したドメイン&lt;/p&gt;
&lt;p&gt;種別：TXTを選択&lt;/p&gt;
&lt;p&gt;内容：Firebaseコンソール画面でコピーしたTXTレコードの値&lt;/p&gt;
&lt;p&gt;追加が完了したら、firebase  Consoleに戻り、所有権を証明ボタンをクリックする。&lt;/p&gt;
&lt;p&gt;ここで失敗した。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ドメイン ********.com の所有権を証明できませんでした。設定をお確かめいただき、もう一度お試しください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのエラーが表示された。&lt;/p&gt;
&lt;p&gt;解決方法がわからずに、途方に暮れていたので、初心に戻りGoogle
Workspace 管理者ヘルプに行くと、&lt;/p&gt;
&lt;p&gt;最初に試すことに48 時間待機すると書かれていたので、待機することにした。&lt;/p&gt;
&lt;p&gt;ちなみに下記サイトでDNSレコードがしっかり適用されているか確認することができる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://toolbox.googleapps.com/apps/dig/&quot;&gt;Google Admin Toolbox Dig&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;全然うまくいかずに、色々DNSレコードをいじっていたら、途端に通った。&lt;/p&gt;
&lt;p&gt;何をしたか、わからない。&lt;/p&gt;
&lt;h3&gt;実行（ドメインとの紐づけ）&lt;/h3&gt;
&lt;p&gt;何をしたかはわかないが、うまくいったようで、セットアップ画面が表示された。&lt;/p&gt;
&lt;p&gt;またレコードを追加する必要がある。&lt;/p&gt;
&lt;p&gt;下記のように追加すれば問題ない。&lt;/p&gt;
&lt;p&gt;ホスト名：作成したドメイン&lt;/p&gt;
&lt;p&gt;種別：Firebaseコンソール画面で表示されたレコードタイプ（私の場合はA）&lt;/p&gt;
&lt;p&gt;内容：Firebaseコンソール画面でコピーしたTXTレコードの値&lt;/p&gt;
&lt;p&gt;追加が完了した後に、終了ボタンをクリックする。&lt;/p&gt;
&lt;p&gt;この時点でカスタムドメインの追加はうまくいったが、ステータスが設定が必要ですと表示されている。&lt;/p&gt;
&lt;h3&gt;最後に&lt;/h3&gt;
&lt;p&gt;設定を完了するために、最後にもうひとつ。&lt;/p&gt;
&lt;p&gt;サブドメインの場合は、すでにあるDNSレコードと干渉する場合がある。&lt;/p&gt;
&lt;p&gt;本サイトでは「*.nove-web.com」のようなレコードが既に存在していた。&lt;/p&gt;
&lt;p&gt;これは見ての通り、すべてのサブドメインを対象にしているので、削除する必要がある。&lt;/p&gt;
&lt;p&gt;ただ、本サイトのように新規で追加する以外にサブドメインを使っている場合は、そのサブドメインのレコードを新規に作成する必要がある。&lt;/p&gt;
&lt;p&gt;後は接続が完了するまで待つ、ひたすら待ちましょう。&lt;/p&gt;
&lt;p&gt;公開ができればそのサイトにアクセスができる。&lt;/p&gt;
&lt;p&gt;今回追加したのは下記サイト。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://angular.nove-web.com/home&quot;&gt;https://angular.nove-web.com/home&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;コスパ最強のWeb アプリ&lt;/h2&gt;
&lt;p&gt;今回はfirebase
hosting で公開したのはAngularを勉強のために立ち上げたブログサイト。&lt;/p&gt;
&lt;p&gt;firebaseとエックスサーバーのドメインを使うことで、結果的に運営費用は0円。&lt;/p&gt;
&lt;p&gt;無料枠の大きいfirebaseとサブドメインが50個まで無料で作れるエックスサーバーには感謝しかない。&lt;/p&gt;
&lt;p&gt;エックスサーバーの詳細は下記をご覧ください。&lt;/p&gt;
&lt;p&gt;[sc name=&quot;exserver_all_unlimited&quot; ][/sc]&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Angularをバージョン指定でインストールする方法は？</title><link>https://blog.nove-b.dev/posts/install-specific-version-angular</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/install-specific-version-angular</guid><content:encoded>&lt;p&gt;Angularを業務で使用することがあり、かつバージョンが12指定とのことだった。&lt;/p&gt;
&lt;p&gt;ちなみに現在のAngularのバージョンは13なので、普通にインストールすると13がインストールされる。&lt;/p&gt;
&lt;p&gt;そこで12を指定し、インストールする方法を調べてみた。&lt;/p&gt;
&lt;h2&gt;Angular12をインストールする&lt;/h2&gt;
&lt;p&gt;バージョン指定でインストールする方法は別段他の言語と変わりなく、ただただ末尾に指定バージョンを記載するだけでOK。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install -g @angular/cli@12.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;つまりこんな感じすれば12がインストールされる。&lt;/p&gt;
&lt;h3&gt;バージョンを確認する&lt;/h3&gt;
&lt;p&gt;きっと問題ないけど、念のためにバージョンを確認する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
$ ng v

   _           _         ____ _   ___
  / \  _ __  __ _ _  _| | __ _ _ __   / ___| |  |_ _|
  / △ \ | &apos;_ \ / _` | | | | |/ _` | &apos;__|  | |  | |  | |
 / ___ \| | | | (_| | |_| | | (_| | |   | |___| |___ | |
 /_/  \_\_| |_|\__, |\__,_|_|\__,_|_|    \____|_____|___|
        |___/


Angular CLI: 12.0.0
Node: 14.17.5
Package Manager: npm 6.14.14
OS: win32 x64

Angular:
...

Package           Version
------------------------------------------------------
@angular-devkit/architect  0.1200.0 (cli-only)
@angular-devkit/core     12.0.0 (cli-only)
@angular-devkit/schematics  12.0.0 (cli-only)
@schematics/angular     12.0.0 (cli-only)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;問題なく12がインストールできている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Angularとセットで使うことが多いmaterial UI をインストールする</title><link>https://blog.nove-b.dev/posts/install-material-ui-with-angular</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/install-material-ui-with-angular</guid><content:encoded>&lt;p&gt;独断と偏見で言わせてもらうと、Angularはそれだけだと使いこなすことができない。&lt;/p&gt;
&lt;p&gt;AngularはAngular側が用意してくれているモジュールをインストールして活用することで、簡単にWeb アプリを作成できるようになる。&lt;/p&gt;
&lt;p&gt;が、そのモジュールなしで使いこなすことは難しい。&lt;/p&gt;
&lt;p&gt;その筆頭がmaterial UIである。&lt;/p&gt;
&lt;h2&gt;material UIとは？&lt;/h2&gt;
&lt;p&gt;material UIは&lt;a href=&quot;https://material.angular.io/&quot;&gt;こちら&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;要はよく使うパーツを用意されたモジュールをインストールするだけで使えるようになるというもの。&lt;/p&gt;
&lt;p&gt;大変便利なのだが、決められたパーツなのでカスタマイズが絶妙に面倒くさいというデメリットもある。&lt;/p&gt;
&lt;p&gt;とは言え、面倒な処理はやってくれるので、非常に重宝する。&lt;/p&gt;
&lt;h2&gt;いざ、インストール&lt;/h2&gt;
&lt;p&gt;それでは実際にインストールしてみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ng add @angular/material
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドを実行後、インストールが進行し、いくつか質問されるので、下記のように回答する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ℹ Using package manager: npm
✔ Found compatible package version: @angular/material@12.2.13.
✔ Package information loaded.

The package @angular/material@12.2.13 will be installed and executed.
Would you like to proceed? Yes
✔ Package successfully installed.
? Choose a prebuilt theme name, or &quot;custom&quot; for a custom theme: Custom
? Set up global Angular Material typography styles? No
? Set up browser animations for Angular Material? Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで無事にインストールが完了した。&lt;/p&gt;
&lt;p&gt;質問に関しては、&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用意されたパレットテーマ、カスタムテーマどちらを使用しますか？&lt;/li&gt;
&lt;li&gt;タイポグラフィにグローバルなCSSを当てますか？&lt;/li&gt;
&lt;li&gt;Angular Material のアニメーション機能を使用しますか？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;という3つの質問。&lt;/p&gt;
&lt;p&gt;少しでもカスタマイズしやすくするために、上記回答にした。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Angular Material UI でカスタムカラーを設定する。</title><link>https://blog.nove-b.dev/posts/set-custom-colors-angular-material-ui</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/set-custom-colors-angular-material-ui</guid><content:encoded>&lt;p&gt;Angular Material UIのカラーパレットがどうにもパッとしない。&lt;/p&gt;
&lt;p&gt;ということで、カスタムカラーを使用することにした。&lt;/p&gt;
&lt;p&gt;カスタムカラーを使用するためにはインストールの段階でカスタムカラーを使用するよ、という宣言が必要だがその方法は前回書いたので、参考にしてほしい。&lt;/p&gt;
&lt;p&gt;さて、さっそくカスタムカラーを設定していく。&lt;/p&gt;
&lt;p&gt;手順としてさらっていくと、自作のパレットを作成し、それを適用するというそれだけのこと。&lt;/p&gt;
&lt;p&gt;なので、まずは自作のパレットを作成する。&lt;/p&gt;
&lt;p&gt;src/assets/_palette.scssを作成し、そこにカラーを書いていく。&lt;/p&gt;
&lt;p&gt;例えばこんな感じに。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
$custom-primary: (
  50: #e8f5ff,
  100: #c5e5ff,
  200: #9fd4ff,
  300: #78c2ff,
  400: #5bb5ff,
  500: #3ea8ff,
  600: #38a0ff,
  700: #3097ff,
  800: #288dff,
  900: #1b7dff,
  A100: #ffffff,
  A200: #ffffff,
  A400: #cce0ff,
  A700: #b3d1ff,
  contrast: (
    50: #000000,
    100: #000000,
    200: #000000,
    300: #000000,
    400: #ffffff,
    500: #ffffff,
    600: #ffffff,
    700: #ffffff,
    800: #ffffff,
    900: #ffffff,
    A100: #000000,
    A200: #000000,
    A400: #000000,
    A700: #000000,
  ),
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に、このパレットを読み込む必要があるので、src/styles.scssに移動する。&lt;/p&gt;
&lt;p&gt;で、まずはカスタムパレットを使用すると宣言する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@use &quot;./assets/palette&quot; as palette;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;あ、ちなみに今回はPrimaryカラーだけをカスタムした、遅ればせながら言っておく。&lt;/p&gt;
&lt;p&gt;そのため、Primaryカラーにカスタムパレットを適用させる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$custom-primary: mat.define-palette(palette.$custom-primary);
$custom-accent: mat.define-palette(mat.$amber-palette, A200, A100, A400);
$custom-warn: mat.define-palette(mat.$red-palette);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;accent、warnはMaterial UIが用意しているカラーを使用している。&lt;/p&gt;
&lt;p&gt;最後にテーマ全体を宣言しておしまい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
$custom-theme: mat.define-light-theme(
  (
    color: (
      primary: $custom-primary,
      accent: $custom-accent,
      warn: $custom-warn,
    ),
  )
);

@include mat.all-component-themes($custom-theme);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;たぶん、Material
UIで作成されたカラーテーマをそのまま使うのは無理があるので、こんな感じでカスタムテーマを作るとずいぶん楽になる。&lt;/p&gt;
&lt;p&gt;参考までにこの作業の&lt;a href=&quot;https://github.com/progblog-sank/angular12-study/commit/995f5a01c9a0eb9ea246ead722c00c7a112d3e51&quot;&gt;Github&lt;/a&gt;をどうぞ。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Angularでwebアプリを作成する時「コンポーネントのベストプラクティス」</title><link>https://blog.nove-b.dev/posts/angular-best-practices-component</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/angular-best-practices-component</guid><content:encoded>&lt;h2&gt;Layout&lt;/h2&gt;
&lt;p&gt;header や footer 等 全てのページで使われるパーツ&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ng g component layouts/componentName
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Pages&lt;/h2&gt;
&lt;p&gt;ページごとのコンテンツを表示するページ&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ng g component pages/componentName
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Parts&lt;/h2&gt;
&lt;p&gt;layout や page で使われるカードなどの UI パーツ&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ng g component parts/componentName
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;テストをするためには必要だが、無駄なファイルを増やさないために&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ng generate component componentName --skip-tests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でspecファイルを作らずに済む。&lt;/p&gt;
&lt;h2&gt;コンポーネントを呼び出したい&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;app-componentName&amp;gt;&amp;lt;/app-componentName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、コンポーネントを呼び込む。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>今更ながら、即時関数がとでも便利でかっこいい</title><link>https://blog.nove-b.dev/posts/immediate-functions-cool</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/immediate-functions-cool</guid><content:encoded>&lt;p&gt;いや、本当に今更なんだけれど、JavaScriptの復習をしていて、「即時関数」の便利さ、スマートさに気が付いた。&lt;/p&gt;
&lt;h2&gt;即時関数を使ってみた&lt;/h2&gt;
&lt;p&gt;今まで初回実行 &amp;amp; 使い回す場合は&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const consoleHello = () =&amp;gt; {
    console.log(&quot;hello&quot;)
}
consoleHello()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように、書いていた。&lt;/p&gt;
&lt;p&gt;が、即時関数を使えば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const consoleHello = (() =&amp;gt; {
    console.log(&quot;hello&quot;)
})()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように書くことができる。&lt;/p&gt;
&lt;p&gt;つまりこれで初回実行 &amp;amp; 関数としての使い回しが可能なのである。&lt;/p&gt;
&lt;p&gt;なんで、いままで使ってこなかったのか。&lt;/p&gt;
&lt;h2&gt;使い回せない&lt;/h2&gt;
&lt;p&gt;と思ったけど、使い回せなかった。&lt;/p&gt;
&lt;p&gt;まあ、即時って言ってるし...&lt;/p&gt;
&lt;p&gt;つまりこういう使い方じゃない。&lt;/p&gt;
&lt;p&gt;使い回すことはできなかったけど、中に関数を書くことはできた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const consoleHello = (() =&amp;gt; {
    console.log(&quot;hello&quot;)
    return {
        consoleGoodbye: () =&amp;gt; {
            console.log(&apos;goodbye&apos;)
        }
    }
})()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じで関数を書いて、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;button onclick=&quot;consoleHello.consoleGoodbye()&quot;&amp;gt;JavaScriptを実行する&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、実行できる。&lt;/p&gt;
&lt;p&gt;うーん、なるほど。&lt;/p&gt;
&lt;p&gt;つまりタイトルでスマートとか書いたけど、思っていたスマート差はなかった...気がする。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>foreachの中で非同期が終わったら僕の肩を叩いてください</title><link>https://blog.nove-b.dev/posts/async-callback-after-foreach</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/async-callback-after-foreach</guid><content:encoded>&lt;p&gt;まずはAPIで色々配列を取得しました。&lt;/p&gt;
&lt;p&gt;そのuuidを使って取得したいAPIがあるので、foreachで回してデータを加工しようと思ったがうまくいきませんでした。&lt;/p&gt;
&lt;p&gt;という事象にひどく悩まされた。&lt;/p&gt;
&lt;p&gt;例えば、こんなコードを実行してみた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
const array = [1, 2, 3, 4, 5]
array.forEach(el =&amp;gt; {
    window.setTimeout(() =&amp;gt; {
        console.log(el)
    }, 1000)
});
console.log(&apos;forEach完了&apos;)

// forEach完了
// 1
// 2
// 3
// 4
// 5

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のコードを実行すると、コメントアウトのようになる。&lt;/p&gt;
&lt;p&gt;いや、違う違う、4が出た後に「forEach完了」が欲しい。&lt;/p&gt;
&lt;p&gt;じゃあ、どうするか？&lt;/p&gt;
&lt;p&gt;のように実行することでコメントアウトのように、つまり臨んだ結果になった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
const array_2 = [1, 2, 3, 4, 5]
var Promises = []

array_2.forEach(el =&amp;gt; {
    Promises.push(
        new Promise((resolve) =&amp;gt; {
            window.setTimeout(() =&amp;gt; {
                console.log(el)
                resolve()
            }, 1000)
        })
    )
});

console.log(&apos;forEach完了！&apos;)

Promise.all(Promises)
    .then(() =&amp;gt; {
        console.log(&apos;forEach(中の非同期処理も含めて)完了！&apos;)
    })

// 1
// 2
// 3
// 4
// 5
// forEach(中の非同期処理も含めて)完了！
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>nove-b</author></item><item><title>react native でアプリを作る環境構築をやってみるよ&amp;#x26a1;</title><link>https://blog.nove-b.dev/posts/setup-react-native-env</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/setup-react-native-env</guid><content:encoded>&lt;p&gt;まずは、Node.js LTSをインストールする必要がある。&lt;/p&gt;
&lt;p&gt;私はnode管理ツールにvoltaを使用しているので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ volta install node
success: installed and set node@16.16.0 (with npm@8.11.0) as default
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↑を実行する。&lt;/p&gt;
&lt;p&gt;Expo CLI のインストールする&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --global expo-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正常にインストールできたかは、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;expo whoami
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↑を実行する。&lt;/p&gt;
&lt;p&gt;結果、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash: expo: command not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;できていない...。&lt;/p&gt;
&lt;p&gt;ログを辿る限り↓が怪しい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Please ensure you have correct permissions to the Volta directory.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;翻訳すると&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Volta ディレクトリに対する正しい権限があることを確認してください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと...、なるほど🤔?&lt;/p&gt;
&lt;p&gt;調べてみるとそそもそもvoltaを使う際は開発者モードを有効にする必要があるとのこと。&lt;/p&gt;
&lt;p&gt;会社のPCはvoltaを入れる前に有効にしていたので気が付かなかった。&lt;/p&gt;
&lt;p&gt;ということで有効にしたうえで再挑戦。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --global expo-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;やって、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;expo whoami
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;やると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Not logged in, run expo login to authenticate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事にインストールできた👍&lt;/p&gt;
&lt;p&gt;公式ドキュメントを見ると&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;インストールが成功すると、まだ Expo アカウントにログインしていないため、「ログインしていません」というメッセージが表示されます。開始するのにアカウントは必要なく、プロジェクトをさらに進めることができます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;と書いてるので、今回は特にログインしない。&lt;/p&gt;
&lt;p&gt;ログインするメリットはあるのだろうか...いったん気にしない。&lt;/p&gt;
&lt;p&gt;ここまでが環境構築かしら。&lt;/p&gt;
&lt;p&gt;次はサンプルアプリを作ってみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>react native でサンプルアプリを立ち上げる&amp;#x1f52d;</title><link>https://blog.nove-b.dev/posts/create-sample-react-native-app</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-sample-react-native-app</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/632/&quot;&gt;前回は環境構築&lt;/a&gt;したので、今回のゴールは簡単なアプリっぽいものを立ち上げるまでとする⚔️&lt;/p&gt;
&lt;p&gt;sampleProjectという名前のサンプルプロジェクトを作成するために下記コマンドを叩く。&lt;/p&gt;
&lt;p&gt;と、沢山の選択肢が示される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ expo init sampleProject
? Choose a template: » - Use arrow-keys. Return to submit.
----- Managed workflow ----- // Expo のサポート下で開発できる（簡単）
blank a minimal app as clean as an empty canvas // １番シンプルな状態で
blank (TypeScript) same as blank but with TypeScript configuration // １ページからスタート
&amp;gt; tabs (TypeScript) several example screens and tabs using react-navigation and TypeScript // 複数の画面遷移ができる状態に
----- Bare workflow ----- // Expo なしでの開発に近く、カスタマイズ性は上がる（難しい）
minimal bare and minimal, just the essentials to get you started
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;今回は勉強なので、１番しっかりしてそうな「複数の画面遷移ができる状態に」を選択。&lt;/p&gt;
&lt;p&gt;結果↓&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ expo init sampleProject
√ Choose a template: » tabs (TypeScript) several example screens and tabs using react-navigation and TypeScript
✔ Downloaded template.
📦 Using npm to install packages.
✔ Installed JavaScript dependencies.

✅ Your project is ready!

To run your project, navigate to the directory and run one of the following npm commands.

- cd sampleProject
- npm start # you can open iOS, Android, or web from here, or run them directly with the commands below.
- npm run android
- npm run ios # requires an iOS device or macOS for access to an iOS simulator
- npm run web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、立ち上げてみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm start
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.

&amp;gt; sampleproject@1.0.0 start
&amp;gt; expo start

Starting project at C:\Users\〇〇\Desktop\reactnative\sampleProject
Starting Metro Bundler
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
█ ▄▄▄▄▄ █▀▄█▀ █ ▄█ ▄▄▄▄▄ █
█ █ █ █▄ ▄███ █ █ █ █
█ █▄▄▄█ █ ▀█▀█ ▀ ██ █▄▄▄█ █
█▄▄▄▄▄▄▄█ ▀▄█ █ █▄█▄▄▄▄▄▄▄█
█ ▄█▄▀█▄ ██ ▀█▄▀▄▄▀ ▄▀▄▄▀█
█▄▄██▄▀▄ █▄▄██ ▄█▄▄▀ ▀▀█▄▄█
██▀ ▄▀█▄█▄█▀▀ ▄ █▀█ ▄█ ██▀█
█▄▀▄▀▄█▄ ▀▀▀█ ▀██ ▄▄ ▀▀██▄█
█▄▄▄██▄▄▄ ▄▄█▀▄ ▄▄▄ █ ▄ █
█ ▄▄▄▄▄ █▄ ▀▀██▄ █▄█ ▀▄ █
█ █ █ █▀ ▀▀▄ ▄▄ █▀█▄█
█ █▄▄▄█ █▀ █ █ █▄ ▄█▄█
█▄▄▄▄▄▄▄█▄█▄▄▄█▄█▄███▄▄█▄▄█

› Metro waiting on exp://192.168.3.9:19000
› Scan the QR code above with Expo Go (Android) or the Camera app (iOS)

› Press a │ open Android
› Press w │ open web

› Press r │ reload app
› Press m │ toggle menu

› Press ? │ show all commands

Logs for your project will appear below. Press Ctrl+C to exit.
Started Metro Bundler
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↑のQRコードをスマホのExpoアプリでスキャンする。&lt;/p&gt;
&lt;p&gt;すると、勝手に長いビルドが走り、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Android Bundling complete 43425ms
Android Running app on SH-M19
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↑のようにスマホアプリが立ち上がる⚡&lt;/p&gt;
&lt;p&gt;試しに、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Text style={styles.title}&amp;gt;Tab One&amp;lt;/Text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↓に変換すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Text style={styles.title}&amp;gt;Hello android App&amp;lt;/Text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事に文字が変更された。&lt;/p&gt;
&lt;p&gt;簡単にアプリを立ち上げることができた💪&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Google AdSense（アドセンス）で得たお金でGoogle広告を打ってみた</title><link>https://blog.nove-b.dev/posts/run-google-ads-with-adsense</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/run-google-ads-with-adsense</guid><content:encoded>&lt;h2&gt;アドセンスが支払い上限を超えた&lt;/h2&gt;
&lt;p&gt;遂に、アドセンスが支払い上限を超えた！&lt;/p&gt;
&lt;p&gt;過去にやっていたブログが、実はまだウェブ世界の片隅で息をしている。&lt;/p&gt;
&lt;p&gt;息をしていると言ってもあっぷあっぷで今にも溺れかけている。&lt;/p&gt;
&lt;p&gt;それもそのはずで最終更新日が2020年8月15日である。&lt;/p&gt;
&lt;p&gt;つまり2年近く制作者である私に放置されていた、だけでなく、存在を忘れていた。&lt;/p&gt;
&lt;p&gt;クレジットカードにあるサーバー費を見て存在を思い出した次第で、なんなら使ってないのにお金を払っているといことにむかついたくらいである。&lt;/p&gt;
&lt;p&gt;だってそうでしょう。&lt;/p&gt;
&lt;p&gt;サーバーを借りたのが、2020年2月15日なので、今日まで計34,100の出費。&lt;/p&gt;
&lt;p&gt;怒りとともに久しぶりに訪れたサイトはアドセンスの自動広告に埋もれている。&lt;/p&gt;
&lt;p&gt;これはもしやと思い、アドセンスの管理画面に行くとなんと支払い上限を超えている。&lt;/p&gt;
&lt;p&gt;単純な私はさっきまでの怒り、そして今まで払った金額を忘れ、8,000円という金額に小躍りした。&lt;/p&gt;
&lt;p&gt;アフェリエイトの収入はあったが、アドセンスの収入は初めてである。&lt;/p&gt;
&lt;p&gt;万歳三唱し、このお金を何に使うか考えた。&lt;/p&gt;
&lt;h2&gt;投資する&lt;/h2&gt;
&lt;p&gt;実はいま、ウェブアプリを作り運営している。&lt;/p&gt;
&lt;p&gt;ユーザーは30人いるが、思った以上に伸びない。&lt;/p&gt;
&lt;p&gt;思った以上にというより、全く伸びない。&lt;/p&gt;
&lt;p&gt;自身が使いたいウェブアプリなのでなんとか、モチベーションを維持しているが、やっぱり多くの人に使って欲しい。&lt;/p&gt;
&lt;p&gt;そこで、そのウェブアプリに投資することにした。&lt;/p&gt;
&lt;p&gt;Google
AdSenseで稼いだお金でGoogle広告を出すというGoogleの手駒になった私は、7,900円という少額の広告を出すことにした。&lt;/p&gt;
&lt;p&gt;こんな少額でも&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;毎月 70～170 回の広告クリック数が見込めます&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;まあ、随分と差があるが...、まあやってみる。&lt;/p&gt;
&lt;h2&gt;経過&lt;/h2&gt;
&lt;p&gt;申請後すぐに、１時間くらいで審査がおり、無事広告が表示され始めたらしい。&lt;/p&gt;
&lt;p&gt;携帯のアプリで見れるのが便利でよろしい。&lt;/p&gt;
&lt;h3&gt;3日間経過&lt;/h3&gt;
&lt;p&gt;インプレッションが1.16万回で、クリックが20回、&lt;/p&gt;
&lt;p&gt;期待したほどじゃないけど、普段オーガニックサーチで人が来ないことを考えると嬉しい限り。&lt;/p&gt;
&lt;p&gt;Googleからの最適化案で「画像追加」という案が出てきたので、横長と正方形の画像追加した。&lt;/p&gt;
&lt;p&gt;ついでに広告の目的という感じで、広告で来たユーザーがどのくらい確率で指定した目的ページに到着したかを測れるので計測することに。&lt;/p&gt;
&lt;p&gt;一応、目的のページはサービスの詳細ページに。&lt;/p&gt;
&lt;p&gt;そして現時点で、ユーザー登録してくれたのは0人😭&lt;/p&gt;
&lt;h3&gt;検索ワードを考える&lt;/h3&gt;
&lt;p&gt;アプリでの検索が多いと思い、検索ワードにアプリを入れたが、たぶんアプリというワードで来た人はコンバージョンに結びつかない。&lt;/p&gt;
&lt;p&gt;ということで、アプリを除外ワードにした。&lt;/p&gt;
&lt;p&gt;さて現時点で、ユーザー登録してくれたのは0人😭&lt;/p&gt;
&lt;h3&gt;アカウントが強制停止されました&lt;/h3&gt;
&lt;p&gt;というメールが来て、驚愕する。&lt;/p&gt;
&lt;p&gt;で、ダッシュボードに行くと確かに配信が停止されている。&lt;/p&gt;
&lt;p&gt;どうやら重要なポリシーに違反しているとかなんとか。&lt;/p&gt;
&lt;p&gt;良くわからないので、問い合わせてしてみる。&lt;/p&gt;
&lt;p&gt;そのあと、支払いが滞っていることを知る。&lt;/p&gt;
&lt;p&gt;クレジットを登録しているので、自動支払いだとばっかり思っていたのだが、どうやら支払いをする必要があるらしい。&lt;/p&gt;
&lt;p&gt;ということで、支払いを済ませ、配信再開を待つ。&lt;/p&gt;
&lt;h3&gt;配信が再開された&lt;/h3&gt;
&lt;p&gt;支払いが滞りなく完了したことで、配信が再開された！&lt;/p&gt;
&lt;p&gt;さて現時点で、ユーザー登録してくれたのは0人😭&lt;/p&gt;
&lt;h2&gt;投資結果&lt;/h2&gt;
&lt;p&gt;結果発表！&lt;/p&gt;
&lt;p&gt;表示期間：9月26日～10月17日（21日間）&lt;/p&gt;
&lt;p&gt;費用：5204円&lt;/p&gt;
&lt;p&gt;クリック数：271&lt;/p&gt;
&lt;p&gt;インプレッション数：9.52万&lt;/p&gt;
&lt;p&gt;平均クリック単価：19円&lt;/p&gt;
&lt;p&gt;―――――――――――――――――&lt;/p&gt;
&lt;p&gt;単価が思った以上に安く、低金額なのに多くのひとが来てくれた。&lt;/p&gt;
&lt;p&gt;が、結局ユーザー登録は０。&lt;/p&gt;
&lt;p&gt;つまり、そもそも需要がない？&lt;/p&gt;
&lt;p&gt;そういうことなのかしら。&lt;/p&gt;
&lt;p&gt;そう考えると市場調査にも使えそうな気がする。&lt;/p&gt;
&lt;p&gt;今回みたいにユーザー数、投稿数増やすのであれば、ココナラで投稿者募るほうが効率いいかもしれない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>大量のスパムコメントが来るようになったのでreCAPTCHAで対応する</title><link>https://blog.nove-b.dev/posts/handle-spam-comments-recaptcha</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/handle-spam-comments-recaptcha</guid><content:encoded>&lt;p&gt;正直少しうれしい気持ちもある。&lt;/p&gt;
&lt;p&gt;スパムコメントを貰ってうれしいだなんてどうかしてるぜ、って思うかもしれないけど、だれにも見られないよりはよっぽどましである、なんて思ってしまうのである。&lt;/p&gt;
&lt;p&gt;がしかし、通知メールがたくさん来るのは許しがたいということで、reCAPTCHAを導入することにした。&lt;/p&gt;
&lt;p&gt;その前に、実際のスパムコメントはこんな感じという風にお披露目しよう。&lt;/p&gt;
&lt;h2&gt;スパムコメントに荒らされたブログ記事&lt;/h2&gt;
&lt;p&gt;該当する記事がこちら↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/623/&quot;&gt;拝啓「葉桜の季節に君を想うということ」を読んでない人に告ぐ。この本はどんでん返しがある。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;うーん、どういう理由でコメントしているのだろうか。&lt;/p&gt;
&lt;p&gt;なんらかのスパムに違いないのだが、Good
Siteと言われるとやっぱり少しうれしい、が排除していく。&lt;/p&gt;
&lt;h2&gt;reCAPTHA設定方法&lt;/h2&gt;
&lt;h3&gt;ログイン＆登録&lt;/h3&gt;
&lt;p&gt;まずはreCAPTCHAにログインをして、サイトを登録する。&lt;/p&gt;
&lt;p&gt;さほど難しい手順じゃないので省略。&lt;/p&gt;
&lt;p&gt;ちなみにreCAPTHAのサイトはこちら↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.google.com/recaptcha/about/&quot;&gt;reCAPTHA&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;プラグインで実装&lt;/h3&gt;
&lt;p&gt;次にプラグインを使用する。&lt;/p&gt;
&lt;p&gt;プラグインを使うのは制作者の恥だなんて思っている時期があったが、車輪の再開発する方がよっぽどダサいことに気が付いた。&lt;/p&gt;
&lt;p&gt;とはいえ、兼ね合いもあるのでほどほどに。&lt;/p&gt;
&lt;p&gt;今回はインストール数の多い「Invisible reCaptcha for
WordPress」を使用することにした。&lt;/p&gt;
&lt;p&gt;Invisible reCaptcha 設定を開き、「サイトキー」「シークレットキー」を入力。&lt;/p&gt;
&lt;p&gt;保存をクリックした後、wordpressタブに移り、保護したい箇所をクリックする。&lt;/p&gt;
&lt;p&gt;更新して右下にreCAPTHAアイコンが表示されていれば問題ない。&lt;/p&gt;
&lt;p&gt;少し寂しいがこれでスパムコメントとおさらばすることができた、と思われる。&lt;/p&gt;
&lt;p&gt;もし以降もスパムコメントが来るのであれば、報告、更新する。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>エクセルのシート名を全件取得した</title><link>https://blog.nove-b.dev/posts/get-all-sheet-names-excel</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/get-all-sheet-names-excel</guid><content:encoded>&lt;h2&gt;How To Excelのシート名全件取得?&lt;/h2&gt;
&lt;p&gt;簡単だったので、書くことがない。&lt;/p&gt;
&lt;p&gt;方法だけ書く。&lt;/p&gt;
&lt;p&gt;ALT+F11&lt;/p&gt;
&lt;p&gt;CTRL+Gキーを押して下部に「イミディエイト」ウィンドウを表示する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;For Each i In ThisWorkbook.Sheets: debug.print i.name : next i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドをコピペ。&lt;/p&gt;
&lt;p&gt;はい、以上。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>変更したファイルを最短でPushするGitコマンド</title><link>https://blog.nove-b.dev/posts/git-command-push-changed-files</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/git-command-push-changed-files</guid><content:encoded>&lt;h2&gt;最短プッシュ&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;git add .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でステージングにあげる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git commit -m “コミットテキスト”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でコミットをする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で現在のブランチにPushできる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>毎回調べるのが面倒なのでVueのベースプロジェクトを作成する</title><link>https://blog.nove-b.dev/posts/create-base-vue-project</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-base-vue-project</guid><content:encoded>&lt;p&gt;特にタイトル以上に説明することもないので、進めていく。&lt;/p&gt;
&lt;h2&gt;Viteを使用しVueをインストールする&lt;/h2&gt;
&lt;p&gt;下記コマンドでVite（ヴィート）を使用しVueをインストールすることができる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm create vite@latest
Need to install the following packages:
  create-vite@3.1.0
Ok to proceed? (y)
√ Project name: ... VueProjectBase
√ Package name: ... vue-project-base
√ Select a framework: » Vue
√ Select a variant: » TypeScript

Scaffolding project in C:\Users\username\Desktop\vite\VueProjectBase...

Done. Now run:

  cd VueProjectBase
  npm install
  npm run dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;今回はVueプロジェクなので、frameworkはVueを指定し、もう考えることなくTypeScriptを指定する。&lt;/p&gt;
&lt;p&gt;で、上記のように指示に従いlocal
serverを立ち上げることができればVueのインストールは完了。&lt;/p&gt;
&lt;h2&gt;nodeのバージョンを指定する&lt;/h2&gt;
&lt;p&gt;nodeのバージョン管理ツールにVolta使用しているので、Node エンジンの固定をする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;volta pin node
volta pin npm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記を実行するとpackage.jsonに、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; &quot;volta&quot;: {
&quot;node&quot;: &quot;16.18.0&quot;,
&quot;npm&quot;: &quot;8.19.2&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と記入され、Volta の設定が記述されたpackage.jsonをチームで共有することで、全員の Node や npm、Yarn のバージョンを揃えることができる。&lt;/p&gt;
&lt;h2&gt;Tailwind.cssを導入する&lt;/h2&gt;
&lt;p&gt;もうクラス名を考えたくないので、基本的にtailwindを使用している。&lt;/p&gt;
&lt;p&gt;ということで本プロジェクトにデフォルトで入れる。&lt;/p&gt;
&lt;p&gt;インストール方法は公式（&lt;a href=&quot;https://tailwindcss.com/docs/guides/vite#vue&quot;&gt;Install Tailwind CSS with Vite&lt;/a&gt;）に従う。&lt;/p&gt;
&lt;h3&gt;Install Tailwind&lt;/h3&gt;
&lt;p&gt;下記コマンドを順に実行する。&lt;/p&gt;
&lt;p&gt;やっていることは、tailwindのインストールと設定ファイルの作成。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install -D tailwindcss postcss autoprefixer
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;npx tailwindcss init -p
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Configure your template paths&lt;/h3&gt;
&lt;p&gt;続いて、パスを構成する。&lt;/p&gt;
&lt;p&gt;tailwind.config.cjsを、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/** @type {import(&apos;tailwindcss&apos;).Config} */
module.exports = {
  content: [
    &quot;./index.html&quot;,
    &quot;./src/**/*.{vue,js,ts,jsx,tsx}&quot;,
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように修正。&lt;/p&gt;
&lt;h3&gt;Add the Tailwind directives to your CSS&lt;/h3&gt;
&lt;p&gt;最後に、./src/style.cssにtailwindを追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでtailwindが有効になった。&lt;/p&gt;
&lt;h2&gt;SVGをコンポーネント化する&lt;/h2&gt;
&lt;p&gt;SVGの取り扱いについても面倒なので、ライブラリに頼る。&lt;/p&gt;
&lt;p&gt;いままではvue-svg-spriteを使っていたのだが、設定が面倒くさい＆今回はViteでプロジェクトを作成したので、vite-svg-loaderを入れる。&lt;/p&gt;
&lt;p&gt;まあ、vue-svg-spriteはいろいろ設定できて便利だったけど、正直そこまでSVG使わないので。&lt;/p&gt;
&lt;h3&gt;install vite-svg-loader&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;npm install vite-svg-loader -D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のコマンドでインストールする。&lt;/p&gt;
&lt;p&gt;続いて、設定していく。&lt;/p&gt;
&lt;p&gt;vite.config.tsに&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import svgLoader from &apos;vite-svg-loader&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記をインポートし、pluginsの箇所に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;svgLoader()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を追加する。&lt;/p&gt;
&lt;p&gt;結果的に、下記のようになっていれば問題ない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { defineConfig } from &apos;vite&apos;
import vue from &apos;@vitejs/plugin-vue&apos;
import svgLoader from &apos;vite-svg-loader&apos;


// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), svgLoader()]
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで設定は完了なので、あとは使用していく。&lt;/p&gt;
&lt;h3&gt;3つの使用方法&lt;/h3&gt;
&lt;p&gt;URL、文字列、コンポーネント、それぞれ３つの方法でインポートすることができる。&lt;/p&gt;
&lt;p&gt;試しにやってみる。&lt;/p&gt;
&lt;p&gt;下記のようにインポートして、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import iconUrl from &quot;./assets/vue.svg?url&quot;;
import iconRow from &quot;./assets/vue.svg?raw&quot;;
import IconComponent from &quot;./assets/vue.svg?component&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下記のように使用する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;lt;img :src=&quot;iconUrl&quot; class=&quot;logo vue&quot; alt=&quot;Vue logo&quot; /&amp;gt;
  &amp;lt;div v-html=&quot;iconRow&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;IconComponent /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;デフォルトはコンポーネントなので、パラメーターが明示されていない時はコンポーネントで使用となる。&lt;/p&gt;
&lt;p&gt;使用するのはこれくらいかしら。&lt;/p&gt;
&lt;p&gt;コードのフォーマット系は別にまとめる。&lt;/p&gt;
&lt;p&gt;作成したプロジェクトは&lt;a href=&quot;https://github.com/nove-b/VueProjectBase&quot;&gt;こちら&lt;/a&gt;。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>vue3のシンタックスシュガーについて調べてみた。</title><link>https://blog.nove-b.dev/posts/explore-vue3-syntax-sugar</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/explore-vue3-syntax-sugar</guid><content:encoded>&lt;p&gt;ちなみに糖衣構文とは、プログラミング言語において、読み書きのしやすさのために導入される書き方とのことらしい。&lt;/p&gt;
&lt;h2&gt;Vue３のシンタックスシュガー&lt;/h2&gt;
&lt;p&gt;Viteで環境構築するとデフォルトで下記のような糖衣構文が使われている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;どうやらVue3.2から使用できるようになったとのこと。&lt;/p&gt;
&lt;p&gt;こちらを使えばreact Likeな書き方ができるっぽいので調べてみた。&lt;/p&gt;
&lt;h2&gt;まずVeturを無効に&lt;/h2&gt;
&lt;p&gt;まずvsCodeの拡張機能の話から入り申し訳ないが、Veturは糖衣構文に対応していないとのこと。&lt;/p&gt;
&lt;p&gt;なので&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=vue.volar&quot;&gt;Volar&lt;/a&gt;を使う必要がある。&lt;/p&gt;
&lt;p&gt;これは公式もアナウンスしている。&lt;/p&gt;
&lt;h2&gt;setup関数がいらない&lt;/h2&gt;
&lt;p&gt;この構文を使えばsetup関数をわざわざ書く必要がない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default defineComponent({})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;をする必要もなければ、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;をする必要もないので、とんでもなくシンプルに書けるようになった。&lt;/p&gt;
&lt;p&gt;というより、よりjavascriptに戻ってきた感がある。&lt;/p&gt;
&lt;h2&gt;Propsを使いたい&lt;/h2&gt;
&lt;p&gt;Propsはscript内で、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;defineProps&amp;lt;Props&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で使用できるようになる。&lt;/p&gt;
&lt;p&gt;デフォルト値を定義するには、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;withDefaults(defineProps&amp;lt;Props&amp;gt;(), {
  propsVal: &quot;&quot;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように。&lt;/p&gt;
&lt;h2&gt;emitを使いたい&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
type Emits {
  (e: &quot;input&quot;, value: string): void;
  (e: &quot;uppublished:value&quot;, value: string): void;
}


defineEmits&amp;lt;Emits&amp;gt;();


const handleInput = ({ target }: { target: HTMLInputElement }) =&amp;gt; {
  emit(&quot;input&quot;, target.value);
  emit(&quot;uppublished:value&quot;, target.value);
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように使えばできる。&lt;/p&gt;
&lt;h2&gt;ライフサイクルはどうなったの？&lt;/h2&gt;
&lt;p&gt;従来通りに使い方で問題ない。&lt;/p&gt;
&lt;p&gt;この記事は&lt;a href=&quot;https://zenn.dev/watataku/articles/271d00d844c554&quot;&gt;https://zenn.dev/watataku/articles/271d00d844c554&lt;/a&gt;の自分用メモなので、詳しくは&lt;a href=&quot;https://zenn.dev/watataku/articles/271d00d844c554&quot;&gt;https://zenn.dev/watataku/articles/271d00d844c554&lt;/a&gt;を参照してください。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Vue3のベースプロジェクトのコードを統一する</title><link>https://blog.nove-b.dev/posts/unify-code-vue3-base-project</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/unify-code-vue3-base-project</guid><content:encoded>&lt;h2&gt;ESLintを導入する&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm i -D eslint eslint-plugin-vue @vue/eslint-config-typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;touch .eslintrc.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で設定ファイルを作成する。&lt;/p&gt;
&lt;p&gt;作成した設定ファイルに、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;env:
browser: true
es2021: true
extends:
- &apos;plugin:vue/vue3-recommended&apos;
- &apos;eslint:recommended&apos;
- &apos;@vue/typescript/recommended&apos;
parserOptions:
ecmaVersion: 12
plugins:
- vue
- &apos;@typescript-eslint&apos;
rules: {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を記入する。&lt;/p&gt;
&lt;p&gt;package.jsonに&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;scripts&quot;: {
...
&quot;lint&quot;: &quot;eslint --fix src/*.{ts,vue} &amp;amp;&amp;amp; eslint --fix src/**/*.{ts,vue}&quot;,
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記Scriptを追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm run lint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで無事にScriptが実行されるかを確認する。&lt;/p&gt;
&lt;p&gt;環境構築時に作成されるvite-env.d.tsがESLintで引っかかるので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch .eslintignore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でESLlint除外設定ファイルを作成し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vite-env.d.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と記入する。&lt;/p&gt;
&lt;h2&gt;Prettierを導入&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm i -D prettier @vue/eslint-config-prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で必要パッケージのインストールをする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch .prettierrc.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、設定ファイルを作成し、設定を記入する。&lt;/p&gt;
&lt;p&gt;設定の意味は&lt;a href=&quot;https://prettier.io/docs/en/options.html&quot;&gt;こちら&lt;/a&gt;を参考に。&lt;/p&gt;
&lt;p&gt;今回は下記を採用した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;printWidth: 80
tabWidth: 2
singleQuote: true
semi: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最後にScriptを追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;scripts&quot;: {
...
&quot;format&quot;: &quot;prettier -w src/*.{ts,vue} &amp;amp;&amp;amp; prettier -w src/**/*.{ts,vue}&quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Scriptを実行し動けば問題ない。&lt;/p&gt;
&lt;h2&gt;同時に実行する&lt;/h2&gt;
&lt;p&gt;ふたつそれぞれ実行するのは面倒なので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;scripts&quot;: {
...
&quot;fix&quot;: &quot;npm run format &amp;amp;&amp;amp; npm run lint&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記を追記し、一気にふたつ動かすことができる。&lt;/p&gt;
&lt;p&gt;無事に動いていれば成功。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Vue3のベースプロジェクトを作成したので、仕上げにhuskyを導入する</title><link>https://blog.nove-b.dev/posts/install-husky-vue3-base-project</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/install-husky-vue3-base-project</guid><content:encoded>&lt;p&gt;コードフォーマット系のプラグインは&lt;a href=&quot;https://media.nove-web.com/693/&quot;&gt;以前の記事&lt;/a&gt;で入れたので、コマンドを実行すれば、コードが統一化される。&lt;/p&gt;
&lt;p&gt;だがしかし、コマンドを実行することを忘れることがあるだろう。人間だもの。&lt;/p&gt;
&lt;p&gt;ということでhuskyを導入し、コミット時にコマンドを走らせるようにする。&lt;/p&gt;
&lt;h2&gt;huskyとは&lt;/h2&gt;
&lt;p&gt;公式サイトのGoogle翻訳によると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Husky はコミットなどを改善します 🐶 ワン!&lt;/p&gt;
&lt;p&gt;コミットまたはプッシュするときに、コミット メッセージのリント、テストの実行、コードのリントなどに使用できます。Husky はすべての Git フックをサポートしています。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと、ワン！&lt;/p&gt;
&lt;p&gt;つまりgitに対する処理をフックとして何らかの処理を行うことができる。&lt;/p&gt;
&lt;p&gt;今回はコード整形の処理を行っていく。&lt;/p&gt;
&lt;h2&gt;huskyをインストールする&lt;/h2&gt;
&lt;p&gt;基本的に&lt;a href=&quot;https://typicode.github.io/husky/&quot;&gt;公式&lt;/a&gt;を見れば問題ない。&lt;/p&gt;
&lt;p&gt;てかそもそも公式を見れば大抵のことは問題ない。&lt;/p&gt;
&lt;p&gt;npx husky-init &amp;amp;&amp;amp; npm install&lt;/p&gt;
&lt;p&gt;で、公式によると↑を実行すれば基本的にOKとのこと。&lt;/p&gt;
&lt;p&gt;上記を実行するとrootに下記ファイルが作成される。&lt;/p&gt;
&lt;p&gt;.husky\pre-commit&lt;/p&gt;
&lt;p&gt;中身を見てみると&lt;/p&gt;
&lt;p&gt;#!/usr/bin/env sh . &quot;$(dirname -, &quot;$0&quot;)/_/husky.sh&quot;&lt;/p&gt;
&lt;p&gt;npm test&lt;/p&gt;
&lt;p&gt;と書かれているのでnpm testの箇所を自身の実行したいコマンドに変更する。&lt;/p&gt;
&lt;p&gt;で、コミット時に実行したいコマンドが実行されていればそれで問題なく完了。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Local by FlywheelでID・PASSWORDを忘れてログインできなくなった時にすること</title><link>https://blog.nove-b.dev/posts/forgot-id-password-local-flywheel</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/forgot-id-password-local-flywheel</guid><content:encoded>&lt;h2&gt;Local by Flywheelにログインできなくなった&lt;/h2&gt;
&lt;p&gt;久々にテーマを更新しようとした時、Local by
Flywheelで作った仮想Wordpress環境にログインできなくなった。&lt;/p&gt;
&lt;p&gt;IDとPASSWORDの両方を思い出せない。&lt;/p&gt;
&lt;p&gt;そこで解決方法を調べてみた。&lt;/p&gt;
&lt;h2&gt;再ログイン方法&lt;/h2&gt;
&lt;p&gt;Local by
Flywheelではデフォルトで「dev-email@flywheel.local」というアドレスがあてがわれている。&lt;/p&gt;
&lt;p&gt;そこでそれを使ってパスワードを再発行すればいい。&lt;/p&gt;
&lt;h3&gt;具体的な手順は&lt;/h3&gt;
&lt;p&gt;Local by FlywheelのADMINボタンからログイン画面行く。&lt;/p&gt;
&lt;p&gt;ログイン画面にある「パスワードをお忘れですか ?」をクリックし、遷移先のユーザー名またはメールアドレスエリアに「dev-email@flywheel.local」を入力する。&lt;/p&gt;
&lt;p&gt;Local by Flywheelに戻りTOOLSタブをクリックし「OPEN
MAILHOG」でmainhogにアクセスする。&lt;/p&gt;
&lt;p&gt;するとそこにメールが来ているので、あとはPassWordを変更するだけ。&lt;/p&gt;
&lt;p&gt;ちなみにそこにIDも書かれているので、次からはIDでログインできるようになる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Wordpressでブログ投稿が楽になる！ アイキャッチ画像が動的に作成できるようにしてみた。</title><link>https://blog.nove-b.dev/posts/dynamic-featured-images-wordpress</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/dynamic-featured-images-wordpress</guid><content:encoded>&lt;h2&gt;アイキャッチ画像が面倒くさい&lt;/h2&gt;
&lt;p&gt;Wordpressでブログを投稿していると面倒なことがある。&lt;/p&gt;
&lt;p&gt;それはアイキャッチ画像の設定である。&lt;/p&gt;
&lt;p&gt;画像探すのも面倒だし、それなりの質が担保されていないとサイト全体がチープに見える。&lt;/p&gt;
&lt;p&gt;だからこのブログでは統一感を出せるように、同じデザインの画像の上にテキストを載せるようにした。&lt;/p&gt;
&lt;p&gt;で、アイキャッチ画像を作成するようページを作成した。&lt;/p&gt;
&lt;p&gt;......、ことは以前ブログで書いた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/62/&quot;&gt;何が面倒って、アイキャッチ画像を設定するほど面倒なことはない&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;効率化したと書いたが、それすら面倒になった。&lt;/p&gt;
&lt;p&gt;なってしまったのである。&lt;/p&gt;
&lt;p&gt;そこで、タイトルを書いたらそれがそのままアイキャッチ画像になる。&lt;/p&gt;
&lt;p&gt;そんな仕組みを作ってみた。&lt;/p&gt;
&lt;p&gt;それがこれである。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/screen-1024x732.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;さて、次はこれをプラグイン化してみようかと思っている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Wordpressの公式プラグイン申請をしたら修正点が書かれたレビューメールがきた</title><link>https://blog.nove-b.dev/posts/review-email-after-plugin-submission</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/review-email-after-plugin-submission</guid><content:encoded>&lt;h2&gt;Incorrect Stable Tag&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Readme で、「安定したタグ」が、メインのプラグイン ファイルに示されているプラ​​グインのバージョンと一致しません。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;h3&gt;Stable tag（安定したタグ）&lt;/h3&gt;
&lt;p&gt;そもそもこの項目を理解していなので調べてみると、どうやら作ったプラグインのバージョンらしい。&lt;/p&gt;
&lt;p&gt;つまり最初は「1.0.0」とかになるのかしら。&lt;/p&gt;
&lt;p&gt;自分の書いたReadmeを見ると「trunk」と書かれている。&lt;/p&gt;
&lt;p&gt;trunkとはいったいなんなんだろうか、なぜ「trunk」とかいたのか自身に問いたい。&lt;/p&gt;
&lt;p&gt;が、過去の自分に問うことなんてできやしないので、調べてみると、「trunk」とはSubversionで使用されるmainブランチのようなものらしい。&lt;/p&gt;
&lt;p&gt;ちなみにSubversionはGitみたいなものらしい。&lt;/p&gt;
&lt;p&gt;WordpressのプラグインはSubversionで管理するので、安定タグは「trunk」に合わせる必要がある。&lt;/p&gt;
&lt;p&gt;みたいなことを湾曲理解し、「trunk」と書いたものだと思われる。&lt;/p&gt;
&lt;p&gt;というわけで「trunk」は当然間違いで「1.0.0」に修正した。&lt;/p&gt;
&lt;h2&gt;Generic function/class/define/namespace names（&lt;strong&gt;一般的な関数/クラス/定義/名前空間名&lt;/strong&gt;）&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;すべてのプラグインには、一意の関数名、名前空間、定義、およびクラス名が必要です。これにより、プラグインが他のプラグインやテーマと競合するのを防ぎます。プラグインを更新して、より一意で明確な名前を使用する必要があります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;そもそもフロントエンドエンジニアなのでPHPのことよくわからないっていう逃げは使えるだろうか。&lt;/p&gt;
&lt;p&gt;いや、WordPressはフロントエンドエンジニアの主戦場だろ、なんて言われるかもしれない。&lt;/p&gt;
&lt;p&gt;言われるかもしれないがわからないものはわからない。&lt;/p&gt;
&lt;p&gt;この文章の意味がわからない。&lt;/p&gt;
&lt;p&gt;ので、例によって調べてみた。&lt;/p&gt;
&lt;p&gt;よくよく読んで見るとPHPは関係ないっぽい。&lt;/p&gt;
&lt;p&gt;つまり、命名の際にPrefixをつけて他のプラグインとぶつからないようにしてくださいってことが言いたいのかしら。&lt;/p&gt;
&lt;p&gt;ということで、Globalに近い変数名、関数名にPrefixを付与した。&lt;/p&gt;
&lt;h2&gt;動作確認&lt;/h2&gt;
&lt;p&gt;はい、修正点すべて直しました。&lt;/p&gt;
&lt;p&gt;はい、ただその修正のおかげで動かなくなりました。&lt;/p&gt;
&lt;p&gt;なんてことがないように再度動きの確認をする。&lt;/p&gt;
&lt;p&gt;問題がないことを確認したので、GithubのURLとともに返信し、これでOK。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Subversion (SVN) を使用し承認されたWordpressプラグインをリリースしてみる</title><link>https://blog.nove-b.dev/posts/release-approved-wordpress-plugin</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/release-approved-wordpress-plugin</guid><content:encoded>&lt;p&gt;ここではWordpressを中心に、Subversion
(SVN) の話をするということを先に断っておく。&lt;/p&gt;
&lt;p&gt;またWordpressのプラグインを承認されると届くメールにリンク集が張られているので、そちらを参照するといい気がする。&lt;/p&gt;
&lt;p&gt;ちなみにそちらは下のリンクになる。&lt;/p&gt;
&lt;p&gt;WordPress プラグイン ディレクトリで Subversion を使用する:
&lt;a href=&quot;https://developer.wordpress.org/plugins/wordpress-org/how-to-use-subversion/&quot;&gt;https://developer.wordpress.org/plugins/wordpress-org/how-to-use-subversion/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この記事ではあくまでも上の断片情報となるので、ご注意を。&lt;/p&gt;
&lt;h2&gt;Subversion (SVN)とは&lt;/h2&gt;
&lt;p&gt;SVN
(Subversion) は、Git に似たバージョン管理システムで、Wordpressのプラグインのリリースリポジトリになる。&lt;/p&gt;
&lt;p&gt;つまり、下記のようになる。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SVN とプラグイン ディレクトリはリリースリポジトリです。Git とは異なり、パフォーマンスが低下する可能性があるため、すべての小さな変更をコミットしないでください。完成した変更のみを SVN リポジトリにプッシュしてください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ちなみに読み方はサブバージョンとまま。&lt;/p&gt;
&lt;h2&gt;まずは使ってみる（習うより慣れろ）&lt;/h2&gt;
&lt;p&gt;まずはフォルダを作成する。&lt;/p&gt;
&lt;p&gt;Subversion
(SVN)はリリースブランチということなので、Gitと同じ場所に作らず、新規でフォルダを作成してみた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;svn on URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;URLはWordpressのプラグイン承認メールに記載されている。&lt;/p&gt;
&lt;p&gt;上記コマンド実行でエラーが出た。&lt;/p&gt;
&lt;p&gt;というのもSubversion (SVN)をインストールしてないからである。&lt;/p&gt;
&lt;h3&gt;Subversion (SVN)をインストール&lt;/h3&gt;
&lt;p&gt;ということでまずはSubversion (SVN)をインストールする必要がある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://subversion.apache.org/&quot;&gt;https://subversion.apache.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上記サイトに行き、&lt;a href=&quot;https://subversion.apache.org/packages.html&quot;&gt;Binary Packages（https://subversion.apache.org/packages.html）&lt;/a&gt;をクリックする。&lt;/p&gt;
&lt;p&gt;Find packages for your operating system:&lt;/p&gt;
&lt;p&gt;↑で任意のシステムを選択する。&lt;/p&gt;
&lt;p&gt;Windowsマシンを使っているのでWindowsを選択する。&lt;/p&gt;
&lt;p&gt;いくつかクライアントの種類があるので、１つを選択する必要がある。&lt;/p&gt;
&lt;p&gt;Subversionクライアントの比較：&lt;a href=&quot;https://en.wikipedia.org/wiki/Comparison_of_Subversion_clients&quot;&gt;https://en.wikipedia.org/wiki/Comparison_of_Subversion_clients&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;調べてみるとどうもTortoiseSVN が有名そうなので、これにした。&lt;/p&gt;
&lt;p&gt;TortoiseSVNを選択し、「 TortoiseSVN 1.14.5 -
64-bit」と「日本語パッケージ」をインストールした。&lt;/p&gt;
&lt;p&gt;たぶんこれでインストールが完了した。&lt;/p&gt;
&lt;h3&gt;チェックアウトする&lt;/h3&gt;
&lt;p&gt;インストールが完了していれば、該当フォルダ（今回で言えば新規で作成したフォルダ）で右クリックをすると、TortoiseSVNというメニューが出るはずなのでサブメニューのチェックアウトを選択する。出てこない場合はその他のオプションを押すと出てくるかもしれない。&lt;/p&gt;
&lt;p&gt;チェックアウトを選択するとURLを選択するポップアップ的なやつが出てくるので、wordpressから送られてきたURLを入力しチェックアウトする。&lt;/p&gt;
&lt;p&gt;チェックアウトが成功すると、チェックアウトで指定したフォルダに、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/assets/
/tags/
/trunk/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記ディレクトリが作成される。&lt;/p&gt;
&lt;h3&gt;SVN フォルダー&lt;/h3&gt;
&lt;p&gt;assetsフォルダは、スクリーンショット、ヘッダー画像、およびプラグイン アイコンが存在する場所。&lt;/p&gt;
&lt;p&gt;tagsフォルダはプラグインの/tagsバージョンを置く場所とのこと（いまいち不明なので要調査）。&lt;/p&gt;
&lt;p&gt;trunkフォルダはプラグイン コードが存在する場所。&lt;/p&gt;
&lt;p&gt;つまりtrunkフォルダにプラグインのコードを送らしい。&lt;/p&gt;
&lt;p&gt;ただ、メインのプラグイン ファイルをトランクのサブフォルダーに入れないでくださいとのことなので、そこは注意が必要。&lt;/p&gt;
&lt;h3&gt;チェックインする&lt;/h3&gt;
&lt;p&gt;trunkフォルダに作成したプラグインの中身を入れる。&lt;/p&gt;
&lt;p&gt;その際、先ほどの注意の通りサブフォルダは作成せずにPHPファイルをそのまま入れる。&lt;/p&gt;
&lt;p&gt;で、turnkフォルダを右クリック、TortoiseSVNメニューを開きcommitを選択。&lt;/p&gt;
&lt;p&gt;するとCommit画面が開くので、commit文言を入れ、commitしたいフィルを選択する。&lt;/p&gt;
&lt;p&gt;最後に、okボタンをクリックする。&lt;/p&gt;
&lt;p&gt;するとwordpressのユーザー名、パスワードを求められるので、wordpress.orgに設定したそれらを記入する。&lt;/p&gt;
&lt;p&gt;問題がなく完了すれば、SVN
URLに行けばファイルがアップロードされていることを確認できる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>プラグインを作成しWordPress（ワードプレス）に申請する方法を申請しつつまとめてみた</title><link>https://blog.nove-b.dev/posts/create-submit-wordpress-plugin</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-submit-wordpress-plugin</guid><content:encoded>&lt;p&gt;まず大前提としてWordpressの初心者である。&lt;/p&gt;
&lt;p&gt;いや、初心者は言い過ぎだろうか、いや、そんなことない、初心者である。&lt;/p&gt;
&lt;p&gt;自作テーマはいくつも作ってきたが、それをWordpressの公式テーマとして申請したこともなければ、プラグインの申請をしたこともない。&lt;/p&gt;
&lt;p&gt;全て野良で行ってきた。&lt;/p&gt;
&lt;p&gt;つまり、Wordpressに関してまったくの初心者であると言っても過言ではない。&lt;/p&gt;
&lt;p&gt;そんな私が一からWordpressのプラグインを公式配布するまでの手順を調べてみたので、ここに残しておく。&lt;/p&gt;
&lt;h2&gt;大前提だが、プラグインは作っておく必要がある&lt;/h2&gt;
&lt;p&gt;言うまでもないと思うのだが、念には念を入れ言っておくと、プラグインは作った状態で以降進んでいく。&lt;/p&gt;
&lt;p&gt;いやプラグインの作り方がわからないのだが、というのであればそれはまた別の記事にするので見てほしい。&lt;/p&gt;
&lt;p&gt;ただ記事にしない可能性もあるので、気長に待つよりは他の人の作成方法を見たほうが得策かもしれない。&lt;/p&gt;
&lt;p&gt;さて、つまりこの段階でプラグインが完成しているという前提で次の話にいく。&lt;/p&gt;
&lt;h2&gt;WordPress.orgのアカウントを作成する&lt;/h2&gt;
&lt;p&gt;これはプラグインの申請に必須なアカウントになるので、まず最初にやっておくことにする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://login.wordpress.org/register?locale=ja&quot;&gt;WordPress.org ログイン ｜ WordPress.org 日本語&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;作成は上記リンクからできる。&lt;/p&gt;
&lt;p&gt;何回か通信が遮断されてストレスを感じたけど、特に難しいことなくアカウントを作成できた。&lt;/p&gt;
&lt;p&gt;しかしまったく管理するアカウントが増えて仕方ない。&lt;/p&gt;
&lt;p&gt;が必要なのであればそれは仕方ない。&lt;/p&gt;
&lt;h2&gt;申請用にreadme.txtを準備する&lt;/h2&gt;
&lt;p&gt;アカウントができたら次に進む。&lt;/p&gt;
&lt;p&gt;「readme.txt」に書かれた内容が、公式サイト個別プラグインのページや管理ページからのインストール画面に表示されるらしい。&lt;/p&gt;
&lt;p&gt;申請に必須かどうかわからないけど、とりあえず埋めることのできる箇所は埋めてみた。&lt;/p&gt;
&lt;p&gt;書き方に関しては「&lt;a href=&quot;https://generatewp.com/plugin-readme/&quot;&gt;Plugin Readme Generator&lt;/a&gt;」なるものがあったので、そちらを利用した。&lt;/p&gt;
&lt;p&gt;でき上がったのが、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;=== Create Eye Catch For Classic ===
Contributors: nove2b
Tags: eyecatch,ogp

You can read the title of the entered blog article and automatically generate a featured image.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じ。&lt;/p&gt;
&lt;p&gt;まあ、これじゃインストールされないだろうけれど、とりあえず今できる最低限の情報は入力した。&lt;/p&gt;
&lt;p&gt;後は無事に申請が通った後に拡張していくことにする。&lt;/p&gt;
&lt;p&gt;ちなみに英語はできないので、Google翻訳のお世話になった。&lt;/p&gt;
&lt;h2&gt;Readme Validatorにかけ、readme.txtのバリデーションをする&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ja.wordpress.org/plugins/developers/readme-validator/&quot;&gt;Readme Validator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上記公式のバリデーションに書けることで「readme.txt」の記入漏れ、記載ミスを見つけることができる。&lt;/p&gt;
&lt;p&gt;早速、バリデーションをすると、警告が表示された。&lt;/p&gt;
&lt;p&gt;曰く、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tested up to フィールドを入力してください。 Stable
tag フィールドがありません。ヒント: /trunk/ を安定版として扱う場合は Stable
tag: trunk と入力してください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;つまりテストしたWordpressのバージョン、そして作成したプラグインのバージョンが漏れているとのこと。&lt;/p&gt;
&lt;p&gt;上記をもとに修正し、ついでに注意の指示に従いいくつか追記した。&lt;/p&gt;
&lt;p&gt;そのうえで再検証。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;=== Create Eye Catch For Classic ===
Contributors: nove2b
Tags: eyecatch,ogp
Requires at least: 6.1
Tested up to: 6.1
Requires PHP: 7.41
Stable tag: trunk

You can read the title of the entered blog article and automatically generate a featured image.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下記、数点の注意が出るだけになった。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;== Frequently Asked Questions == セクションが見つかりません == Changelog
== セクションが見つかりません == Upgrade Notice
== セクションが見つかりません == Screenshots
== セクションが見つかりません 寄付リンクは見つかりませんでした&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ここら辺はまだ潰せそうにないので、現時点では無視をする。&lt;/p&gt;
&lt;p&gt;ちなみにこの記述の仕方だと、「Stable tag: trunk」の箇所が間違えている。&lt;/p&gt;
&lt;p&gt;そのあたりはレビューメールがきたという記事に記載した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/719/&quot;&gt;WordPressの公式プラグイン申請をしたら修正点が書かれたレビューメールがきた&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;申請してみる&lt;/h2&gt;
&lt;p&gt;やっとここで申請することができる。&lt;/p&gt;
&lt;p&gt;この時点で満足のいくプラグインにしておく必要が当然ある。&lt;/p&gt;
&lt;p&gt;満足が行くプラグインであれば、&lt;a href=&quot;https://ja.wordpress.org/plugins/developers/add/&quot;&gt;Add your Plugin｜ WordPress.org 日本語&lt;/a&gt;かたプラグインを申請する。&lt;/p&gt;
&lt;p&gt;対象のデータをZip化し、アップロードするだけで申請は完了。&lt;/p&gt;
&lt;p&gt;なんて簡単と思ったらエラーが出た。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;エラー: ライセンスが定義されていません。&lt;/p&gt;
&lt;p&gt;プラグインでライセンスが宣言されていません。GPLv2
(またはそれ以降) 互換のライセンスを選び、readme.txt を更新してください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;どうやらライセンスは必須らしい。&lt;/p&gt;
&lt;p&gt;ライセンスを追加してして再申請をした結果、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thank you for uploading...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という文言が表示されていれば申請できているらしい。&lt;/p&gt;
&lt;p&gt;数分後に、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[WordPress プラグインディレクトリ] プラグイン申請の成功&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;というメールが届き、無事に申請が完了した。&lt;/p&gt;
&lt;p&gt;審査結果はメールで届くとのこと。&lt;/p&gt;
&lt;p&gt;ちなみに申請時には「現在&lt;strong&gt;30&lt;/strong&gt;件のプラグインがレビュー待ち中です。」とのことだったので、ただただ待つ。&lt;/p&gt;
&lt;h3&gt;WordPress Plugin Directory] Review in Progress:Plugin Name&lt;/h3&gt;
&lt;p&gt;申請した次の日には上記タイトルのメールがきた。&lt;/p&gt;
&lt;p&gt;本文曰く、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are issues with your plugin code preventing it from being approved
immediately. We have pended your submission in order to help you correct all
issues so that it may be approved and published.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;つまり、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;プラグイン コードに問題があり、すぐに承認されません。すべての問題を修正して承認および公開できるようにするため、送信を保留しました。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;全て英文だし、何が何やらといった具合だが、しっかり読むと、直すべきところを書いてくれている。&lt;/p&gt;
&lt;p&gt;すごい親切、いたせりつくせり。&lt;/p&gt;
&lt;p&gt;書かれていた修正点は別の記事にした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/719/&quot;&gt;WordPressの公式プラグイン申請をしたら修正点が書かれたレビューメールがきた&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;で、これらの修正点に対応したうえで、再度審査して欲しいという旨をGoogle翻訳を駆使し返信した。&lt;/p&gt;
&lt;p&gt;そしてまた返事を待つことに。&lt;/p&gt;
&lt;h3&gt;Your review has been successfully completed.&lt;/h3&gt;
&lt;p&gt;待つこと3日で、審査に通ったメールが届いた。&lt;/p&gt;
&lt;p&gt;曰く、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;レビューは正常に完了しました。 SVN リポジトリへのアクセス方法の詳細は、24 時間以内に、プラグインを送信したアドレスに電子メールで送信されます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;また、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;レビューが成功しても、プラグインにすべてのセキュリティ問題やガイドライン違反&lt;strong&gt;がない&lt;/strong&gt;ことを保証するものではないことに注意してください。私たちは、あなたと同じように人間です。人間は間違いを犯します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;つまり、自分のコードには自分で責任を持てということらしい。&lt;/p&gt;
&lt;p&gt;まあ、それは間違いない。&lt;/p&gt;
&lt;p&gt;ただ、SVN リポジトリへのアクセス方法の詳細のメールが届かない。&lt;/p&gt;
&lt;p&gt;24時間以内ということなのでもうしばらく待つ。&lt;/p&gt;
&lt;h2&gt;[WordPress Plugin Directory] PluginName has been approved!&lt;/h2&gt;
&lt;p&gt;待つこと12時間、上記タイトルのメールが届いた。&lt;/p&gt;
&lt;p&gt;これでやっと、承認ということらしい。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;アカウントへのアクセスが有効になったら、任意の SVN クライアントを使用してコードをアップロードできます。 SVN
(またはプラグイン ディレクトリ) を初めて使用する場合は、このメールのすべてのリンクを確認してください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ということなので、要はSubversion
(SVN)のリポジトリが用意されたので、そちらを使ってアップロードしてねということ。&lt;/p&gt;
&lt;p&gt;ちなみにこのSubversion
(SVN) は申請時に初めて知って、これが原因で審査に引っかかったことは別記事にした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/719/&quot;&gt;WordPressの公式プラグイン申請をしたら修正点が書かれたレビューメールがきた&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;またこれにコミットする方法を調べないといけない。&lt;/p&gt;
&lt;h2&gt;Subversion を使用しプラグインをアップロードする&lt;/h2&gt;
&lt;p&gt;こちらは長くなるので別記事にまとめた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/732/&quot;&gt;Subversion (SVN) を使用し承認されたWordPressプラグインをリリースしてみる&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;そこまで悩むこともなかったけど、Subversion
(SVN) のインストールが一番面倒だったかもしれない。&lt;/p&gt;
&lt;h2&gt;作成したプラグイン「Create Eye Catch For Classic」&lt;/h2&gt;
&lt;p&gt;作成したプラグインは&lt;a href=&quot;https://wordpress.org/plugins/create-eye-catch-for-classic/&quot;&gt;こちら&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wordpress.org/plugins/create-eye-catch-for-classic/&quot;&gt;Create Eye Catch For Classic&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/1669442340100.jpg&quot; alt=&quot;プラグインを作成しWordPress（ワードプレス）に申請する方法を申請しつつまとめてみた&quot; /&gt;&lt;/p&gt;
&lt;p&gt;こんな感じのアイキャッチ画像をタイトルを入れるだけで自動で作成してくれるプラグイン。&lt;/p&gt;
&lt;p&gt;もしよかったら使ってみてください。&lt;/p&gt;
&lt;h2&gt;プラグインを作成した感想&lt;/h2&gt;
</content:encoded><author>nove-b</author></item><item><title>今後のことを考え、WordPressの記事をGitで管理しGithubに一元管理することにした</title><link>https://blog.nove-b.dev/posts/manage-wordpress-posts-git</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/manage-wordpress-posts-git</guid><content:encoded>&lt;h2&gt;なぜGit管理をするのか&lt;/h2&gt;
&lt;p&gt;過去にいくつものブログをCloseさせ、その記事データは残ってない。 なんでエクスポートしなかったんだろうという思いがたまに頭をもたげる。 そしてまた新しいブログをOpenし、Closeする時、エクスポートせずにサーバーを解約してしまうのである。&lt;/p&gt;
&lt;p&gt;エクスポートすればいいとわかっているのだが、ブログをCloseさせる時はもうブログなんてやることないと思っている。 そう思っているので、エクスポートせずに解約する。そしてまた懲りずにブログを始め、後悔するということを繰り返してきた。&lt;/p&gt;
&lt;p&gt;そこで記事をGitで管理しGithubに一元管理しようと思った。&lt;/p&gt;
&lt;h3&gt;Gitで管理しGithubにあげるメリット&lt;/h3&gt;
&lt;p&gt;メリットはいくつもある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;マークダウンで書ける&lt;/li&gt;
&lt;li&gt;どこでも書ける&lt;/li&gt;
&lt;li&gt;気に入っているエディタで書ける&lt;/li&gt;
&lt;li&gt;まるで仕事しているかのように会社でこっそりブログを書ける&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特に最後のメリットはでかい。 というのもこのブログは主に技術を扱っている。そして新しい技術を得るのは主に仕事中のことである。家に帰って書こうとしても忘れるし、該当のコードがわからなかったりする。だからこそ、学んだ瞬間に会社で書けるというメリットはでかい。&lt;/p&gt;
&lt;p&gt;そういうわけで、記事を資産化していく。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Gitブランチで作業中に他ブランチをmergeしたくなったけど、現在の作業をまだmergeしたくない時の対処方法はstashする</title><link>https://blog.nove-b.dev/posts/stash-changes-before-git-merge</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/stash-changes-before-git-merge</guid><content:encoded>&lt;h2&gt;状況&lt;/h2&gt;
&lt;p&gt;修正中に、どうしても取り込みたいブランチがあったけど、まだCommitはしたくない。&lt;/p&gt;
&lt;h2&gt;対応方法&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;stash&lt;/code&gt;→&lt;code&gt;merge&lt;/code&gt;→&lt;code&gt;apply&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;git stash save で一時的に保存する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git stash save
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記だと何ために&lt;code&gt;stash&lt;/code&gt;するのかわからなくなるのでコメントを付けることが推奨される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git stash save &quot;任意のメッセージ&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実行すると、変更履歴から消えるが、新規作成したファイルは削除されないので、変更履歴に残り続ける。&lt;br /&gt;
なお、残り続けているファイルは退避できていないということなので、安易に消さないようにした方がいい。&lt;/p&gt;
&lt;p&gt;※&lt;code&gt;stash&lt;/code&gt;は未追跡のファイルを退避してくれない。未追跡のファイルも含めたいときは&lt;code&gt;-u&lt;/code&gt;オプションを付ける必要がある。&lt;/p&gt;
&lt;h3&gt;git stash list で保存できているか確認する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git stash list
// =&amp;gt; 「stash@{番号}」: On 「ブランチ名」: 「メッセージ」
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように表示できていれば問題ない。&lt;/p&gt;
&lt;h3&gt;作業を行う&lt;/h3&gt;
&lt;p&gt;ここで本来やりたかったことに着手する。&lt;br /&gt;
今回であれば取り込みたいブランチをマージする。&lt;/p&gt;
&lt;h3&gt;git stash apply で保存データを復旧する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git stash apply 復旧したいstash名
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;名前を省略すると、一番最新のstashを復旧されるので、最新のものを復旧する際は名前なしで問題ない。&lt;/p&gt;
&lt;p&gt;復旧できたことが確認できればOK。&lt;/p&gt;
&lt;h3&gt;git stash drop で保存データを削除する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt; git stash drop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;わからなくならないように適宜、削除する。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Angularでコンポーネントを再レンダリングする</title><link>https://blog.nove-b.dev/posts/re-render-component-angular</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/re-render-component-angular</guid><content:encoded>&lt;h2&gt;コンポーネントを再レンダリングさせたい&lt;/h2&gt;
&lt;p&gt;色々な状況が複雑に絡み合っていた。ある処理を行ったあと、初期表示に戻したいという要件があり、それじゃあということで、表示用にデータを作り直したりと色々手を尽くしたが、前述したように色々な状況が複雑に絡み合っていせいで、どうにもできなかった。&lt;/p&gt;
&lt;p&gt;そこで、いっそコンポーネントをまるっと再レンダリングしちゃえ、ということにした。&lt;/p&gt;
&lt;p&gt;で、それを実現するのが下記コード。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;constructor(private router: Router) {}
~
this.router.navigateByUrl(&apos;/RefreshComponent&apos;, { skipLocationChange: true }).then(() =&amp;gt; {
    this.router.navigate([&apos;Your actualComponent&apos;]);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;行われていることは、１度&lt;code&gt;RefreshComponent&lt;/code&gt;というページに飛び、&lt;code&gt;Your actualComponent&lt;/code&gt;に戻ってくるという処理。ただユーザーはそれに気が付かない。つまりハック的な対処方法なので、使うのは自己責任で。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Javascriptで任意の値を持つn個の配列を作成する</title><link>https://blog.nove-b.dev/posts/create-n-arrays-javascript</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-n-arrays-javascript</guid><content:encoded>&lt;h2&gt;ネットで見つけた方法は&lt;/h2&gt;
&lt;p&gt;どうやら下記コードで目的は達成できるらしい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; new Array(10).fill(0).map(() =&amp;gt; 0)
 // =&amp;gt; [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;いったい、どうしてこうなるのか。&lt;/p&gt;
&lt;h2&gt;何が行われているのか？&lt;/h2&gt;
&lt;h3&gt;new Array()&lt;/h3&gt;
&lt;p&gt;かっこの中に入れた&lt;code&gt;Length&lt;/code&gt;分の配列を作成する。&lt;/p&gt;
&lt;p&gt;つまり&lt;code&gt;new Array(10)&lt;/code&gt;であれば10個の値を含む配列を作成してくれる。&lt;/p&gt;
&lt;p&gt;ちなみに値は&lt;code&gt;undefined&lt;/code&gt;になる&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;fill()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;fill() メソッドは、開始位置（既定値は 0）から終了位置（既定値は array.length）までのすべての要素を、静的な値に変更した配列を返します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;つまり先ほど作った10個の&lt;code&gt;undefined&lt;/code&gt;を持つ配列の&lt;code&gt;undefined&lt;/code&gt;を&lt;code&gt;0&lt;/code&gt;に変更してくれるということ？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(new Array(10).fill(0))
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ということらしい。&lt;/p&gt;
&lt;p&gt;この時点でタイトル（n個の任意の値を持つ配列を作成する）という目的は達成されている。&lt;/p&gt;
&lt;p&gt;いったい&lt;code&gt;map()&lt;/code&gt;は何をしているのか？&lt;/p&gt;
&lt;h2&gt;map()&lt;/h2&gt;
&lt;p&gt;このコードでいえば&lt;code&gt;map()&lt;/code&gt;は配列の個数分取り出して&lt;code&gt;0&lt;/code&gt;を入れるという、まったく生産性のない動きをしている。&lt;/p&gt;
&lt;p&gt;つまり本タイトルという目的を達成するためであれば、不要以外の何物でもない。&lt;/p&gt;
&lt;h2&gt;n個の任意の値を持つ配列を作成する方法&lt;/h2&gt;
&lt;p&gt;ということで結論は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(new Array(10).fill(0))
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に落ち着いた。&lt;/p&gt;
&lt;h3&gt;map()が必要な場合は？&lt;/h3&gt;
&lt;p&gt;ちなみに&lt;code&gt;map()&lt;/code&gt;が必要な時は、必要とする値がオブジェクトの時らしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mebee.info/2022/07/17/post-73841/&quot;&gt;javascript fillでオブジェクトの配列を作成した際の注意点&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上に詳しく説明されているけど、どうやら指定した個数分参照渡しされているということ。 つまり、3つの配列を作り、その2番目の&lt;code&gt;key&lt;/code&gt;を変更しようとしたところ、すべての&lt;code&gt;key&lt;/code&gt;が変更される結果になる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const v = new Array(3).fill({hello: &apos;Hello&apos;, world:&apos;World&apos;})
v[2].hello = &apos;goodbye&apos;
console.log(v)
// [
//     {
//         &quot;hello&quot;: &quot;goodbye&quot;,
//         &quot;world&quot;: &quot;World&quot;
//     },
//     {
//         &quot;hello&quot;: &quot;goodbye&quot;,
//         &quot;world&quot;: &quot;World&quot;
//     },
//     {
//         &quot;hello&quot;: &quot;goodbye&quot;,
//         &quot;world&quot;: &quot;World&quot;
//     }
// ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そのため、&lt;code&gt;map&lt;/code&gt;で入れなおす必要がある。&lt;/p&gt;
&lt;p&gt;念のためシンプルな個数分の配列で行ったけど、問題なかった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const v = new Array(10).fill(0)
v[2] = 2
console.log(v)
// (10) [0, 0, 2, 0, 0, 0, 0, 0, 0, 0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;オブジェクトの時だけことは起こるらしい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Dockerに座学でざっくり入門してみる</title><link>https://blog.nove-b.dev/posts/getting-started-docker-study</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/getting-started-docker-study</guid><content:encoded>&lt;p&gt;※この記事を書いているのはフロントエンドを専門にしているので、バックエンド側の「いろは」は何も知りません。&lt;br /&gt;
フロント専が&lt;code&gt;Docker&lt;/code&gt;とはいったいと頭を抱えつつ、ざっくり入門する記事になります。&lt;/p&gt;
&lt;h2&gt;Dockerに入門、重い腰を上げる理由&lt;/h2&gt;
&lt;p&gt;実はというほどでもないが、&lt;code&gt;nestJs&lt;/code&gt;もコマンド１つでローカルホストを立ち上げることができるし、公式ドキュメントもローカルホストで書かれている。つまりあえて&lt;code&gt;Docker&lt;/code&gt;に入門する必要もないのだが、開発の参考にする記事を調べると、ことごとく&lt;code&gt;Docker&lt;/code&gt;で作業しているし、どうやらデプロイも&lt;code&gt;Docker&lt;/code&gt;のファイルを使って行っているようである。であれば、こちらも開発環境を合わせた方が開発がよっぽど楽になるので、この機会に入門しちゃうことにした。&lt;/p&gt;
&lt;h2&gt;なぜDockerを使うのか&lt;/h2&gt;
&lt;p&gt;と聞くと、「環境を揃えたい」という回答が良く聞こえてくるが、いまいちピンと来てない。そもそもフロントエンドであれば&lt;code&gt;Package.json&lt;/code&gt;で環境を揃えられるんじゃないのと言いたくなる。けどそれを言うと無知と思われるのも嫌なので、調べてみることにした。&lt;/p&gt;
&lt;h2&gt;NodeとOSを揃えられる&lt;/h2&gt;
&lt;h3&gt;Nodeのバージョンを共有できる&lt;/h3&gt;
&lt;p&gt;調べてみると、&lt;code&gt;Node&lt;/code&gt;のバージョンアップを揃えられるというのが強みらしい。&lt;br /&gt;
これは確かに納得できる。&lt;br /&gt;
今までのプロジェクトでも&lt;code&gt;Node&lt;/code&gt;のバージョンが揃ってなくて苦労したことは良くある。&lt;code&gt;Package.json&lt;/code&gt;の方で依存ライブラリを管理してもその大本である&lt;code&gt;Node&lt;/code&gt;のバージョンが管理されていなければ意味がない。まあ、&lt;code&gt;Volta&lt;/code&gt;を使って&lt;code&gt;Package.json&lt;/code&gt;に&lt;code&gt;Node&lt;/code&gt;のバージョンをピン止めすれば同じと思ったけど、そもそも皆が皆&lt;code&gt;Node&lt;/code&gt;のパッケージマネージャに&lt;code&gt;Volta&lt;/code&gt;を使っているわけじゃないので、そううまくはいかない。ただそれで言うと&lt;code&gt;Docker&lt;/code&gt;もそうなので、納得できるけどこのメリットを享受するために&lt;code&gt;Docker&lt;/code&gt;を入れようとは正直思わない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.volta.sh/guide/&quot;&gt;Volta - The Hassle-Free JavaScript Tool Manager&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;OSを揃えられる&lt;/h3&gt;
&lt;p&gt;どうやらイメージという設定ファイルで&lt;code&gt;OS&lt;/code&gt;を指定できるらしい。&lt;br /&gt;
つまり今まで&lt;code&gt;OS&lt;/code&gt;ごとに環境構築で苦労することがあったが、それがなくなるらしい。というのも&lt;code&gt;Docker&lt;/code&gt;を使うことで、使っている&lt;code&gt;OS&lt;/code&gt;に環境構築するというわけではなく、&lt;code&gt;Docker&lt;/code&gt;上のコンテナに環境を構築するので、&lt;code&gt;OS&lt;/code&gt;に依存しなくなるということらしい。&lt;/p&gt;
&lt;h2&gt;実際に使うことでメリットを享受するしかない&lt;/h2&gt;
&lt;p&gt;なんか色々な記事を見てみたが、メリットと感じるのは上に上げた２つだけだった。導入手順を考えるとあえて使う気にもならないが、社会的に&lt;code&gt;Docker&lt;/code&gt;を使おう的な風潮を感じるので、今回の個人開発で導入してみて、所感を述べようと思う。使わずに批判するのは一番よくないって誰かが言っていた気がするし。 あとざっと調べてみた感じ、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;デプロイが簡単にできる？&lt;/li&gt;
&lt;li&gt;環境をそのまま渡すことができるので、譲渡しやすい？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;みたいなメリットがあるのかなと感じた。 とりあえず、物は試しで手を動かして入門してみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>windows11にDockerをインストールする</title><link>https://blog.nove-b.dev/posts/install-docker-windows11</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/install-docker-windows11</guid><content:encoded>&lt;h2&gt;Windows 11 HomeにDockerをインストールする&lt;/h2&gt;
&lt;p&gt;先人の知恵を借り、やってみる。&lt;/p&gt;
&lt;h3&gt;WSL2/Linuxをインストールする&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Docker&lt;/code&gt;を起動させるには&lt;code&gt;Linux OS&lt;/code&gt;が必要になる。そこで「Windows Subsystem for
Linux」、通称&lt;code&gt;WSL&lt;/code&gt;をインストールする必要がある。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Linux 用 Windows サブシステムを使用すると、開発者は、従来の仮想マシンまたはデュアルブート セットアップのオーバーヘッドなしで、ほとんどのコマンド ラインツール、ユーティリティ、アプリケーションを含む GNU/Linux 環境を変更せずそのまま Windows 上で直接実行できます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ということでインストールしてみる。&lt;code&gt;powerShell&lt;/code&gt;を管理者モードで開き、Cドライブ直下で下記コマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wsl --install
インストール中: 仮想マシン プラットフォーム
仮想マシン プラットフォーム はインストールされました。
インストール中: Linux 用 Windows サブシステム
Linux 用 Windows サブシステム はインストールされました。
インストール中: Ubuntu
Ubuntu はインストールされました。
要求された操作は正常に終了しました。変更を有効にするには、システムを再起動する必要があります。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事にインストールできたっぽいので指示に従い再起動する。再起動すると&lt;code&gt;Ubuntu&lt;/code&gt;
の初期設定（ユーザ名とパスワードの設定）が始まるので、ユーザー名とパスワードを設定する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: nove-b
New password:
Retype new password:
passwd: password updated successfully
Installation successful!
To run a command as administrator (user &quot;root&quot;), use &quot;sudo &amp;lt;command&amp;gt;&quot;.
See &quot;man sudo_root&quot; for details.

Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.79.1-microsoft-standard-WSL2 x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

This message is shown once a day. To disable it please create the
/home/nove-b/.hushlogin file.
nove-b@DESKTOP-GCVP4M3:~$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでWSLのインストールは完了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;\\wsl.localhost\Ubuntu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記パスで&lt;code&gt;Ubuntu&lt;/code&gt;フォルダにアクセスできる。&lt;/p&gt;
&lt;h3&gt;Docker Desktop for Windowsをインストールする&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.docker.com/&quot;&gt;Dockerの公式サイト&lt;/a&gt;に行き、&lt;code&gt;Download Docker Desktop&lt;/code&gt;をクリックし、&lt;code&gt;Docker Desktop for Windows&lt;/code&gt;をインストールする。&lt;/p&gt;
&lt;p&gt;インストール完了後、インストーラーをクリックしインストールをすすめる。ショートカットを作るか聞かれるので、好きなほうを選択しokをクリックする。&lt;/p&gt;
&lt;p&gt;これでインストール完了。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>DockerでnextJsとnestJsの環境構築をする</title><link>https://blog.nove-b.dev/posts/setup-nextjs-nestjs-docker</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/setup-nextjs-nestjs-docker</guid><content:encoded>&lt;h2&gt;NextJsとNestJsをDockerで立ち上げる&lt;/h2&gt;
&lt;p&gt;あくまでも&lt;code&gt;Docker&lt;/code&gt;のハンズオンなので別に何でもいいのだが、どうせならということで、次に考えている構成でやってみることにした。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;a href=&quot;https://qiita.com/a_ya_ka/items/229e234fbf0fbcf8743d&quot;&gt;【環境構築】NestJS+Next.js+TypeScript+Dockerの環境構築ハンズオン&lt;/a&gt;に倣うようにすすめていくので、こちらの記事を参考にした方がいいかもしれない。&lt;/p&gt;
&lt;h2&gt;docker-compose.ymlファイルを作成する&lt;/h2&gt;
&lt;p&gt;プロジェクトのルートで&lt;code&gt;docker-compose.yml&lt;/code&gt;ファイルを作成する。そのために下記コマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実行後、&lt;code&gt;docker-compose.yml&lt;/code&gt;という名前の空ファイルができていることを確認することができる。&lt;/p&gt;
&lt;p&gt;このファイルに&lt;code&gt;Docker&lt;/code&gt;の設定を書いていく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &quot;3.7&quot;

services:
  backend:
    build:
      context: .
      dockerfile: ./docker/backend/Dockerfile
    tty: true
    volumes:
      - type: bind
        source: ./backend
        target: /api
    ports:
      , &quot;3000:3000&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;設定内容は把握できていないが、これでバックエンドの&lt;code&gt;docker-compose.yml&lt;/code&gt;が作成できたらしい。&lt;/p&gt;
&lt;p&gt;まずはバックエンドのみで起動するためフロントエンドの設定は書かない。&lt;/p&gt;
&lt;h2&gt;バックエンドの設定&lt;/h2&gt;
&lt;p&gt;それではバックエンド、つまり&lt;code&gt;NestJs&lt;/code&gt;側の設定をすすめていく。&lt;/p&gt;
&lt;h3&gt;Dockerファイルの作成&lt;/h3&gt;
&lt;p&gt;設定ファイルに書いた&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dockerfile: ./docker/backend/Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で指示したディレクトリを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir docker
cd docker
mkdir backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作成したディレクトリに&lt;code&gt;Dockerfile&lt;/code&gt;を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd backend
touch Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作成が完了したら以下の内容を記述する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM node:16.18.0
WORKDIR /api
CMD [&quot;npm&quot;, &quot;run&quot;, &quot;start&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ちなみにnodeのバージョンは&lt;a href=&quot;https://qiita.com/a_ya_ka/items/229e234fbf0fbcf8743d&quot;&gt;参考にした記事&lt;/a&gt;の通りではなく、なんとなく現在他案件で使用しているバージョンにしてみた。&lt;/p&gt;
&lt;p&gt;↓のちに下記に変更した（よくわからないけど）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM node:16-alpine3.16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで&lt;code&gt;Docker&lt;/code&gt;側の設定は完了。&lt;/p&gt;
&lt;h3&gt;NestJsをインストールする&lt;/h3&gt;
&lt;p&gt;次にNestJsをインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ../..
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;プロジェクトのルートに戻り、&lt;code&gt;nest new&lt;/code&gt;を実行※１する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nest new
? What name would you like to use for the new project? backend
? Which package manager would you ❤️  to use? npm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように2つ聞かれるので、1つ目は&lt;code&gt;backend&lt;/code&gt;、2つ目は任意の&lt;code&gt;package manager&lt;/code&gt;を選択する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Thanks for installing Nest 🙏
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;が表示されればインストール完了。&lt;/p&gt;
&lt;p&gt;※1 &lt;code&gt;@nestjs/cli&lt;/code&gt;をインストールしたことない人、つまり初めての人は&lt;code&gt;nest new&lt;/code&gt;
の前に下記コマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm i -g @nestjs/cli
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;バックエンドを起動する&lt;/h3&gt;
&lt;p&gt;まずは&lt;code&gt;Docker&lt;/code&gt;を起動する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;色々処理が走り終わった後に&lt;code&gt;http://localhost:3000/&lt;/code&gt;にアクセスできれば起動が成功している。&lt;/p&gt;
&lt;h2&gt;フロントエンドの作成&lt;/h2&gt;
&lt;p&gt;次にフロントエンドの作成をするので、いったん&lt;code&gt;Docker&lt;/code&gt;は落としておく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose down
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Dockerファイルの作成&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;cd docker
mkdir frontend
cd frontend
touch Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで作成した&lt;code&gt;Dockerfile&lt;/code&gt;に以下を追記する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM node:16.18.0
EXPOSE 3333
WORKDIR /app

RUN apk update &amp;amp;&amp;amp; \
    apk upgrade

CMD [&quot;npm&quot;, &quot;run&quot;, &quot;dev&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;docker-compose.ymlファイルに追記&lt;/h3&gt;
&lt;p&gt;バックエンドの環境構築の際に書いた&lt;code&gt;docker-compose.yml&lt;/code&gt;にフロントエンドの設定を追記する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &quot;3.7&quot;

services:
  backend:
    build:
      context: .
      dockerfile: ./docker/backend/Dockerfile
    tty: true
    volumes:
      - type: bind
        source: ./backend
        target: /api
    ports:
      , &quot;3000:3000&quot;

  // 以下、追記箇所
  frontend:
    build:
      context: .
      dockerfile: ./docker/frontend/Dockerfile
    tty: true
    volumes:
      - type: bind
        source: ./frontend
        target: /app
    ports:
      , &quot;3333:3333&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;NextJsをインストールする&lt;/h3&gt;
&lt;p&gt;プロジェクトのルートに戻り&lt;code&gt;NextJs&lt;/code&gt;をインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npx create-next-app@latest --typescript
Need to install the following packages:
  create-next-app@13.1.2
Ok to proceed? (y) y
√ What is your project named? ... frontend
√ Would you like to use ESLint with this project? ... No / Yes
√ Would you like to use `src/` directory with this project? ... No / Yes
√ Would you like to use experimental `app/` directory with this project? ... No / Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;なんか今まで聞かれたことない質問をされたが（&lt;code&gt;Next13&lt;/code&gt;のせいか）、今回の肝となるのは&lt;code&gt;Project Name&lt;/code&gt;で&lt;code&gt;frontend&lt;/code&gt;と答えればいい。&lt;/p&gt;
&lt;p&gt;...全部Yesにするべきだったかもしれない。が、今回は気にすることないのでそのまま進める。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;Next&lt;/code&gt;の&lt;code&gt;package.json&lt;/code&gt;のポートを&lt;code&gt;3333&lt;/code&gt;に変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;scripts&quot;: {
    &quot;dev&quot;: &quot;next -p 3333&quot;,
    &quot;build&quot;: &quot;next build&quot;,
    &quot;start&quot;: &quot;next start&quot;,
    &quot;lint&quot;: &quot;next lint&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;サーバーを起動する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コケたので調べたら&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 以下、追記箇所
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;が原因だったので、削除で再実行。&lt;/p&gt;
&lt;p&gt;またエラーが出たので、調査すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RUN apk update &amp;amp;&amp;amp; \
    apk upgrade
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;どうやらフロントの&lt;code&gt;Dockerfile&lt;/code&gt;でエラーが出ていたので、上記該当行削除して再実行したら無事に&lt;code&gt;Docker&lt;/code&gt;が起動した。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RUN apk update &amp;amp;&amp;amp; apk upgrade --no-cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でも動作した。ただこのコマンド何をしているかはわからない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://localhost:3333/&lt;/code&gt;にアクセスするとブラウザでも動いていることが確認できた。&lt;/p&gt;
&lt;p&gt;とりあえずスタートラインに立てた。&lt;/p&gt;
&lt;p&gt;立って気づいたけど、ホットリロードが効かない。これはまた別で調査する。今回はともかく&lt;code&gt;Docker&lt;/code&gt;で基本的な環境構築まで。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Dockerで立ち上げたNextJs・NestJsのプロジェクトでホットリロードを可能にする</title><link>https://blog.nove-b.dev/posts/enable-hot-reloading-dockerized-nextjs-nestjs</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/enable-hot-reloading-dockerized-nextjs-nestjs</guid><content:encoded>&lt;h2&gt;Dockerで環境構築したファイルを変更してもブラウザで表示が変更されない&lt;/h2&gt;
&lt;p&gt;そもそも作成した環境は下記記事の通り。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/?p=789&quot;&gt;DockerでnextJsとnestJsの環境構築をする&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;で、色々検証してみた結果、&lt;code&gt;Docker&lt;/code&gt;を止め、再度立ち上げれば更新されているということが分かった。原因が分かった、これで一件落着とはならない。 何でも不便すぎる。&lt;/p&gt;
&lt;p&gt;そこでホットリロードが効くように調査してみた。&lt;/p&gt;
&lt;h2&gt;結論（いったん諦める）&lt;/h2&gt;
&lt;p&gt;フロントエンドに限り、ブラウザを更新すれば、表示が更新されることは確認できた。&lt;/p&gt;
&lt;h3&gt;フロントエンド（NextJs）&lt;/h3&gt;
&lt;p&gt;フロントエンド（&lt;code&gt;NextJs&lt;/code&gt;）側の設定は、&lt;code&gt;docker-compose.yml&lt;/code&gt;に下記変更を加えたらホットリロードが効くようになった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  frontend:
    build:
      context: .
      dockerfile: ./docker/frontend/Dockerfile
    tty: true
    volumes:
      - type: bind
        source: ./frontend
        target: /app
    + environment:
    +  - WATCHPACK_POLLING=true
    ports:
      , &quot;3333:3333&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...ただめちゃくちゃ重い。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;何回かやっていると、なんかうまくいかなくなったので、&lt;/strong&gt;
上記の追加分を削除し、下記で対応した。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;next.config.js&lt;/code&gt;に下記を追加。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  webpackDevMiddleware: config =&amp;gt; {
    config.watchOptions = {
      poll: 1000,
      aggregateTimeout: 300,
    }
    return config
  },
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで同じく重いけど、リロードに対応した。&lt;/p&gt;
&lt;p&gt;ホットリロードにも対応しているようだけど、&lt;code&gt;Docker&lt;/code&gt;が重すぎてわからない。&lt;/p&gt;
&lt;h3&gt;バックエンド（NestJs）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;NestJs&lt;/code&gt;を色々調べてもよくわかなかったので、&lt;code&gt;Docker&lt;/code&gt;について調べると、下記記事を見つけた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zenn.dev/motoishimotoi/articles/8adedc934334cc&quot;&gt;Dockerを使っていてhot reload系が効かなかったとき&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この１つ目「wsl上にファイルを置いていない」が該当したので、確認してみることにした。&lt;/p&gt;
&lt;p&gt;が、これがなかなか厄介で大変な気がする。&lt;/p&gt;
&lt;p&gt;もっと簡単そうなのが、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;env CHOKIDAR_USEPOLLING=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を&lt;code&gt;Dockerfile&lt;/code&gt;に記述する。&lt;/p&gt;
&lt;p&gt;あるいは、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;environment:
  - CHOKIDAR_USEPOLLING=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を&lt;code&gt;docker-compose.yml&lt;/code&gt;に追記するというもの。&lt;/p&gt;
&lt;p&gt;なんか採用しなかったけど、&lt;code&gt;frontend&lt;/code&gt;でも同じようなことをしている。&lt;/p&gt;
&lt;p&gt;とりあえず&lt;code&gt;docker-compose.yml&lt;/code&gt;で試してみることにした。&lt;/p&gt;
&lt;p&gt;が、反応しない。&lt;/p&gt;
&lt;p&gt;仕方ないので、&lt;code&gt;Dockerfile&lt;/code&gt;にもやってみる。&lt;/p&gt;
&lt;p&gt;こちらも反応しない。&lt;/p&gt;
&lt;p&gt;つまり、「wsl上にファイルを置く」必要があるのか。&lt;/p&gt;
&lt;p&gt;いったん保留にする。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>DockerプロジェクトをWSL上に置き、ホットリロード問題解決を試みる</title><link>https://blog.nove-b.dev/posts/resolve-hot-reload-issue-wsl-docker</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/resolve-hot-reload-issue-wsl-docker</guid><content:encoded>&lt;h2&gt;Dockerで立ち上げたサーバーが遅すぎる。&lt;/h2&gt;
&lt;p&gt;「はい、サーバーが立ち上がるまで、5分かかりました」&lt;/p&gt;
&lt;p&gt;なんていう先生の声が脳内でリフレインする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コマンドを打った後の話である。&lt;/p&gt;
&lt;p&gt;何が言いたいかというと、&lt;code&gt;Docker&lt;/code&gt;で立ち上げたサーバーが以上に重い。&lt;/p&gt;
&lt;p&gt;立ち上げ後、ブラウザが表示されるまで5分以上かかり、更新をクリック後、更新がかかるまで5分以上かかる。&lt;/p&gt;
&lt;p&gt;これじゃ、なかなか作業が進まない。&lt;/p&gt;
&lt;p&gt;それに前述、前回書いたようにホットリロードがかからないし、そもそも遅すぎてホットリロードが正常に機能しているかがわからない。&lt;/p&gt;
&lt;h3&gt;どう解決するか&lt;/h3&gt;
&lt;p&gt;じゃあ、どうするべきか。&lt;/p&gt;
&lt;p&gt;うまくいくかはわからないが、これもまた前回の記事で書いたように、「wsl上にファイルを置く」ということで少なくともホットリロードは解決するかもしれない。&lt;/p&gt;
&lt;p&gt;またDockerもWSL上で動かしているので、開発環境のスピードも上がるかもしれない。&lt;/p&gt;
&lt;p&gt;というのも下記のような内容のコメントを見つけた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;特殊な理由がない限り、複数のオペレーティング システム間でファイルを操作しないことをお勧めします。 Linux コマンド ライン (Ubuntu、OpenSUSE など) で作業している場合、最速のパフォーマンス速度を実現するには、ファイルを WSL ファイル システムに格納します。
&lt;a href=&quot;https://learn.microsoft.com/ja-jp/windows/wsl/compare-versions#performance-across-os-file-systems&quot;&gt;Microsoft公式 - OS ファイル システム間でのパフォーマンス&lt;/a&gt;
ということでやってみる。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;ファイルを WSL ファイル システムに格納する&lt;/h2&gt;
&lt;p&gt;まずは&lt;code&gt;Ubuntu&lt;/code&gt;を開く。そうするとターミナルが開くので&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pwd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コマンドで自身がどこにいるかを確認する。たぶん&lt;code&gt;/home/UserName&lt;/code&gt;にいる。&lt;/p&gt;
&lt;p&gt;次にそこにプロジェクトフォルダを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir projectName
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作成したプロジェクトに移動し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd projectName
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;VsCodeを開く。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;code .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そこでプロジェクトを作成する。 今回は&lt;a href=&quot;https://media.nove-web.com/789/&quot;&gt;「DockerでnextJsとnestJsの環境構築をする」&lt;/a&gt;で作成したものと同じものを作成した。&lt;/p&gt;
&lt;p&gt;次に拡張機能&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl&quot;&gt;WSL&lt;/a&gt;を取ると、リモート接続してくれる。&lt;/p&gt;
&lt;p&gt;そこで&lt;code&gt;Docker&lt;/code&gt;を起動すれば上手く行くと思うが、起動後すぐに落ちる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The command &apos;docker&apos; could not be found in this WSL 2 distro.
We recommend to activate the WSL integration in Docker Desktop settings.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラー出ていること確認した。&lt;/p&gt;
&lt;p&gt;エラー文通りに実行する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Docker Desktop &amp;gt;Resources &amp;gt;WSL integration&lt;/code&gt;で&lt;code&gt;Ubuntu&lt;/code&gt;を&lt;code&gt;on&lt;/code&gt;にする。&lt;/p&gt;
&lt;p&gt;これにより&lt;code&gt;Docker&lt;/code&gt;コマンドは使えるようになったが、まだ起動しない。&lt;/p&gt;
&lt;p&gt;よくわからないので&lt;code&gt;docker compose up&lt;/code&gt;を実行（&lt;code&gt;-d&lt;/code&gt;）を取って実行すると、エラーログなようなものが出てきた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker compose up
[+] Running 2/0
 ⠿ Container nextnestdockerbase-frontend-1  Created                                                                                         0.0s
 ⠿ Container nextnestdockerbase-backend-1   Created                                                                                         0.0s
Attaching to nextnestdockerbase-backend-1, nextnestdockerbase-frontend-1
nextnestdockerbase-backend-1   |
nextnestdockerbase-backend-1   | &amp;gt; backend@0.0.1 start:dev
nextnestdockerbase-backend-1   | &amp;gt; nest start --watch
nextnestdockerbase-backend-1   |
nextnestdockerbase-backend-1   | sh: 1: nest: Permission denied
nextnestdockerbase-frontend-1  |
nextnestdockerbase-frontend-1  | &amp;gt; frontend@0.1.0 dev
nextnestdockerbase-frontend-1  | &amp;gt; next -p 3333
nextnestdockerbase-frontend-1  |
nextnestdockerbase-frontend-1  | sh: 1: next: Permission denied
nextnestdockerbase-backend-1 exited with code 126
nextnestdockerbase-frontend-1 exited with code 126
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ちなみに&lt;code&gt;-d&lt;/code&gt;は&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;コンテナはバックグランドで起動し、そのまま実行し続けます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことらしい。&lt;/p&gt;
&lt;p&gt;......解決できない。 環境構築の時間をかけすぎるのも問題なので、ここでいったん&lt;code&gt;Docker&lt;/code&gt;と仲違いすることにした。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>買った時の値段以上の価値を発揮しているもの(ambie、Kindle、gram、Palmo、STANLEY、アルト)</title><link>https://blog.nove-b.dev/posts/products-exceed-value-bought</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/products-exceed-value-bought</guid><content:encoded>&lt;h2&gt;個人的にコスパ最強のものたち&lt;/h2&gt;
&lt;p&gt;買った時の値段以上の価値を発揮しているものをまとめみた。&lt;br /&gt;
たぶん来世でも購入する気がする。&lt;/p&gt;
&lt;h2&gt;ambie sound earcuffs （アンビー サウンド イヤカフ） AM-TW01&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/ambie-%E8%80%B3%E3%82%92%E3%81%B5%E3%81%95%E3%81%8C%E3%81%AA%E3%81%84%E3%81%AA%E3%81%8C%E3%82%89%E8%81%B4%E3%81%8D-%E6%9C%80%E5%A4%A76%E6%99%82%E9%96%93%E9%80%A3%E7%B6%9A%E5%86%8D%E7%94%9F%EF%BC%8B%E3%82%B1%E3%83%BC%E3%82%B9%E5%85%85%E9%9B%BB2%E5%9B%9E-CVC8-0%E5%AF%BE%E5%BF%9C%E3%83%9E%E3%82%A4%E3%82%AF-Adaptive%E5%AF%BE%E5%BF%9C/dp/B09MJVP4NZ?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&amp;amp;crid=3O53IUC5MIID7&amp;amp;keywords=ambie+sound+earcuffs+%EF%BC%88%E3%82%A2%E3%83%B3%E3%83%93%E3%83%BC+%E3%82%B5%E3%82%A6%E3%83%B3%E3%83%89+%E3%82%A4%E3%83%A4%E3%82%AB%E3%83%95%EF%BC%89+AM-TW01&amp;amp;qid=1676554212&amp;amp;sprefix=ambie+sound+earcuffs+%E3%82%A2%E3%83%B3%E3%83%93%E3%83%BC+%E3%82%B5%E3%82%A6%E3%83%B3%E3%83%89+%E3%82%A4%E3%83%A4%E3%82%AB%E3%83%95+am-tw01%2Caps%2C375&amp;amp;sr=8-1&amp;amp;linkCode=li3&amp;amp;tag=nove0822-22&amp;amp;linkId=2372440124eabcafe659a1afad38084b&amp;amp;language=ja_JP&amp;amp;ref_=as_li_ss_il&quot;&gt;&lt;img src=&quot;//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;amp;ASIN=B09MJVP4NZ&amp;amp;Format=_SL250_&amp;amp;ID=AsinImage&amp;amp;MarketPlace=JP&amp;amp;ServiceVersion=20070822&amp;amp;WS=1&amp;amp;tag=nove0822-22&amp;amp;language=ja_JP&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;img src=&quot;https://ir-jp.amazon-adsystem.com/e/ir?t=nove0822-22&amp;amp;language=ja_JP&amp;amp;l=li3&amp;amp;o=9&amp;amp;a=B09MJVP4NZ&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;イヤーカフ型のワイヤレスイヤホンで外音取り込みに特化している。&lt;br /&gt;
０歳児の育児中や、車の運転、散歩の時に重宝している。&lt;br /&gt;
着せ替えも可能で様々な色のカバーが出ている。&lt;br /&gt;
が、完全ワイヤレスが出た時の限定カラーを買えたのが自慢なので、着せ替えするつもりはない。&lt;/p&gt;
&lt;p&gt;あと仕事中も常に装着し、音楽を聞いている。&lt;br /&gt;
呼びかけられれもすぐに気がつくので、なんの問題もない。&lt;/p&gt;
&lt;p&gt;外音取り込み特化ということで、うるさい場所だと音量をあげないと聞こえなくなるのがデメリットだが、そこはトレードオフと割り切っている。&lt;/p&gt;
&lt;p&gt;つけていることに違和感がなさ過ぎて、音楽聞きつつお風呂に入ったのはご愛敬。&lt;/p&gt;
&lt;h3&gt;買うべき理由&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;耳の中が息苦しくない&lt;/li&gt;
&lt;li&gt;耳に悪くなさそうに気がしている&lt;/li&gt;
&lt;li&gt;会話しながらも音楽を聞ける&lt;/li&gt;
&lt;li&gt;散歩中に後ろから迫る車に気が付くことができる&lt;/li&gt;
&lt;li&gt;着せ替え可能なのでその日の気分でイヤホンの色を替えられる&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;改善点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;音漏れの不安が付きまとう&lt;/li&gt;
&lt;li&gt;充電がケースなしで10時間は持ってほしい（現状実働、4時間～6時間）&lt;/li&gt;
&lt;li&gt;マルチペアリングに対応してほしい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3xrxGNb&quot;&gt;ambie sound earcuffs （アンビー サウンド イヤカフ） AM-TW01&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Kindle Paperwhite&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/Kindle-Paperwhite-6-8%E3%82%A4%E3%83%B3%E3%83%81%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4-%E8%89%B2%E8%AA%BF%E8%AA%BF%E7%AF%80%E3%83%A9%E3%82%A4%E3%83%88%E6%90%AD%E8%BC%89-%E5%BA%83%E5%91%8A%E3%81%A4%E3%81%8D/dp/B08N41Y4Q2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&amp;amp;crid=V92DGJKO7DIF&amp;amp;keywords=Kindle+Paperwhite&amp;amp;qid=1676554333&amp;amp;sprefix=kindle+paperwhite%2Caps%2C619&amp;amp;sr=8-2&amp;amp;linkCode=li3&amp;amp;tag=nove0822-22&amp;amp;linkId=324f1cc9d12a9efc18d1c88e9f3ce2ad&amp;amp;language=ja_JP&amp;amp;ref_=as_li_ss_il&quot;&gt;&lt;img src=&quot;//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;amp;ASIN=B08N41Y4Q2&amp;amp;Format=_SL250_&amp;amp;ID=AsinImage&amp;amp;MarketPlace=JP&amp;amp;ServiceVersion=20070822&amp;amp;WS=1&amp;amp;tag=nove0822-22&amp;amp;language=ja_JP&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;img src=&quot;https://ir-jp.amazon-adsystem.com/e/ir?t=nove0822-22&amp;amp;language=ja_JP&amp;amp;l=li3&amp;amp;o=9&amp;amp;a=B08N41Y4Q2&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;電子書籍の代表格。&lt;br /&gt;
正直、紙の本には戻れないし、紙の本しか出さない作家の本は読めなくなってしまった。&lt;br /&gt;
やっぱり紙は場所を取る。&lt;br /&gt;
家の本棚も蒐集癖を誘うシリーズや全集、過去に買った紙の本限定の作家を除き、ブックオフに売ってしまった。&lt;/p&gt;
&lt;p&gt;そして紙の本しか出さない作家に対し、キンドルリクエストを送りまくってる。&lt;/p&gt;
&lt;p&gt;最近は全集もKindleで買ってる。&lt;/p&gt;
&lt;p&gt;あと何よりキンドルアンリミテッドが便利すぎる。&lt;br /&gt;
月額980円で対象の本を読み放題。&lt;br /&gt;
だいたい月に15冊の文庫本を読むので、980 - 15 * 500 で6520円お得に。&lt;/p&gt;
&lt;p&gt;まあ時期によるのだが、大抵は初回2か月99円、あるいは初月に限り無料なので、試しに入会し、その2か月で読みまくるのもありだと思う。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://rcm-fe.amazon-adsystem.com/e/cm?o=9&amp;amp;p=12&amp;amp;l=ur1&amp;amp;category=kindleunlimited&amp;amp;banner=0AB3H18G96CHRYZ8TV02&amp;amp;f=ifr&amp;amp;linkID=1c611b6287b5fa2b670fac02fa9ceb1e&amp;amp;t=nove0822-22&amp;amp;tracking_id=nove0822-22&quot; width=&quot;300&quot; height=&quot;250&quot; scrolling=&quot;no&quot; border=&quot;0&quot; marginwidth=&quot;0&quot; style=&quot;border:none;&quot; frameborder=&quot;0&quot; sandbox=&quot;allow-scripts allow-same-origin allow-popups allow-top-navigation-by-user-activation&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h3&gt;買うべき理由&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;本を複数冊持ち歩く必要がない&lt;/li&gt;
&lt;li&gt;どこでもいつでも本を買い、読み始めることが可能&lt;/li&gt;
&lt;li&gt;部屋が片付く&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;改善点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;読めない本がある&lt;/li&gt;
&lt;li&gt;漫画とか雑誌は読みにくい&lt;/li&gt;
&lt;li&gt;アマゾンアカウントが失われたらデータが消える&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3IsOppx&quot;&gt;Kindle Paperwhite&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;LG ノートパソコン gram 999g/14インチ&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/dp/B0B5RJ8F1H?_encoding=UTF8&amp;amp;aaxitk=7d5814c2ab9a66521a8f16c2313b6029&amp;amp;content-id=amzn1.sym.940fa71d-7f78-44a7-86e7-0cc4901f1d5f%3Aamzn1.sym.940fa71d-7f78-44a7-86e7-0cc4901f1d5f&amp;amp;hsa_cr_id=0&amp;amp;pd_rd_plhdr=t&amp;amp;pd_rd_r=afae2967-5867-48a1-ba4b-92c2bb6cbc43&amp;amp;pd_rd_w=iuPw7&amp;amp;pd_rd_wg=PI6yi&amp;amp;qid=1676554415&amp;amp;sr=1-1-ac08f2b1-eb5b-4f1a-aa64-9e8f448c33ed&amp;amp;linkCode=li3&amp;amp;tag=nove0822-22&amp;amp;linkId=4990700099bd95eff79b3b9e3e6b1ecf&amp;amp;language=ja_JP&amp;amp;ref_=as_li_ss_il&quot;&gt;&lt;img src=&quot;//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;amp;ASIN=B0B5RJ8F1H&amp;amp;Format=_SL250_&amp;amp;ID=AsinImage&amp;amp;MarketPlace=JP&amp;amp;ServiceVersion=20070822&amp;amp;WS=1&amp;amp;tag=nove0822-22&amp;amp;language=ja_JP&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;img src=&quot;https://ir-jp.amazon-adsystem.com/e/ir?t=nove0822-22&amp;amp;language=ja_JP&amp;amp;l=li3&amp;amp;o=9&amp;amp;a=B0B5RJ8F1H&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;軽いし、かっこいいノートパソコン。&lt;br /&gt;
4年間、ほぼ毎日使っている。&lt;br /&gt;
このパソコンで沢山のwebサービスを作り、ブログを作り、仕事をした。&lt;/p&gt;
&lt;p&gt;ただこれは他のパソコンでも別に良かった気がしているので、次もこのパソコンを買うかと言うと正直微妙。 ただ1キロを切るパソコンの持ち運びの体験は初めてだったので、4年前に衝撃を受けた。&lt;/p&gt;
&lt;p&gt;あと当時CMの水島ヒロがかっこよかった。&lt;/p&gt;
&lt;p&gt;今は軽いパソコンはたくさんあるので、積極的におすすめはしない。 ただ間違いはないと思われる。&lt;/p&gt;
&lt;p&gt;そういうことなので「買うべき理由」、「改善点」省略する。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3IcIiEO&quot;&gt;LG ノートパソコン gram 999g/14インチ&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Palmo for Kindle Paperwhite&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/Palmo-%E3%82%B1%E3%83%BC%E3%82%B9-%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3-%E3%82%AB%E3%83%90%E3%83%BC-%E9%BB%92/dp/B07MZ2MJG7?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&amp;amp;crid=13QVZP2PZ1M11&amp;amp;keywords=Palmo+for+Kindle+Paperwhite&amp;amp;qid=1676554494&amp;amp;s=computers&amp;amp;sprefix=palmo+for+kindle+paperwhite%2Ccomputers%2C426&amp;amp;sr=1-3&amp;amp;linkCode=li3&amp;amp;tag=nove0822-22&amp;amp;linkId=6e7208d673acc5fd6d88940376b8e555&amp;amp;language=ja_JP&amp;amp;ref_=as_li_ss_il&quot;&gt;&lt;img src=&quot;//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;amp;ASIN=B07MZ2MJG7&amp;amp;Format=_SL250_&amp;amp;ID=AsinImage&amp;amp;MarketPlace=JP&amp;amp;ServiceVersion=20070822&amp;amp;WS=1&amp;amp;tag=nove0822-22&amp;amp;language=ja_JP&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;img src=&quot;https://ir-jp.amazon-adsystem.com/e/ir?t=nove0822-22&amp;amp;language=ja_JP&amp;amp;l=li3&amp;amp;o=9&amp;amp;a=B07MZ2MJG7&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;これはKindle Paperwhiteの保護カバー。&lt;br /&gt;
保護カバーと言っているが写真を見てわかるように、角だけが保護されている。&lt;br /&gt;
なので包み込むような安心感はないが、なにより持ちやすい。&lt;/p&gt;
&lt;p&gt;ゴムの中に指を入れることで、片手で安心して本を読める。&lt;/p&gt;
&lt;p&gt;色々試した結果、これより良いカバーはないという結論に至った。&lt;/p&gt;
&lt;h3&gt;買うべき理由&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;軽い&lt;/li&gt;
&lt;li&gt;持ちやすい&lt;/li&gt;
&lt;li&gt;これより良いカバーが存在しない&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;改善点&lt;/h3&gt;
&lt;p&gt;-使用することで十分ペイできるが、見た目のわりに少々値段が高い&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3E8SnRW&quot;&gt;Palmo for Kindle Paperwhite&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;STANLEY(スタンレー) 真空スリムクエンチャー&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/STANLEY-%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%AC%E3%83%BC-%E7%9C%9F%E7%A9%BA%E3%82%B9%E3%83%AA%E3%83%A0%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%81%E3%83%A3%E3%83%BC-0-47L-09871-015/dp/B089PX7JT8?keywords=STANLEY%28%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%AC%E3%83%BC%29+%E7%9C%9F%E7%A9%BA%E3%82%B9%E3%83%AA%E3%83%A0%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%81%E3%83%A3%E3%83%BC&amp;amp;qid=1676554575&amp;amp;sr=8-2&amp;amp;linkCode=li3&amp;amp;tag=nove0822-22&amp;amp;linkId=a3d7d6cc515f7a0ded2f29ffc699cd04&amp;amp;language=ja_JP&amp;amp;ref_=as_li_ss_il&quot;&gt;&lt;img src=&quot;//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;amp;ASIN=B089PX7JT8&amp;amp;Format=_SL250_&amp;amp;ID=AsinImage&amp;amp;MarketPlace=JP&amp;amp;ServiceVersion=20070822&amp;amp;WS=1&amp;amp;tag=nove0822-22&amp;amp;language=ja_JP&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;img src=&quot;https://ir-jp.amazon-adsystem.com/e/ir?t=nove0822-22&amp;amp;language=ja_JP&amp;amp;l=li3&amp;amp;o=9&amp;amp;a=B089PX7JT8&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;ストロー付きのタンブラー。&lt;br /&gt;
家でアイスコーヒーを入れ会社で愛用している。&lt;/p&gt;
&lt;p&gt;保冷性に優れ、帰宅時にも氷が解けていない。&lt;/p&gt;
&lt;p&gt;通勤時の車でも飲むのでストロー付きというのが本当にありがたい。&lt;/p&gt;
&lt;p&gt;ストローがストロー穴とほぼ同じ大きさなので倒してもこぼれない。&lt;br /&gt;
PC使用時も安心してコーヒーが飲める優れもの。&lt;/p&gt;
&lt;h3&gt;買うべき理由&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;保冷性、保温性に優れている&lt;/li&gt;
&lt;li&gt;冷たい飲み物は付属のストローで飲める&lt;/li&gt;
&lt;li&gt;蓋つきなので零れない&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;改善点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;出先で冷たい物を飲み終えた後、温かいものを入れた時にストローの取扱いに困る&lt;/li&gt;
&lt;li&gt;ストローを洗うのが面倒に感じる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3HZMWFU&quot;&gt;STANLEY(スタンレー) 真空スリムクエンチャー&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;アルト&lt;/h2&gt;
&lt;p&gt;SUZUKIの軽自動車、アルト。&lt;br /&gt;
これも別におすすめはしないけど、個人的にコスパの高い買い物だった。&lt;/p&gt;
&lt;p&gt;通勤時、公共交通機関を使うと1時間30分かかるが、車だと45分くらいでつく。&lt;br /&gt;
で、会社が駐車場を用意してくれるというので、それじゃあ、車を買おうということになった。&lt;/p&gt;
&lt;p&gt;通勤用なので安いものでいいけど、中古は詳しくないので避けたい。ということで新古車で探すことに。 そこでであったのが50万のアルト。もちろん乗り出しはもっと費用がかかったけど、70万に届かないくらいで購入できた。&lt;/p&gt;
&lt;p&gt;ナビもオーディオもなしで、カメラだけつけた。&lt;/p&gt;
&lt;p&gt;ナビはGoogle mapでいいしオーディオだって&lt;a href=&quot;https://amzn.to/3xrxGNb&quot;&gt;ambie&lt;/a&gt;でいい。&lt;/p&gt;
&lt;p&gt;もう1年経つけど時短、ストレスとかを踏まえるとQOLが爆上がりした。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavaScriptで文字列falseをBoolean型に変更しようとして沼に落ちた</title><link>https://blog.nove-b.dev/posts/convert-string-false-to-boolean</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/convert-string-false-to-boolean</guid><content:encoded>&lt;h2&gt;文字列をBoolean型に変換するとtrueになる&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;console.log(Boolean(&apos;false&apos;))
// true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特に何も考えず上記コードを書きデバック時にはまった。&lt;/p&gt;
&lt;p&gt;他の型は上記のような書き方でうまく変換できるので、原因解明に時間がかかった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Boolean&quot;&gt;Boolean()&lt;/a&gt;を調べてみると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意: 文字列への型強制や数値への型強制などの他の型の変換とは異なり、論理値への型強制はオブジェクトからプリミティブに変換しようとするわけではありません。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;どうやらこのようなことらしい。&lt;/p&gt;
&lt;p&gt;じゃあ、いったいどうすればいいのか。&lt;/p&gt;
&lt;h2&gt;文字列falseをBoolean型にする方法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;console.log(JSON.parse((&apos;false&apos;).toLowerCase()))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コードでうまく変換できた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>windows11にMySQLをインストールする</title><link>https://blog.nove-b.dev/posts/install-mysql-windows11</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/install-mysql-windows11</guid><content:encoded>&lt;h2&gt;Windows11にMySqlをインストールする&lt;/h2&gt;
&lt;h3&gt;まずは存在確認をする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;mysql --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドでバージョンが出るようであれば、すでにインストール済みなので、この記事は必要ない。 バージョンが出ないようであれば下記の手順でインストールする。&lt;/p&gt;
&lt;h3&gt;インストール&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.mysql.com/downloads/windows/installer/5.7.html&quot;&gt;MySql&lt;/a&gt;のダウンロードページに行き、Windows
(x86,
32-bit)をインストールする。なぜか２つあるので、容量の大きい方にした。ダウンローボタンをクリックするとページ遷移するので、そのページでインストールする。&lt;/p&gt;
&lt;h3&gt;インストールの設定&lt;/h3&gt;
&lt;p&gt;インストーラーを起動すると、設定が始まるので、進めていく。
&lt;a href=&quot;https://prog-8.com/docs/mysql-env-win&quot;&gt;Progate&lt;/a&gt;を参考（以降すべて参考する）に設定した。 ちょくちょく違う箇所があったけど、そこれらへんは流れに任せた。&lt;/p&gt;
&lt;h3&gt;環境変数の設定&lt;/h3&gt;
&lt;p&gt;環境変数を設定し、コマンドプロンプトからMySQLコマンドを使えるようにする。 環境変数に設定されているMySqlの設定を、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Program Files\MySQL\MySQL Shell 8.0\bin
↓
C:\Program Files\MySQL\MySQL Server 5.7\bin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に変更する。&lt;/p&gt;
&lt;p&gt;完了後、管理者モードのコマンドで、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysql --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を実行し、バージョンが出れば、インストール完了。&lt;/p&gt;
&lt;h3&gt;動作確認&lt;/h3&gt;
&lt;p&gt;最後に念のため動作確認をしておく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Windows\System32&amp;gt;net start mysql57
MySQL57 サービスを開始します.
MySQL57 サービスは正常に開始されました。
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;ログイン&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;C:\Windows\System32&amp;gt;mysql --user=root --password
Enter password: ********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.41-log MySQL Community Server (GPL)

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type &apos;help;&apos; or &apos;\h&apos; for help. Type &apos;\c&apos; to clear the current input statement.

mysql&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記の通り、ログインも可能に。&lt;/p&gt;
&lt;h4&gt;ログアウト&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;mysql&amp;gt; exit;
Bye
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Bye&lt;/code&gt;は可愛い。&lt;/p&gt;
&lt;h4&gt;停止&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;C:\Windows\System32&amp;gt;net stop mysql57
MySQL57 サービスを停止中です.
MySQL57 サービスは正常に停止されました。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで一通り試せた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>windows11に入れたMySQLをGUI(HeidiSQL)で確認する</title><link>https://blog.nove-b.dev/posts/check-mysql-heidisql-windows11</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/check-mysql-heidisql-windows11</guid><content:encoded>&lt;h2&gt;GUIとは？&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;GUI&lt;/code&gt;とは、グラフィカルユーザインターフェース(Graphical User
Interface)の略語。コンピュータへ出す命令や指示等を、ユーザが画面上で視覚的に捉えて行動を指定できるもので、それまで主流であった命令文を入力して実行する方式(&lt;code&gt;CUI&lt;/code&gt;)に比べ、直感的に操作できるのが特長。&lt;/p&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://it-trend.jp/words/gui&quot;&gt;GUIとは - 意味の解説｜ITトレンドのIT用語集&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;つまり本来コマンドとかで操作することを、ツールで体現できるようにしたもの。&lt;/p&gt;
&lt;h2&gt;HeidiSQLを使用する&lt;/h2&gt;
&lt;p&gt;色々調べると、&lt;a href=&quot;https://jp.navicat.com/store/navicat-for-mysql&quot;&gt;Navicat for MySQL&lt;/a&gt;、&lt;a href=&quot;https://dev.mysql.com/downloads/installer/&quot;&gt;MySQL Workbench&lt;/a&gt;とかがあるらしい。&lt;a href=&quot;https://jp.navicat.com/store/navicat-for-mysql&quot;&gt;Navicat for MySQL&lt;/a&gt;は有料で、&lt;a href=&quot;https://dev.mysql.com/downloads/installer/&quot;&gt;MySQL Workbench&lt;/a&gt;は&lt;code&gt;MySQL Installer&lt;/code&gt;の中に付随しているツールらしい。&lt;/p&gt;
&lt;p&gt;今回使用する&lt;code&gt;HeidiSQL&lt;/code&gt;はオープンソースのデータベース管理ソフトで、&lt;code&gt;MySQL&lt;/code&gt;だけでなく&lt;code&gt;Microsoft SQL Server&lt;/code&gt;にも対応しているらしい。&lt;/p&gt;
&lt;p&gt;特別優れているという感じじゃないけど、聞いたことがあるのでこのツールを使用することにした。&lt;/p&gt;
&lt;h3&gt;インストール&lt;/h3&gt;
&lt;p&gt;インストールは&lt;a href=&quot;https://forest.watch.impress.co.jp/library/software/heidisql/download_11208.html&quot;&gt;HeidiSQL&lt;/a&gt;をクリックすることで開始される。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;code&gt;Microsoft Store&lt;/code&gt;でもインストールできるっぽかった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Microsoft Store&lt;/code&gt;でインストールする方がいいのかもしれないけれど、そこら辺の違いがわからないので、別で調査したい。&lt;/p&gt;
&lt;h2&gt;Windows11に入れたMySQLを接続する&lt;/h2&gt;
&lt;p&gt;ここからが本題で、&lt;code&gt;Windows11&lt;/code&gt;に入れた&lt;code&gt;MySQL&lt;/code&gt;を&lt;code&gt;HeidiSQL&lt;/code&gt;で見れるようにしていく。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;新規ボタンをクリックする&lt;/li&gt;
&lt;li&gt;セッション名を任意の名前にする（今回は&lt;code&gt;Windows11 MySQ&lt;/code&gt;Lにしてみた）&lt;/li&gt;
&lt;li&gt;ホスト名／IP: &lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ユーザー: &lt;code&gt;root&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;パスワード: インストールした&lt;code&gt;MySQL&lt;/code&gt;のパスワード&lt;/li&gt;
&lt;li&gt;&lt;code&gt;net start mysql57&lt;/code&gt;で&lt;code&gt;MySQL&lt;/code&gt;をスタート&lt;/li&gt;
&lt;li&gt;「接続」で&lt;code&gt;HeidiSQL&lt;/code&gt;でデータベースを確認できた。&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>nove-b</author></item><item><title>個人開発で読んだ瞬間の感想を投稿するウェブアプリを開発して約1.5年経過した現在の数字と思い</title><link>https://blog.nove-b.dev/posts/share-thoughts-web-app-development</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/share-thoughts-web-app-development</guid><content:encoded>&lt;h2&gt;現状&lt;/h2&gt;
&lt;p&gt;個人開発で一儲けしてやろうという人もいると思うが、現実はこんなものである。&lt;/p&gt;
&lt;p&gt;ユーザー数：&lt;strong&gt;37人&lt;/strong&gt;&lt;br /&gt;
過去１か月のアクティブユーザー：&lt;strong&gt;1人（自分）&lt;/strong&gt;&lt;br /&gt;
過去28日間の訪問ユーザー：&lt;strong&gt;37人&lt;/strong&gt;&lt;br /&gt;
過去28日間の検索クリック：&lt;strong&gt;2回&lt;/strong&gt;&lt;br /&gt;
過去28日間の検索表示数：&lt;strong&gt;60回&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;この通り、だいたい１日に１人来てくれれば御の字。&lt;/p&gt;
&lt;h2&gt;そもそもどんなサイトなのよ？&lt;/h2&gt;
&lt;p&gt;「いやいや、そもそもサイトのコンセプトが悪いんじゃない」のと言いたい気持ちはわかる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flashbook.app/home&quot;&gt;What is Flash Book ⚡&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;コンセプトは上記の通りなので、ぜひサイトに訪れて確認してほしい。&lt;/p&gt;
&lt;p&gt;それだけで...、１ユーザーが訪問してくれるだけで、本サービスには大きな１歩である。&lt;/p&gt;
&lt;h3&gt;自分が使いたいサービスを作った&lt;/h3&gt;
&lt;p&gt;このコンセプトを見てどう思うかはわからないが、少なくとも自分には需要があった。&lt;/p&gt;
&lt;p&gt;本の感想を書くのは面倒だけど、書きたいことはある。&lt;/p&gt;
&lt;p&gt;読みながら考えたこと、思ったことをシェアしたいという欲求が常々あった。&lt;/p&gt;
&lt;p&gt;自分の欲求に応えるように作ったので1年半も本サービスが続いている。&lt;/p&gt;
&lt;p&gt;やっぱり自分が１ユーザーになれるというのは強い。&lt;/p&gt;
&lt;h3&gt;過去に作ったサービスはことごとく消えていった&lt;/h3&gt;
&lt;p&gt;というのも、このサービス以前にいくつかのサービスを作ったが、それらはすぐに手放した。&lt;/p&gt;
&lt;p&gt;なぜってアクティブユーザーが０だったから。&lt;/p&gt;
&lt;p&gt;誰も使ってくれないし、自分自身も別に利用する必要がない。&lt;/p&gt;
&lt;p&gt;当然、そんなサービス不要ということで、さよならした。&lt;/p&gt;
&lt;p&gt;自分が使わないと、使い勝手もわからないし、修正のしようもない。&lt;/p&gt;
&lt;p&gt;さよならしたいくつかのサービスが教えてくれたことは「制作者がサービスの１ユーザーであれ」という教訓１つ。&lt;/p&gt;
&lt;h2&gt;サービスを広めるためにやったこと&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Twitterで告知
&lt;ul&gt;
&lt;li&gt;これはそれなりに効果があって何人か登録までしてくれたが、留まってはくれなかった&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ココナラでのコンテンツ作成
&lt;ul&gt;
&lt;li&gt;あまりにも自分だけが呟いているとさすがにと思ったので、ココナラで使用してくれる人を募った。コンテンツは増えたがそれだけだった&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Google広告
&lt;ul&gt;
&lt;li&gt;8000 円だけ&lt;a href=&quot;https://media.nove-web.com/641/&quot;&gt;Google広告を打ってみた&lt;/a&gt;PV数は飛躍的に伸びたが、ユーザーは増えなかった&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;読書メータでの布教
&lt;ul&gt;
&lt;li&gt;現在進行形で進めている&lt;/li&gt;
&lt;li&gt;同様のテーマを取り扱っているだけあってそれなりに人が来てくれている&lt;/li&gt;
&lt;li&gt;今後も続けていきたい&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;１年半近く続けてきて思うこと&lt;/h3&gt;
&lt;p&gt;個人開発でバズるなんてよっぽどのことない限り難しく、基本的に赤字の垂れ流しになる。&lt;br /&gt;
だからこそ自分自身の為になるサービスを作るべきで、自分の役に立つならそれでいいや、というマインドじゃないと続けられない。&lt;/p&gt;
&lt;p&gt;とは言え、どこかで見切りをつける必要もある。&lt;/p&gt;
&lt;p&gt;自分で作ったサービスって誰からも愛されていなくとも、可愛くて仕方ないので、ずるずる続けちゃいそうな気がしている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Windows11に入れたMySQLとNest.Jsを接続し、テーブルを作成する</title><link>https://blog.nove-b.dev/posts/connect-nestjs-mysql-windows11</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/connect-nestjs-mysql-windows11</guid><content:encoded>&lt;h2&gt;MySQLにデータベースを作成する&lt;/h2&gt;
&lt;p&gt;まず、&lt;code&gt;Windows11&lt;/code&gt;にいれた&lt;code&gt;MySQL&lt;/code&gt;にデータベースを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;net start mysql57
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;mySQLを立ち上げ、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysql --user=root --password
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でログインする。&lt;/p&gt;
&lt;p&gt;次に、下記クエリでデータベースを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE DATABASE dbName;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Query OK, 1 row affected (0.01 sec)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と出ればデータベースが作成できている。&lt;/p&gt;
&lt;p&gt;念のため、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SHOW databases;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記クエリで確認すればデータベースを一覧で確認できる。&lt;/p&gt;
&lt;h2&gt;NestJsから接続する&lt;/h2&gt;
&lt;h3&gt;TypeORMをインストールする&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;SQL および NoSQL データベースと統合するために、Nest は@nestjs/typeormパッケージを提供します。Nest がTypeORMを使用するのは、それが TypeScript で利用できる最も成熟したオブジェクト リレーショナル マッパー (ORM) だからです。TypeScript で記述されているため、Nest フレームワークとうまく統合されます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ちなみに&lt;code&gt;TypeORM&lt;/code&gt;とは&lt;code&gt;node.js&lt;/code&gt;で実行される、&lt;code&gt;TypeScript&lt;/code&gt;で作った&lt;code&gt;Object Relational Mapper&lt;/code&gt;ライブラリのこと。&lt;/p&gt;
&lt;p&gt;ちなみにちなみに、&lt;code&gt;Object Relational Mapper&lt;/code&gt;ライブラリとは、データベースとオブジェクト指向プログラミング言語の間の非互換なデータを変換するプログラミング技法のことらしい。&lt;/p&gt;
&lt;p&gt;つまり、いい感じに変換してくれるやつという浅い理解で進めていく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save @nestjs/typeorm typeorm mysql2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Appモジュール読み込む&lt;/h3&gt;
&lt;p&gt;インストールができたら、&lt;code&gt;app.module.ts&lt;/code&gt;に&lt;code&gt;TypeOrmModule&lt;/code&gt;をインポートする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Module } from &apos;@nestjs/common&apos;;
import { TypeOrmModule } from &apos;@nestjs/typeorm&apos;;

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: &apos;mysql&apos;,
      host: &apos;localhost&apos;,
      port: 3306,
      username: &apos;root&apos;,
      password: &apos;password&apos;,
      database: &apos;dbName&apos;,
      entities: [],
      synchronize: true,
    }),
  ],
})
export class AppModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Entityを作成する&lt;/h3&gt;
&lt;p&gt;テーブルを作るために&lt;code&gt;Entity&lt;/code&gt;を作成していく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch test.entity.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で&lt;code&gt;Entity&lt;/code&gt;ファイルを&lt;code&gt;src/&lt;/code&gt;に作成し、下記コードを記入する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Entity, Column, PrimaryGeneratedColumn } from &apos;typeorm&apos;;

@Entity()
export class Test {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column({ default: true })
  isActive: boolean;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Appモジュールに知らせる&lt;/h3&gt;
&lt;p&gt;作成した&lt;code&gt;Entity&lt;/code&gt;ファイルを&lt;code&gt;app.module.ts&lt;/code&gt;に読み込み、共有する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Module } from &apos;@nestjs/common&apos;;
import { TypeOrmModule } from &apos;@nestjs/typeorm&apos;;
import { AppController } from &apos;./app.controller&apos;;
import { AppService } from &apos;./app.service&apos;;
import { Test } from &apos;./test.entity&apos;;

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: &apos;mysql&apos;,
      host: &apos;localhost&apos;,
      port: 3306,
      username: &apos;root&apos;,
      password: &apos;password&apos;,
      database: &apos;dbName&apos;,
      entities: [Test],
      synchronize: true,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記でセーブすると、データベースにテーブルが作成できていることを確認できる。&lt;/p&gt;
&lt;p&gt;案外簡単に接続ができた。次は&lt;code&gt;CRUD&lt;/code&gt;操作をしていく予定。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>NestJsにおけるMigrationと「synchronize: true」を調べてみた</title><link>https://blog.nove-b.dev/posts/explore-nestjs-migration-synchronize</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/explore-nestjs-migration-synchronize</guid><content:encoded>&lt;h2&gt;synchronize: true とは&lt;/h2&gt;
&lt;p&gt;公式ドキュメントを呼んでいる際は読み飛ばしたが、下記のようなことが書かれていた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Setting synchronize: true shouldn&apos;t be used in production - otherwise you can
lose production data.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;翻訳すると「設定synchronize:
trueは本番環境では使用しないでください。そうしないと、本番データが失われる可能性があります。」とのこと。読み飛ばすにはあまりにも恐ろしい項目な気もするが、当時に自分は気にも留めなかった。&lt;/p&gt;
&lt;p&gt;これがマイグレーション作業と深く結びついている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;synchronize: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この設定は、アプリケーションをデプロイしたときに&lt;code&gt;DB&lt;/code&gt;のテーブルが&lt;code&gt;Entity&lt;/code&gt;から自動的に生成されるというもの。 そのため前回の記事のように、&lt;code&gt;Entity&lt;/code&gt;を作成しセーブすることで自動的にテーブルが作成された。&lt;/p&gt;
&lt;p&gt;どうやらすごく便利な設定だと思うようだが、危険もある。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Entityの状態がDBに同期されるため一見便利にみえますが、Entityのカラムを消したときにDBのカラムも消えてしまうため、誤ってPasswordのカラムを消してしまうなどのリスクがあります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;確かに誤って、コードを削除し、保存したらすべてのデータが消えるというのは非常に恐ろしい。&lt;/p&gt;
&lt;p&gt;そこで本番に上げる前に&lt;code&gt;synchronize: false&lt;/code&gt;にし、マイグレーションファイルを元に手動で&lt;code&gt;DB&lt;/code&gt;の状態を更新するようにしていく必要がある。&lt;/p&gt;
&lt;h2&gt;Migrationとは&lt;/h2&gt;
&lt;p&gt;マイグレーションの正体は普通の&lt;code&gt;JS&lt;/code&gt;ファイルで、&lt;code&gt;SQL&lt;/code&gt;を使用してデータベースのスキーマを更新したり、既存のデータベースに変更を加えるというものです。&lt;/p&gt;
&lt;p&gt;つまり、同期的な変更ではなく、こちらでコマンドを行うことで、データベースを変更してくれる。&lt;/p&gt;
&lt;p&gt;いざ、本番で操作するよりは、開発の時点でテスト的に触っておいた方が良さそうなので、どこかでテストする。その際、詳細な操作方法を追記する。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>git pullした時に、「error invalid path」というエラーが出たので解決する</title><link>https://blog.nove-b.dev/posts/resolve-error-invalid-path-git-pull</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/resolve-error-invalid-path-git-pull</guid><content:encoded>&lt;h2&gt;error: invalid path&lt;/h2&gt;
&lt;p&gt;タイトルに書いたが、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error: invalid path
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;git pull&lt;/code&gt; したところ上記エラーがでた。&lt;/p&gt;
&lt;p&gt;調査しつつメモに残そうと本記事のタイトルでマークダウンファイルを作成しようとしたところ、エラーがでた。つまりたぶん、それが原因だと思われる。ちなみにエラーの内容は、&lt;code&gt;:&lt;/code&gt;をファイル名に使うことはできないとのこと。&lt;/p&gt;
&lt;p&gt;でまあ、たぶん上記の通りなんだろうけれど、いちおう調べてみた結果「ファイル名にWindowsのファイルシステムで使えない文字]が含まれているのが原因」とその通り。&lt;/p&gt;
&lt;h2&gt;解決方法&lt;/h2&gt;
&lt;p&gt;シンプルな解決方法はブラウザで&lt;code&gt;Github&lt;/code&gt;にアクセスし、名前を変更する。&lt;/p&gt;
&lt;p&gt;または、&lt;code&gt;Git&lt;/code&gt;の設定を変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config --global core.protectNTFS false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ファイル名に禁則文字を含むリポジトリを &lt;code&gt;Clone&lt;/code&gt;
できない（&lt;code&gt;true&lt;/code&gt;）という設定を&lt;code&gt;false&lt;/code&gt;にすることで、エラーははかなくなる。&lt;/p&gt;
&lt;p&gt;ただ結局&lt;code&gt;Clone&lt;/code&gt;したことでファイル名が変更されたので、ファイル名を変更する必要があった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>NestJsとMySQLでCRUD操作を行ってみた</title><link>https://blog.nove-b.dev/posts/do-crud-nestjs-mysql</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/do-crud-nestjs-mysql</guid><content:encoded>&lt;h2&gt;前回の修正と準備&lt;/h2&gt;
&lt;p&gt;前回&lt;code&gt;test&lt;/code&gt;という&lt;code&gt;Entity&lt;/code&gt;を作ったけど、わかりにくくなるので&lt;code&gt;sample&lt;/code&gt;に変更した。&lt;/p&gt;
&lt;h3&gt;モジュールの作成&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;npx nest g module sample
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まず上記コマンドを使用し、モジュールを作る。なぜモジュール化するかを調べると散らかるので、また別の機会に。&lt;/p&gt;
&lt;p&gt;公式ドキュメントに&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;対応するモジュール ディレクトリ内のドメインの近くに作成することをお勧めします。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;と記載されているので、&lt;code&gt;sample.entity.ts&lt;/code&gt;を作成したサンプルモジュール内に移行する。&lt;/p&gt;
&lt;h3&gt;必要なファイルを作成する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt; npx nest g controller sample --no-spec
 npx nest g service sample --no-spec
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;controller&lt;/code&gt;と&lt;code&gt;service&lt;/code&gt;を作成する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;controller&lt;/code&gt;はルーティングを指定し、&lt;code&gt;service&lt;/code&gt;は処理の記述を書くファイルという認識。&lt;/p&gt;
&lt;p&gt;最後に、DBと疎通操作するための&lt;code&gt;Repository&lt;/code&gt;を作成する。なぜか作成するコマンドが用意されていないようなので、自作する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd src/sample
touch sample.repository.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;各ファイルを作成する&lt;/h2&gt;
&lt;h3&gt;sample.repository.ts&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;リポジトリはEntityManagerと同じですが、その操作は具象エンティティに限定されます。EntityManagerを介してリポジトリにアクセスすることができます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;上記を読んでもなんのことかわからない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Injectable } from &apos;@nestjs/common&apos;;
import { Sample } from &apos;src/sample/sample.entity&apos;;
import { Repository } from &apos;typeorm&apos;;
import { InjectRepository } from &apos;@nestjs/typeorm&apos;;

@Injectable()
export class SampleRepository extends Repository&amp;lt;Sample&amp;gt; {
  constructor(@InjectRepository(Sample) repository: Repository&amp;lt;Sample&amp;gt;) {
    super(repository.target, repository.manager, repository.queryRunner);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;sample.controller.ts&lt;/h3&gt;
&lt;p&gt;これは先述した通り、ルーティングを指定するもの。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Controller, Delete, Get, Param, Patch, Post } from &apos;@nestjs/common&apos;;
import { Sample } from &apos;./sample.entity&apos;;
import { SampleService } from &apos;./sample.service&apos;;

@Controller(&apos;sample&apos;)
export class SampleController {
  constructor(private readonly sService: SampleService) {}

  @Post()
  create() {
    return this.sService.createSample();
  }

  @Get()
  async findAll(): Promise&amp;lt;Sample[]&amp;gt; {
    return await this.sService.findAll();
  }

  @Get(&apos;:id&apos;)
  findOne(@Param(&apos;id&apos;) id: string) {
    return this.sService.findOne(+id);
  }

  @Patch(&apos;:id&apos;)
  update(@Param(&apos;id&apos;) id: string) {
    return this.sService.update(+id);
  }

  @Delete(&apos;:id&apos;)
  remove(@Param(&apos;id&apos;) id: string) {
    return this.sService.remove(+id);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;sample.service.ts&lt;/h3&gt;
&lt;p&gt;これは先述した通り、処理を指定するもの。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Injectable, NotFoundException } from &apos;@nestjs/common&apos;;
import { DeleteResult } from &apos;typeorm&apos;;
import { Sample } from &apos;./sample.entity&apos;;
import { SampleRepository } from &apos;./sample.repository&apos;;

@Injectable()
export class SampleService {
  constructor(private readonly sampleRepository: SampleRepository) {}

  // データ固定で新規作成
  public async createSample(): Promise&amp;lt;Sample&amp;gt; {
    return await this.sampleRepository.save({
      firstName: &apos;first&apos;,
      lastName: &apos;last&apos;,
      isActive: true,
    });
  }

  // 全件取得
  async findAll() {
    return await this.sampleRepository.find();
  }

  // id指定でデータ取得
  async findOne(id: number) {
    const sample = await this.sampleRepository.findOneBy({ id });
    if (!sample) {
      throw new NotFoundException(
        `${id}に一致するデータが見つかりませんでした。`,
      );
    }
    return sample;
  }

  // データ固定で更新
  async update(id: number): Promise&amp;lt;Sample&amp;gt; {
    const updated = await this.sampleRepository.update(id, {
      firstName: &apos;firstUpdate&apos;,
    });

    const updatedPost = await this.sampleRepository.findOneBy({ id });
    if (updatedPost) {
      return updatedPost;
    }

    throw new NotFoundException(
      `${id}に一致するデータが見つかりませんでした。`,
    );
  }

  // データ削除
  async remove(id: number): Promise&amp;lt;DeleteResult&amp;gt; {
    const response = await this.sampleRepository.delete(id);

    if (!response.affected) {
      throw new NotFoundException(
        `${id} に一致するデータが見つかりませんでした`,
      );
    }

    return response;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;sample.module.tsにまとめる&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import { Module } from &apos;@nestjs/common&apos;;
import { TypeOrmModule } from &apos;@nestjs/typeorm&apos;;
import { SampleController } from &apos;./sample.controller&apos;;
import { SampleRepository } from &apos;./sample.repository&apos;;
import { SampleService } from &apos;./sample.service&apos;;
import { Sample } from &apos;./sample.entity&apos;;

@Module({
  imports: [TypeOrmModule.forFeature([Sample])],
  exports: [TypeOrmModule],
  controllers: [SampleController],
  providers: [SampleService, SampleRepository],
})
export class SampleModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで諸々処理は完了した。&lt;/p&gt;
&lt;h2&gt;C:Create&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ curl -X POST localhost:3000/sample
{&quot;firstName&quot;:&quot;first&quot;,&quot;lastName&quot;:&quot;last&quot;,&quot;isActive&quot;:true,&quot;id&quot;
:2}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;R:Read&lt;/h2&gt;
&lt;h3&gt;全件取得&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;http://localhost:3000/sample/1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記にアクセスすると、下記が取得できる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[{&quot;id&quot;:1,&quot;firstName&quot;:&quot;firstUpdate&quot;,&quot;lastName&quot;:&quot;last&quot;,&quot;isActive&quot;:true},{&quot;id&quot;:3,&quot;firstName&quot;:&quot;first&quot;,&quot;lastName&quot;:&quot;last&quot;,&quot;isActive&quot;:true}]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Id指定で取得&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;http://localhost:3000/sample/1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記にアクセスすると、下記が取得できる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&quot;id&quot;:1,&quot;firstName&quot;:&quot;firstUpdate&quot;,&quot;lastName&quot;:&quot;last&quot;,&quot;isActive&quot;:true}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;U:Update&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ curl -X PATCH localhost:3000/sample/1
{&quot;id&quot;:1,&quot;firstName&quot;:&quot;firstUpdate&quot;,&quot;lastName&quot;:&quot;last&quot;,&quot;isActi
ve&quot;:true}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;D:Delete&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ curl -X DELETE localhost:3000/sample/2
{&quot;raw&quot;:[],&quot;affected&quot;:1}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでCRUD処理はできた。 ただ現状、すべてこちらで用意したデータを保存しているので、次はそこを触ってみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>複雑な文字列パターンをマッチさせる必要がある場合はIF分ではなく正規表現を使うべきだとChat GPTが言ってた</title><link>https://blog.nove-b.dev/posts/use-regex-complex-string-patterns</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/use-regex-complex-string-patterns</guid><content:encoded>&lt;h2&gt;従来&lt;/h2&gt;
&lt;p&gt;考えてみたと書いたが、そもそも従来の書き方だとどうしても汚く見えてしまうので、これを機に綺麗にしようという次第である。&lt;/p&gt;
&lt;p&gt;で、その従来の書き方といえば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
/* 文豪がランダムで抽出される */
const targetArray = [&apos;三島由紀夫&apos;,&apos;太宰治&apos;,&apos;夏目漱石&apos;,&apos;芥川龍之介&apos;,&apos;宮沢賢治&apos;]
const randamIndex =  Math.floor( Math.random() * targetArray.length );
const target = targetArray[randamIndex]

/* 文豪が芥川か太宰ならture */
const matchCondition = (target) =&amp;gt; {
    return target === &apos;芥川龍之介&apos; || target === &apos;太宰治&apos;
}

console.log(target, matchCondition(target))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じ。&lt;br /&gt;
条件が少なければ別にいいけど、条件が多い場合は&lt;code&gt;target === &apos;hoge&apos;&lt;/code&gt;を沢山繋いでいく必要がある。&lt;/p&gt;
&lt;p&gt;これをもっと綺麗にしたい。&lt;/p&gt;
&lt;h2&gt;正規表現を使いましょう&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;const condition = /\芥川龍之介|太宰治\b/
console.log(target, condition.test(target))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで、わざわざ&lt;code&gt;target === &apos;hoge&apos;&lt;/code&gt;でつなぐことなく&lt;code&gt;/\芥川龍之介|太宰治\b/&lt;/code&gt;に文豪名を増やしていくだけで済むようになった。&lt;/p&gt;
&lt;h2&gt;Chat GPTは？&lt;/h2&gt;
&lt;p&gt;考えたコードが本当に正しいか、シンプルか、美しいかの判定ができないので、流行の&lt;code&gt;Chat GPT&lt;/code&gt;にも考えてもらった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;三島由紀夫、太宰治、夏目漱石、芥川龍之介、宮沢賢治の中の1つがランダムに抽出されるデータがあり、抽出されたデータが芥川龍之介か太宰治ならtrueを返すコードをJavascriptで書いて

こんにちは！下記がそのコードになります：

const writers = [&apos;三島由紀夫&apos;, &apos;太宰治&apos;, &apos;夏目漱石&apos;, &apos;芥川龍之介&apos;, &apos;宮沢賢治&apos;];
const selectedWriter = writers[Math.floor(Math.random() * writers.length)];

if (selectedWriter === &apos;芥川龍之介&apos; || selectedWriter === &apos;太宰治&apos;) {
  console.log(true);
} else {
  console.log(false);
}
このコードでは、有名な作家のリスト writers が定義されています。次に、このリストからランダムに1つの作家が選択されます。最後に、選択された作家が芥川龍之介か太宰治か判定され、その結果に応じてTrueまたはFalseが出力されます。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;従来のコードが返ってきた。&lt;br /&gt;
しかも文字から作家ってことまで理解してる...。&lt;/p&gt;
&lt;p&gt;じゃあ、正規表現についても聞いてみた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const writers = [&apos;三島由紀夫&apos;, &apos;太宰治&apos;, &apos;夏目漱石&apos;, &apos;芥川龍之介&apos;, &apos;宮沢賢治&apos;];
const selectedWriter = writers[Math.floor(Math.random() * writers.length)];
const condition = /芥川龍之介|太宰治/;

console.log(selectedWriter, condition.test(selectedWriter));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;書き方が少し違う。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const condition = /\芥川龍之介|太宰治\b/
↓ Chat GPT
const condition = /芥川龍之介|太宰治/;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Chat GPT&lt;/code&gt;の書き方だと、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const writers = [&apos;三島由紀夫&apos;, &apos;太宰治&apos;, &apos;夏目漱石&apos;, &apos;芥川龍之介&apos;, &apos;宮沢賢治&apos;];
const selectedWriter = &apos;芥川龍之介は歯車を書いた&apos;
const condition = /芥川龍之介|太宰治/;

console.log(selectedWriter, condition.test(selectedWriter));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでも&lt;code&gt;true&lt;/code&gt;が返ってくる。ここら辺は質問の仕方によるのかしら。 人間が言葉で質問している限り、&lt;code&gt;Chat GPT&lt;/code&gt;が必ずしも正解を返すとは限らないので、注意するべきだと肝に銘じた。&lt;/p&gt;
&lt;p&gt;最後に&lt;code&gt;Chat GPT&lt;/code&gt;にIF分を使うべきか正規表現を使うべきか質問してみた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;これはアプリケーションによって異なりますが、通常は正規表現を使用するべきか、If文を使用するべきかは、比較的短い文字列を比較する場合はIf文を、複雑な文字列パターンをマッチさせる必要がある場合は正規表現を使用する方が良いです。 If文は単純で直感的で、判定処理の流れがわかりやすいです。正規表現は複雑な文字列パターンを扱うことができるため、文字列比較の機能を強化することができます。 つまり、文字列を比較するのに十分なIf文であれば、正規表現を使用する必要はありませんが、複雑な文字列パターンを扱う必要がある場合は、正規表現が有用です。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;br /&gt;
これは思っていた通りで安心した。&lt;/p&gt;
&lt;p&gt;さっき肝に銘じたばかりなのに&lt;code&gt;Chat GPT&lt;/code&gt;と意見が一致して安心しているあたり、なんだかなといった具合。&lt;/p&gt;
&lt;p&gt;AI、あな恐ろし。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>NestJSでDTO(データ転送用オブジェクト)を使用しCRUD操作を行ってみる</title><link>https://blog.nove-b.dev/posts/do-crud-dto-nestjs</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/do-crud-dto-nestjs</guid><content:encoded>&lt;h2&gt;検証ライブラリーをインストール&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm install class-validator --save
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これは、見出しの通りPOST時に検証してくるライブラリー。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;デコレータおよび非デコレータ ベースの検証の使用を許可します。内部的には、validator.jsを使用して検証を実行します。Class-validator は、ブラウザと node.js プラットフォームの両方で動作します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ちなみにバージョンは&lt;code&gt;&quot;class-validator&quot;: &quot;^0.14.0&quot;&lt;/code&gt;←の通り。&lt;/p&gt;
&lt;h2&gt;データ転送オブジェクトを作成する&lt;/h2&gt;
&lt;h3&gt;データ転送オブジェクト (DTO)とは&lt;/h3&gt;
&lt;p&gt;アプリケーションで受信するデータ用に適切なデータ構造を作成、検証しやすくするもの。
&lt;code&gt;DTO&lt;/code&gt;
を使うことで、リクエスト本文から抽出されるオブジェクトの形状を指定でき、検証の組み込みが容易になるとのこと。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;code&gt;DTO&lt;/code&gt;は英語名(&lt;code&gt;Data Transfer Object&lt;/code&gt;)と日本語読みの略が一致した稀有な例。&lt;/p&gt;
&lt;h3&gt;DTO をセットアップする&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;src/sample/dto&lt;/code&gt;に&lt;code&gt;create-sample.dto.ts&lt;/code&gt;を作成する。ファイルの内容は下記の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { IsBoolean, IsString } from &apos;class-validator&apos;;

export class CreateSampleDTO {
    @IsString()
    firstName: string;

    @IsString()
    lastName: string;

    @IsBoolean()
    isActive: boolean;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記でフィールドのデータ型が &lt;code&gt;string&lt;/code&gt;or&lt;code&gt;boolean&lt;/code&gt;型であるかを確認している。&lt;/p&gt;
&lt;h2&gt;それぞれのファイルにDTOを読み込む&lt;/h2&gt;
&lt;p&gt;ファイルのインポートは割愛する。&lt;/p&gt;
&lt;h3&gt;sample.controller.ts&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;  create() {
    return this.sService.createSample();
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↓に変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  create(@Body() createSampleDTO: CreateSampleDTO): Promise&amp;lt;Sample&amp;gt; {
    return this.sService.createSample(createSampleDTO);
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;sample.service.ts&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;  public async createSample(): Promise&amp;lt;Sample&amp;gt; {
    return await this.sampleRepository.save({
      firstName: &apos;first&apos;,
      lastName: &apos;last&apos;,
      isActive: true,
    });
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↓に変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  async createSample(createSampleDTO: CreateSampleDTO): Promise&amp;lt;Sample&amp;gt; {
    return await this.sampleRepository.save({
      firstName: createSampleDTO.firstName,
      lastName: createSampleDTO.lastName,
      isActive: createSampleDTO.isActive,
    });
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;実際にポストしてみる&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ curl -d &apos;{&quot;firstName&quot;:&quot;taro&quot;, &quot;lastName&quot;:&quot;yamada&quot;, &quot;isActive&quot;:true}&apos; -H &quot;Content-Type: application/json&quot; -X POST http://localhost:3000/sample{&quot;firstName&quot;:&quot;taro&quot;,&quot;lastName&quot;:&quot;yamada&quot;,&quot;isActive&quot;:true,&quot;id&quot;:11}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;データの作成ができていることを確認できた。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ curl -d &apos;{&quot;firstName&quot;:&quot;taro&quot;, &quot;lastName&quot;:&quot;yamada&quot;, &quot;isActive&quot;:&quot;string&quot;}&apos; -H &quot;Content-Type: application/json&quot; -X POST http://localhost:3000/sample{&quot;firstName&quot;:&quot;taro&quot;,&quot;lastName&quot;:&quot;yamada&quot;,&quot;isActive&quot;:false,&quot;id&quot;:12}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Boolean&lt;/code&gt;指定の&lt;code&gt;isActive&lt;/code&gt;を&lt;code&gt;string&lt;/code&gt;で送ったら&lt;code&gt;false&lt;/code&gt;で登録された。&lt;/p&gt;
&lt;p&gt;ついでに&lt;code&gt;string&lt;/code&gt;指定の箇所に&lt;code&gt;number&lt;/code&gt;を送ったらそのまま&lt;code&gt;number&lt;/code&gt;で登録された。&lt;/p&gt;
&lt;p&gt;つまり&lt;code&gt;class-validator&lt;/code&gt;が動いてない。&lt;/p&gt;
&lt;p&gt;これは別で調査する。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>NestJSとclass-validatorでPOST時に検証をする</title><link>https://blog.nove-b.dev/posts/validate-post-request-class-validator-nestjs</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/validate-post-request-class-validator-nestjs</guid><content:encoded>&lt;h2&gt;class-validatorをインストールした&lt;/h2&gt;
&lt;p&gt;前回は&lt;code&gt;class-validator&lt;/code&gt;をインストールし&lt;code&gt;DTO&lt;/code&gt;と接続した。&lt;/p&gt;
&lt;p&gt;が、結果は前回の記事に書いた通りだった。&lt;/p&gt;
&lt;p&gt;なので、バリデートを効くようにしたい。&lt;/p&gt;
&lt;h2&gt;main.tsにバリデートを読み込む&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;import { ValidationPipe } from &apos;@nestjs/common&apos;;
import { NestFactory } from &apos;@nestjs/core&apos;;
import { AppModule } from &apos;./app.module&apos;;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;つまりバリデートするという指示が漏れていた。&lt;/p&gt;
&lt;p&gt;ただこれだと&lt;code&gt;class-transformer&lt;/code&gt;が足りないと怒られる。&lt;/p&gt;
&lt;h2&gt;class-transformerをインストールする&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm i --save class-transformer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで怒られなくなった。&lt;/p&gt;
&lt;h2&gt;間違った情報をPOSTする&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ curl -d &apos;{&quot;firstName&quot;:1111, &quot;lastName&quot;:&quot;yamada&quot;, &quot;isActive&quot;:&quot;string&quot;}&apos; -H &quot;Content-Type: application/json&quot; -X POST http://localhost:3000/sample

{&quot;statusCode&quot;:400,&quot;message&quot;:[&quot;firstName must be a string&quot;,&quot;
isActive must be a boolean value&quot;],&quot;error&quot;:&quot;Bad Request&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;よし、怒られたのでオッケー。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>拡張機能で管理していたSCSSをnode.jsで管理するように変更する</title><link>https://blog.nove-b.dev/posts/manage-scss-nodejs</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/manage-scss-nodejs</guid><content:encoded>&lt;h2&gt;package.jsonのひな型を作成する&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;色々効かれるが基本的にEnterを押しておけば問題ない。 押し続けていると&lt;code&gt;package.json&lt;/code&gt;が作成されている。&lt;/p&gt;
&lt;h2&gt;sassをインストール&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm i -D sass
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで&lt;code&gt;sass&lt;/code&gt;をインストールする。&lt;/p&gt;
&lt;p&gt;今回は下記バージョンがインストールされた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;sass&quot;: &quot;^1.58.0&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gitでソースコードを管理している場合は、&lt;code&gt;.gitignore&lt;/code&gt;ファイルを作成し&lt;code&gt;node_modules/&lt;/code&gt;と記入するのが吉。&lt;/p&gt;
&lt;h2&gt;Scriptを登録する&lt;/h2&gt;
&lt;p&gt;ちなみに今回は&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/assets/scss/style.scss
↓
/assets/css/style.css
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように変換したい。&lt;/p&gt;
&lt;p&gt;先ほど作成した&lt;code&gt;package.json&lt;/code&gt;に&lt;code&gt;Script&lt;/code&gt;を登録する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &quot;scripts&quot;: {
    &quot;watch:sass&quot;: &quot;sass --no-source-map --watch assets/scss/:assets/css/&quot;
  },
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;登録後、&lt;code&gt;Script&lt;/code&gt;を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm run watch:sass

&amp;gt; media-nove@1.0.0 watch:sass
&amp;gt; sass --no-source-map --watch assets/scss/:assets/css/

Compiled assets\scss\style.scss to assets\css\style.css.
Sass is watching for changes. Press Ctrl-C to stop.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以降、&lt;code&gt;scss&lt;/code&gt;を変更するたびに、コンパイルされる。&lt;/p&gt;
&lt;p&gt;たぶん、拡張機能のコンパイルと展開のされ方が違うので、実際にページを見て崩れがないかを確認したほうがいい。&lt;/p&gt;
&lt;h2&gt;拡張機能について&lt;/h2&gt;
&lt;p&gt;拡張機能は便利だけど、開発環境の共有ができないので、依存しすぎるのは良くないなあ、と思い直した。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>VSCodeの拡張機能「Draw.io Integration」でER図を作成する</title><link>https://blog.nove-b.dev/posts/create-er-diagrams-vscode-draw-io</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-er-diagrams-vscode-draw-io</guid><content:encoded>&lt;h2&gt;そもそもER図とは？&lt;/h2&gt;
&lt;p&gt;ER図とは「データベース設計における代表的な設計図のこと」らしい。そして「作成したER図がそのまま物理データベース上に変換できることから、データベース設計手法におけるデファクトスタンダード」とのこと。&lt;/p&gt;
&lt;p&gt;つまりたぶん、ER図を書くという技術は必要不可欠っぽい。&lt;/p&gt;
&lt;h3&gt;データモデル&lt;/h3&gt;
&lt;p&gt;ER図はシステムの上流工程の中で段階的に設計するらしく、各工程で作成するER図の状態のことを「データモデル」というらしい。&lt;/p&gt;
&lt;h4&gt;概念モデル&lt;/h4&gt;
&lt;p&gt;要件定義工程で作成するデータモデル。&lt;br /&gt;
最初にシステム全体における「もの」や「できごと」をエンティティ、リレーションシップとして洗い出し、概要を表したもの。&lt;/p&gt;
&lt;h4&gt;論理モデル&lt;/h4&gt;
&lt;p&gt;基本設計工程で作成するデータモデル&lt;br /&gt;
特定のデータベースに依存しないレベルで具体化した状態を表したもの。&lt;/p&gt;
&lt;h4&gt;物理モデル&lt;/h4&gt;
&lt;p&gt;詳細設計工程で作成するデータモデル&lt;br /&gt;
Oracle Database等の特定の物理データベース向けに論理モデルの変換をする。&lt;br /&gt;
例えばデータ型を追加したり、物理データベースに即したアルファベットに変換する。&lt;br /&gt;
ER図の最終形態がこの物理モデル。&lt;/p&gt;
&lt;p&gt;と色々書いたけどほとんど&lt;a href=&quot;https://products.sint.co.jp/ober/blog/create-er-diagram&quot;&gt;ER図とは？書き方やテクニックをわかりやすく解説&lt;/a&gt;を参考にしたので、こっちを参考にした方がよっぽど良い。&lt;/p&gt;
&lt;h2&gt;どう書くか&lt;/h2&gt;
&lt;p&gt;で、ここからが本題になる。 じゃER図は何を使って書くべきなのか。&lt;/p&gt;
&lt;p&gt;参考までに会社のバックエンド担当に聞くと「&lt;code&gt;A5:SQL Mk-2&lt;/code&gt;」を使っているとのこと。&lt;/p&gt;
&lt;p&gt;なるほど、それを使うかと思ったけど、自宅のパソコンはパフォーマンスが良くないので、出来れば開くソフトを少なくしたい。&lt;/p&gt;
&lt;p&gt;ということで、どうせ開いている「&lt;code&gt;VS code&lt;/code&gt;」で書ける拡張機能を探してみた。&lt;/p&gt;
&lt;h2&gt;Draw.io Integration&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This unofficial extension integrates Draw.io (also known as diagrams.net) into
VS Code.&lt;br /&gt;
Mentioned in the official diagrams.net blog.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;↑が&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio&quot;&gt;本家&lt;/a&gt;の説明文。&lt;/p&gt;
&lt;p&gt;詳細は&lt;a href=&quot;https://qiita.com/riku-shiru/items/5ab7c5aecdfea323ec4e&quot;&gt;VSCodeでDraw.ioが使えるようになったらしい！&lt;/a&gt;に詳しい。&lt;/p&gt;
&lt;p&gt;そこから引用すると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Draw.ioとはdraw.ioにアクセスするだけで、フローチャートやネットワーク図、ER図といった豊富なテンプレートを使用して簡単にお絵かきをすることができるサービスになります。&lt;br /&gt;
Draw.ioで作成した図はPNGやJPEGなどの画像形式だけでなく、 SVGやXMLといった豊富な拡張子でエクスポートすることが可能です。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;このサービスが&lt;code&gt;VS code&lt;/code&gt;で使えるようになったらしい。&lt;/p&gt;
&lt;h3&gt;.dioファイルを作成する&lt;/h3&gt;
&lt;p&gt;拡張子を&lt;code&gt;.dio&lt;/code&gt;に設定したファイルを作成することで利用が開始される。&lt;/p&gt;
&lt;p&gt;ちなみに、
&lt;code&gt;.drawio.png&lt;/code&gt;とか&lt;code&gt;drawio.svg&lt;/code&gt;でファイルを生成すると、&lt;code&gt;import&lt;/code&gt;や&lt;code&gt;export&lt;/code&gt;の必要なくそのまま画像として利用できたり、編集することが可能らしい。&lt;/p&gt;
&lt;p&gt;ファイルを作った瞬間、編集画面が表示されたすごい。&lt;/p&gt;
&lt;p&gt;あとは&lt;a href=&quot;https://e-seventh.com/draw-io-er-diagram/&quot;&gt;diagrams.net(draw.io)でER図を描く方法　※画像つき解説&lt;/a&gt;とかの通り、&lt;code&gt;draw.io&lt;/code&gt;でER図各サイトを参考にすれば問題ない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Githubでリポジトリ用のプルリクエストテンプレートを作成する</title><link>https://blog.nove-b.dev/posts/create-pull-request-template-github</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-pull-request-template-github</guid><content:encoded>&lt;h2&gt;プルリク時の記述を共通化する&lt;/h2&gt;
&lt;p&gt;プルリク時に各々違うフォーマットで書かれるとレビューする人が大変なので、テンプレートを使用し共通化を図ることにした。 基本的に&lt;a href=&quot;https://docs.github.com/ja/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository&quot;&gt;リポジトリ用のプルリクエストテンプレートの作成&lt;/a&gt;を参考にすれば間違いないが、ここでは最もシンプルな方法を共有する。&lt;/p&gt;
&lt;h2&gt;共通用テンプレートの作成&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;cd project-root
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずはプロジェクトのルートに移動する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir .github
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に&lt;code&gt;.github&lt;/code&gt;フォルダを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch PULL_REQUEST_TEMPLATE.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で&lt;code&gt;PULL_REQUEST_TEMPLATE.md&lt;/code&gt;という空のファイルを作成する。&lt;/p&gt;
&lt;p&gt;そこでにテンプレート内容を書けばok。&lt;/p&gt;
&lt;h2&gt;どんなテンプレにすればいいか&lt;/h2&gt;
&lt;p&gt;正直プルリクの運用は迷うことばかりなので、&lt;a href=&quot;https://zenn.dev/praha/articles/02ba95449a5ac4?utm_source=pocket_saves&quot;&gt;プルリクのレビューを効率的に進めるためにルールを作ってみた話&lt;/a&gt;を参考にした。&lt;/p&gt;
&lt;h3&gt;テンプレート内容&lt;/h3&gt;
&lt;p&gt;上記リンクから内容を拝借する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## チケットもしくは概要

&amp;lt;!--
close #XX

or

ログイン機能の実装
--&amp;gt;

## やったこと

&amp;lt;!--
- Hoge コンポーネントに props を追加
- Fuga コンポーネントを実装
--&amp;gt;

## 特に見て欲しいところ

&amp;lt;!--
- 新しいライブラリを追加したが、他に妥当な物があるか
- テストケースがこれで十分かどうか
--&amp;gt;

## 動作確認手順

&amp;lt;!--
1. ログインフォーム(/login)にアクセス
1. メアドとパスワードを入力してログインを実行する
1. ログインが成功してユーザー一覧ページにリダイレクトされること
--&amp;gt;

## TODO（できればIssueを立ててリンクを貼りましょう）

&amp;lt;!--
- [ ] バリデーション
- [ ] エラーメッセージ
--&amp;gt;

## その他情報

&amp;lt;!--
参考にした記事
--&amp;gt;

## レビューコメント

レビュー時は prefix（テキストでも絵文字でもOK） を付けて、どのレベル感のコメントか明示してください

- ⚠️ must:  必ず直すべき
- 💭 imo:  自分の考えは〜
- 🐾 nits: 細かい指摘
- ❓ ask:  質問/確認
- 🖊️ memo: メモ書き

## マージについて

マージするのはレビュワーでもPRを開いた人でもどちらでもOKです！
Approveはするけどコメントを残すね→開いた人が修正するかどうか判断し、そのままor修正後にマージ
完璧なPRだ！→レビュワーがそのままマージ
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://zenn.dev/praha/articles/02ba95449a5ac4?utm_source=pocket_saves&quot;&gt;プルリクのレビューを効率的に進めるためにルールを作ってみた話&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>NestJSでMySQLと接続するモジュールを外部化し環境変数にする</title><link>https://blog.nove-b.dev/posts/externalize-nestjs-mysql-connection</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/externalize-nestjs-mysql-connection</guid><content:encoded>&lt;h2&gt;環境変数化とDB接続のモジュール化&lt;/h2&gt;
&lt;p&gt;綺麗にって漠然と書いたが、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;環境変数化&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DB&lt;/code&gt;接続のモジュール作成&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;を行っていく。&lt;/p&gt;
&lt;h3&gt;DB接続のモジュール作成&lt;/h3&gt;
&lt;p&gt;まずは外部モジュール化する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nest g mo database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、データ接続用のモジュールを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Module } from &apos;@nestjs/common&apos;;
import { TypeOrmModule } from &apos;@nestjs/typeorm&apos;;

@Module({
    imports: [
        TypeOrmModule.forRootAsync({
                useFactory: () =&amp;gt; ({
                type: &apos;mysql&apos;,
                host: &apos;localhost&apos;,
                port: 3306,
                username: &apos;username&apos;,
                password: &apos;password&apos;,
                database: &apos;database-name&apos;,
                entities: [],
                synchronize: true,
            }),
        }),
    ],
})
export class DatabaseModule { }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に、&lt;code&gt;app.module.ts&lt;/code&gt;の方を編集する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Module({
  imports: [
    DatabaseModule,
  ],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;設定をべたで&lt;code&gt;import&lt;/code&gt;していたので、それを外部モジュールに変換する。&lt;/p&gt;
&lt;p&gt;これで外部化は完了。&lt;/p&gt;
&lt;h3&gt;環境変数化&lt;/h3&gt;
&lt;p&gt;次に環境変数化していく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install @nestjs/config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、環境変数から読み込むためのパッケージをインストールする。&lt;/p&gt;
&lt;p&gt;バージョンは &lt;code&gt;&quot;@nestjs/config&quot;: &quot;^2.3.1&quot;&lt;/code&gt;だった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;ファイルをルートに作成し、そこに環境変数を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DATABASE_USER=test
DATABASE_PASSWORD=test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DatabaseModuleの読み込みを環境変数に変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      imports: [
        ConfigModule.forRoot({
          envFilePath: [&quot;.env&quot;],
        }),
      ],
      useFactory: () =&amp;gt; ({
        type: &apos;mysql&apos;,
        host: process.env.DATABASE_HOST,
        port: Number(process.env.DATABASE_PORT),
        username: process.env.DATABASE_USER,
        password: process.env.DATABASE_PASSWORD,
        database: process.env.DATABASE_NAME,
        entities: [Sample],
        synchronize: true,
      }),
    }),
  ],
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでいままで通りデータが取得できていれば問題ない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>NestJSでOpenAPIツール「swagger」を生成する</title><link>https://blog.nove-b.dev/posts/generate-swagger-nestjs</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/generate-swagger-nestjs</guid><content:encoded>&lt;h2&gt;依存関係をインストールする&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm install --save @nestjs/swagger
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;main.tsを編集する&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Swaggerの記述
  const config = new DocumentBuilder()
    .setTitle(&apos;Cats example&apos;)
    .setDescription(&apos;The cats API description&apos;)
    .setVersion(&apos;1.0&apos;)
    .addTag(&apos;cats&apos;)
    .build();
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup(&apos;api&apos;, app, document);

  await app.listen(3000);
}
bootstrap();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;後は上の記述を編集し、&lt;code&gt;http://localhost:3000/api/&lt;/code&gt;を開けば作成されている。&lt;/p&gt;
&lt;p&gt;非常に楽なので活用していきたい。&lt;/p&gt;
&lt;h2&gt;APIをグルーピングする&lt;/h2&gt;
&lt;p&gt;これだと&lt;code&gt;cats&lt;/code&gt;というタグができるがその中は空になり、すべてが&lt;code&gt;default&lt;/code&gt;にグルーピングされる。&lt;/p&gt;
&lt;p&gt;任意のグルーピングを作りたい時は、&lt;code&gt;hoge.controller.ts&lt;/code&gt;を下記のように変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Controller } from &apos;@nestjs/common&apos;;
import { ApiTags } from &apos;@nestjs/swagger&apos;;

@Controller(&apos;hoge&apos;)
@ApiTags(&apos;hoge&apos;)
export class HogeController {
  constructor(private readonly sService: HogeService) {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで意図した形になる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>AngularでObjectを返すカスタムPipeを作ったがValueへのアクセス方法がわかなかったので調べてみた</title><link>https://blog.nove-b.dev/posts/access-value-custom-pipe-angular</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/access-value-custom-pipe-angular</guid><content:encoded>&lt;h2&gt;Objectを返すPipe&lt;/h2&gt;
&lt;p&gt;template側で展開するとこんな感じのやつ。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;value | customPipe |json

{hoge:&apos;hoge&apos;, fugo:&apos;fugo&apos;, piyo.&apos;piyo&apos;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;参照方法は簡単&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;(value | customPipe).hoge
// hoge
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で参照できる、ただこれだけ。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>WardPressの管理をGit Flowで管理していたが、VSCodeの拡張機能「WordPress Post」を使うことで世界が変わった。</title><link>https://blog.nove-b.dev/posts/wordpress-management-vscode-wordpress-post</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/wordpress-management-vscode-wordpress-post</guid><content:encoded>&lt;p&gt;&lt;code&gt;WordPress&lt;/code&gt;の記事管理に頭を悩ませてきた。&lt;/p&gt;
&lt;p&gt;で、行きついた先が、&lt;a href=&quot;https://media.nove-web.com/748/&quot;&gt;今後のことを考え、WordPressの記事をGitで管理しGithubに一元管理することにした&lt;/a&gt;だったのだが、色々運用を決めていくとどうにも面倒で仕方なくなってきた。&lt;/p&gt;
&lt;h2&gt;Githubでの運用方法&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;書きたい題材が見つかった時に&lt;code&gt;Issue&lt;/code&gt;をたてる&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Issue&lt;/code&gt;からブランチをきり、記事を作成する&lt;/li&gt;
&lt;li&gt;プルリクを作成する&lt;/li&gt;
&lt;li&gt;記事を&lt;code&gt;WordPress&lt;/code&gt;にコピペ&lt;/li&gt;
&lt;li&gt;公開&lt;/li&gt;
&lt;li&gt;プルリクを承認する&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;という手順を自らに課したせいで、更新が億劫で仕方なかった。&lt;/p&gt;
&lt;p&gt;そんなときに救世主である&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=masa86.wordpress-post&quot;&gt;WordPress Post&lt;/a&gt;という&lt;code&gt;VSCode&lt;/code&gt;の拡張機能にであった。&lt;/p&gt;
&lt;h2&gt;WordPress Postとは？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;この Visual Studio
Code 拡張機能は、WordPress に記事を投稿するアクションを提供します。これは、人々が Visual
Studio Code を使用して Markdown で WordPress 記事を作成するのに役立ちます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;簡単に言うと、&lt;code&gt;VSCode&lt;/code&gt;で記事を書き、&lt;code&gt;WordPress&lt;/code&gt;の管理画面を開くことなく、公開まで持っていける。&lt;/p&gt;
&lt;p&gt;という最強の拡張機能！&lt;/p&gt;
&lt;p&gt;使い方は作者の&lt;a href=&quot;https://masa86.net/blog-wordpress-post/&quot;&gt;ブログ&lt;/a&gt;に詳しい。&lt;/p&gt;
&lt;p&gt;これにより先ほどの手順が驚くほど簡略化された。&lt;/p&gt;
&lt;h2&gt;WordPress Postを使った公開手順&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;記事を下書き設定で書く&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WardPress&lt;/code&gt;からカテゴリ・タグ・アイキャッチ画像を選択&lt;/li&gt;
&lt;li&gt;公開&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;WardPressからカテゴリ・タグ・アイキャッチ画像を選択&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;は個人的に独自の手法を使っているのでまあ仕方ない。&lt;/p&gt;
&lt;p&gt;管理画面に行かなくてはいけないものの、相当簡略化された。&lt;/p&gt;
&lt;p&gt;さらに当然&lt;code&gt;Git&lt;/code&gt;管理も問題ない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/855/&quot;&gt;来世でも使うと思われるVisual Studio Codeの拡張機能をまとめてみた&lt;/a&gt;間違いなく、こちらの記事に更新をかけ、追加するべき拡張機能である。&lt;/p&gt;
&lt;p&gt;だがしかし、過去にこれで管理してないファイルはどのように対処する必要があるのか...?&lt;/p&gt;
&lt;p&gt;たぶん、過去のは二元管理になるかしら。&lt;/p&gt;
&lt;p&gt;とは言え、この拡張機能が素晴らしいことは間違いない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>ER図におけるリレーションのカーディナリティが覚えられなかったのでまとめてみる</title><link>https://blog.nove-b.dev/posts/summary-cardinality-er-diagrams</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/summary-cardinality-er-diagrams</guid><content:encoded>&lt;h2&gt;ER図の種類&lt;/h2&gt;
&lt;p&gt;そもそも知らなかったがER図には複数の書き方があるらしく、有名なのは「IE記法」と「IDEF1X記法」というものらしい。ふたつの記法は似ているがカーディナリティの違いがあるとか。&lt;/p&gt;
&lt;p&gt;IDEF1X記法はリレーションを「●」などで表現することが特徴でIE方より細かい表現ができるが、その分直観さが失われるらしい。複雑なのは避けたいので、今回はIE記法で進めていく。&lt;/p&gt;
&lt;p&gt;そもそもIE記法しかないと思っていた......。&lt;/p&gt;
&lt;h2&gt;カーディナリティの種類&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;記号&lt;/th&gt;
&lt;th&gt;意味&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;l&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;鳥の足（3つ股の線）&lt;/td&gt;
&lt;td&gt;2以上&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;主にこんな感じの記号を駆使していく。&lt;/p&gt;
&lt;h2&gt;実際にやってみる&lt;/h2&gt;
&lt;p&gt;内田百閒という好きな作家でER図を作っていく。&lt;/p&gt;
&lt;p&gt;ちなみにおすすめは、下記３作品。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/%E7%AC%AC%E4%B8%80%E9%98%BF%E6%88%BF%E5%88%97%E8%BB%8A-%E6%96%B0%E6%BD%AE%E6%96%87%E5%BA%AB-%E5%86%85%E7%94%B0-%E7%99%BE%E3%81%91%E3%82%93/dp/4101356335?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&amp;amp;keywords=%E5%86%85%E7%94%B0%E7%99%BE%E9%96%92&amp;amp;qid=1679265583&amp;amp;sr=8-5&amp;amp;linkCode=li3&amp;amp;tag=nove0822-22&amp;amp;linkId=b0f1832783b8ad9b4411f618e0bb0e7b&amp;amp;language=ja_JP&amp;amp;ref_=as_li_ss_il&quot;&gt;&lt;img src=&quot;//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;amp;ASIN=4101356335&amp;amp;Format=_SL250_&amp;amp;ID=AsinImage&amp;amp;MarketPlace=JP&amp;amp;ServiceVersion=20070822&amp;amp;WS=1&amp;amp;tag=nove0822-22&amp;amp;language=ja_JP&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;img src=&quot;https://ir-jp.amazon-adsystem.com/e/ir?t=nove0822-22&amp;amp;language=ja_JP&amp;amp;l=li3&amp;amp;o=9&amp;amp;a=4101356335&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/%E5%86%A5%E9%80%94%E3%83%BB%E6%97%85%E9%A0%86%E5%85%A5%E5%9F%8E%E5%BC%8F-%E5%B2%A9%E6%B3%A2%E6%96%87%E5%BA%AB-%E5%86%85%E7%94%B0-%E7%99%BE%E3%81%91%E3%82%93/dp/4003112717?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&amp;amp;keywords=%E5%86%85%E7%94%B0%E7%99%BE%E9%96%92&amp;amp;qid=1679265583&amp;amp;sr=8-10&amp;amp;linkCode=li3&amp;amp;tag=nove0822-22&amp;amp;linkId=0c2fbab432e30f0c677517c69af5cb62&amp;amp;language=ja_JP&amp;amp;ref_=as_li_ss_il&quot;&gt;&lt;img src=&quot;//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;amp;ASIN=4003112717&amp;amp;Format=_SL250_&amp;amp;ID=AsinImage&amp;amp;MarketPlace=JP&amp;amp;ServiceVersion=20070822&amp;amp;WS=1&amp;amp;tag=nove0822-22&amp;amp;language=ja_JP&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;img src=&quot;https://ir-jp.amazon-adsystem.com/e/ir?t=nove0822-22&amp;amp;language=ja_JP&amp;amp;l=li3&amp;amp;o=9&amp;amp;a=4003112717&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/%E7%99%BE%E9%AC%BC%E5%9C%92%E9%9A%8F%E7%AD%86-%E6%96%B0%E6%BD%AE%E6%96%87%E5%BA%AB-%E5%86%85%E7%94%B0-%E7%99%BE%E3%81%91%E3%82%93/dp/4101356319?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&amp;amp;keywords=%E7%99%BE%E9%96%93+%E9%9A%8F%E7%AD%86&amp;amp;qid=1679265724&amp;amp;sr=8-1&amp;amp;linkCode=li3&amp;amp;tag=nove0822-22&amp;amp;linkId=d6f519e9a124a444fee3be462b1434b8&amp;amp;language=ja_JP&amp;amp;ref_=as_li_ss_il&quot;&gt;&lt;img src=&quot;//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;amp;ASIN=4101356319&amp;amp;Format=_SL250_&amp;amp;ID=AsinImage&amp;amp;MarketPlace=JP&amp;amp;ServiceVersion=20070822&amp;amp;WS=1&amp;amp;tag=nove0822-22&amp;amp;language=ja_JP&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;img src=&quot;https://ir-jp.amazon-adsystem.com/e/ir?t=nove0822-22&amp;amp;language=ja_JP&amp;amp;l=li3&amp;amp;o=9&amp;amp;a=4101356319&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;１対１の関係&lt;/h3&gt;
&lt;p&gt;これはまあ、シンプルに内田百閒とその詳細を表すときが該当する。 例えば内田百閒という漢字とその読み方を表すと下記のようなER図になる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/OneOne.drawio.png&quot; alt=&quot;１対１の関係&quot; /&gt;&lt;/p&gt;
&lt;p&gt;内田百閒という作家名は「うちだひゃっけん」という読み方しかないので、１対１の関係になる。&lt;/p&gt;
&lt;h3&gt;１対多の関係&lt;/h3&gt;
&lt;p&gt;良く使われる表現だが、曖昧な状況を表している。&lt;/p&gt;
&lt;p&gt;「1対多という関係は決まっているが、それ以上は決まっていない」という、データベース設計の初期段階の時に使う。&lt;br /&gt;
設計が進むにつれ、「1対0以上の関係」「1対1以上の関係」のように具体化してく必要がある。&lt;/p&gt;
&lt;p&gt;例えば内田百閒とその作品はこれに該当する。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/OneMany.drawio.png&quot; alt=&quot;１対多の関係&quot; /&gt;&lt;/p&gt;
&lt;p&gt;内田百閒はたぶん複数の著作を持っているので、１対多の関係になる。&lt;/p&gt;
&lt;h3&gt;1対0以上の関係&lt;/h3&gt;
&lt;p&gt;それじゃあ、１対多の関係を具体化していく。&lt;/p&gt;
&lt;p&gt;１対多とはいえ、１に紐づくものが０の場合も存在する場合は、1対0以上の関係になる。&lt;/p&gt;
&lt;p&gt;過去に遡り、百間がまだ著作を出版していなかった時、下記のようなER図で表現できる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/OneOverZero.drawio.png&quot; alt=&quot;1対0以上の関係&quot; /&gt;&lt;/p&gt;
&lt;p&gt;もしかすると百間は著作を出版することなく人生を終える可能性もあるので、0を許容する必要がある。 そういう場合は1対0以上の関係になる。&lt;/p&gt;
&lt;h3&gt;1対1以上の関係&lt;/h3&gt;
&lt;p&gt;とはいえ、百間は最高の作品を複数残した。&lt;/p&gt;
&lt;p&gt;そのため、少なくとも1件以上は彼に紐づけることができる。&lt;/p&gt;
&lt;p&gt;つまり、1対1以上の関係の関係になり、下記のように表現することができる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/OneOverOne.drawio.png&quot; alt=&quot;1対1以上の関係&quot; /&gt;&lt;/p&gt;
&lt;p&gt;なんとなくこれがいまいち理解できてない気がする。&lt;br /&gt;
そして内田百閒だけだとこれは表現できない気がするので、「作家」と「出版社」というリレーションにする。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/ManyMany.drawio.png&quot; alt=&quot; 多対多の関係&quot; /&gt;&lt;/p&gt;
&lt;p&gt;作家は0以上の出版社から本を出版することができ、出版社から出版する人が0人以上いる。&lt;br /&gt;
うん、そういうこと。&lt;/p&gt;
&lt;p&gt;たぶんここら辺を理解できれば問題ないと思われる。&lt;br /&gt;
あとは結局数をこなしていけば、必然的に覚えれる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>NestJSのエラーレスポンスをカスタマイズする</title><link>https://blog.nove-b.dev/posts/customize-error-response-nestjs</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/customize-error-response-nestjs</guid><content:encoded>&lt;p&gt;&lt;code&gt;NestJS&lt;/code&gt;を用いAPI作成をしているのだが、&lt;code&gt;Response&lt;/code&gt;を共通化したいと思ったので、実装してみた。&lt;/p&gt;
&lt;h2&gt;Responseの定石&lt;/h2&gt;
&lt;p&gt;とは言えそもそも&lt;code&gt;Response&lt;/code&gt;の形をどのようにするのがいいのかわからなかったので調べた結果、&lt;a href=&quot;https://github.com/omniti-labs/jsend&quot;&gt;omniti-labs/jsend&lt;/a&gt;が参考になりそうだった。 これを参考に以下のような型で返すことにした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export interface Response {
  status: &apos;success&apos; | &apos;error&apos;;
  data: any;
  message: string[] | null;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;ValidationPipeを使用する場合、エラーレスポンスの形式はBadRequestExceptionがデフォルト&lt;/h2&gt;
&lt;p&gt;たぶんドキュメントにある通り（&lt;a href=&quot;https://docs.nestjs.com/techniques/validation&quot;&gt;Documentation | NestJS - A progressive Node.js framework&lt;/a&gt;）なので、ほとんどの場合&lt;code&gt;ValidationPipe&lt;/code&gt;を使用することになる。 そうするとエラーレスポンスの形式は&lt;code&gt;BadRequestException&lt;/code&gt;がデフォルトになるので、以下のように返ってくる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;statusCode&quot;: 400,
  &quot;message&quot;: &quot;Bad Request Exception&quot;,
  &quot;error&quot;: &quot;Bad Request&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これは意図した形ではないのでカスタマイズする必要がある。&lt;/p&gt;
&lt;h2&gt;http-exception.filter.tsを作成する&lt;/h2&gt;
&lt;p&gt;カスタマイズするにはそれ用の&lt;code&gt;Exception filters&lt;/code&gt;を用意する必要がある。
&lt;code&gt;Exception filters&lt;/code&gt;とは、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nestには例外処理レイヤーが組み込まれており、アプリケーション全体で処理されない例外をすべて処理する責任を負っています。アプリケーションのコードで処理できない例外は、このレイヤーでキャッチされ、適切なユーザーフレンドリーな応答が自動的に送信されます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;というものらしい。&lt;/p&gt;
&lt;p&gt;とにかく例外フィルターは、NestJSアプリケーションが例外をキャッチした場合に呼び出されるらしい。&lt;/p&gt;
&lt;h3&gt;実装は簡単&lt;/h3&gt;
&lt;p&gt;まずは&lt;code&gt;http-exception.filter.ts&lt;/code&gt;を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
} from &apos;@nestjs/common&apos;;
import { Response } from &apos;express&apos;;

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse&amp;lt;Response&amp;gt;();
    const status = exception.getStatus();

    response.status(status).json({
      status: &apos;error&apos;,
      data: null,
      message: (exception.getResponse() as any).message || [
        &apos;何らかのエラーが発生しました。&apos;,
      ],
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;それを&lt;code&gt;main.ts&lt;/code&gt;で読み込むだけで、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  　app.useGlobalPipes(new ValidationPipe());
＋  app.useGlobalFilters(new HttpExceptionFilter());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;エラーレスポンスが期待した形になって返却されるようになった。&lt;/p&gt;
&lt;h3&gt;余談&lt;/h3&gt;
&lt;p&gt;これを実装するときに脳死で&lt;code&gt;ChatGPT&lt;/code&gt;に質問したところ、いくら質問してもうまく実装できず、ドキュメントを見たら即解決した。 馬鹿と鋏は使いようということで。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavaScriptの配列で重複したものを削除し、ユニークな配列を作成する</title><link>https://blog.nove-b.dev/posts/remove-duplicates-javascript-array</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/remove-duplicates-javascript-array</guid><content:encoded>&lt;h2&gt;配列から重複したものを削除する&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;const numberArray = [0, 1, 1, 2, 3, 4, 4, 5];

const set = new Set(numberArray);
const newNumberArray = [...set];
console.log(newNumberArray)

// [0, 1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ただこれだけ。&lt;br /&gt;
これだけだと物足りないので説明をすると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;上記のコードは、配列numberArrayから重複を除いた値を取得し、新しい配列newNumberArrayに格納しています。具体的には、配列numberArrayをSetオブジェクトに変換し、Setオブジェクトのユニークな値を持つ新しい配列を作成しています。&lt;br /&gt;
スプレッド演算子(...)を使用して、Setオブジェクトを配列に変換していることに注目してください。これにより、新しい配列newNumberArrayが作成され、それにはnumberArrayのユニークな値が含まれます。&lt;br /&gt;
最後に、console.logを使用してnewNumberArrayをコンソールに出力しています。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;って&lt;code&gt;Chat GPT&lt;/code&gt;が説明してくれました。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>次世代フロントエンドツールViteを用いて、React+TypeScript+Tailwindcssの環境を開発する</title><link>https://blog.nove-b.dev/posts/develop-react-typescript-tailwindcss-vite</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/develop-react-typescript-tailwindcss-vite</guid><content:encoded>&lt;h2&gt;Vite（読み方はヴィート）とは？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;次世代フロントエンドツール&lt;br /&gt;
最先端をいく開発環境を構築しましょう と謳うように下記のような特徴を持つ。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;瞬時にスタートするサーバ&lt;/li&gt;
&lt;li&gt;超高速な HMR&lt;/li&gt;
&lt;li&gt;豊富な機能&lt;/li&gt;
&lt;li&gt;最適化されたビルド&lt;/li&gt;
&lt;li&gt;ユニバーサルなプラグイン&lt;/li&gt;
&lt;li&gt;完全に型定義がされている API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これを読んでもピンとこないと思うので、まずは環境構築をしてみてほしい。 そのスピードに驚くこと、間違いない。&lt;/p&gt;
&lt;h2&gt;React &amp;amp; TypeScrpt の環境構築&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ npm create vite@latest MyApp -- --template react-ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というコマンドを叩くだけで、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Need to install the following packages:
  create-vite@4.2.0
Ok to proceed? (y) y
√ Package name: ... MyApp

Scaffolding project in C:\Project\MyApp...

Done. Now run:

  cd MyApp
  npm install
  npm run dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;環境が構築される。 この時点でもう&lt;code&gt;React&lt;/code&gt;の開発環境が構築されている。&lt;/p&gt;
&lt;h2&gt;Tailwindを導入する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;react&lt;/code&gt;における&lt;code&gt;css&lt;/code&gt;の取り扱いは少し癖があり悩むところがあるので、何も考えずに&lt;code&gt;tailwind&lt;/code&gt;を導入する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで&lt;code&gt;Tailwind&lt;/code&gt;のインストールと設定ファイルを作成する。&lt;/p&gt;
&lt;h3&gt;設定ファイルに追記&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;tailwind.config.js&lt;/code&gt;を下記に変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/** @type {import(&apos;tailwindcss&apos;).Config} */
export default {
  content: [
    &quot;./index.html&quot;,
    &quot;./src/**/*.{js,ts,jsx,tsx}&quot;,
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tailwindのcssを読み込む&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;index.css&lt;/code&gt;に下記を追記する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで当初の目標としていた開発環境は構築できた。&lt;br /&gt;
後はお好みでソースフォーマット系のプラグインを入れるのも良し。&lt;br /&gt;
開発に取り掛かるのも良し。&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/vitejs/vite/tree/main/packages/create-vite&quot;&gt;https://github.com/vitejs/vite/tree/main/packages/create-vite&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://tailwindcss.com/docs/guides/vite&quot;&gt;https://tailwindcss.com/docs/guides/vite&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavaScriptで2つの配列を比較し、一致したものを取り出す方法コード</title><link>https://blog.nove-b.dev/posts/compare-extract-matching-arrays-javascript</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/compare-extract-matching-arrays-javascript</guid><content:encoded>&lt;p&gt;なんかよくやるのに、良く忘れるのでメモしておく&lt;/p&gt;
&lt;h2&gt;2つの配列を比較し一致したものを取り出したい。&lt;/h2&gt;
&lt;p&gt;特に難しいことはないのでまるっとコードを記載する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const a:string[] =[&apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;]
const b:string[] =[&apos;d&apos;, &apos;e&apos;, &apos;f&apos;, &apos;g&apos;]

// 期待値
// const c = string[] = [&apos;d&apos;]

const c = a.filter(a =&amp;gt;b.includes(a))
console.log(c)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで&lt;code&gt;c&lt;/code&gt;は期待値になる。&lt;/p&gt;
&lt;h2&gt;どっちをFilterするのか&lt;/h2&gt;
&lt;p&gt;さて、いつもよくわからなくなるのは、どっちを回すべきなのかということ。&lt;/p&gt;
&lt;p&gt;例えば今回は両者ともに&lt;code&gt;Length&lt;/code&gt;が4つだからいいけれど、例えば5と10だとどうなるのか。&lt;/p&gt;
&lt;h3&gt;実際にやってみる&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const a: string[] = [&apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos;, &apos;g&apos;, &apos;h&apos;, &apos;i&apos;, &apos;j&apos;]
const b: string[] = [&apos;b&apos;, &apos;d&apos;, &apos;f&apos;, &apos;h&apos;, &apos;i&apos;, &apos;xx&apos;]

const c = a.filter(a =&amp;gt; b.includes(a))
console.log(c)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const a: string[] = [&apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos;, &apos;g&apos;, &apos;h&apos;, &apos;i&apos;, &apos;j&apos;]
const b: string[] = [&apos;b&apos;, &apos;d&apos;, &apos;f&apos;, &apos;h&apos;, &apos;i&apos;, &apos;xx&apos;]

const c = b.filter(b =&amp;gt; a.includes(b))
console.log(c)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で試してみたところ、結果は同じになった。&lt;/p&gt;
&lt;p&gt;それぞれ、&lt;/p&gt;
&lt;p&gt;1つ目のコードではaの要素のうち、配列bにも含まれている要素を取り出した。&lt;/p&gt;
&lt;p&gt;2つ目のコードではbの要素のうち、配列aにも含まれている要素を取り出した。&lt;/p&gt;
&lt;p&gt;どちらの方法を選択しても結果は変わらないが、コードの意図を明確にするために、&lt;code&gt;xの要素のうち、配列xxにも含まれている要素を取り出した&lt;/code&gt;というのをコードで表現する必要がある。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavaScriptでUnary plus (+)を使いかっこよくNumber型に変換する</title><link>https://blog.nove-b.dev/posts/convert-number-unary-plus-javascript</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/convert-number-unary-plus-javascript</guid><content:encoded>&lt;p&gt;他人のコードを盗み見ていた時&lt;code&gt;+&apos;0&apos;&lt;/code&gt;なるコードを発見しなんだろうと調べてみた。&lt;/p&gt;
&lt;h2&gt;職人の技は目で盗め&lt;/h2&gt;
&lt;p&gt;ってよく昔気質な職業で聞かれる言葉だけど、有名で最先端の技術がオープンソースで誰でも見れる状態であるプログラミングにも言えるんじゃないかと思っている。&lt;/p&gt;
&lt;p&gt;暇さえあれば、&lt;code&gt;Github&lt;/code&gt;で他人のコードを読んでますってかっこいいので言ってみたいけど、噓になるので言えない。&lt;/p&gt;
&lt;p&gt;ただ仕事中はできる限り、時間が空いた時にコードをを読むようにしている。&lt;/p&gt;
&lt;p&gt;特に自分に関係のないプルリクなんかも追いかけるようにしている。&lt;/p&gt;
&lt;p&gt;そこで&lt;code&gt;+&apos;0&apos;&lt;/code&gt;なるコードを発見した。&lt;/p&gt;
&lt;p&gt;ぱっと見、計算をしているようだと思ったけど、どうやら違いそうなので調べてみた。&lt;/p&gt;
&lt;h2&gt;単項プラス (+) / Unary plus (+)&lt;/h2&gt;
&lt;p&gt;簡単に言うと&lt;code&gt;Number&lt;/code&gt;に変換してくれるもの。&lt;/p&gt;
&lt;p&gt;つまり&lt;code&gt;+&apos;0&apos;&lt;/code&gt;は&lt;code&gt;Number(0)と&lt;/code&gt;同様の扱い。&lt;/p&gt;
&lt;p&gt;ただ&lt;code&gt;Number()&lt;/code&gt;関数の方がぱっと見でわかりやすいので、あえて 単項演算子を使うメリットはないかもしれない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>letの仕様に関する知識を問うJavaScriptの問題</title><link>https://blog.nove-b.dev/posts/test-let-specification-javascript</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/test-let-specification-javascript</guid><content:encoded>&lt;p&gt;先日、とあるSNSを見ていたら、&lt;code&gt;JavaScript&lt;/code&gt;の問題が出されていた。&lt;/p&gt;
&lt;h2&gt;さて、ここで問題&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;let a = 10

if(true) {
    let a = 20
    console.log(a, &apos;inside&apos;)
}
console.log(a, &apos;outside&apos;)

// Q. What is the output of thie below code?
// 1. 20, &apos;inside&apos; and 20, &apos;output
// 2. 20, &apos;inside&apos; and 10, &apos;output
// 3. 10, &apos;inside&apos; and 10, &apos;output
// 4. 10, &apos;inside&apos; and 20, &apos;output
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このコードを実行した結果、どのような結果が求められるでしょう。&lt;/p&gt;
&lt;h2&gt;予想&lt;/h2&gt;
&lt;p&gt;面白そうなので実行する前に推測してみる。 まず、&lt;code&gt;If文&lt;/code&gt;が&lt;code&gt;true&lt;/code&gt;なので当然のように&lt;code&gt;If&lt;/code&gt;の中身が実行される。 ここで&lt;code&gt;Let&lt;/code&gt;の仕様の話になるのだが、Letは関数内でスコープされるので、先頭で定義された&lt;code&gt;Let&lt;/code&gt;と&lt;code&gt;If文&lt;/code&gt;の中の&lt;code&gt;Let&lt;/code&gt;は違うものだということになる。&lt;/p&gt;
&lt;p&gt;結果、&lt;code&gt;If文&lt;/code&gt;の中の&lt;code&gt;a&lt;/code&gt;は&lt;code&gt;20&lt;/code&gt;となり、&lt;code&gt;outside&lt;/code&gt;の&lt;code&gt;a&lt;/code&gt;はどこからも影響を受けずに&lt;code&gt;10&lt;/code&gt;のままになる。&lt;/p&gt;
&lt;p&gt;つまり&lt;code&gt;2&lt;/code&gt;が正解になると予想される。&lt;/p&gt;
&lt;h2&gt;結果&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[LOG]: 20,  &quot;inside&quot;
[LOG]: 10,  &quot;outside&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正しいと証明された。&lt;/p&gt;
&lt;p&gt;たぶん予想の仮説も正しいが、念のため&lt;code&gt;Chat Gpt&lt;/code&gt;に聞いてみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;このコードの出力は、以下のようになります：

20, &apos;inside&apos; and 10, &apos;output
理由は次のとおりです：

最初の行で、変数 a に値 10 を代入します。

次に、if 文の中に入りますが、条件式は true なので、ブロック内のコードが実行されます。

ブロック内で、変数 a に値 20 を代入します。これは新しいスコープ内で宣言されたローカル変数です。

console.log(a, &apos;inside&apos;) を実行すると、20, &apos;inside&apos; が出力されます。

if 文のブロックを抜けると、元のスコープに戻ります。

console.log(a, &apos;outside&apos;) を実行すると、10, &apos;outside&apos; が出力されます。これは、最初に宣言されたグローバル変数 a の値が表示されています。

したがって、最終的な出力は 20, &apos;inside&apos; と 10, &apos;outside&apos; になります。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;うん、同じことを言っているので一安心した。&lt;/p&gt;
&lt;h2&gt;Var or Const&lt;/h2&gt;
&lt;h3&gt;Var&lt;/h3&gt;
&lt;p&gt;ちなみに&lt;code&gt;Var&lt;/code&gt;で定義すると、&lt;code&gt;a&lt;/code&gt;が毎回上書きされるので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[LOG]: 20,  &quot;inside&quot;
[LOG]: 20,  &quot;outside&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;になる。&lt;/p&gt;
&lt;h3&gt;Const&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Const&lt;/code&gt;も&lt;code&gt;Let&lt;/code&gt;と同様の結果になる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>NestJsで作成したプロジェクトをAWSのLambdaにあげて動かすまでの作業ログを残しておく</title><link>https://blog.nove-b.dev/posts/deploy-nestjs-aws-lambda</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/deploy-nestjs-aws-lambda</guid><content:encoded>&lt;p&gt;個人開発プロジェクトのバックエンドを&lt;code&gt;NestJS&lt;/code&gt;で作成した。 公開したいので、&lt;code&gt;aws&lt;/code&gt;の&lt;code&gt;Lambda&lt;/code&gt;に乗せて動かしてみることにした。&lt;/p&gt;
&lt;p&gt;初めての&lt;code&gt;aws&lt;/code&gt;、いつかの自分のために記録として一挙手一投足のログを残しておくことにする。&lt;/p&gt;
&lt;h2&gt;前提&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ node -v
v18.16.0

&quot;@nestjs/cli&quot;: &quot;^9.0.0&quot;,

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;バージョンは上記の通り。&lt;/p&gt;
&lt;p&gt;で、&lt;code&gt;Docker&lt;/code&gt;の設定ファイルを諸々作ったが、使っていないので、ない前提でいく。&lt;/p&gt;
&lt;p&gt;さて、それでは進めていく。&lt;/p&gt;
&lt;h2&gt;AWSアカウントの作成&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/jp/&quot;&gt;AWSの公式ウェブサイト&lt;/a&gt;でアカウントを作成する必要がある。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ルートユーザーの E メールアドレス
AWS アカウント名
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で新規アカウント作成ができる。&lt;/p&gt;
&lt;p&gt;その後、認証コードを経て、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;パスワード
連絡先情報(英語で書けって言われたのでchatGPTに住所教えて英語にしてもらった...個人情報)
請求情報
本人確認
サポートプランを選択→無料のベーシックを選択
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/jp/register-flow/&quot;&gt;AWS アカウント作成の流れ&lt;/a&gt;を参考にすればいけるけど、意外と時間画かかったし、アカウント作成時にクレジットカードを登録することはいい気がしない。&lt;/p&gt;
&lt;p&gt;とりあえず、これでアカウント作成が完了した。&lt;/p&gt;
&lt;h2&gt;必要なパッケージのインストール&lt;/h2&gt;
&lt;p&gt;ここからは&lt;a href=&quot;https://docs.nestjs.com/faq/serverless&quot;&gt;NestJS-サーバーレス&lt;/a&gt;の公式を参考にしていく。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;説明のために、Nest
(@nestjs/platform-express完全に機能する HTTP ルーター全体を使用して起動) をサーバーレスフレームワーク (この場合は AWS
Lambda をターゲットとしています) と統合します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;公式も&lt;code&gt;aws&lt;/code&gt;で説明してくれているので、ありがたい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm i @vendia/serverless-express aws-lambda
$ npm i -D @types/aws-lambda serverless-offline
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずは上記の通り、必要なパッケージをインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &quot;@vendia/serverless-express&quot;: &quot;^4.10.4&quot;,
    &quot;aws-lambda&quot;: &quot;^1.0.7&quot;,

    &quot;@types/aws-lambda&quot;: &quot;^8.10.119&quot;,
    &quot;serverless-offline&quot;: &quot;^12.0.4&quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のようなバージョンがインストールされた。&lt;/p&gt;
&lt;p&gt;次に、&lt;code&gt;serverless.yml&lt;/code&gt;ファイルを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;service: serverless-example

plugins:
  - serverless-offline

provider:
  name: aws
  runtime: nodejs14.x

functions:
  main:
    handler: dist/main.handler
    events:
      - http:
          method: ANY
          path: /
      - http:
          method: ANY
          path: &apos;{proxy+}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;とりあえず公式をコピペしたやつ。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;service: serverless-example
↓
service: backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という風に&lt;code&gt;package.json&lt;/code&gt;に合わせた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;node.js&lt;/code&gt;のバージョンも揃えたほうがいいのかもだけど、いったんこのままで進める。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;main.ts&lt;/code&gt;を編集する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { ValidationPipe } from &apos;@nestjs/common&apos;;
import { NestFactory } from &apos;@nestjs/core&apos;;
import { SwaggerModule, DocumentBuilder } from &apos;@nestjs/swagger&apos;;
import { AppModule } from &apos;./app.module&apos;;
import { HttpExceptionFilter } from &apos;./shared/filter/http-exception.filter&apos;;
import serverlessExpress from &apos;@vendia/serverless-express&apos;;
import { Callback, Context, Handler } from &apos;aws-lambda&apos;;

let server: Handler;


async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.init();

  // Swaggerの記述とかバリデーションの記述

  （...略）

  const expressApp = app.getHttpAdapter().getInstance();
  return serverlessExpress({ app: expressApp });
}
bootstrap();


export const handler: Handler = async (
  event: any,
  context: Context,
  callback: Callback,
) =&amp;gt; {
  server = server ?? (await bootstrap());
  return server(event, context, callback);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように変更した。&lt;/p&gt;
&lt;p&gt;最後に&lt;code&gt;tsconfig.json&lt;/code&gt;の&lt;code&gt;esModuleInterop&lt;/code&gt;を有効にする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    ...
    &quot;esModuleInterop&quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、下記コマンドを打つと&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; npm run build
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;アプリケーションが実行されたら、ブラウザを開いてhttp://localhost:3000/dev/&lt;a href=&quot;%5BANY_ROUTE%5D%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%82%A8%E3%83%B3%E3%83%89%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%81%8C%E3%81%82%E3%82%8B%E5%A0%B4%E6%89%80&quot;&gt;ANY_ROUTE&lt;/a&gt;
に移動します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ということなので、やってみる。&lt;/p&gt;
&lt;p&gt;が、「このサイトにアクセスできません」になる。&lt;/p&gt;
&lt;p&gt;そもそもサーバーを立ち上げてないので動くわけがない。&lt;/p&gt;
&lt;p&gt;じゃあどうするのか。&lt;/p&gt;
&lt;p&gt;いらいらググると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npx serverless offline
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というコマンドを叩く必要がありそう。てかドキュメントにも書いてあった。&lt;/p&gt;
&lt;p&gt;そういうことなので実行してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Need to install the following packages:
  serverless@3.32.2
Ok to proceed? (y)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;なんか出たけど、&lt;code&gt;y&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;入っていないパッケージを参照するよ、ということらしい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server ready: http://localhost:3000 🚀


ANY /dev/api/v1/users/name (λ: main)
× [504] - Lambda timeout.


ANY /dev (λ: main)
× [504] - Lambda timeout.


ANY /dev/api (λ: main)
× [504] - Lambda timeout.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;なんかタイムアウトしてるけど、動いているっぽい。&lt;/p&gt;
&lt;p&gt;タイムアウトの原因をデータベースとの接続と考え、データベースを介さない、ただ文字列を返却するだけのエンドポイントを作成し、テストする。&lt;/p&gt;
&lt;p&gt;変わらず、タイムアウトした。&lt;/p&gt;
&lt;p&gt;仕方ないので、&lt;code&gt;main.ts&lt;/code&gt;をまるっとドキュメントのコピペにした。&lt;/p&gt;
&lt;p&gt;これで動けば&lt;code&gt;main.ts&lt;/code&gt;に問題がある。&lt;/p&gt;
&lt;p&gt;動かない。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;serverless.yml&lt;/code&gt;の&lt;code&gt;service: serverless-example&lt;/code&gt;を戻したら、データベースを介さないやつは動いた。&lt;/p&gt;
&lt;p&gt;そしてまた何回か繰り返すとタイムアウトした。&lt;/p&gt;
&lt;p&gt;再度起動しなおしたら、データベースの値を取得出来た。&lt;/p&gt;
&lt;p&gt;そういうわけで、&lt;code&gt;main.ts&lt;/code&gt;をもとに戻してみる。&lt;/p&gt;
&lt;p&gt;タイムアウトした。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.ts&lt;/code&gt;の原因を探る。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { NestFactory } from &apos;@nestjs/core&apos;;
import serverlessExpress from &apos;@vendia/serverless-express&apos;;
import { ValidationPipe } from &apos;@nestjs/common&apos;;
import { Callback, Context, Handler } from &apos;aws-lambda&apos;;
import { AppModule } from &apos;./app.module&apos;;
import { SwaggerModule, DocumentBuilder } from &apos;@nestjs/swagger&apos;;
import { HttpExceptionFilter } from &apos;./shared/filter/http-exception.filter&apos;;

let server: Handler;


async function bootstrap(): Promise&amp;lt;Handler&amp;gt; {
  const app = await NestFactory.create(AppModule);
  await app.init();


  // Swaggerの記述とかバリデーションの記述

  （...略）

  const expressApp = app.getHttpAdapter().getInstance();
  return serverlessExpress({ app: expressApp });
}


export const handler: Handler = async (
  event: any,
  context: Context,
  callback: Callback,
) =&amp;gt; {
  server = server ?? (await bootstrap());
  return server(event, context, callback);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これにしたら動いた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bootstrap();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;の実行場所が問題だったっぽい。&lt;/p&gt;
&lt;p&gt;というわけで&lt;code&gt;service: serverless-example&lt;/code&gt;を&lt;code&gt;service: backend&lt;/code&gt;に戻した。&lt;/p&gt;
&lt;p&gt;これでサーバーレスのテストをローカルでできた。&lt;/p&gt;
&lt;p&gt;追記:2023年6月30日&lt;/p&gt;
&lt;p&gt;ローカルでテストする際に、timeoutが頻発するので調べたところ、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;プロバイダーの下にタイムアウトを追加します。ラムダのタイムアウトの最大値は 900 秒です。実行時間に応じて 30 秒などに設定し、何が起こるかを確認してください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という&lt;a href=&quot;https://stackoverflow.com/questions/60588274/frequent-timeout-with-app-using-serverless-framework-aws-lambda-gateway-expre&quot;&gt;記事&lt;/a&gt;を見つけた。&lt;/p&gt;
&lt;p&gt;実際に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;provider:
  name: aws
  runtime: nodejs18.x
  timeout: 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;にしたところ、タイムアウトしなくなった。&lt;/p&gt;
&lt;h2&gt;AWSにデプロイ&lt;/h2&gt;
&lt;p&gt;次に&lt;code&gt;aws&lt;/code&gt;にデプロイする必要があると思っている。&lt;/p&gt;
&lt;p&gt;その為に何をすればいいのか調べて実行していく。&lt;/p&gt;
&lt;p&gt;もしかして、コンソールに入り関数を作成し、&lt;code&gt;zip&lt;/code&gt;ファイルをアップロードすればいいだけ？&lt;/p&gt;
&lt;p&gt;そんな気がするのでそれでやってみる。&lt;/p&gt;
&lt;h3&gt;Lambdaの関数作成&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;AWS Lambda&lt;/code&gt; ダッシュボードの 関数を作成をクリックする。&lt;/p&gt;
&lt;p&gt;一から作成を選択し、関数名を決める。&lt;/p&gt;
&lt;p&gt;次に、関数の記述に使用する言語を選択します。ということで&lt;code&gt;Node.js 14.x&lt;/code&gt;を選択した。理由してはローカルでサーバレスのテストをした時のランタイムに&lt;code&gt;Node.js 14.x&lt;/code&gt;を使用したので。&lt;/p&gt;
&lt;p&gt;よく考えたら&lt;code&gt;18&lt;/code&gt;で作ってるんだけど、今回は気にしないことにする。&lt;/p&gt;
&lt;p&gt;（※このログを書いた後に&lt;code&gt;Node.js 18.x&lt;/code&gt;にした。）&lt;/p&gt;
&lt;p&gt;アーキテクチャっていうのは&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x86_64
arm64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のふたつがあってよくわからないので、&lt;code&gt;x86_64&lt;/code&gt;を選択した。&lt;/p&gt;
&lt;p&gt;一応調べてみると下記に詳しい。&lt;/p&gt;
&lt;p&gt;https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/foundation-arch.html&lt;/p&gt;
&lt;p&gt;どうやら値段が違うようで、&lt;code&gt;arm64&lt;/code&gt;の方が安そうな気がする。&lt;/p&gt;
&lt;p&gt;ということで、&lt;code&gt;arm64&lt;/code&gt;を選択することにした。&lt;/p&gt;
&lt;p&gt;（※このログを書いた後に&lt;code&gt;x86_64&lt;/code&gt;にした。）&lt;/p&gt;
&lt;p&gt;で、関数の作成を終了する。&lt;/p&gt;
&lt;h3&gt;Zip のアップロード&lt;/h3&gt;
&lt;p&gt;作成後遷移したページでコードタブをクリックし、&lt;code&gt;npm run build&lt;/code&gt;で作成された&lt;code&gt;dist&lt;/code&gt;フォルダを&lt;code&gt;zip&lt;/code&gt;化し、アップロードする。&lt;/p&gt;
&lt;h3&gt;API Gatewayの構築&lt;/h3&gt;
&lt;p&gt;次に &lt;code&gt;API Gateway&lt;/code&gt;のダッシュボードにいき、&lt;code&gt;HTTP API&lt;/code&gt;の構築を行う。&lt;/p&gt;
&lt;p&gt;統合で先ほど作成した関数を選択する。&lt;code&gt;API&lt;/code&gt;名は特に決まりないよう。&lt;/p&gt;
&lt;p&gt;次にルート設定でリソースパスを&lt;code&gt;/{proxy+}&lt;/code&gt;に変更する。&lt;/p&gt;
&lt;p&gt;最後に「ステージを設定」は変更せず、そのまま 作成をする。&lt;/p&gt;
&lt;p&gt;どうやら次に権限の設定があるらしい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;API Gateway&lt;/code&gt;
コンソールで、先ほど作成した API の詳細ページを開く。左のタブから、「統合」を選択し、ルートの統合の詳細を見る。&lt;/p&gt;
&lt;p&gt;アクセス許可を呼び出すのポリシーステートメント例の、&lt;code&gt;source-arn&lt;/code&gt;内の文字列をコピーしておく。&lt;/p&gt;
&lt;p&gt;また&lt;code&gt;Lambda&lt;/code&gt;に戻り、設定→アクセス権限、リソースベースポリシー内の アクセス権限を追加をクリック。&lt;/p&gt;
&lt;p&gt;AWSのサービス を選択し、下の画像のように入力して保存します。ソースARNに先ほどの文字列を追加。&lt;/p&gt;
&lt;p&gt;アクションは&lt;code&gt;lambda:InvokeFunction&lt;/code&gt;を選択する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;URL&lt;/code&gt;にアクセスするが、&lt;code&gt;{&quot;message&quot;:&quot;Internal Server Error&quot;}&lt;/code&gt;になる。謎が深い。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;serverless.yml&lt;/code&gt;にならい、&lt;code&gt;dist/main.handler&lt;/code&gt;にハンドラを変更したが変わらない。&lt;/p&gt;
&lt;p&gt;検索すると&lt;a href=&quot;https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/http-api-troubleshooting-lambda.html&quot;&gt;HTTP API Lambda 統合に関する問題のトラブルシューティング&lt;/a&gt;のページにたどり着いたので、見ていく。&lt;/p&gt;
&lt;p&gt;最近気が付いたけど、結局公式見るのが一番早い。&lt;/p&gt;
&lt;p&gt;急がば回れ、誰が考えたか知らないけど、先人の知恵ほど偉大なものはない。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;内部サーバーエラーのトラブルシューティングを行うには、ログ形式に $context.integrationErrorMessage ログ記録変数を追加し、HTTP
API のログを表示します。これを達成するには、次の操作を行います。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という操作をするらしいけど、何言ってるのか全くわからない。&lt;/p&gt;
&lt;p&gt;とりあえず、下記公式の通り進める。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CloudWatch コンソール (https://console.aws.amazon.com/cloudwatch/) を開きます。

[ロググループ] を選択します。

[ロググループの作成] を選択します。

ロググループ名を入力し、[作成] を選択します。

ロググループの Amazon リソースネーム (ARN) を書き留めます。ARN 形式は、arn:aws:logs:region: account-id:log-group:log-group-name です。HTTP API のアクセスのログ記録を有効にするには、ロググループ ARN が必要です。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;やろうと思ったけど、既にグループがあったので、「ロググループの Amazon リソースネーム (ARN) を書き留めます。」だけやった。&lt;/p&gt;
&lt;p&gt;次に下記の公式通りの手順を行う。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://console.aws.amazon.com/apigateway で API Gateway コンソールにサインインします。

HTTP API を選択します。

[モニタリング] で、[ログ記録] を選択します。

API のステージを選択します。

[編集] を選択し、アクセスログを有効にします。

[Log destination] (ログの送信先) で、前のステップで作成したロググループの ARN を入力します。

[ログの形式] で、[CLF] を選択します。

ログ形式の末尾に $context.integrationErrorMessage を追加します。

[保存] を選択します。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Network Failureでできない（※ 今思えば、タイムアウトしていた？）。謎が深い。&lt;/p&gt;
&lt;p&gt;諦めて、ロググループにあった既存のグループのログを見てみると、&lt;code&gt;@nestjs/core&lt;/code&gt;モジュールを見つけることができない的なことが書いてある。&lt;/p&gt;
&lt;p&gt;それをchat
GPTに聞くと&lt;code&gt;node_modules&lt;/code&gt;もアップロードしろという返答が返ってきたので試してみる。&lt;/p&gt;
&lt;p&gt;重すぎてあげられない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;s３&lt;/code&gt;を使えとのこと。&lt;/p&gt;
&lt;p&gt;そういうことであればと思うのだが、お金発生しているのか不安になる。&lt;/p&gt;
&lt;p&gt;調べるとAWS 無料利用枠があるっぽいので行ってみる。&lt;/p&gt;
&lt;p&gt;アップロードした&lt;code&gt;s3&lt;/code&gt;のデータを&lt;code&gt;Lambda&lt;/code&gt;にアップロードする。&lt;/p&gt;
&lt;p&gt;リレージョンが異なるので無理っぽい ??&lt;/p&gt;
&lt;p&gt;よくよく見ると、&lt;code&gt;Lambda&lt;/code&gt;のリレージョンシドニーでやってた。&lt;/p&gt;
&lt;p&gt;東京に作り直す。&lt;/p&gt;
&lt;p&gt;東京に作り直したけど、&lt;code&gt;s3&lt;/code&gt;のファイルサイズが大きすぎると怒られた。&lt;/p&gt;
&lt;p&gt;たぶん、&lt;code&gt;node_modules&lt;/code&gt;に&lt;code&gt;devDependencies&lt;/code&gt;も含まれているからなので、&lt;code&gt;Dependencies&lt;/code&gt;
のみのパッケージをインストールする&lt;code&gt;npm install --production&lt;/code&gt;コマンドで&lt;code&gt;node_modules&lt;/code&gt;を作成する。&lt;/p&gt;
&lt;p&gt;ついでに&lt;code&gt;zip&lt;/code&gt;ファイルに&lt;code&gt;package.json&lt;/code&gt;と&lt;code&gt;package.look.json&lt;/code&gt;も入れてみる(結果的に正しかった)。&lt;/p&gt;
&lt;p&gt;でも無理で、色々試した結果、&lt;code&gt;dist&lt;/code&gt;フォルダがダメだということに気が付いた。&lt;/p&gt;
&lt;p&gt;つまり、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;package.json&lt;/li&gt;
&lt;li&gt;node_modules&lt;/li&gt;
&lt;li&gt;main.ts etc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という構成にしなければならないことに気が付いた。&lt;/p&gt;
&lt;p&gt;かつ、&lt;code&gt;bcrypt&lt;/code&gt;が使用できないいっぽいので&lt;code&gt;bcryptjs&lt;/code&gt;を使用するこにした。&lt;/p&gt;
&lt;p&gt;で、あげたら今度はタイムアウトになった。 すこしづつ進んでいるが、まだできない。&lt;/p&gt;
&lt;p&gt;基本設定でタイムアウトを&lt;code&gt;30秒&lt;/code&gt;にした。&lt;/p&gt;
&lt;p&gt;次に秘密鍵のエラーが出た。
&lt;code&gt;JWT&lt;/code&gt;の秘密鍵を&lt;code&gt;env&lt;/code&gt;で管理しているのだからそりゃそうだ。&lt;/p&gt;
&lt;p&gt;環境変数を設定すると、ログからエラーが消えたが、&lt;code&gt;{&quot;message&quot;:&quot;Service Unavailable&quot;}&lt;/code&gt;という結果になる。&lt;/p&gt;
&lt;p&gt;新しい。&lt;/p&gt;
&lt;p&gt;ログを見ると&lt;code&gt;Unable to connect to the database&lt;/code&gt;ということなのでデータベースに接続てきていないらしい。&lt;/p&gt;
&lt;p&gt;ローカルの&lt;code&gt;MySQL&lt;/code&gt;に接続できないだろし、これを機に&lt;code&gt;RDS&lt;/code&gt;の構築をすることにした。&lt;/p&gt;
&lt;h2&gt;RDSの作成&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Amazon RDS コンソールの [データベースページ] を開いて、[データベースの作成] を選択します。
[標準作成] オプションを選択したままにし、[エンジンのオプション] で [MySQL] を選択します。
[テンプレート] で、[無料利用枠] を選択します。
[設定] で、[DB インスタンス識別子] に ****** を入力します。
以下を実行して、ユーザー名とパスワードを設定します。
[認証情報の設定] では、[マスターユーザー名] の設定を admin のままにします。
[マスターパスワード] には、データベースにアクセスするためのパスワードを入力して確認します。
次の操作を実行して、データベース名を指定します。
残りのデフォルトオプションはすべて選択したままにして、[追加設定] ペインまで下にスクロールします。
このペインを展開し、[最初のデータベース名] として ****** を入力します。
残りのデフォルトオプションはすべて選択したままにして、[データベースの作成] を選択します。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;やり方は公式に詳しかったのでそのようにした。&lt;/p&gt;
&lt;p&gt;同時にLambdaの環境変数を編集した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DATABASE_HOST:*****.rds.amazonaws.com(RDSのエンドポイント)
DATABASE_NAME	******
DATABASE_PASSWORD	******
DATABASE_PORT	3306  ← よくわからないけどローカルで設定していた数字のまま
DATABASE_USER	******
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でエンドポイントを叩いたが、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&quot;message&quot;:&quot;Service Unavailable&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;うまくいかない。&lt;/p&gt;
&lt;p&gt;色々と調べてみると、&lt;code&gt;IMAロール&lt;/code&gt;と&lt;code&gt;VPC&lt;/code&gt;の設定が必要とのこと。&lt;/p&gt;
&lt;p&gt;https://qiita.com/kobayashi_0226/items/d8f97c652873d80b1367&lt;/p&gt;
&lt;p&gt;上記記事を見つつ、ぽちぽちやっているとできた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&quot;status&quot;:&quot;success&quot;,&quot;data&quot;:{&quot;newComment&quot;:[]},&quot;message&quot;:null}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ただ、どうも接続できないエンドポイントがある。&lt;/p&gt;
&lt;p&gt;調べてみると&lt;code&gt;NestJS&lt;/code&gt;の&lt;code&gt;synchronize&lt;/code&gt;オプションを&lt;code&gt;True&lt;/code&gt;にしたままだったのが原因っぽい。&lt;/p&gt;
&lt;p&gt;次は踏み台サーバーを作成し、&lt;code&gt;RDS&lt;/code&gt;の中身を見てみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavaScriptにおけるcount++と++countの違いについて調べてみた</title><link>https://blog.nove-b.dev/posts/javascript-count-vs-pluspluscount</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/javascript-count-vs-pluspluscount</guid><content:encoded>&lt;p&gt;なんとなく怪しいので、&lt;code&gt;count++&lt;/code&gt;と&lt;code&gt;++count&lt;/code&gt;について調べてメモしておく。&lt;/p&gt;
&lt;h2&gt;実行してみる&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;const pre = () =&amp;gt; {
    let count = 0
    console.log(++count, &apos;pre&apos;)
}

const post = () =&amp;gt; {
    let count = 0
    console.log(count++, &apos;post&apos;)
}

pre() // [LOG]: 1,  &quot;pre&quot;
post() // [LOG]: 0,  &quot;post&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;前置インクリメント演算子&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pre()&lt;/code&gt;の方はcountの値が1増えてから更新された値が返されるので、1が出力される。&lt;/p&gt;
&lt;h2&gt;後置インクリメント演算子&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;post()&lt;/code&gt;の方はcount の現在の値を返し、その後に1を加算するので、0が出力される。&lt;/p&gt;
&lt;p&gt;それぞれ適宜場合を見て使用する必要がある。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>AWSのRDSに接続したいけど踏み台サーバーでうまく接続できなかったので、RDSをパブリックサブネットに置きHeidiSQLで接続を試みる</title><link>https://blog.nove-b.dev/posts/aws-rds-heidisql-public-subnet</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/aws-rds-heidisql-public-subnet</guid><content:encoded>&lt;p&gt;&lt;code&gt;aws&lt;/code&gt;の&lt;code&gt;RDS&lt;/code&gt;に&lt;code&gt;EC2&lt;/code&gt;を踏み台サーバーとしてアクセスしようとしたけど、うまくいかなかったので、&lt;code&gt;RDS&lt;/code&gt;を一時的にパブリックサブネットにしたうえでアクセスしてみる。
&lt;code&gt;aws&lt;/code&gt;知識0だがパブリックサブネットに変更するのは問題がありそうな気がするけど、テスト環境なのでやってみる。&lt;/p&gt;
&lt;h2&gt;パブリックアクセスを有効にする&lt;/h2&gt;
&lt;p&gt;RDS &amp;gt; データベース &amp;gt; 該当DB名に行き、変更ボタンをクリックする。&lt;/p&gt;
&lt;p&gt;接続の追加設定を選択し、パブリックアクセス可能にチェックを入れるて保存する。&lt;/p&gt;
&lt;h2&gt;セキュリティグループの変更&lt;/h2&gt;
&lt;h3&gt;ポート3306の解放&lt;/h3&gt;
&lt;p&gt;接続とセキュリティ &amp;gt; VPC セキュリティグループをクリックする。&lt;/p&gt;
&lt;p&gt;インバウンドルール &amp;gt; インバウンドのルールを編集をクリックする。&lt;/p&gt;
&lt;p&gt;タイプでMYSQL/Auroraを選択する。&lt;/p&gt;
&lt;p&gt;ソース でMyIPを選択すると今使用しているパソコンのIPアドレスでの接続に制限できる。&lt;/p&gt;
&lt;h2&gt;接続してみる&lt;/h2&gt;
&lt;p&gt;接続できない。&lt;/p&gt;
&lt;h2&gt;セキュリティグループを追加してみる&lt;/h2&gt;
&lt;p&gt;全部公開できそうなセキュリティグループを作成し、そちらを適用させる。&lt;/p&gt;
&lt;h3&gt;インバウンドグループ&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;IP バージョン&lt;/th&gt;
&lt;th&gt;タイプ&lt;/th&gt;
&lt;th&gt;プロトコル&lt;/th&gt;
&lt;th&gt;ポート範囲&lt;/th&gt;
&lt;th&gt;ソース&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;IPv4&lt;/td&gt;
&lt;td&gt;すべてのトラフィック&lt;/td&gt;
&lt;td&gt;すべて&lt;/td&gt;
&lt;td&gt;すべて&lt;/td&gt;
&lt;td&gt;0.0.0.0/0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;アウトバウンドルール&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;IP バージョン&lt;/th&gt;
&lt;th&gt;タイプ&lt;/th&gt;
&lt;th&gt;プロトコル&lt;/th&gt;
&lt;th&gt;ポート範囲&lt;/th&gt;
&lt;th&gt;送信先&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;IPv4&lt;/td&gt;
&lt;td&gt;すべてのトラフィック&lt;/td&gt;
&lt;td&gt;すべて&lt;/td&gt;
&lt;td&gt;すべて&lt;/td&gt;
&lt;td&gt;0.0.0.0/0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;接続してみる&lt;/h2&gt;
&lt;p&gt;これでクライアントツールで&lt;code&gt;RDS&lt;/code&gt;にアクセスすることができた。&lt;/p&gt;
&lt;p&gt;これでとりあえずテーブルの中身を見たいという課題は解決できた。&lt;/p&gt;
&lt;p&gt;次は踏み台サーバーを設置し、正規の流れでアクセスできるようにしたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>LambdaにのせたNestJSでapp.enableCors();を指定しているのにCORSエラーがでたので解消するまでを記録した</title><link>https://blog.nove-b.dev/posts/lambda-nestjs-cors-error</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/lambda-nestjs-cors-error</guid><content:encoded>&lt;h2&gt;POSTメソッドを叩いたらエラーが出た&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;NestJS&lt;/code&gt;で作成した&lt;code&gt;API&lt;/code&gt;を&lt;code&gt;Lambdaに乗せ&lt;/code&gt;、&lt;code&gt;API Gateway&lt;/code&gt;でエンドポイントを作成した。&lt;/p&gt;
&lt;p&gt;フロントエンドは&lt;code&gt;NextJS&lt;/code&gt;で作成し、&lt;code&gt;Vercel&lt;/code&gt;にデプロイした。&lt;/p&gt;
&lt;p&gt;で、無事画面表示と&lt;code&gt;Get&lt;/code&gt;が成功し、得たいデータが表示された。&lt;/p&gt;
&lt;p&gt;ただ&lt;code&gt;POST API&lt;/code&gt;を叩いた時&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Access to fetch at &apos;https://xxxxxx.amazonaws.com/api/v1/login&apos; from origin &apos;https://xxxxxxx.vercel.app&apos; has been blocked by CORS policy: Response to preflight request doesn&apos;t pass access control check: It does not have HTTP ok status.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーがでた。&lt;/p&gt;
&lt;h3&gt;CORSは有効にしている&lt;/h3&gt;
&lt;p&gt;上のエラーを読む限り、&lt;code&gt;CORS&lt;/code&gt;に関するエラーということがわかる。&lt;/p&gt;
&lt;p&gt;ただ&lt;code&gt;NestJS&lt;/code&gt;の方で&lt;code&gt;CORS&lt;/code&gt;は有効にしている。&lt;/p&gt;
&lt;p&gt;該当のソースは下記の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const app = await NestFactory.create(AppModule);
  await app.init();

  app.useGlobalPipes(new ValidationPipe());
  app.useGlobalFilters(new HttpExceptionFilter());

  // CORSの有効化
  app.enableCors();

  const expressApp = app.getHttpAdapter().getInstance();
  return serverlessExpress({ app: expressApp });

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Get&lt;/code&gt;はできているし、&lt;code&gt;CORS&lt;/code&gt;もきっと有効に出来ているに違いない。&lt;/p&gt;
&lt;p&gt;じゃあ、なんで&lt;code&gt;POST&lt;/code&gt;はできないの？&lt;/p&gt;
&lt;p&gt;沼に落ちた。&lt;/p&gt;
&lt;h2&gt;解決方法&lt;/h2&gt;
&lt;p&gt;ちなみに同じ状況に陥った人のために先に解決方法を載せておくと、下記のように&lt;code&gt;await app.init();&lt;/code&gt;の位置が肝だった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const app = await NestFactory.create(AppModule);
app.enableCors()
app.useGlobalPipes(new ValidationPipe());
app.useGlobalFilters(new HttpExceptionFilter());
await app.init();
const expressApp = app.getHttpAdapter().getInstance();
return serverlessExpress({ app: expressApp });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;理由はいまいちわからないので、ここには記載しない。&lt;/p&gt;
&lt;h2&gt;ここに至るまでの道のり（読むかは自己判断で）&lt;/h2&gt;
&lt;p&gt;上記の通りで解決するので後はただの蛇足。&lt;/p&gt;
&lt;p&gt;ただ自分がどのように解決に至ったかをログとして残しておく。&lt;/p&gt;
&lt;p&gt;見る価値があるかはわからない。&lt;/p&gt;
&lt;h2&gt;API GatewayでCORSを設定する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;AWS&lt;/code&gt;のほうでも同様に&lt;code&gt;CORS&lt;/code&gt;を設定する必要があるのか？　という思いで設定した。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;API Gateway &amp;gt; CORS&lt;/code&gt;で設定にいき、下記の通り設定した。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Access-Control-Allow-Origin&lt;/th&gt;
&lt;th&gt;*&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Allow-Headers&lt;/td&gt;
&lt;td&gt;content-type,authorization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Allow-Methods&lt;/td&gt;
&lt;td&gt;GET,POST,PUT,DELETE,OPTIONS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;がエラーが変わらないので、&lt;a href=&quot;https://zenn.dev/myonie/articles/9b5178aa91d7e0&quot;&gt;ReactからCognitoで認証認可されたAPI Gatewayを呼び出す&lt;/a&gt;を参考に下記の通り変更した。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Access-Control-Allow-Origin&lt;/th&gt;
&lt;th&gt;https://vote-for-name.vercel.app&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Allow-Headers&lt;/td&gt;
&lt;td&gt;content-type,authorization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Allow-Methods&lt;/td&gt;
&lt;td&gt;*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Max-Age&lt;/td&gt;
&lt;td&gt;-1秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Allow-Credentials&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;に変更したが意味がなかった。&lt;/p&gt;
&lt;p&gt;※ てかNestJSでCORSを設定しなくてもここで設定できる？（未確認）それならソースビルドしなくていいので負担が減りそう。いつか試してみたい。&lt;/p&gt;
&lt;p&gt;##　NestJS側でCORS有効化の書き方を変更してみる&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const app = await NestFactory.create(AppModule);
  await app.init();

  app.useGlobalPipes(new ValidationPipe());
  app.useGlobalFilters(new HttpExceptionFilter());

 app.use((req: any, res: any, next: any) =&amp;gt; {
    res.header(&apos;Access-Control-Allow-Origin&apos;, &apos;*&apos;);
    res.header(&apos;Access-Control-Allow-Headers&apos;, &apos;Content-Type,  Authorization&apos;);
    res.header(&apos;Access-Control-Allow-Methods&apos;, &apos;*&apos;);
    next();
  });

  const expressApp = app.getHttpAdapter().getInstance();
  return serverlessExpress({ app: expressApp });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;にしたみたけど変わらず、エラーが出続ける。&lt;/p&gt;
&lt;p&gt;そもそも&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; app.use((req: any, res: any, next: any) =&amp;gt; {
    res.header(&apos;Access-Control-Allow-Origin&apos;, &apos;*&apos;);
    res.header(&apos;Access-Control-Allow-Headers&apos;, &apos;Content-Type,  Authorization&apos;);
    res.header(&apos;Access-Control-Allow-Methods&apos;, &apos;*&apos;);
    next();
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これを追加した時点で、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; app.enableCors()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を削除してるけど、これも必要なんじゃないかということで復活してみる。&lt;/p&gt;
&lt;p&gt;が、変わらず無理のまま。&lt;/p&gt;
&lt;p&gt;エラーで&lt;code&gt;preflight&lt;/code&gt;がどうこう言っているので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (&apos;OPTIONS&apos; == req.method) {
    res.send(204);
}
else {
    next();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/57640113/cors-it-does-not-have-http-ok-status&quot;&gt;CORS &quot;It does not have HTTP ok status.&quot;&lt;/a&gt;上記を追加してみた。&lt;/p&gt;
&lt;p&gt;ができない。&lt;/p&gt;
&lt;p&gt;同様に、上記サイトを参考に&lt;code&gt;app.options(&apos;*&apos;, cors())&lt;/code&gt;を追加し見たが、そんな型存在しないともっと前の段階で怒られた。&lt;/p&gt;
&lt;h2&gt;Githubで他の人のソースを探る&lt;/h2&gt;
&lt;p&gt;どうやら順番が違うことに気が付いて無事解決。&lt;/p&gt;
&lt;p&gt;諦めずに取り組んで良かった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>エックスサーバーで借りたドメインのサブドメイン使用し、Vercelにカスタムドメインを設定する</title><link>https://blog.nove-b.dev/posts/xserver-subdomain-vercel-custom-domain</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/xserver-subdomain-vercel-custom-domain</guid><content:encoded>&lt;p&gt;過去にドメイン関係のトラブルに見舞われたことがある。&lt;/p&gt;
&lt;p&gt;ドメイン関係のトラブルはクリティカルなので非常にそわそわする。&lt;/p&gt;
&lt;p&gt;そんな時エックスサーバーのサポートが手厚く、以来、レンタルサーバー・ドメインはエックスサーバーにお世話になっている。&lt;/p&gt;
&lt;p&gt;そのため、今回新たに作成したWebサービスもエックスドメインで借りたドメインのサブドメインに紐づけることにした。&lt;/p&gt;
&lt;p&gt;サーバーは&lt;code&gt;Vercel&lt;/code&gt;に浮気した。&lt;/p&gt;
&lt;h2&gt;エックスサーバーでサブドメインを作成する&lt;/h2&gt;
&lt;p&gt;前述したとおり、エックスサーバーは非常にサポートが充実している。&lt;/p&gt;
&lt;p&gt;なので、サブドメインの作成を改めてここに書く必要なんてない。&lt;/p&gt;
&lt;p&gt;公式が最も正しく、詳しい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.xserver.ne.jp/manual/man_domain_subdomain_setting.php&quot;&gt;サブドメイン設定&lt;/a&gt;を参考にサブドメインを作成する。&lt;/p&gt;
&lt;h2&gt;Vercelに紐づける&lt;/h2&gt;
&lt;p&gt;大前提としてVercelにプロジェクトが既にあるという体で進めていく。&lt;/p&gt;
&lt;h3&gt;Vercel管理画面&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Settingsタブ&lt;/code&gt;をクリックし&lt;code&gt;Project Settingsページ&lt;/code&gt;に遷移する。&lt;/p&gt;
&lt;p&gt;サイドナビの&lt;code&gt;Domains&lt;/code&gt;をクリックし、&lt;code&gt;input&lt;/code&gt;に作成したサブドメインを入力し&lt;code&gt;Add&lt;/code&gt;ボタンをクリックする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://&lt;/code&gt;は不要なので注意。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Invalid Configuration&lt;/code&gt;という警告がでるが、&lt;code&gt;Vercel&lt;/code&gt;に認識はしてもらった。&lt;/p&gt;
&lt;h2&gt;エックスサーバー管理画面&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;DNSレコード設定&lt;/code&gt;をクリックし&lt;code&gt;DNSレコード一覧&lt;/code&gt;から対象ドメインを選択し変更ボタンをクリックする。&lt;/p&gt;
&lt;p&gt;ここでDNSレコードが設定できるので、下記のように設定する。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;項目&lt;/th&gt;
&lt;th&gt;値&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ホスト名&lt;/td&gt;
&lt;td&gt;[サブドメイン名]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;種別&lt;/td&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内容&lt;/td&gt;
&lt;td&gt;cname.vercel-dns.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;優先度&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;上記設定を追加し、しばらく待つ。&lt;/p&gt;
&lt;h3&gt;Vercelサービスに割り当てられるドメイン&lt;/h3&gt;
&lt;p&gt;サービスを作成すると独自に、割り当てられるドメインがある。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;service-name.vercel.app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のようなやつ。&lt;/p&gt;
&lt;p&gt;独自ドメインを設定した暁には、このドメインをリダイレクトするのがいいと思われる。&lt;/p&gt;
&lt;p&gt;先ほど設定したドメインの下にこのドメインがあると思うので、&lt;code&gt;Editボタン&lt;/code&gt;をクリックすると、&lt;code&gt;Redirect to&lt;/code&gt;というセレクトボックスがある。&lt;/p&gt;
&lt;p&gt;そこに先ほど設定したドメインが表示されると思うので、選択し、&lt;code&gt;Save&lt;/code&gt;すればリダイレクトが完了する。&lt;/p&gt;
&lt;p&gt;もしこの設定を行わないとGoogleのクローラーはどのように判断するのだろうか。&lt;/p&gt;
&lt;p&gt;コピーサイトと間違われることもありそうなので、リダイレクトはしたほうがいい。&lt;/p&gt;
&lt;p&gt;ただサブドメインを使用する場合は、友人に共有したいけどメインドメインがばれるのが嫌という人も多いだろう。&lt;/p&gt;
&lt;p&gt;その場合はシェア用に取っておくのも有りかもしれない。&lt;/p&gt;
&lt;h2&gt;Vercel管理画面にて、Valid Configuration・Assigned to main&lt;/h2&gt;
&lt;p&gt;5分くらいで&lt;code&gt;Valid Configuration&lt;/code&gt;が上記のような表記に変更された。&lt;/p&gt;
&lt;p&gt;実際に設定したドメインを訪れると作成したサービスにアクセスすることができた。&lt;/p&gt;
&lt;p&gt;キャッシュを消さないと見れないかもしれないので注意が必要。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>ColとRow、そして行と列は縦横一体どっちを向いているのかを完全に理解した。</title><link>https://blog.nove-b.dev/posts/col-row-understood</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/col-row-understood</guid><content:encoded>&lt;h2&gt;Row（行）&lt;/h2&gt;
&lt;p&gt;横方向を表す。 つまり、テーブルや行列などで、水平方向に並んでいる要素の集まり。&lt;/p&gt;
&lt;h2&gt;Col（列）&lt;/h2&gt;
&lt;p&gt;縦方向を表す。 つまり、テーブルや行列などで、垂直方向に並んでいる要素の集まり。&lt;/p&gt;
&lt;h2&gt;疑問&lt;/h2&gt;
&lt;p&gt;要素の集まりというのが肝な気がする。 それを考えると色々しっくりきた。 どうしっくりきたかの言語化はできない。&lt;/p&gt;
&lt;p&gt;ので、以前の疑問を解消する形で言語化に近づけてみる。&lt;/p&gt;
&lt;h3&gt;4列シート&lt;/h3&gt;
&lt;p&gt;夜行バスの４列シートは横並びに４つシートが並んでいるという意味なので、４行シートではないのかという疑問が浮かんだ。&lt;/p&gt;
&lt;p&gt;ただ１番前から見た時、垂直方向に並んでいる要素の集まりが４つある、つまり４列になる。&lt;/p&gt;
&lt;h3&gt;rowSpan&lt;/h3&gt;
&lt;p&gt;これは&lt;code&gt;HTML&lt;/code&gt;の&lt;code&gt;Table&lt;/code&gt;に関する属性で垂直方向のセルを結合する。いや垂直方向に結合するなら&lt;code&gt;ColSpan&lt;/code&gt;ではという疑問が浮かんだが、横並びの集まりを垂直方向に結合するので&lt;code&gt;RowSpan&lt;/code&gt;で正しい。&lt;/p&gt;
&lt;h2&gt;覚え方&lt;/h2&gt;
&lt;p&gt;ぱっと思い浮かばないので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Row Gyo Yoko 🤙
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というラップっぽく覚えることにした。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>CORSでクロスオリジンの設定をする際に、なんでドメインを絞り込む必要があるのか浅く理解した</title><link>https://blog.nove-b.dev/posts/cors-why-domain-restriction</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/cors-why-domain-restriction</guid><content:encoded>&lt;h2&gt;本記事は不確かな情報が多く含まれる可能性がある&lt;/h2&gt;
&lt;p&gt;本職はフロントエンドエンジニアで、基本的に取得した情報に色をつけ表示させることで会社内での居場所を維持してきた。&lt;/p&gt;
&lt;p&gt;ただ最近個人開発でバックエンドに触れることが増えセキュリティにも興味が出てきた。&lt;/p&gt;
&lt;p&gt;ただ、まだまだ浅い理解しかない。&lt;/p&gt;
&lt;p&gt;何が言いたいかというと、この記事は不確かな情報を含んでいる可能性があるということ。&lt;/p&gt;
&lt;h2&gt;浅く理解したくなったきっかけ&lt;/h2&gt;
&lt;p&gt;最近、個人開発ということで&lt;code&gt;NestJS&lt;/code&gt;で&lt;code&gt;API&lt;/code&gt;を作成した、&lt;/p&gt;
&lt;p&gt;作成した&lt;code&gt;API&lt;/code&gt;を&lt;code&gt;Lambda&lt;/code&gt;に乗せ、カスタムドメインを設定せずに使用している。&lt;/p&gt;
&lt;p&gt;そのため、&lt;code&gt;CORS&lt;/code&gt;のクロスオリジンを指定する必要があった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NestJS&lt;/code&gt;は一行ですべてのドメインに対し&lt;code&gt;CORS&lt;/code&gt;を許可することができる。&lt;/p&gt;
&lt;p&gt;開発環境ではそれでいいが、本番で運営するにあたり、許可するドメインを指定する必要がありそうだということを調べて知った。&lt;/p&gt;
&lt;p&gt;しかし、なぜ？ という疑問が生じた。&lt;/p&gt;
&lt;p&gt;いくら絞ったところで&lt;code&gt;curl&lt;/code&gt;コマンドで叩けるので別に絞る必要がないのでは？&lt;/p&gt;
&lt;p&gt;という疑問を解決するために調べてみた。&lt;/p&gt;
&lt;h2&gt;CORSを指定しないことで考えられるセキュリティリスク&lt;/h2&gt;
&lt;h3&gt;クロスサイトリクエストフォージェリ（CSRF）攻撃&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CSRF&lt;/code&gt;は悪意のある攻撃サイトにユーザーが訪問した際、意図しないリクエストが&lt;code&gt;CSRF&lt;/code&gt;の脆弱性のあるウェブアプリケーションに投げられ、設定の変更や、強制投稿が行われるということ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zenn.dev/yktakaha4/articles/study_csrf_attack&quot;&gt;CSRF(Cross-Site Request Forgery)攻撃について&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;このサイトが非常に参考になった。&lt;/p&gt;
&lt;h3&gt;CORSで防げる&lt;/h3&gt;
&lt;p&gt;このサイトにあげられている下記のようなポイントのうち、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;対象のWebサイトのユーザが、正規の手順でログイン済であることを前提とする&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;対象のWebサイトが、設計上意図しない更新操作を受け付けてしまうことで攻撃が成立する&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;「対象のWebサイトが、設計上意図しない更新操作を受け付けてしまうことで攻撃が成立する」を&lt;code&gt;CORS&lt;/code&gt;の設定で防ぐことができる。&lt;/p&gt;
&lt;p&gt;悪意のあるサイトのドメインが&lt;code&gt;CORS&lt;/code&gt;で許可されていなければ、いくらリクエストが飛ばされたところで問題ない。&lt;/p&gt;
&lt;p&gt;そのため、&lt;code&gt;CORS&lt;/code&gt;のドメインは信頼されたドメインに絞り込む必要がある。&lt;/p&gt;
&lt;p&gt;そういうこと。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>無料枠のよくわからないawsの無料枠について真剣に調べてみた</title><link>https://blog.nove-b.dev/posts/ws-free-tier</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/ws-free-tier</guid><content:encoded>&lt;p&gt;個人開発で&lt;code&gt;aws&lt;/code&gt;デビューをしたが、料金不安なので調べてみることにした。 正直開発したサービスが&lt;code&gt;aws&lt;/code&gt;の何のサービスを使用しているかわからないので請求書ダッシュボードからあげだしてみた。&lt;/p&gt;
&lt;h2&gt;請求書ダッシュボードにあるデータ&lt;/h2&gt;
&lt;p&gt;AWSの概要 アクティブなサービスの合計数：８ アクティブな AWS リージョンの合計数：５&lt;/p&gt;
&lt;p&gt;アクティブなサービスの合計数が何かというのを調べるために、&lt;code&gt;aws の請求 &amp;gt; 請求&lt;/code&gt;に行き、サービス別料金を見ると一覧で見れる。&lt;/p&gt;
&lt;h3&gt;アクティブなサービス&lt;/h3&gt;
&lt;p&gt;今回は下記を使用しているらしい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API Gateway&lt;/li&gt;
&lt;li&gt;CloudWatch&lt;/li&gt;
&lt;li&gt;Data Transfer&lt;/li&gt;
&lt;li&gt;Elastic Compute Cloud&lt;/li&gt;
&lt;li&gt;Key Management Service&lt;/li&gt;
&lt;li&gt;Lambda&lt;/li&gt;
&lt;li&gt;Relational Database Service&lt;/li&gt;
&lt;li&gt;Simple Storage Service&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ぱっと見、知らないサービスもあったが、いったん寝かせておく。&lt;/p&gt;
&lt;h3&gt;アクティブな AWS リージョン&lt;/h3&gt;
&lt;p&gt;次にアクティブな &lt;code&gt;aws&lt;/code&gt; リージョンの合計数について調べてみる。&lt;/p&gt;
&lt;p&gt;調べた感じ利用できるリレージョンとのこと、つまり使用しているリレージョンではない。&lt;/p&gt;
&lt;p&gt;つまり気にしなくていい。&lt;/p&gt;
&lt;h2&gt;awsの無料枠&lt;/h2&gt;
&lt;p&gt;AWSの無料枠は注意が必要。 というのも3パターンの無料枠がある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;無料トライアル
&lt;ul&gt;
&lt;li&gt;指定期間利用できる無料枠&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;12 か月間無料
&lt;ul&gt;
&lt;li&gt;AWS に最初にサインアップした日から 12 か月間無料で使用できるプラン&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;無料枠
&lt;ul&gt;
&lt;li&gt;有効期限はなく、AWS のすべてのお客様が利用可能&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;つまり上の２つは期限が過ぎれば支払いが発生する可能性がある。&lt;/p&gt;
&lt;p&gt;また最後の１つも枠を超えれば、支払いが発生する可能性がある。&lt;/p&gt;
&lt;p&gt;ただこちらは枠さえ守れば永久的に無料で使用することができる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/jp/free/?all-free-tier.sort-by=item.additionalFields.SortRank&amp;amp;all-free-tier.sort-order=asc&amp;amp;awsf.Free%20Tier%20Types=*all&amp;amp;awsf.Free%20Tier%20Categories=*all&quot;&gt;AWS 無料利用枠&lt;/a&gt;を参照することで無料枠を調査することができる。&lt;/p&gt;
&lt;p&gt;これを用い、使用したサービスの無料枠を中心に見ていきたい。&lt;/p&gt;
&lt;h2&gt;今回使用したawsのサービスがどういう無料枠の形態を取っているか&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;API Gatewayは12か月無料で以降は課金される。&lt;/li&gt;
&lt;li&gt;CloudWatchは無期限無料で10 のカスタムメトリクスおよびアラームが無料とのこと
&lt;ul&gt;
&lt;li&gt;カスタムメトリックスはユーザーが独自に定義し、収集、監視できるメトリックデータのこと&lt;/li&gt;
&lt;li&gt;アラームとは特定の条件が満たされた場合にユーザーに通知を送信するための仕組み&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Data Transferは記述がない。
&lt;ul&gt;
&lt;li&gt;使っているかもわからない&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Elastic Compute Cloud（EC2）は12か月無料で以降は課金される。&lt;/li&gt;
&lt;li&gt;Key Management Serviceは無期限無料で20,000/月の無料リクエスト枠がある&lt;/li&gt;
&lt;li&gt;Lambdaは無期限無料で100 万/月の無料リクエスト枠がある&lt;/li&gt;
&lt;li&gt;Relational Database Serviceは12か月無料で以降は課金される。&lt;/li&gt;
&lt;li&gt;Simple Storage Service（S3）は12か月無料で以降は課金される。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;うーん、どうなんだろう&lt;/h2&gt;
&lt;p&gt;正直、釈然としない。&lt;/p&gt;
&lt;p&gt;実際12か月経ち、どれくらい課金されるのか、やってみないとわからない部分が大きすぎる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;aws&lt;/code&gt;、勉強のために触れてみたけど、正直定額制の方が精神的にいい。&lt;/p&gt;
&lt;p&gt;ちょっと代替案探してみる。&lt;/p&gt;
&lt;p&gt;それまで請求ダッシュボードを定期的に見に行かなくちゃ。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>フロントエンド専のエンジニアが見よう見まねでawsのLambdaを用いて個人開発をした</title><link>https://blog.nove-b.dev/posts/rontend-engineer-aws-lambda-personal-project</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/rontend-engineer-aws-lambda-personal-project</guid><content:encoded>&lt;h2&gt;誰も興味ないサイトの紹介をする意義&lt;/h2&gt;
&lt;p&gt;仕事では主に&lt;code&gt;Angular&lt;/code&gt;、&lt;code&gt;Vue&lt;/code&gt;、&lt;code&gt;React&lt;/code&gt;を使っているフロントエンドしかできない30歳が、インフラ～すべてに手を出してみた。&lt;/p&gt;
&lt;p&gt;作成したはいいけど、12か月後、&lt;code&gt;aws&lt;/code&gt;の無料枠終了を見据え、運用する気はない。&lt;/p&gt;
&lt;p&gt;そこで、ひとつ記事にでも残しておこうという思いで筆を取ることにした。&lt;/p&gt;
&lt;h2&gt;作成したサービス&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/48-1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/48-2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/48-3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/48-4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/48-5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;vote-for-name.nove-web.com&quot;&gt;Vote For Name-難読エンジニアワードの読み方を投票で決めよう&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;簡単なアンケートサイト。&lt;/p&gt;
&lt;p&gt;アイデアに関しては、悲しいかな、特筆すべき点はない。&lt;/p&gt;
&lt;p&gt;エンジニアリングするうえで、読み方がよくわからない言葉が良くあるので、それを投票で決めようといった魂胆。&lt;/p&gt;
&lt;p&gt;競合とかは特に調べていない。&lt;/p&gt;
&lt;h2&gt;使用した技術&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;インフラ
&lt;ul&gt;
&lt;li&gt;aws Lambda&lt;/li&gt;
&lt;li&gt;aws RDB&lt;/li&gt;
&lt;li&gt;aws API GateWay&lt;/li&gt;
&lt;li&gt;Vercel&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;バックエンド
&lt;ul&gt;
&lt;li&gt;NestJS&lt;/li&gt;
&lt;li&gt;TypeORM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;フロントエンド
&lt;ul&gt;
&lt;li&gt;NextJS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;インフラ&lt;/h2&gt;
&lt;p&gt;インフラは初めて、&lt;code&gt;aws&lt;/code&gt;に手を出してみた。&lt;/p&gt;
&lt;p&gt;永久無料枠がない従量課金制は初めてなので、請求に不安を感じる。&lt;/p&gt;
&lt;p&gt;柔軟にスケールできていいのだろうけれど、スケールアップしないので、定額の方がうれしい。&lt;/p&gt;
&lt;p&gt;まあ、いい勉強にはなった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1012/&quot;&gt;無料枠のよくわからないawsの無料枠について真剣に調べてみた&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1009/&quot;&gt;CORSでクロスオリジンの設定をする際に、なんでドメインを絞り込む必要があるのか浅く理解した&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/980/&quot;&gt;AWSのRDSに接続したいけど踏み台サーバーでうまく接続できなかったので、RDSをパブリックサブネットに置きHeidiSQLで接続を試みる&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;バックエンド&lt;/h2&gt;
&lt;p&gt;バックエンドには&lt;code&gt;NestJS&lt;/code&gt;を採用した。&lt;/p&gt;
&lt;p&gt;理由は、フロントと言語を統一することで効率化を図れるという点と、学習コストが低そうだった点。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Angular&lt;/code&gt;に似ている言語ということで、普段&lt;code&gt;Angular&lt;/code&gt;を業務利用している身としては、非常に手っ取り早く、概要をつかむことができた。&lt;/p&gt;
&lt;p&gt;言語としての不満はなく、今後も使っていきたいと思ったが、いかんせん日本語の情報が少なく苦労した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/916/&quot;&gt;NestJSのエラーレスポンスをカスタマイズする&lt;/a&gt;
&lt;a href=&quot;https://media.nove-web.com/972/&quot;&gt;NestJsで作成したプロジェクトをAWSのLambdaにあげて動かすまでの作業ログを残しておく&lt;/a&gt;
&lt;a href=&quot;https://media.nove-web.com/991/&quot;&gt;LambdaにのせたNestJSでapp.enableCors();を指定しているのにCORSエラーがでたので解消するまでを記録した&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;フロント&lt;/h2&gt;
&lt;p&gt;迷うことなく、&lt;code&gt;NextJS&lt;/code&gt;にした。&lt;/p&gt;
&lt;p&gt;現在、個人開発をするとなったら、一択の選択肢かなと感じている。&lt;/p&gt;
&lt;p&gt;ただ今回、&lt;code&gt;Next13&lt;/code&gt;の&lt;code&gt;AppDir&lt;/code&gt;にちょっと戸惑う点もあった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SSR&lt;/code&gt;の書き方とかが簡略してていいと思う反面、サーバーコンポーネントとかの概念がいまだにつかみ切れていない。&lt;/p&gt;
&lt;p&gt;それでも、引き続き&lt;code&gt;NextJS&lt;/code&gt;を採用し続けると思われる。&lt;/p&gt;
&lt;p&gt;フロントのサーバーは&lt;code&gt;Vercel&lt;/code&gt;にアップした&lt;code&gt;NextJS&lt;/code&gt;使うのであれば、第一の選択肢だろうし、実際そうなった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/997/&quot;&gt;エックスサーバーで借りたドメインのサブドメイン使用し、Vercelにカスタムドメインを設定する&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;このサービスの今後&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;aws&lt;/code&gt;の無料枠を終えた後も続けるメリットはないので、運用していく気はない。&lt;/p&gt;
&lt;p&gt;ただせっかく勉強のために作ったので、無料枠を終えるまでは暇を見つけて、&lt;code&gt;issue&lt;/code&gt;を解決していきたいと考えている。&lt;/p&gt;
&lt;h3&gt;isuue&lt;/h3&gt;
&lt;p&gt;動けばいいやという思いもありつくったので、細かい箇所を理解しつつ、ブラッシュアップしていきたい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初回アクセス時Vercelがサーバーレス関数の発火をまたずにタイムアウトする。&lt;/li&gt;
&lt;li&gt;CORSの設定をちゃんやる&lt;/li&gt;
&lt;li&gt;LambdaとGithubの連携をする&lt;/li&gt;
&lt;li&gt;JWT認証をCSRF認証に変更してみる&lt;/li&gt;
&lt;li&gt;マイグレーションの設定をちゃんとやる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とか🤔🤔&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavaScriptで１行足すだけで、以降の処理を５秒間待つことができる</title><link>https://blog.nove-b.dev/posts/javascript-wait-5-seconds</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/javascript-wait-5-seconds</guid><content:encoded>&lt;p&gt;&lt;code&gt;dom&lt;/code&gt;の操作をしていると、&lt;/p&gt;
&lt;p&gt;「あれ、動かない、domの生成がまだ行われていない？　試しに５秒待った後に実行してみよう」&lt;/p&gt;
&lt;p&gt;みたいなことが良くある。&lt;/p&gt;
&lt;p&gt;その都度、下記のように実行してきた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;window.setTimeout(() =&amp;gt; {
    operation()
}, 5000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という風に、&lt;code&gt;setTimeout&lt;/code&gt;の中に該当する関数を入れていく。&lt;/p&gt;
&lt;p&gt;ただこれだと、入れるべき関数がたくさんあると面倒くさい。&lt;/p&gt;
&lt;p&gt;そこで以降すべて５秒後に実行されるというワンライナーを覚えることにした。&lt;/p&gt;
&lt;h2&gt;それ以降の行はすべて５秒後に実行されますよっと&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;await new Promise((resolve) =&amp;gt; setTimeout(resolve, 5000));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ただこれだけのこと。&lt;/p&gt;
&lt;p&gt;ただこれだと&lt;code&gt;async&lt;/code&gt;をつけたメソッドを用意する必要があるけれど。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React NativeでHello World（環境構築～サンプルアプリ立ち上げまで）</title><link>https://blog.nove-b.dev/posts/hello-world-react-native</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/hello-world-react-native</guid><content:encoded>&lt;p&gt;過去に&lt;code&gt;React Native&lt;/code&gt;の環境構築はしたことがあるが (&lt;a href=&quot;https://media.nove-web.com/632/&quot;&gt;react native でアプリを作る環境構築をやってみるよ⚡&lt;/a&gt;)、それから随分と経つので、再度0からやってみる。&lt;/p&gt;
&lt;h2&gt;Expo Goの利用&lt;/h2&gt;
&lt;p&gt;モバイル開発が初めての場合は&lt;code&gt;Expo Go&lt;/code&gt;の仕様が推奨されているので、それにならうことにする。 必要なのは、最新バージョンの&lt;code&gt;Node.js&lt;/code&gt;とスマホまたはエミュレータ。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;React Native CLI&lt;/code&gt; という環境もあるが、&lt;code&gt;Xcode&lt;/code&gt;
または&lt;code&gt;Android Studio&lt;/code&gt;になるとのこと。 また初めてであれば環境構築に1時間を要することになる。&lt;/p&gt;
&lt;p&gt;ということで、迷うことなく&lt;code&gt;Expo Go&lt;/code&gt;を採用した。&lt;/p&gt;
&lt;p&gt;開発サーバーの起動まではとてもシンプルで下記コマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx create-expo-app AwesomeProject

cd AwesomeProject
npx expo start
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;既存ディレクトリへの展開&lt;/h2&gt;
&lt;p&gt;ただ今回はリポジトリ作成済みでディレクトリが存在していたので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx create-expo-app $(pwd)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで現ディレクトリに&lt;code&gt;App&lt;/code&gt;を展開した。&lt;/p&gt;
&lt;p&gt;そのうえで開発環境PCとエミュレータスマホを同一のWi-Fiに接続し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx expo start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで開発サーバーを立ち上げた。&lt;/p&gt;
&lt;p&gt;エミュレータスマホで&lt;code&gt;App.js&lt;/code&gt;に書かれた、&lt;code&gt;Open up App.js to start working on your app!&lt;/code&gt;が表示されれば、立ち上げが成功している。&lt;/p&gt;
&lt;h2&gt;Hello World !&lt;/h2&gt;
&lt;p&gt;次に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Text&amp;gt;Open up App.js to start working on your app!&amp;lt;/Text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Text&amp;gt;Hello World!&amp;lt;/Text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に変更すれば、当然、&lt;code&gt;Hello World!&lt;/code&gt;が表示される。&lt;/p&gt;
&lt;p&gt;これで&lt;code&gt;React Native&lt;/code&gt;でスマホを開発するスタート地点に立った。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>隙間時間に英語の勉強ができるようにネイティブ キャンプ（Native Camp）を始めました</title><link>https://blog.nove-b.dev/posts/started-native-camp-english-study</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/started-native-camp-english-study</guid><content:encoded>&lt;h2&gt;英語を話す必要性を感じた瞬間&lt;/h2&gt;
&lt;p&gt;英語が喋れるようになりたいと思ったことは何度もあるが、必要性を感じたことはなかった。&lt;/p&gt;
&lt;p&gt;だって翻訳機がこんなにも発達した世の中なのだから。&lt;/p&gt;
&lt;p&gt;わざわざ英語を覚えることに、脳のメモリを使わなくてもって思っていた。&lt;/p&gt;
&lt;h2&gt;英語学習のきっかけ&lt;/h2&gt;
&lt;p&gt;それがなぜ、英語を話せる必要性を感じたかというと、話はこの記事を書いている今から数日だけ遡る。&lt;/p&gt;
&lt;p&gt;その日は仕事中に次に個人開発するアプリのことを考えていた。アプリの技術に何を採用するかということで頭を悩ませていた。やりたい言語はたくさんある。しかし時間は有限である。ということで行き着いた結論は、自分の好きな企業、サービスが採用している技術を採用しようということになった。&lt;/p&gt;
&lt;p&gt;そういうわけで好きな企業の採用サイトを横断していると多くの企業で英語を採用基準にしているではないですか。&lt;/p&gt;
&lt;p&gt;なんということでしょう。中には公用語に英語を採用している企業もある。&lt;/p&gt;
&lt;p&gt;つまり好きな企業に行くには英語が必須である。ということに気がついてしまった。&lt;/p&gt;
&lt;h2&gt;英語学習の方法を検討&lt;/h2&gt;
&lt;p&gt;そういうわけで英語の勉強を始めようと思いたった。&lt;/p&gt;
&lt;p&gt;じゃ、どう勉強するか。 思いついたのは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Udemy&lt;/li&gt;
&lt;li&gt;YouTuber&lt;/li&gt;
&lt;li&gt;Podcast&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とかだが、性格上座学とか受動的な勉強は向いていない。&lt;/p&gt;
&lt;p&gt;それにそういういった勉強はすでに義務教育9年間、さらに高校、大学で行っており、いま喋れていない現実がある。&lt;/p&gt;
&lt;p&gt;うん、やっぱり能動的に学習する必要がある。&lt;/p&gt;
&lt;p&gt;多分英語で会話をするのが一番の近道に違いない。サラリーマン金太郎もそれで英語とサウジアラビア語を覚えていた。&lt;/p&gt;
&lt;p&gt;ということで、外国人と話ができる環境を探すことにした。最初に思いつくのは英会話だけど、仕事と双子の似非育児をしている身としては、そんな時間は取れない。&lt;/p&gt;
&lt;p&gt;じゃあ、そもそもいつ時間が取れるかというと、まあ、1番は車の中、つまり通勤中である。&lt;/p&gt;
&lt;p&gt;そこで勉強できるのがベストに違いない。ということで色々調べると、オンライン英会話というのがあるらしい。それを使えば車の中の暇な時間を勉強の時間に充てられるんじゃないかということで、さらに調べてみると、NativeCampというオンライン英会話が良さそうだった。&lt;/p&gt;
&lt;h2&gt;NativeCampの選択理由&lt;/h2&gt;
&lt;p&gt;複数あるうちで NativeCamp がいいと思ったのは、24時間即時レッスン可能で、回数無制限という点である。&lt;/p&gt;
&lt;p&gt;通勤は、特に帰りは何時になるかわからないので予約せずに即時レッスンができるというのは理想的だった。&lt;/p&gt;
&lt;p&gt;まあ、それ以上に、7日間無料で、有料登録すれば Amazon ギフトカードが貰えるというのも大きな後押しになったけど。&lt;/p&gt;
&lt;p&gt;そういうことで、NativeCamp 始めました。&lt;/p&gt;
&lt;p&gt;とりあえず７日間の無料体験でどこまでできるかやってみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React NativeにTypeScriptを導入する</title><link>https://blog.nove-b.dev/posts/integrate-typescript-react-native</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/integrate-typescript-react-native</guid><content:encoded>&lt;h2&gt;TypeScript 関係をインストールする。&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm install -D @tsconfig/react-native @types/jest @types/react @types/react-test-renderer typescript
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドでTypeScriptの依存パッケージをインストールする。&lt;/p&gt;
&lt;p&gt;完了するとPackage.jsonが&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &quot;devDependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.20.0&quot;
  },
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;から&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &quot;devDependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.20.0&quot;,
    &quot;@tsconfig/react-native&quot;: &quot;^3.0.2&quot;,
    &quot;@types/jest&quot;: &quot;^29.5.4&quot;,
    &quot;@types/react&quot;: &quot;^18.2.21&quot;,
    &quot;@types/react-test-renderer&quot;: &quot;^18.0.1&quot;,
    &quot;typescript&quot;: &quot;^5.2.2&quot;
  },

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に更新される。&lt;/p&gt;
&lt;h2&gt;tsconfig.jsonを作成する&lt;/h2&gt;
&lt;p&gt;Appのルートに&lt;code&gt;tsconfig.json&lt;/code&gt;を作成し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;extends&quot;: &quot;@tsconfig/react-native/tsconfig.json&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を記述する。&lt;/p&gt;
&lt;h2&gt;Tsxファイルの作成と動作確認&lt;/h2&gt;
&lt;p&gt;最後に&lt;code&gt;Javascript&lt;/code&gt;ファイルを&lt;code&gt;*.tsx&lt;/code&gt;に変換する。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You should leave the ./index.js entrypoint file as it is otherwise you may run
into an issue when it comes to bundling a production build.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;と公式に書かれていたが、そもそも&lt;code&gt;index.js&lt;/code&gt;を見つけることができなかったからドキュメントが古い？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App.tsx&lt;/code&gt;に型のない関数を書くと&lt;code&gt;ts&lt;/code&gt;エラーが出たので、うまく機能していると思われる。&lt;/p&gt;
&lt;p&gt;また無事に&lt;code&gt;App&lt;/code&gt;を開けたので、動作も問題ない。&lt;/p&gt;
&lt;p&gt;ちなみに、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx create-expo-app --template
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を使えば初期のApp作成時に&lt;code&gt;TypeScript&lt;/code&gt;を導入できるので、こっちでやるべきだった。&lt;/p&gt;
&lt;p&gt;参考&lt;a href=&quot;https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project&quot;&gt;Using TypeScript&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>ネイティブ キャンプ（Native Camp）の無料期間を終え、初めて自身の英語力に対し明るい未来をみた</title><link>https://blog.nove-b.dev/posts/bright-future-after-native-camp</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/bright-future-after-native-camp</guid><content:encoded>&lt;p&gt;前回の記事で書いたように、隙間時間で英語の勉強をしたいということで、オンライン英会話のネイティブキャンプ（&lt;a href=&quot;https://www.nativecamp.net/&quot;&gt;Native Camp&lt;/a&gt;）を始めてみた。&lt;/p&gt;
&lt;h2&gt;始めたきっかけ&lt;/h2&gt;
&lt;p&gt;その無料期間が終わったので、無料期間を終え思うことを書いておく。そもそもなぜ、オンライン英会話を始めたいと思ったのか。数あるオンライン英会話サービスからネイティブキャンプを選んだのかというのはざっくり前記事に書いたのだが、一応本記事にもまとめておく。&lt;/p&gt;
&lt;h3&gt;なぜ、英会話を始めようと思ったのか？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;転職の気になる企業の公用語が英語だった&lt;/li&gt;
&lt;li&gt;職場で海外のデザイナーとやり取りしている人がかっこいい&lt;/li&gt;
&lt;li&gt;プログラミングのドキュメントなどの資源は英語での情報が多い&lt;/li&gt;
&lt;li&gt;子どもができ、海外旅行とか行く際に少しでも危険を避けたい（過去にハワイでかもられた経験有）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;なぜオンライン英会話を始めようと思ったのか？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;双子似非育児中のため、決まって確保できる時間がない&lt;/li&gt;
&lt;li&gt;通勤時の車で英語でフリートークするのが最も効率的だと思ったから&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;なぜ、ネイティブキャンプを選んだのか？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;時間を指定しない即時レッスンが可能だった&lt;/li&gt;
&lt;li&gt;レッスン回数無制限だった&lt;/li&gt;
&lt;li&gt;無料お試し期間が7日間ついていた&lt;/li&gt;
&lt;li&gt;初回登録でAmazonギフト券5000円分がもらえた&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特に、時間指定なしの即時レッスン、回数無制限はネイティブキャンプのみだったので、正直迷うことなく、ネイティブキャンプに決めた。&lt;/p&gt;
&lt;h2&gt;無料期間終了後の感想&lt;/h2&gt;
&lt;p&gt;そして無料期間を終えた今、思うことを書いていく。&lt;/p&gt;
&lt;p&gt;そもそも車の中で英語でフリートークして楽しくめきめき英語力向上という前提が著しく間違えていた。初回だしお手並み拝見で最初のレッスンを受けてみたが、何を言っているかわからない。相手は当然英語しか話さないので、何とか食らいつく。これまで習ってきた英語で何とか聞き取り、何とかついていく。それだけで精一杯なのである。&lt;/p&gt;
&lt;p&gt;こんなんじゃフリートークなんて夢のまた夢である。想像していたレッスン方法ではないけど、英語しか話せない相手に食い下がりつつ、レッスンを受けるというのもそれはそれで英語力の向上が見込める気がする。というのも複数回レッスンを受けているとなんとなく会話が通じるようになってきたのである。これはきっと続けていれば、30年間無理だった英語がマスターできるかもしれないという光が少し見えた無料期間だった。&lt;/p&gt;
&lt;p&gt;そういうわけでポジティブな感情を抱き、無料期間を終えた。当然、本会員登録もした。&lt;/p&gt;
&lt;h2&gt;無料期間終了後の情報まとめ&lt;/h2&gt;
&lt;p&gt;ネイティブキャンプの情報をまとめてみる。&lt;/p&gt;
&lt;h3&gt;ポジティブなところ&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;先生が英語しか話さない（甘えることができない環境に身を置ける）&lt;/li&gt;
&lt;li&gt;音声のみでOK&lt;/li&gt;
&lt;li&gt;キャラクター先生がいる（パンダのFanFan先生最高、緊張せずに会話できる）&lt;/li&gt;
&lt;li&gt;時間に縛られない即時レッスン（実力的に車の中は無理だけど、子どもたちが寝た深夜にレッスン可能）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ネガティブなところ&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;今のところ見つけられていない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今回の無料期間で5回のレッスンを受けた。7日間で5回だったので、思ったより受けられていない。ただこれは時期的な問題で、来週引っ越しを控えており、荷造りに時間を取られているのである。間違いなく、始めるタイミングを間違えた。そこだけは後悔しているが、ネガティブキャンプに出会えたことは幸運だった。時間のない人には特におすすめできる。次は一か月後の感想を書く、その時はもしかすると英語で記事を書いているかもしれないし、書いていないかもしれない。 、&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>TypeScriptのIndex Signatureでプロパティに制限をかけたかったので、今更ながらよくよく調べてみた</title><link>https://blog.nove-b.dev/posts/typescript-index-signature</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/typescript-index-signature</guid><content:encoded>&lt;p&gt;&lt;code&gt;Index Signature&lt;/code&gt;を使用することでプロパティの型を指定することができる。&lt;/p&gt;
&lt;p&gt;例えば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface BodyType {
    [key: number]: {
        min: number,
        max: number
    }
}

const body:BodyType =
    {
        String: {
            min: 0,
            max: 230
        },
        1: {
            min:0,
            max:300
        }
    }


console.log(body.String.min)}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように&lt;code&gt;number&lt;/code&gt;型という風に明示的に宣言することで、&lt;code&gt;String&lt;/code&gt;という文字列を&lt;code&gt;key&lt;/code&gt;に指定したことでエラーを吐かせることが可能である。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type &apos;{ hello: { min: number; max: number; }; 1: { min: number; max: number; }; }&apos; is not assignable to type &apos;BodyType&apos;.
  Object literal may only specify known properties, and &apos;hello&apos; does not exist in type &apos;BodyType&apos;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逆に&lt;code&gt;Index Signature&lt;/code&gt;を文字列という風に明示的に宣言することで、&lt;code&gt;1&lt;/code&gt;という&lt;code&gt;Key&lt;/code&gt;がエラーを吐きそうだが、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is because when indexing with a number, JavaScript will actually convert
that to a string before indexing into an object&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という風に文字列にしてからアクセスするので問題ないということで、エラーは出ない。&lt;/p&gt;
&lt;h2&gt;Index Signatureでは特定の文字列を持つプロパティのみを制約することはできない&lt;/h2&gt;
&lt;p&gt;じゃあ、&lt;code&gt;key&lt;/code&gt;が特定の文字列のみの場合はどうすればいいか？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface BodyType {
    [key in &apos;a&apos; | &apos;b&apos;]: {
        min: number,
        max: number
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記の記述すると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A computed property name in an interface must refer to an expression whose type is a literal type or a &apos;unique symbol&apos; type.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出る。&lt;/p&gt;
&lt;p&gt;エラーが出たコードを実現しようとすると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface Content {
    min: number,
    max: number
}
interface BodyType {
    a: Content,
    b: Content
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という風に記載することで解決できる。&lt;/p&gt;
&lt;p&gt;そもそも&lt;code&gt;Index Signature&lt;/code&gt;の定義が&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sometimes you don’t know all the names of a type’s properties ahead of time,
but you do know the shape of the values.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という風に型のプロパティ名を事前にすべて把握していない場合に使用する物なので、そもそも実現しようとしていることが間違え。&lt;/p&gt;
&lt;p&gt;間違えだけれど、ちなみに、&lt;code&gt;Type&lt;/code&gt;を使用することで、上記のような書き方で実現することができる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type BodyType = {
    [key in &apos;a&apos; | &apos;b&apos; | &apos;c&apos;]: {
        min: number,
        max: number
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;InterfaceとTypeの違いは別で調べたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React NativeでTailwind CSSを使用したいので、nativewindを導入した</title><link>https://blog.nove-b.dev/posts/integrate-nativewind-react-native</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/integrate-nativewind-react-native</guid><content:encoded>&lt;p&gt;&lt;code&gt;React Native&lt;/code&gt;で&lt;code&gt;Tailwind CSS&lt;/code&gt;を使用したいということで調べてみると下記２つが該当した。&lt;/p&gt;
&lt;h2&gt;tailwind-rnとnativewindの比較&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vadimdemedes/tailwind-rn&quot;&gt;tailwind-rn ☆4.1k&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/marklawlor/nativewind&quot;&gt;nativewind ☆3k&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;スターは&lt;code&gt;tailwind-rn&lt;/code&gt;が上回っているけど、活動の多さでは&lt;code&gt;nativewind&lt;/code&gt;が上回っているようなので、&lt;code&gt;nativewind&lt;/code&gt;を採用した。&lt;/p&gt;
&lt;h2&gt;nativewindの導入&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nativewind.dev/&quot;&gt;ドキュメント&lt;/a&gt;も丁寧なのでなぞって行っていく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm i nativewind
npm i --dev tailwindcss
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで該当パッケージをインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx tailwindcss init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に上記コマンドで&lt;code&gt;tailwind.config.js&lt;/code&gt;を作成し、下記のように記載する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// tailwind.config.js

module.exports = {
- content: [],
+ content: [&quot;./App.{js,jsx,ts,tsx}&quot;, &quot;./&amp;lt;custom directory&amp;gt;/**/*.{js,jsx,ts,tsx}&quot;],
  theme: {
    extend: {},
  },
  plugins: [],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;custom directory&amp;gt;&lt;/code&gt;は自身のディレクトリに編集する。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;babel.config.js&lt;/code&gt;を下記のように編集していく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: [&quot;babel-preset-expo&quot;],
+   plugins: [&quot;nativewind/babel&quot;],
  };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上とのことなので、起動してみる。 無事に開発環境は動いている。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;nativewind&lt;/code&gt;の記述を反映することができるか確認してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Text&amp;gt;Hello World!&amp;lt;/Text&amp;gt;
      &amp;lt;StatusBar style=&quot;auto&quot; /&amp;gt;
    &amp;lt;/View&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;View className=&quot;flex-1 items-center justify-center bg-white&quot;&amp;gt;
      &amp;lt;Text&amp;gt;Hello World!&amp;lt;/Text&amp;gt;
      &amp;lt;StatusBar style=&quot;auto&quot; /&amp;gt;
    &amp;lt;/View&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に変換した。結果大量のエラーが出現した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;No overload matches this call.
  Overload 1 of 2, &apos;(props: ViewProps | Readonly&amp;lt;ViewProps&amp;gt;): View&apos;, gave the following error.
    Type &apos;{ children: Element[]; className: string; }&apos; is not assignable to type &apos;IntrinsicAttributes &amp;amp; IntrinsicClassAttributes&amp;lt;View&amp;gt; &amp;amp; Readonly&amp;lt;ViewProps&amp;gt;&apos;.
      Property &apos;className&apos; does not exist on type &apos;IntrinsicAttributes &amp;amp; IntrinsicClassAttributes&amp;lt;View&amp;gt; &amp;amp; Readonly&amp;lt;ViewProps&amp;gt;&apos;.
  Overload 2 of 2, &apos;(props: ViewProps, context: any): View&apos;, gave the following error.
    Type &apos;{ children: Element[]; className: string; }&apos; is not assignable to type &apos;IntrinsicAttributes &amp;amp; IntrinsicClassAttributes&amp;lt;View&amp;gt; &amp;amp; Readonly&amp;lt;ViewProps&amp;gt;&apos;.
      Property &apos;className&apos; does not exist on type &apos;IntrinsicAttributes &amp;amp; IntrinsicClassAttributes&amp;lt;View&amp;gt; &amp;amp; Readonly&amp;lt;ViewProps&amp;gt;&apos;.ts(2769)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;エラーの解消&lt;/h2&gt;
&lt;p&gt;エラーを解消していく。&lt;/p&gt;
&lt;p&gt;そもそも&lt;code&gt;nativewind&lt;/code&gt;を&lt;code&gt;expo&lt;/code&gt;で使用するサンプルが&lt;code&gt;Github&lt;/code&gt;に用意されていたので、それを見つつ解消していく。&lt;/p&gt;
&lt;p&gt;まず最初に変更した&lt;code&gt;tailwind.config.js&lt;/code&gt;を&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;content: [&quot;./App.tsx&quot;],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に変更する。&lt;/p&gt;
&lt;p&gt;次に、&lt;code&gt;babel.config.js&lt;/code&gt;はそのまま。&lt;/p&gt;
&lt;p&gt;で、ここまでで不足しているっぽいファイルを追加していく。&lt;/p&gt;
&lt;p&gt;まずは、&lt;code&gt;styles.css&lt;/code&gt;をルートに追加する。 内容は&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;あと&lt;code&gt;nativewind.d.ts&lt;/code&gt;という型ファイル。&lt;/p&gt;
&lt;p&gt;中身は&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/// &amp;lt;reference types=&quot;nativewind/types&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これにの追加により&lt;code&gt;className&lt;/code&gt;の型エラーが解消された。&lt;/p&gt;
&lt;p&gt;最後にapp.tsxに&lt;code&gt;import &quot;./styles.css&quot;;&lt;/code&gt;という感じで追加した&lt;code&gt;style.css&lt;/code&gt;をインポートする。&lt;/p&gt;
&lt;p&gt;で、実行すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error: App.tsx: ~\App.tsx: Use process(css).then(cb) to work with async plugins
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出た。 https://github.com/marklawlor/nativewind/issues/556
も上がっている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/marklawlor/nativewind/issues/498&quot;&gt;過去issue&lt;/a&gt;で解決済だったので、それを参照し
&lt;code&gt;tailwind&lt;/code&gt;のバージョンを&quot;^3.3.2”に変更したところ、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error: App.tsx: ~\App.tsx: Use process(css).then(cb) to work with async plugins
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このエラーは消えた。&lt;/p&gt;
&lt;p&gt;次に、下記エラーと遭遇する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Unable to resolve &quot;./styles.css&quot; from &quot;App.tsx&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このエラーは&lt;code&gt;App.tsx&lt;/code&gt;の&lt;code&gt;import &quot;./styles.css&quot;;&lt;/code&gt;を削除したら消えた。&lt;/p&gt;
&lt;h2&gt;動作確認&lt;/h2&gt;
&lt;p&gt;最後に起動したところ、無事に&lt;code&gt;nativewind&lt;/code&gt;の記述が反映されていることを確認できた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React Nativeにコードフォーマッター（ESLint・Prettierを導入する）</title><link>https://blog.nove-b.dev/posts/setup-eslint-prettier-react-native</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/setup-eslint-prettier-react-native</guid><content:encoded>&lt;h2&gt;インストール ESLint&lt;/h2&gt;
&lt;p&gt;まずは&lt;code&gt;ESLint&lt;/code&gt;を導入する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save-dev eslint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;React Native&lt;/code&gt;には基本的に入っているという情報があったが、検索しても引っかからなかったので、上記コマンドでインストールした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+     &quot;eslint&quot;: &quot;^8.49.0&quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;を確認し、追加されたことを確認した。&lt;/p&gt;
&lt;h2&gt;Setting ESLint&lt;/h2&gt;
&lt;p&gt;次に&lt;code&gt;ESLint&lt;/code&gt;の設定をしていく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx eslint --init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで設定をスタートする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;You can also run this command directly using &apos;npm init @eslint/config&apos;.
Need to install the following packages:
  @eslint/create-config@0.4.6
Ok to proceed? (y) y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まず、なんか追加でインストールしろと言われたのでインストールする。&lt;/p&gt;
&lt;p&gt;その後、設定が始まる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? How would you like to use ESLint? (Use arrow keys) // ESLintをどのように利用しますか？
  To check syntax only // 構文のみをチェック
  To check syntax and find problems // 構文をチェックし問題を見つける
&amp;gt; To check syntax, find problems, and enforce code style // 構文をチェックし問題を見つけ、コードスタイルを強制します
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;文法をチェックするだけではなく、自動で修正までを行ってもらうことにした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? What type of modules does your project use? ... // プロジェクトでどの種類のモジュールを使用しますか？
&amp;gt; JavaScript modules (import/export) // JavaScriptモジュール (import/export)
  CommonJS (require/exports) // CommonJS (require/exports)
  None of these // どちらでもない
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;React Native&lt;/code&gt;では主に&lt;code&gt;import/export&lt;/code&gt;を使うので&lt;code&gt;JavaScript modules (import/export)&lt;/code&gt;を選択して次に進める。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Which framework does your project use? ...
&amp;gt; React
  Vue.js
  None of these
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;React Native&lt;/code&gt;は&lt;code&gt;React&lt;/code&gt;を基盤にするので&lt;code&gt;React&lt;/code&gt;を選択する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Does your project use TypeScript? » No / Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用するので&lt;code&gt;Yes&lt;/code&gt;を選択する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; Where does your code run? ...  (Press &amp;lt;space&amp;gt; to select, &amp;lt;a&amp;gt; to toggle all, &amp;lt;i&amp;gt; to invert selection)
    Browser
√ Node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;React Native&lt;/code&gt;は&lt;code&gt;Node&lt;/code&gt;ベースなので&lt;code&gt;Node&lt;/code&gt;を選択する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? How would you like to define a style for your project? ... // プロジェクトのスタイルをどのように定義しますか？
  Use a popular style guide // 人気のあるスタイルガイドを使用
&amp;gt; Answer questions about your style // スタイルについて質問に答える
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;どのスタイルガイドを使うのか選択するか、勝手に決められるのも怖いので自身で選択するにした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? What format do you want your config file to be in? ...
&amp;gt; JavaScript
  YAML
  JSON
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ESLint&lt;/code&gt;の設定ファイルをどのように持つか。&lt;code&gt;JavaScript&lt;/code&gt;にした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? What style of indentation do you use? ...
&amp;gt; Tabs
  Spaces
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;インデントをどう持つかはタブにした。&lt;/p&gt;
&lt;p&gt;※ のちにスペースに変更する（いつもスペースなのに間違えた。）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? What quotes do you use for strings? ...
  Double
&amp;gt; Single
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;シングルクォーテーションかダブルクォーテーションかの選択、シングルにした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
? What line endings do you use? ...
&amp;gt;  Unix
 Windows
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改行（行末の処理）の方法を選ぶもの、&lt;code&gt;Unix&lt;/code&gt;を選ぶのが標準っぽいのでそれにならった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; Do you require semicolons? » No / Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;セミコロンの有無について、いつもつけないので、&lt;code&gt;No&lt;/code&gt;にした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@typescript-eslint/eslint-plugin@latest eslint-plugin-react@latest @typescript-eslint/parser@latest
? Would you like to install them now? » No / Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;設定を終えると、必要なパッケージを提案してくれたので、&lt;code&gt;Yes&lt;/code&gt;でそれを受け入れる、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Which package manager do you want to use? ...
&amp;gt; npm
  yarn
  pnpm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;パッケージマネージャーを聞かれるので、使用しているマネージャーを選択する。&lt;/p&gt;
&lt;p&gt;これで設定は完了した。&lt;/p&gt;
&lt;h2&gt;実行していく&lt;/h2&gt;
&lt;p&gt;次に&lt;code&gt;package.json&lt;/code&gt;にスクリプトを登録する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &quot;lint&quot;: &quot;eslint .&quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;npm run lint&lt;/code&gt;で実行すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   1:44  error  Extra semicolon                                    semi
   2:42  error  Extra semicolon                                    semi
   7:1   error  Expected indentation of 1 tab but found 2 spaces   indent
   8:1   error  Expected indentation of 2 tabs but found 4 spaces  indent
   8:5   error  &apos;React&apos; must be in scope when using JSX            react/react-in-jsx-scope
   9:1   error  Expected indentation of 3 tabs but found 6 spaces  indent
   9:7   error  &apos;React&apos; must be in scope when using JSX            react/react-in-jsx-scope
  10:1   error  Expected indentation of 3 tabs but found 6 spaces  indent
  10:7   error  &apos;React&apos; must be in scope when using JSX            react/react-in-jsx-scope
  11:1   error  Expected indentation of 2 tabs but found 4 spaces  indent
  12:1   error  Expected indentation of 1 tab but found 2 spaces   indent
  12:4   error  Extra semicolon                                    semi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事にソースに対して&lt;code&gt;Lint&lt;/code&gt;が働いていることが分かった。&lt;/p&gt;
&lt;p&gt;スクリプトに&lt;code&gt;--fix&lt;/code&gt;オプションをつけることで、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &quot;lint&quot;: &quot;eslint . --fix&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修正まで行ってくれ、エラーが3件まで減った。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   8:3  error  &apos;React&apos; must be in scope when using JSX  react/react-in-jsx-scope
   9:4  error  &apos;React&apos; must be in scope when using JSX  react/react-in-jsx-scope
  10:4  error  &apos;React&apos; must be in scope when using JSX  react/react-in-jsx-scope
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ちなみにエラーは上記の通り。&lt;/p&gt;
&lt;p&gt;こちらは&lt;code&gt;.eslintrc.js&lt;/code&gt;の&lt;code&gt;rules&lt;/code&gt;に下記設定を追加することで回避できる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	&apos;react/jsx-uses-react&apos;: &apos;off&apos;,
	&apos;react/react-in-jsx-scope&apos;: &apos;off&apos;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで無事にエラーがゼロ件になった。&lt;/p&gt;
&lt;p&gt;アプリが無事に立ち上げることも確認できたので&lt;code&gt;ESLint&lt;/code&gt;の導入は成功した。&lt;/p&gt;
&lt;h2&gt;インストール Prettier&lt;/h2&gt;
&lt;p&gt;次に&lt;code&gt;Prettier&lt;/code&gt;をインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save-dev prettier eslint-plugin-prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ルートに&lt;code&gt;.prettierrc.js&lt;/code&gt;を作成し、下記内容を記載する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module.exports = {
  semi: false,
  singleQuote: true,
  trailingComma: &apos;all&apos;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;ESLintへPrettierを設定する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.eslintrc.js&lt;/code&gt;に下記のように反映する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	&apos;plugins&apos;: [
		&apos;@typescript-eslint&apos;,
		&apos;react&apos;,
		+ &apos;prettier&apos;
	],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;rules&lt;/code&gt;に &lt;code&gt;&apos;prettier/prettier&apos;: &apos;error&apos;,&lt;/code&gt;を追加する。&lt;/p&gt;
&lt;p&gt;最後にスクリプトを登録する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &quot;format&quot;: &quot;prettier --check .&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;実行していく&lt;/h2&gt;
&lt;p&gt;実行すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[warn] .eslintrc.js
[warn] app.json
[warn] App.tsx
[warn] babel.config.js
[warn] globals.d.ts
[warn] prettierrc.js
[warn] styles.css
[warn] tailwind.config.js
[warn] tsconfig.json
[warn] Code style issues found in 9 files. Run Prettier to fix.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という結果に。&lt;/p&gt;
&lt;p&gt;修正まで行ってくれるようにする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &quot;format&quot;: &quot;prettier --write .&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記行うと修正まで行ってくれたけれど、そのあとに&lt;code&gt;ESLint&lt;/code&gt;を実行すると膨大な&lt;code&gt;Warning&lt;/code&gt;が出るようになってしまった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ESLint&lt;/code&gt;でセミコロン消してるのに&lt;code&gt;Prettier&lt;/code&gt;でつけてたりしていて、見る感じ競合している。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prettierrc.js&lt;/code&gt;に&lt;code&gt;.&lt;/code&gt;が必要なことを忘れていた。後は&lt;code&gt;ESLint&lt;/code&gt;の設定と競合しないように設定を変えていけばできた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>WindowsにGoをインストールしてHello Worldしてみる</title><link>https://blog.nove-b.dev/posts/install-go-windows-hello-world</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/install-go-windows-hello-world</guid><content:encoded>&lt;h2&gt;インストール Go&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://go.dev/doc/install&quot;&gt;Download and install&lt;/a&gt;のページに行き、環境に適したものをインストールする。&lt;/p&gt;
&lt;p&gt;インストールするとシステムが立ち上げるので、手順に沿って進めていく。&lt;/p&gt;
&lt;p&gt;Finish後、&lt;code&gt;Go&lt;/code&gt;がインストールされていることを確認する。&lt;/p&gt;
&lt;p&gt;コマンドを開き、&lt;code&gt;go version&lt;/code&gt;を叩くと&lt;code&gt;go version go1.21.1 windows/amd64&lt;/code&gt;と表示された。&lt;/p&gt;
&lt;p&gt;これでインストールされていることを確認できた。&lt;/p&gt;
&lt;h2&gt;Hello World&lt;/h2&gt;
&lt;p&gt;次に&lt;code&gt;HelloWord&lt;/code&gt;を表示させる。&lt;/p&gt;
&lt;p&gt;まずは任意の場所に適当なフォルダを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; mkdir HelloWorldGo
 cd  HelloWorldGo
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;モジュールを作成する&lt;/h2&gt;
&lt;p&gt;次に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go mod init example/hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドでモジュールの作成を行うのだが、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&apos;go&apos; は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出た。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Path&lt;/code&gt;を調べてみるとしっかりと通っている。 ということで再起動をする。&lt;/p&gt;
&lt;p&gt;再起動で、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go mod init example/hello
go: creating new go.mod: module example/hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事に叩けるようになった。&lt;/p&gt;
&lt;p&gt;上記コマンドで作成されたのは、&lt;code&gt;go.mod&lt;/code&gt;というファイルで、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module example/hello

go 1.21.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という記載がある。&lt;/p&gt;
&lt;p&gt;調べてみるとこれは、依存関係のバージョン管理をするものらしい。 つまり、スクリプトを記述しない&lt;code&gt;JavaScript&lt;/code&gt;の&lt;code&gt;package.json&lt;/code&gt;みたいなものらしい。&lt;/p&gt;
&lt;p&gt;疑問点が解消されたので、次に行く。&lt;/p&gt;
&lt;h2&gt;Mainパッケージの作成&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;hello.go&lt;/code&gt;ファイルを作成し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
    fmt.Println(&quot;Hello, World!&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;をと記述する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; go run .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドを叩けば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Goエンジニアのスタートラインに立てた。&lt;/p&gt;
&lt;h2&gt;外部パッケージの呼び出し&lt;/h2&gt;
&lt;p&gt;外部パッケージのコードを呼び出してみる。&lt;/p&gt;
&lt;p&gt;まずは&lt;a href=&quot;https://pkg.go.dev/&quot;&gt;https://pkg.go.dev/&lt;/a&gt;でパッケージを検索する。 今回はチュートリアルに沿って、&lt;a href=&quot;https://pkg.go.dev/rsc.io/quote/v4&quot;&gt;https://pkg.go.dev/rsc.io/quote/v4&lt;/a&gt;というパッケージを使用することにする。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;hello.go&lt;/code&gt;の内容を変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

import &quot;rsc.io/quote&quot;

func main() {
    fmt.Println(quote.Go())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&quot;rsc.io/quote&quot;&lt;/code&gt;を&lt;code&gt;import&lt;/code&gt;して&lt;code&gt;&quot;rsc.io/quote&quot;&lt;/code&gt;のパッケージを使用するできるようにした。&lt;/p&gt;
&lt;p&gt;次にルートに&lt;code&gt;go.sum&lt;/code&gt;ファイルを作成する。&lt;/p&gt;
&lt;p&gt;このファイルでは&lt;code&gt;go.mod&lt;/code&gt;で定義したプロジェクトのモジュール構成と依存関係のバージョン管理に使用するらしい。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;go mod tidy&lt;/code&gt;コマンドを実行する。&lt;/p&gt;
&lt;p&gt;このコマンドは&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;実際に使われていない依存関係を削除&lt;/li&gt;
&lt;li&gt;importした依存関係をインストール&lt;/li&gt;
&lt;li&gt;つまり、プロジェクトの依存関係を最新化できる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上記の通りの動きをする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;go mod tidy
go: finding module for package rsc.io/quote
go: found rsc.io/quote in rsc.io/quote v1.5.2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実行すると上記のように依存関係がインストールされた。&lt;/p&gt;
&lt;p&gt;最後に実行してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; go run .
Don&apos;t communicate by sharing memory, share memory by communicating.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という風によくわからない文章が出力された。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rsc/quote/blob/v4.0.1/quote.go#L22&quot;&gt;Github&lt;/a&gt;を見ると、そういう風に返すようにできているので、正しく動いている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go Lang でモジュールを作成し、それをMainパッケージで使用する</title><link>https://blog.nove-b.dev/posts/create-module-go-lang-main-package</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-module-go-lang-main-package</guid><content:encoded>&lt;h2&gt;呼び出したいモジュールを作成する&lt;/h2&gt;
&lt;p&gt;まずは利用する&lt;code&gt;greetings&lt;/code&gt;モジュールを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go mod init example.com/greetings
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go: creating new go.mod: module example.com/greetings
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というメッセ―ジとともに、&lt;code&gt;go.mod&lt;/code&gt;が作成される。&lt;/p&gt;
&lt;p&gt;ちなみにコマンドに記入した`example.com‘はドメイン名ではGo ツールによってモジュールをダウンロードできるパスになるっぽいらしいけれど、よくわからない。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;greetings.go&lt;/code&gt;というファイルを作成し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package greetings

import &quot;fmt&quot;

// Hello returns a greeting for the named person.
func Hello(name string) string {
    // Return a greeting that embeds the name in a message.
    message := fmt.Sprintf(&quot;Hi, %v. Welcome!&quot;, name)
    return message
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように記入する。&lt;/p&gt;
&lt;p&gt;これでパッケージは作成できた。&lt;/p&gt;
&lt;h2&gt;mainのパッケージを作成する&lt;/h2&gt;
&lt;p&gt;次にこれを呼び出していく。&lt;/p&gt;
&lt;p&gt;先ほど作成した&lt;code&gt;greetings&lt;/code&gt;モジュールが格納されているフォルダと同階層に&lt;code&gt;hello&lt;/code&gt;フォルダを作成する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;home&amp;gt;/
 |-- greetings/
 |-- hello/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;今までの通りモジュールを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go mod init hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ドメインは必須じゃないということだったので、省略してみたが、無事に作成することができた。&lt;/p&gt;
&lt;p&gt;次に、&lt;code&gt;hello.go&lt;/code&gt;にコードを記載していく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;

    &quot;example.com/greetings&quot;
)

func main() {
    // Get a greeting message and print it.
    message := greetings.Hello(&quot;Gladys&quot;)
    fmt.Println(message)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このコードでは&lt;code&gt;ｍain&lt;/code&gt;パッケージを宣言している。&lt;code&gt;Go&lt;/code&gt;ではアプリケーションとして実行されるコードは&lt;code&gt;main&lt;/code&gt;パッケージ内に存在する必要があるらしい。&lt;/p&gt;
&lt;p&gt;以下、Chat-GPTのよると&lt;/p&gt;
&lt;p&gt;Go言語における &lt;code&gt;main&lt;/code&gt;
パッケージは、実行可能なプログラムを定義する特別なパッケージです。&lt;/p&gt;
&lt;p&gt;具体的には以下の特徴があります：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;エントリーポイント&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt; パッケージ内の &lt;code&gt;func main()&lt;/code&gt;
が、プログラムのエントリーポイント（起動点）となります。この関数が最初に呼び出されます。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;実行可能ファイルの生成&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt; パッケージを含むプログラムは、&lt;code&gt;go build&lt;/code&gt;
コマンドを使って実行可能なバイナリファイルにコンパイルできます。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;単独実行可能ファイル&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;
パッケージを持つプログラムは、単体で実行可能なプログラムとして使われます。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;必要なパッケージのインポート&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;
パッケージは他のパッケージをインポートできます。これによって、他のパッケージの機能を利用することができます。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mainパッケージ以外のパッケージには必要ない要素&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt; パッケージ以外のパッケージは、エントリーポイントとなる &lt;code&gt;func main()&lt;/code&gt;
を持つ必要はありません。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;例えば、以下は &lt;code&gt;main&lt;/code&gt; パッケージの例です：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
    fmt.Println(&quot;Hello, World!&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このプログラムは &lt;code&gt;main&lt;/code&gt; パッケージであり、&lt;code&gt;func main()&lt;/code&gt;
関数が定義されています。このプログラムは &lt;code&gt;fmt&lt;/code&gt;
パッケージをインポートし、コンソールに &quot;Hello, World!&quot; と出力します。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main&lt;/code&gt;
パッケージを持つプログラムは、通常、Go言語で実行可能なプログラムとしてビルドされます。&lt;/p&gt;
&lt;p&gt;関数の方では&lt;code&gt;example.com/greetings&lt;/code&gt;の&lt;code&gt;Hello&lt;/code&gt;関数を呼び出し、使用している。&lt;/p&gt;
&lt;p&gt;そのうえで、&lt;code&gt;go mod tidy&lt;/code&gt;でモジュールを最新化する。&lt;/p&gt;
&lt;p&gt;実際の運用ではリポジトリからモジュールを 公開し&lt;code&gt;import&lt;/code&gt;して使用するのだが、&lt;code&gt;greetings&lt;/code&gt;モジュールをまだ公開していないため&lt;code&gt;example.com/greetings&lt;/code&gt;をローカルで見つかられるように調整する必要がある。&lt;/p&gt;
&lt;p&gt;調整するためには下記のコマンドを叩く必要がある。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go mod edit -replace example.com/greetings=../greetings
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このコマンドでモジュール パス をローカルパスにリダイレクトするように&lt;code&gt;hello&lt;/code&gt;モジュールが編集される。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;go mod tidy&lt;/code&gt;でモジュールを最新化する。&lt;/p&gt;
&lt;p&gt;VSCodeでエラーが出ているけれど、実行すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run .
Hi, Gladys. Welcome!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事に動いていることが確認できた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>WordPress.orgに登録したプラグインをGitHub Actionを使用しGitHub上で管理する</title><link>https://blog.nove-b.dev/posts/manage-wordpress-plugin-github-action</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/manage-wordpress-plugin-github-action</guid><content:encoded>&lt;p&gt;WordPressのバージョン管理は&lt;code&gt;Subversion&lt;/code&gt;
で行われるのだが、なかなか慣れずに更新が億劫になってきたので、&lt;code&gt;Github&lt;/code&gt;で更新できるようにしてみた。&lt;/p&gt;
&lt;h3&gt;過去関連記事&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/732/&quot;&gt;Subversion (SVN) を使用し承認されたWordPressプラグインをリリースしてみる&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Github Actionを使用する&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://10up.com/&quot;&gt;10up.com&lt;/a&gt;がWordPress.orgのプラグインリポジトリにデプロイする&lt;a href=&quot;https://github.com/10up/action-wordpress-plugin-deploy&quot;&gt;GitHub Actions&lt;/a&gt;を公開してくれているので、それを活用させていただく。&lt;/p&gt;
&lt;h2&gt;Github リポジトリを作成する&lt;/h2&gt;
&lt;h3&gt;ディレクトリ構成&lt;/h3&gt;
&lt;p&gt;まずはいつも通り&lt;code&gt;Github&lt;/code&gt;のリポジトリを作成する。&lt;/p&gt;
&lt;p&gt;本当にいつも通りで問題ないけれど、&lt;code&gt;WordPress&lt;/code&gt;のスラッグのとリポジトリ名を揃えた方が後々ほんの少しだけ楽になる。&lt;/p&gt;
&lt;p&gt;ディレクトリ構成は下記のようにする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── .wordpress-org
│   ├── banner-772x250.png
│   ├── icon-128x128.png
│   └── screenshot-1.png
├── README.md
├── plugin-sample.php
└── readme.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.wordpress-org&lt;/code&gt;に&lt;code&gt;SVNリポジトリ&lt;/code&gt;の&lt;code&gt;assets&lt;/code&gt;フォルダの中身をコピーする。&lt;/p&gt;
&lt;h3&gt;Github Action を作成する&lt;/h3&gt;
&lt;p&gt;リポジトリのActionsへ行き、New workflow → set up a workflow
yourselfで&lt;code&gt;YAML&lt;/code&gt;ファイルの作成画面に行く。&lt;/p&gt;
&lt;p&gt;ファイル名はわかりやすい名前（ex:&lt;code&gt;wordpress-plugin-deploy&lt;/code&gt;）を指定する。&lt;/p&gt;
&lt;p&gt;次に&lt;a href=&quot;https://github.com/10up/action-wordpress-plugin-deploy&quot;&gt;action-wordpress-plugin-deploy&lt;/a&gt;ページにある&lt;a href=&quot;https://github.com/10up/action-wordpress-plugin-deploy#deploy-on-pushing-a-new-tag&quot;&gt;Example Workflow Files&lt;/a&gt;の内容をコピペする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Deploy to WordPress.org
on:
  push:
    tags:
    , &quot;*&quot;
jobs:
  tag:
    name: New tag
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - name: Build # Remove or modify this step as needed
      run: |
        npm install
        npm run build
    - name: WordPress Plugin Deploy
      uses: 10up/action-wordpress-plugin-deploy@stable
      env:
        SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
        SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
        SLUG: my-super-cool-plugin # optional, remove if GitHub repo name matches SVN slug, including capitalization
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Github&lt;/code&gt;のブランチが&lt;code&gt;main&lt;/code&gt;の場合は&lt;code&gt;actions/checkout@master&lt;/code&gt;を&lt;code&gt;actions/checkout@main&lt;/code&gt;にする（曖昧）&lt;/li&gt;
&lt;li&gt;特に&lt;code&gt;npm&lt;/code&gt;を使用していない場合は、下記記述を削除する。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;    - name: Build # Remove or modify this step as needed
     run: |
       npm install
       npm run build
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;スラッグとリポジトリ名と同一であれば&lt;code&gt;SLUG: my-super-cool-plugin # optional, remove if GitHub repo name matches SVN slug, including capitalization&lt;/code&gt;は不要なので削除する。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;完了後、&lt;code&gt;Commit&lt;/code&gt;する。&lt;/p&gt;
&lt;p&gt;リポジトリ名&lt;code&gt;/.github/workflows/&lt;/code&gt;
配下に先程のファイルが作成されていれば、問題なくこの手順は完了。&lt;/p&gt;
&lt;h3&gt;SVNのログイン情報を登録&lt;/h3&gt;
&lt;p&gt;下記の手順で該当ページまで遷移する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Settings → Secrets and variables → Actions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;遷移後、&lt;code&gt;New repository secret&lt;/code&gt;をクリックし、&lt;code&gt;SVN_USERNAME&lt;/code&gt;と&lt;code&gt;SVN_PASSWORD&lt;/code&gt;の登録をする。&lt;/p&gt;
&lt;p&gt;それぞれWordPress.orgログイン情報と同じだった。&lt;/p&gt;
&lt;h2&gt;デプロイしてみる&lt;/h2&gt;
&lt;p&gt;開発環境で下記コマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git tag 0.0.1
git push origin 0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;タグが発行されるたびに&lt;code&gt;Github Actions&lt;/code&gt;が発火し、WordPress.orgのプラグインリポジトリにデプロイしてくれる。&lt;/p&gt;
&lt;p&gt;これでWordPressのプラグインを同一管理できるようになった。&lt;/p&gt;
&lt;p&gt;● 参考&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wp.tekapo.com/2019/11/26/wordpress-github-actions-plugin-deployment-by-10up-workflow/&quot;&gt;GitHub ActionsでWordPressのプラグインをGitHubのリポジトリからWordPress.orgのプラグインリポジトリにデプロイする。&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>TypeScriptで定義済みの型からプロパティを取り出し新しい型を作る方法</title><link>https://blog.nove-b.dev/posts/typescript-pick-properties</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/typescript-pick-properties</guid><content:encoded>&lt;h2&gt;過去に定義した型から新しい型を生成する&lt;/h2&gt;
&lt;p&gt;TypeScriptで型を定義したのち、その中の一部を使いたくなる時がある。&lt;/p&gt;
&lt;p&gt;例えば、&lt;code&gt;Person&lt;/code&gt;という型を定義した時、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export interface Person {
  age: number
  sex: &apos;man&apos; | &apos;woman&apos;
  bloodType: &apos;A&apos; | &apos;B&apos; | &apos;O&apos; | &apos;AB&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;bloodType&lt;/code&gt;という型を使用したいという時がある。&lt;/p&gt;
&lt;p&gt;そういう時は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export type BloodType = Person[&apos;bloodType&apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように書くことで型を取り出すことができる。&lt;/p&gt;
&lt;h2&gt;最初から最小で作るの吉？&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;export interface Age {
  age: number;
}

export type Sex = &apos;man&apos; | &apos;woman&apos;;

export type BloodType = &apos;A&apos; | &apos;B&apos; | &apos;O&apos; | &apos;AB&apos;;

export interface Person {
  age: Age;
  sex: Sex;
  bloodType: BloodType;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そもそも上記のように最小で作っておいた方がいい？&lt;/p&gt;
&lt;p&gt;ただ使わないものも多いので、取り出す方が労力が少なく済みそうな気がする。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React NativeでBottom Tabs Navigatorを使用しタブナビゲーションを実装する</title><link>https://blog.nove-b.dev/posts/implement-bottom-tabs-navigator-react-native</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/implement-bottom-tabs-navigator-react-native</guid><content:encoded>&lt;p&gt;スマホアプリでよく見るボトムメニューを&lt;code&gt;React Native&lt;/code&gt;で導入するには、&lt;code&gt;Bottom Tabs Navigator&lt;/code&gt;というパッケージをインストールする必要がある。&lt;/p&gt;
&lt;p&gt;ちなみにナビゲーションには他にも&lt;code&gt;Stack Navigator&lt;/code&gt;というものもあり、こちらは一覧画面から詳細画面への遷移等に用いられるらしい。&lt;/p&gt;
&lt;p&gt;詳細は↓に引用した。&lt;/p&gt;
&lt;h3&gt;StackNavigator&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;StackNavigatorは主にはアプリにおける「一覧画面」と「詳細画面」のような関係性がある画面間の遷移の用いられます。特徴として画面が手前に積み重なっていくような挙動をし、iOSの右スワイプ(画面の左端を掴んで右にスワイプ)やAndroidの戻るボタンで1つ前の画面に戻ることができます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://zenn.dev/nekoniki/articles/1fce848b88ff0f&quot;&gt;【RN】StackとBottomTabNavigatorを組み合わせたサンプル&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;BottomTabNavigator&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;アプリにおいて機能がいくつかのカテゴリに分かれている場合にBottomTabNavigatorは用いられます。TwitterやFacebookやInstagramなど、多機能なアプリは大概このBottomTabNavigatorで画面制御を行っています。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://zenn.dev/nekoniki/articles/1fce848b88ff0f&quot;&gt;【RN】StackとBottomTabNavigatorを組み合わせたサンプル&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;実践していく&lt;/h2&gt;
&lt;p&gt;まずは移動するページが欲しいので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir src
mkdir src/screens
touch src/screens/Sample.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;適当に作成する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sample.tsx&lt;/code&gt;は&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React from &quot;react&quot;;
import { ScrollView, View, Text } from &quot;react-native&quot;;
const Sample = () =&amp;gt; {
    return (
        &amp;lt;ScrollView&amp;gt;
            &amp;lt;View&amp;gt;
                &amp;lt;Text&amp;gt;Sample&amp;lt;/Text&amp;gt;
            &amp;lt;/View&amp;gt;
        &amp;lt;/ScrollView&amp;gt;
    )
}

export default Sample;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じになる。&lt;/p&gt;
&lt;p&gt;ちなみに、&lt;code&gt;div&lt;/code&gt;に相当するものが&lt;code&gt;View&lt;/code&gt;コンポーネントで、&lt;code&gt;p&lt;/code&gt;タグに相当するのが&lt;code&gt;Text&lt;/code&gt;コンポーネント。そして&lt;code&gt;ScrollView&lt;/code&gt;はコンテンツをスクロールできるようにするもの。&lt;/p&gt;
&lt;p&gt;作成したページを&lt;code&gt;App.tsx&lt;/code&gt;で読み込む。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import Sample from &apos;./src/screens/Sample&apos;

export default function App() {
  return (
    &amp;lt;Sample /&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同様に&lt;code&gt;Sample2&lt;/code&gt;とかを作成する。&lt;/p&gt;
&lt;p&gt;ただこの時点で&lt;code&gt;App.tsx&lt;/code&gt;に読み込むのは。&lt;code&gt;Sample&lt;/code&gt;か&lt;code&gt;Sample2&lt;/code&gt;のどちらか一方でいい。&lt;/p&gt;
&lt;h2&gt;必要なパッケージをインストールする&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm install @react-navigation/native
npx expo install react-native-screens react-native-safe-area-context
npm install @react-navigation/bottom-tabs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記インストール後に&lt;code&gt;App.tsx&lt;/code&gt;を下記のように変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { NavigationContainer } from &apos;@react-navigation/native&apos;
import Sample from &apos;./src/screens/Sample&apos;
import Sample2 from &apos;./src/screens/Sample2&apos;;
import { createBottomTabNavigator } from &apos;@react-navigation/bottom-tabs&apos;;

const Tab = createBottomTabNavigator();

export default function App() {
  return (

    &amp;lt;Tab.Navigator&amp;gt;
      &amp;lt;Tab.Screen
      name=&quot;Sample&quot;
      component={Sample}
      /&amp;gt;
      &amp;lt;Tab.Screen
      name=&quot;Sample2&quot;
      component={Sample2}
      /&amp;gt;
    &amp;lt;/Tab.Navigator&amp;gt;

  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでタブは完成した。&lt;/p&gt;
&lt;p&gt;実機で確認することでページ遷移していることを確認できる。&lt;/p&gt;
&lt;h3&gt;カスタマイズの例&lt;/h3&gt;
&lt;h2&gt;アイコンの付与&lt;/h2&gt;
&lt;p&gt;タブにアイコンを付与するには、&lt;/p&gt;
&lt;p&gt;&lt;code&gt;import { iconType } from &quot;@expo/vector-icons&quot;;&lt;/code&gt;でアイコンをインストールし、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Tab.Screen
  name=&quot;FromGift&quot;
  component={FromGift}
  options={{
    title: &quot;Give&quot;,
    tabBarIcon: ({ color, size }) =&amp;gt; (
      &amp;lt;SimpleLineIcons name=&quot;present&quot; color={color} size={size} /&amp;gt;
    ),
  }}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tabにオプションを追加する。&lt;/p&gt;
&lt;h2&gt;スタイルの変更&lt;/h2&gt;
&lt;p&gt;&amp;lt;html&amp;gt; &amp;lt;body&amp;gt; &amp;lt;!--StartFragment--&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;キーワード&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;headerStyle&lt;/td&gt;
&lt;td&gt;ヘッダーのスタイルを記述する部分&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;headerTintColor&lt;/td&gt;
&lt;td&gt;ヘッダーのタイトルの色&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;headerTitleStyle&lt;/td&gt;
&lt;td&gt;ヘッダータイトルのスタイルを記述する部分&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tabBarStyle&lt;/td&gt;
&lt;td&gt;下方のタブのスタイルを記述する部分&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tabBarInactiveTintColor&lt;/td&gt;
&lt;td&gt;タブバーアイコンの色&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tabBarActiveTintColor&lt;/td&gt;
&lt;td&gt;タブバーのアクティブ（表示されている方）の色&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;!--EndFragment--&amp;gt; &amp;lt;/body&amp;gt; &amp;lt;/html&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Tab.Navigator
    screenOptions={{
      headerStyle: {
        backgroundColor: &quot;#666&quot;,
      },
      headerTintColor: &quot;#fff&quot;,
      headerTitleStyle: {
        fontWeight: &quot;bold&quot;,
      },
      tabBarStyle: {
        backgroundColor: &quot;#666&quot;,
      },
      tabBarInactiveTintColor: &quot;#ffffff88&quot;,
      tabBarActiveTintColor: &quot;#fff&quot;,
    }}
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じでスタイルも変更できる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React NativeでStackNavigatorを使用し一覧から詳細への遷移を実装する</title><link>https://blog.nove-b.dev/posts/implement-stacknavigator-react-native</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/implement-stacknavigator-react-native</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/1090/&quot;&gt;過去&lt;/a&gt;に&lt;code&gt;Bottom Tabs Navigator&lt;/code&gt;を作成したので、今回は、&lt;code&gt;Stack Navigator&lt;/code&gt;を導入する。&lt;/p&gt;
&lt;p&gt;実装に期待する動きは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;タブ移動が可能&lt;/li&gt;
&lt;li&gt;タブ移動後に詳細ページへの遷移が可能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上記の通りなので、&lt;code&gt;Bottom Tabs Navigator&lt;/code&gt;と&lt;code&gt;Stack Navigator&lt;/code&gt;を併用する必要がある。&lt;/p&gt;
&lt;p&gt;その前提で進めていく。&lt;/p&gt;
&lt;h2&gt;必要なパッケージをインストールする&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm install @react-navigation/stack
npm install react-native-gesture-handler
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;インストール後、必要なファイルを作成する。&lt;/p&gt;
&lt;h2&gt;実装していく&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;mkdir src
mkdir src/stack
touch src/screens/SampleStackScreen.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;SampleStackScreen.tsx&lt;/code&gt;は下記の通りになる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React from &apos;react&apos;
import Sample from &apos;../screens/Sample&apos;
import { createStackNavigator } from &apos;@react-navigation/stack&apos;
import SampleDetail from &apos;../screens/SampleDetail&apos;
const Stack = createStackNavigator()

const SampleStackScreen = () =&amp;gt; {
  return (
    &amp;lt;Stack.Navigator screenOptions={{ headerShown: false }}&amp;gt;
      &amp;lt;Stack.Screen name=&quot;Sample&quot; component={Sample} /&amp;gt;
      &amp;lt;Stack.Screen name=&quot;SampleDetail&quot; component={SampleDetail} /&amp;gt;
    &amp;lt;/Stack.Navigator&amp;gt;
  )
}

export default SampleStackScreen
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記は、&lt;code&gt;Sample&lt;/code&gt;と&lt;code&gt;SampleDetail&lt;/code&gt;への遷移について書かれている。&lt;/p&gt;
&lt;p&gt;次にこれをタブナビゲーションに適応させる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App.tsx&lt;/code&gt;に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Tab.Screen
  name=&quot;SampleStackScreen&quot;
  component={SampleStackScreen}
  options={{
    title: &apos;Sample&apos;,
    tabBarIcon: ({ color, size }) =&amp;gt; (
      &amp;lt;SimpleLineIcons name=&quot;present&quot; color={color} size={size} /&amp;gt;
    ),
  }}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように記載する。&lt;/p&gt;
&lt;p&gt;これでタブ移動で&lt;code&gt;SampleStackScreen&lt;/code&gt;が開けるようになった。&lt;/p&gt;
&lt;p&gt;そしてここには一覧ページと詳細ページへの遷移が記述されているので、まず、&lt;code&gt;Sample&lt;/code&gt;が開く。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sample&lt;/code&gt;は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { NavigationProp, ParamListBase } from &apos;@react-navigation/native&apos;
import React from &apos;react&apos;
import { ScrollView, View, Text, FlatList, Button } from &apos;react-native&apos;

const data = [
  { id: &apos;1&apos;, text: &apos;アイテム 1&apos; },
  { id: &apos;2&apos;, text: &apos;アイテム 2&apos; },
  { id: &apos;3&apos;, text: &apos;アイテム 3&apos; },
  { id: &apos;4&apos;, text: &apos;アイテム 4&apos; },
  { id: &apos;5&apos;, text: &apos;アイテム 5&apos; },
  { id: &apos;6&apos;, text: &apos;アイテム 6&apos; },
  { id: &apos;7&apos;, text: &apos;アイテム 7&apos; },
  { id: &apos;8&apos;, text: &apos;アイテム 8&apos; },
  { id: &apos;9&apos;, text: &apos;アイテム 9&apos; },
  { id: &apos;10&apos;, text: &apos;アイテム 10&apos; },
  { id: &apos;11&apos;, text: &apos;アイテム 11&apos; },
  { id: &apos;12&apos;, text: &apos;アイテム 12&apos; },
  { id: &apos;13&apos;, text: &apos;アイテム 13&apos; },
  { id: &apos;14&apos;, text: &apos;アイテム 14&apos; },
  { id: &apos;15&apos;, text: &apos;アイテム 15&apos; },
  { id: &apos;16&apos;, text: &apos;アイテム 16&apos; },
  { id: &apos;17&apos;, text: &apos;アイテム 17&apos; },
  { id: &apos;18&apos;, text: &apos;アイテム 18&apos; },
  { id: &apos;19&apos;, text: &apos;アイテム 19&apos; },
  { id: &apos;20&apos;, text: &apos;アイテム 20&apos; },
]

interface SampleProps {
  navigation: NavigationProp&amp;lt;ParamListBase&amp;gt; // 必要に応じて正確な型を指定する
}

const Sample: React.FC&amp;lt;SampleProps&amp;gt; = ({ navigation }) =&amp;gt; {
  return (
    &amp;lt;ScrollView className=&quot;p-5&quot;&amp;gt;
      &amp;lt;FlatList
        data={data}
        keyExtractor={(item) =&amp;gt; item.id}
        renderItem={({ item }) =&amp;gt; (
          &amp;lt;View &amp;gt;
            &amp;lt;Text&amp;gt;コンテンツ {item.id}&amp;lt;/Text&amp;gt;
            &amp;lt;Button
              title=&quot;詳細へ&quot;
              onPress={() =&amp;gt;
                navigation.navigate(&apos;SampleDetail&apos;, { id: item.id })
              }
            /&amp;gt;
          &amp;lt;/View&amp;gt;
        )}
      /&amp;gt;
    &amp;lt;/ScrollView&amp;gt;
  )
}

export default Sample
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じにする。&lt;/p&gt;
&lt;p&gt;そうすると、20件のカードが表示される。&lt;/p&gt;
&lt;p&gt;そこにボタンがあり、ボタンをプレスすることで&lt;code&gt;SampleDetail&lt;/code&gt;に遷移する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SampleDetail&lt;/code&gt;は下記のように記載することで、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { RouteProp, useRoute } from &apos;@react-navigation/native&apos;
import React from &apos;react&apos;
import { ScrollView, View, Text } from &apos;react-native&apos;

type ParamList = {
  YourScreenName: { id: number } // ここでidの型を指定する
}

type RouteParams = RouteProp&amp;lt;ParamList, &apos;YourScreenName&apos;&amp;gt;

const SampletDetail = () =&amp;gt; {
  const route = useRoute()
  const id = route.params?.id
  return (


    詳細 { id }


)
}

export default SampletDetail
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;遷移後のページで&lt;code&gt;id&lt;/code&gt;が表示されるようになった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>ブログに埋め込まれたアフェリエイトリンクをチェックするChromeの拡張機能</title><link>https://blog.nove-b.dev/posts/check-affiliate-links-blog-chrome-extension</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/check-affiliate-links-blog-chrome-extension</guid><content:encoded>&lt;h2&gt;ステルスアフェリエイト広告の規制強化&lt;/h2&gt;
&lt;p&gt;よくわからないけど、ステルスマーケティングは景品表示法違反ということで、令和5年10月1日から規制されることになるらしい。&lt;/p&gt;
&lt;p&gt;ということでPR表記がないアフェリエイト広告（多くの場合PR表記なんてない）も規制の対象になるとのこと。&lt;/p&gt;
&lt;p&gt;なので、今後ステレスアフェリエイト広告は撲滅するかもしれないけれど、ニュースに疎いのでそんなことは知らなかった。&lt;/p&gt;
&lt;p&gt;知らなかったうえで、アフェリエイト広告に嫌気がさしたので、ブログに埋め込まれたアフェリエイトリンクをチェックするChromeの拡張機能を作ってみた。&lt;/p&gt;
&lt;h2&gt;アフェリエイト広告に嫌気がさし、Chrome拡張機能開発&lt;/h2&gt;
&lt;p&gt;アフェリエイト広告を自身もブログでやっていたことがあるので、何も知らずに騙されることはないが、やっていたので、どれがアフェリエイト広告なのか判断がつく。&lt;/p&gt;
&lt;p&gt;分かってしまうが結果、世の中アフェリエイト広告だらけという現実に嫌気がさしてきた。&lt;/p&gt;
&lt;p&gt;また見分けがつくとは言え、マウスオーバーしないと判断ができない。&lt;/p&gt;
&lt;p&gt;なので地雷原を歩くように最新の注意をはらってきた。&lt;/p&gt;
&lt;p&gt;まあ、別にアフェリエイト広告を踏んだところでどうでもいいんだけど、なんとなく気になる。&lt;/p&gt;
&lt;p&gt;そういった経緯で前述したようにブログに埋め込まれたアフェリエイトリンクをチェックするChromeの拡張機能を作った。&lt;/p&gt;
&lt;h2&gt;アフェリエイトリンクを赤枠で囲む拡張機能&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nove-b/AffiliateLinkChecker&quot;&gt;ブログに埋め込まれたアフェリエイトリンクをチェックするChromeの拡張機能&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;使用すると、&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/61-1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;のようにアフェリエイトリンクが赤枠で囲まれ、リンク文字列の前に💰マークが付く。&lt;/p&gt;
&lt;p&gt;これで一目でアフェリエイトリンクが判断でき、快適なブラウザ生活を送れるようになった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>アクセストークン等を使用せず、お手軽にMastodonのタイムラインをWebページに読み込むことできる仕組みを作成した</title><link>https://blog.nove-b.dev/posts/create-mastodon-timeline-without-access-token</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-mastodon-timeline-without-access-token</guid><content:encoded>&lt;h2&gt;Hello Mastodon&lt;/h2&gt;
&lt;p&gt;TwitterよりMastodonの方がよっぽど居心地がいい。&lt;/p&gt;
&lt;p&gt;ということでMastodonにより生息するようになったのだが、フォローしたい人もいないければ、フォローしてくれる人もいない。&lt;/p&gt;
&lt;p&gt;というのも分散型ということで、Mastodonは検索が弱く、フォローしたい人をうまく探し出せないようだった。&lt;/p&gt;
&lt;p&gt;そのため、エンジニアと相互関係になりたいのだが、そもそもフォローしたい人をいまだに見つけ出せずにいる。&lt;/p&gt;
&lt;p&gt;ということで、このブログに埋め込むことで、このブログにたどり着いてくれた人（たぶんエンジニア）にフォローをしてもらおうと思い立った。&lt;/p&gt;
&lt;p&gt;そこでこのブログにMastodonのタイムラインを埋め込んだ。&lt;/p&gt;
&lt;h2&gt;手軽にMastodonのタイムラインを埋め込める！&lt;/h2&gt;
&lt;p&gt;そしてどうせならだれでも使えるようにしようということで、公開することにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nove-b/mastodon-timeline&quot;&gt;mastodon-timeline&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;アクセストークン等を使用せず、お手軽にMastodonのタイムラインをWebページに読み込むことができますので、ぜひ使ってみてください。&lt;/p&gt;
&lt;p&gt;そしてFediverseで繋がりましょう。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/images/66-1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>コンパイルを含む、ワードプレスのテーマをLocal（旧Local by Flywheel）で作成する場合にシンボリックリンクを使うようになった</title><link>https://blog.nove-b.dev/posts/use-symlinks-for-wordpress-theme-local-development</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/use-symlinks-for-wordpress-theme-local-development</guid><content:encoded>&lt;h2&gt;WordPressのテーマをどう管理するか&lt;/h2&gt;
&lt;p&gt;Local（旧Local by
Flywheel）を使用してワードプレスのテーマを作成する時、フォルダ構成とかをどうすればいいのかいつも悩んでいた。&lt;/p&gt;
&lt;p&gt;作成したテーマをGithubで管理する場合は、Local（旧Local by
Flywheel）のフォルダ構成の中にテーマフォルダを作成し、その中をGit管理し、&lt;code&gt;node_modules&lt;/code&gt;もそこで管理していた。&lt;/p&gt;
&lt;p&gt;ただ本当にそれでいいのかしら。&lt;/p&gt;
&lt;p&gt;テーマの中に&lt;code&gt;node_modules&lt;/code&gt;がある場合はワードプレスにアップロードする時は&lt;code&gt;node_modules&lt;/code&gt;は削除したりして運用していたが、面倒くさい。&lt;/p&gt;
&lt;p&gt;そんな時に、いまさらながらと思われるかもだが、シンボリックリンクを知った。&lt;/p&gt;
&lt;h2&gt;シンボリックを使用してみる&lt;/h2&gt;
&lt;p&gt;シンボリックリンクを作成すれば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── .git
├── node_modules
├── package.json
├── src
└── theme-name
    ├── assets
    ├── index.php
    └── ...etc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のようなディレクト構成にし、開発ディレクトリの&lt;code&gt;src&lt;/code&gt;にある&lt;code&gt;Sass&lt;/code&gt;と&lt;code&gt;ts&lt;/code&gt;のようなコンパイルが必要なものを
&lt;code&gt;theme-name&lt;/code&gt;にビルドすることで、&lt;code&gt;theme-name&lt;/code&gt;に不要なものを格納せずに済む。&lt;/p&gt;
&lt;p&gt;そのうえで、&lt;code&gt;theme-name&lt;/code&gt;を&lt;code&gt;Local（旧Local by Flywheel）&lt;/code&gt;の&lt;code&gt;wp-content/themes/theme-name&lt;/code&gt;とリンクさせれば、良い。&lt;/p&gt;
&lt;p&gt;コマンドプロンプトを管理者で開き、下記コマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mklink /D &quot;C:\Users\USER_NAME\Local Sites\SITE_NAME\app\public\wp-content\themes_link&quot; &quot;C:\Users\USER_NAME\デスクトップ\SITE_NAME\wp\wp-content\themes/theme-name&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記はシンボリックを作成するコマンドで&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mklink /D &amp;lt;シンボリックリンクのパス&amp;gt; &amp;lt;リンク先のパス&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;となる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>nth-childとnth-of-typeの違いを理解する</title><link>https://blog.nove-b.dev/posts/understand-difference-between-nth-child-and-nth-of-type</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/understand-difference-between-nth-child-and-nth-of-type</guid><content:encoded>&lt;h2&gt;nth-child&lt;/h2&gt;
&lt;p&gt;親要素内のすべての子要素に対して適用され、その中から条件に一致する要素が選択される。 そのため要素の種類に関係なく、すべての子要素が考慮される。&lt;/p&gt;
&lt;h2&gt;nth-of-type&lt;/h2&gt;
&lt;p&gt;親要素内の特定の要素タイプ（タグ名）に対して適用され、その中から条件に一致する要素が選択される。 そのため要素の種類に基づいて選択がされる。&lt;/p&gt;
&lt;h2&gt;具体例&lt;/h2&gt;
&lt;p&gt;例えば以下のコードがあった時、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;example&quot;&amp;gt;
  &amp;lt;div&amp;gt;Item 1&amp;lt;/div&amp;gt;
  &amp;lt;p&amp;gt;Item 2&amp;lt;/p&amp;gt;
  &amp;lt;div&amp;gt;Item 3&amp;lt;/div&amp;gt;
  &amp;lt;p&amp;gt;Item 4&amp;lt;/p&amp;gt;
  &amp;lt;div&amp;gt;Item 5&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;nth-child&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;.example div:nth-child(3) {
  color: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この場合、.example内の直下のdiv要素の中から、3番目の要素（&quot;Item 3&quot;）が赤くなる。&lt;/p&gt;
&lt;h3&gt;nth-of-type&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;.example div:nth-of-type(3) {
  color: blue;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この場合、.example内の直下のdiv要素の中から、同じ種類の要素の中で3番目の要素（&quot;Item
5&quot;）が青くなる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>VS Codeの拡張機能「Ascii Tree Generator」を使用しツリーファイル構造をサクッと作成する</title><link>https://blog.nove-b.dev/posts/vs-code-ascii-tree-generator-tree-file-structure</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/vs-code-ascii-tree-generator-tree-file-structure</guid><content:encoded>&lt;h2&gt;VS Code の拡張機能「Ascii Tree Generator」&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=aprilandjan.ascii-tree-generator&quot;&gt;インストール&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ディレクトリ構造など面倒なツリーを#タグを使って簡単に書けるようにしてれる拡張機能。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aprilandjan/vscode-ascii-tree-generator&quot;&gt;Github&lt;/a&gt;のドキュメントに詳しい説明がある。&lt;/p&gt;
&lt;h2&gt;使用方法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# public
# dist
## index.d.ts
## index.js
# src
## index.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↑ のように作成し選択、&lt;code&gt;Ctrl+Shift+P&lt;/code&gt;でコマンドを開き、&lt;code&gt;Pre-Formatted Tree String&lt;/code&gt;を選択する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── public
├── dist
│   ├── index.d.ts
│   └── index.js
└── src
  └── index.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そうすると上記のように展開される。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go LangでWebAPIを作成するために、まずはDockerでMySQLを構築する</title><link>https://blog.nove-b.dev/posts/setup-docker-mysql-golang-webapi</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/setup-docker-mysql-golang-webapi</guid><content:encoded>&lt;p&gt;普段フロントエンドをメインとしているので、バックエンドの環境構築に疎い。 今までは&lt;code&gt;Firebase&lt;/code&gt;を使用することが多く、前回はじめて&lt;code&gt;NestJS&lt;/code&gt;で本格的にバックエンドの構築をした。 とは言え&lt;code&gt;NestJS&lt;/code&gt;は&lt;code&gt;Javascript&lt;/code&gt;である。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/822/&quot;&gt;Windows11に入れたMySQLとNest.Jsを接続し、テーブルを作成する&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;難しかったけど、新しいことに挑戦した感じがしなかった。 しかもその時、とにかく早く実装したかったので、&lt;code&gt;MySQL&lt;/code&gt;を&lt;code&gt;Windows&lt;/code&gt;にインストールしたうえでテストしていた。&lt;/p&gt;
&lt;p&gt;実際の案件ではそんなことありえないので、しっかり&lt;code&gt;Docker&lt;/code&gt;で環境を構築し、言語は&lt;code&gt;Go Lang&lt;/code&gt;を採用することにした。&lt;/p&gt;
&lt;h2&gt;まずはDockerでMySQLを構築する&lt;/h2&gt;
&lt;h3&gt;docker-compose.yaml を作成する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3&apos;
services:
  mysql:
    image: mysql:latest
    container_name: my-mysql-container
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
      MYSQL_DATABASE: your_database_name
      MYSQL_USER: your_username
      MYSQL_PASSWORD: your_password
    ports:
      , &quot;3306:3306&quot;
    volumes:
      - ./data:/var/lib/mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、&lt;code&gt;docker-compose up -d&lt;/code&gt;を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error during connect: this error may indicate that the docker daemon is not running: Get &quot;http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/containers/json?all=1&amp;amp;filters=%7B%22label%22%3A%7B%22com.docker.compose.project%3Dproject-backend%22%3Atrue%7D%7D&quot;: open //./pipe/docker_engine: The system cannot find the file specified.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出た。&lt;/p&gt;
&lt;p&gt;よく分からないけど、&lt;code&gt;Docker&lt;/code&gt;が起動していないことが原因のようなので、&lt;code&gt;Start-Service docker&lt;/code&gt;コマンドを入力しろと&lt;code&gt;GPT&lt;/code&gt;に教えてもらったが、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&apos;Start-Service&apos; は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出た。&lt;/p&gt;
&lt;h2&gt;Dockerを立ち上げる&lt;/h2&gt;
&lt;p&gt;そういえば&lt;code&gt;Docker Desktop&lt;/code&gt;なるものを過去に使ったことがあるのを思い出したので、&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Docker Desktop&lt;/code&gt;を立ち上げて再度挑戦してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker-compose up -d
[+] Running 11/11
 - mysql Pulled                                                    52.7s
   - 8e0176adc18c Pull complete                                     14.4s
   - 2d2c52718f65 Pull complete                                     14.7s
   - d88d03ce139b Pull complete                                     14.9s
   - 4a7d7f11aa1e Pull complete                                     15.5s
   - ce5949193e4c Pull complete                                     15.7s
   - f7f024dfb329 Pull complete                                     15.8s
   - 5fc3c840facc Pull complete                                     27.9s
   - 509068e49488 Pull complete                                     28.1s
   - cbc847bab598 Pull complete                                     45.2s
   - 942bef62a146 Pull complete                                     45.6s
[+] Running 2/2
 - Network project-backend_default  Created            0.4s
 - Container my-mysql-container                   Started            8.7s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;いけた、っぽい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HeidiSQL&lt;/code&gt;で接続してみる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ネットワークの種類: MySQL（必要に応じてSSHトンネリング）&lt;/li&gt;
&lt;li&gt;ホスト名/IP: 127.0.0.1（これはローカルマシンのIPアドレスです）&lt;/li&gt;
&lt;li&gt;ユーザー: Docker
Composeファイルで指定したMySQLユーザー（この場合、your_username）&lt;/li&gt;
&lt;li&gt;パスワード: Docker
Composeファイルで指定したMySQLパスワード（この場合、your_password）&lt;/li&gt;
&lt;li&gt;ポート: 3306（これはデフォルトのMySQLポート）&lt;/li&gt;
&lt;li&gt;データベース: Docker
Composeファイルで指定したMySQLデータベース（この場合、your_database_name）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上記手順で接続することができた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go LangでWebAPIを作成するために、GolangでMySQLに接続する</title><link>https://blog.nove-b.dev/posts/connect-mysql-golang-webapi</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/connect-mysql-golang-webapi</guid><content:encoded>&lt;h2&gt;HeidiSQLでSQLを実行する&lt;/h2&gt;
&lt;p&gt;次に、&lt;a href=&quot;https://media.nove-web.com/1124/&quot;&gt;Go LangでWebAPIを作成するために、まずはDockerでMySQLを構築する&lt;/a&gt;で作った&lt;code&gt;MySQL&lt;/code&gt;にデータベースを作成する。&lt;code&gt;HeidiSQL&lt;/code&gt;から作成しようとするが、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL 0A80E90FC (1044): Access denied for user &apos;your_username&apos;@&apos;%&apos; to database &apos;project&apos;uery
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という権限エラーが出るようになった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3&apos;
services:
  mysql:
    image: mysql:latest
    container_name: project
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: project
      MYSQL_USER: username
      MYSQL_PASSWORD: password
    ports:
      , &quot;3306:3306&quot;
    volumes:
      - ./data:/var/lib/mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に変更したらできた。ちょっと理由はわからない。&lt;/p&gt;
&lt;p&gt;で、projectというデータベースで&lt;code&gt;SQL&lt;/code&gt;を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE sample (
  id INT AUTO_INCREMENT PRIMARY KEY,
  firstName VARCHAR(255),
  lastName VARCHAR(255),
  isActive BOOLEAN DEFAULT TRUE
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでSampleのテーブルを作成することが出来た。&lt;/p&gt;
&lt;h2&gt;GoLangでテーブルを作成する&lt;/h2&gt;
&lt;p&gt;次に&lt;code&gt;GORM&lt;/code&gt;をインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を実行すると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require (
	github.com/jinzhu/inflection v1.0.0 // indirect
	github.com/jinzhu/now v1.1.5 // indirect
	github.com/mattn/go-sqlite3 v1.14.18 // indirect
	gorm.io/driver/sqlite v1.5.4 // indirect
	gorm.io/gorm v1.25.5 // indirect
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更新された。&lt;/p&gt;
&lt;p&gt;上のふたつは謎だけど、それっぽいのは入ってきた。&lt;/p&gt;
&lt;p&gt;よく考えたら&lt;code&gt;MySQL&lt;/code&gt;を使用するので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go get -u gorm.io/driver/mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;だった。&lt;/p&gt;
&lt;p&gt;ちなみに不要パッケージの削除方法はわからなかった。(要調査)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt;に下記をコピペ。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
package main

import (
	&quot;gorm.io/driver/mysql&quot;
	&quot;gorm.io/gorm&quot;
)

type User struct {
	// gorm.Modelをつけると、idとCreatedAtとUpdatedAtとDeletedAtが作られる
	gorm.Model

	Name     string
	Age      int
	IsActive bool
}

func main() {
	// dbを作成します
	db := dbInit()

	// dbをmigrateします
	db.AutoMigrate(&amp;amp;User{})
}

func dbInit() *gorm.DB {
	dsn := &quot;root:password@tcp(127.0.0.1:3306)/project?charset=utf8mb4&amp;amp;parseTime=true&quot;
	db, err := gorm.Open(mysql.Open(dsn), &amp;amp;gorm.Config{})
	if err != nil {
		panic(&quot;failed to connect database&quot;)
	}
	return db
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで実行すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ go run src/main.go

2023/11/28 17:51:13 C:/01_myPROJECT/project-Backend/src/main.go:22 SLOW SQL &amp;gt;= 200ms
[282.042ms] [rows:0] CREATE TABLE `users` (`id` bigint unsigned AUTO_INCREMENT,`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,`deleted_at` datetime(                    (3) NULL,`name` longtext,`age` bigint,`is_active` boolean,PRIMARY KEY (`id`),INDEX `idx_users_deleted_at` (`deleted_at`))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作成した&lt;code&gt;DB&lt;/code&gt;に&lt;code&gt;users&lt;/code&gt;テーブルが作成された。&lt;/p&gt;
&lt;p&gt;これで接続が確認できた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go LangでWebAPIを作成するために、Golangでサーバーを立ち上げる</title><link>https://blog.nove-b.dev/posts/setup-server-golang-webapi</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/setup-server-golang-webapi</guid><content:encoded>&lt;h2&gt;net/httpでサーバーを立ち上げる&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;DB&lt;/code&gt;と接続することはできたので、次はエンドポイント作成のためサーバーを立ち上げる。&lt;/p&gt;
&lt;p&gt;サーバーを構築する組み込みのパッケージが用意されているので、そちらを使用する。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pkg.go.dev/net/http&quot;&gt;net/http&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;インストールの仕方がないとか思っていたけど、組み込み、つまり標準装備なので特にインストールは必要なく、&lt;code&gt;import&lt;/code&gt;すれば使用可能だった。&lt;/p&gt;
&lt;p&gt;で、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
  &quot;fmt&quot;
  &quot;log&quot;
  &quot;net/http&quot;
)

func homePage(w http.ResponseWriter, r *http.Request){
  fmt.Fprintf(w, &quot;Welcome to the HomePage!&quot;)
  fmt.Println(&quot;Endpoint Hit: homePage&quot;)
}

func handleRequests() {
  http.HandleFunc(&quot;/&quot;, homePage)
  log.Fatal(http.ListenAndServe(&quot;:8081&quot;, nil))
}

func main() {
    handleRequests()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記をmain.goに記載したうえで、&lt;code&gt;$ go run src/main.go&lt;/code&gt;を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://localhost:8081/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に訪れると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Welcome to the HomePage!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;が表示されている。これでサーバー立ち上げの確認ができた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go LangでWebAPIを作成するために、GolangでエンドポイントにアクセスしDBからデータを取得する</title><link>https://blog.nove-b.dev/posts/access-endpoints-fetch-data-golang-webapi</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/access-endpoints-fetch-data-golang-webapi</guid><content:encoded>&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1125/&quot;&gt;Go LangでWebAPIを作成するために、GolangでMySQLに接続する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1126/&quot;&gt;Go LangでWebAPIを作成するために、Golangでサーバーを立ち上げる&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;で&lt;code&gt;DB&lt;/code&gt;と接続することはできたし、サーバーを立ち上げることに成功した。&lt;/p&gt;
&lt;h2&gt;User情報を取得するAPIを作成する&lt;/h2&gt;
&lt;p&gt;次は、特定のエンドポイントにアクセスした際に、&lt;code&gt;DB&lt;/code&gt;からデータを取得する。&lt;/p&gt;
&lt;p&gt;具体的には&lt;code&gt;http://localhost:8081/usrs&lt;/code&gt;にアクセスした際に&lt;code&gt;users&lt;/code&gt;テーブルのデータを取得できるようにしたい。&lt;/p&gt;
&lt;h3&gt;エンドポイントを作成する&lt;/h3&gt;
&lt;p&gt;まずは&lt;code&gt;http://localhost:8081/usrs&lt;/code&gt;のエンドポイントを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func sample(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, &quot;Welcome to the sample!&quot;)
	fmt.Println(&quot;Endpoint Hit: sample&quot;)
}

func handleRequests() {
	http.HandleFunc(&quot;/sample&quot;, sample)
	log.Fatal(http.ListenAndServe(&quot;:8081&quot;, nil))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;handleRequests&lt;/code&gt;を&lt;code&gt;main&lt;/code&gt;関数の中で実行すれば&lt;code&gt;http://localhost:8081/usrs&lt;/code&gt;にアクセスした際に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Welcome to the sample
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と表示されるようになった。&lt;/p&gt;
&lt;p&gt;ちになみに、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	fmt.Fprintf(w, &quot;Welcome to the sample!&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記の&lt;code&gt;w&lt;/code&gt;が謎で調べてみたところ、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;w を使用して Write メソッドを呼び出すことで、HTTPレスポンスの本文をクライアントに送信することができます。fmt.Fprintf(w,
&quot;Welcome to the
sample!&quot;) は、fmt.Fprintf 関数を使用してフォーマットされた文字列を w.Write を介してクライアントに送信しています。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことだった。&lt;/p&gt;
&lt;p&gt;いまいち理解しかねるけれど、なんとなく必要なことは分かった。&lt;/p&gt;
&lt;h3&gt;DBのデータをフェッチする&lt;/h3&gt;
&lt;p&gt;次に&lt;code&gt;http://localhost:8081/usrs&lt;/code&gt;にアクセスした際にDBの値を返すようにしてみる。&lt;/p&gt;
&lt;p&gt;まずは&lt;code&gt;DB&lt;/code&gt;に接続する関数を作成する。 これは前回も作成した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func dbInit() *gorm.DB {
	dsn := &quot;root:password@tcp(127.0.0.1:3306)/project?charset=utf8mb4&amp;amp;parseTime=true&quot;
	db, err := gorm.Open(mysql.Open(dsn), &amp;amp;gorm.Config{})
	if err != nil {
		panic(&quot;failed to connect database&quot;)
	}
	return db
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に、&lt;code&gt;DB&lt;/code&gt;から&lt;code&gt;Fetch&lt;/code&gt;する関数を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
var users []User

func fetchUsers(w http.ResponseWriter, r *http.Request) {
	db := dbInit()

	db.Find(&amp;amp;users)
	fmt.Println(users)
	profJson, _ := json.Marshal(users)
	fmt.Fprintf(w, string(profJson))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最後にエンドポイントにアクセスした際に&lt;code&gt;fetchUsers&lt;/code&gt;を実行するように設定する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func handleRequests() {
	http.HandleFunc(&quot;/users&quot;, fetchUsers)
	log.Fatal(http.ListenAndServe(&quot;:8081&quot;, nil))
}

func main() {
	handleRequests()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで&lt;code&gt;http://localhost:8081/users&lt;/code&gt;にアクセスすると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[{&quot;ID&quot;:1,&quot;CreatedAt&quot;:&quot;2023-01-01T12:00:00Z&quot;,&quot;UpdatedAt&quot;:&quot;2023-01-01T12:30:00Z&quot;,&quot;DeletedAt&quot;:null,&quot;Name&quot;:&quot;John Doe&quot;,&quot;Age&quot;:25,&quot;IsActive&quot;:true},{&quot;ID&quot;:2,&quot;CreatedAt&quot;:&quot;2023-01-02T09:15:00Z&quot;,&quot;UpdatedAt&quot;:&quot;2023-01-02T10:00:00Z&quot;,&quot;DeletedAt&quot;:null,&quot;Name&quot;:&quot;Jane Smith&quot;,&quot;Age&quot;:30,&quot;IsActive&quot;:false}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;が取得できた。&lt;/p&gt;
&lt;p&gt;全体像はこんな感じ。&lt;/p&gt;
&lt;h2&gt;全体のコード&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;

	&quot;gorm.io/driver/mysql&quot;
	&quot;gorm.io/gorm&quot;
)

type User struct {
	// gorm.Modelをつけると、idとCreatedAtとUpdatedAtとDeletedAtが作られる
	gorm.Model

	Name     string
	Age      int
	IsActive bool
}

var users []User

func handleRequests() {
	http.HandleFunc(&quot;/users&quot;, fetchUsers)
	log.Fatal(http.ListenAndServe(&quot;:8081&quot;, nil))
}

func main() {
	handleRequests()
}

func dbInit() *gorm.DB {
	dsn := &quot;root:password@tcp(127.0.0.1:3306)/project?charset=utf8mb4&amp;amp;parseTime=true&quot;
	db, err := gorm.Open(mysql.Open(dsn), &amp;amp;gorm.Config{})
	if err != nil {
		panic(&quot;failed to connect database&quot;)
	}
	return db
}

func fetchUsers(w http.ResponseWriter, r *http.Request) {
	db := dbInit()

	db.Find(&amp;amp;users)
	fmt.Println(users)
	profJson, _ := json.Marshal(users)
	fmt.Fprintf(w, string(profJson))
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;全体のコード（リファクタリング版）&lt;/h2&gt;
&lt;p&gt;ここまでをリファクタリングしてみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;os&quot;

	&quot;github.com/joho/godotenv&quot;
	&quot;gorm.io/driver/mysql&quot;
	&quot;gorm.io/gorm&quot;
)

type User struct {
	// gorm.Modelをつけると、idとCreatedAtとUpdatedAtとDeletedAtが作られる
	gorm.Model

	Name     string
	Age      int
	IsActive bool
}

var db *gorm.DB

func init() {
	err := godotenv.Load() // 追加
	if err != nil {
		log.Fatal(&quot;Error loading .env file&quot;)
	}
	db = initDB()
}

func initDB() *gorm.DB {
	dsn := os.Getenv(&quot;DB_CONNECTION_STRING&quot;)
	if dsn == &quot;&quot; {
		log.Fatal(&quot;DB_CONNECTION_STRING 環境変数が設定されていません&quot;)
	}

	db, err := gorm.Open(mysql.Open(dsn), &amp;amp;gorm.Config{})
	if err != nil {
		log.Fatalf(&quot;データベースへの接続に失敗しました: %v&quot;, err)
	}

	return db
}

func handleRequests() {
	http.HandleFunc(&quot;/users&quot;, fetchUsers)
	log.Fatal(http.ListenAndServe(&quot;:8081&quot;, nil))
}

func main() {
	handleRequests()
}

func fetchUsers(w http.ResponseWriter, r *http.Request) {
	var users []User
	db.Find(&amp;amp;users)

	profJSON, err := json.Marshal(users)
	if err != nil {
		http.Error(w, &quot;ユーザーデータのマーシャリングに失敗しました&quot;, http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, string(profJSON))
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;を使用するために、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go get github.com/joho/godotenv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を実行する必要がある。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go LangでWebAPIを作成するために、GolangでDBのデータを取得するmainファイルをそれぞれの責務に分割する</title><link>https://blog.nove-b.dev/posts/split-main-file-responsibilities-golang-webapi</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/split-main-file-responsibilities-golang-webapi</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://media.nove-web.com/1127/&quot;&gt;Go LangでWebAPIを作成するために、GolangでエンドポイントにアクセスしDBからデータを取得する&lt;/a&gt;でデータ取得の処理は確認できた。&lt;/p&gt;
&lt;h2&gt;リファクタリング&lt;/h2&gt;
&lt;p&gt;次に現状、&lt;code&gt;main.go&lt;/code&gt;にすべての記述をしていたが、それぞれ簡単に責務ごとにフォルダを分けることにした。&lt;/p&gt;
&lt;p&gt;分け方は、下記の通り。&lt;/p&gt;
&lt;h3&gt;db フォルダ:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;データベース関連の処理:
db フォルダは主にデータベースとのやり取りに関するコードを含みます。&lt;/li&gt;
&lt;li&gt;データベースの初期化:
db.go ファイルではデータベースの初期化と接続に関するコードがあります。&lt;/li&gt;
&lt;li&gt;モデルの定義: データベースのテーブルに対応するモデルを定義します（例:
db.Model）。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// db/db.go
package db

import (
	&quot;fmt&quot;
	&quot;os&quot;

	&quot;gorm.io/driver/mysql&quot;
	&quot;gorm.io/gorm&quot;
)

var DB *gorm.DB

type Model struct {
	gorm.Model
}

func InitDB() {
	dsn := os.Getenv(&quot;DB_CONNECTION_STRING&quot;)
	if dsn == &quot;&quot; {
		fmt.Println(&quot;DB_CONNECTION_STRING 環境変数が設定されていません&quot;)
		os.Exit(1)
	}

	var err error
	DB, err = gorm.Open(mysql.Open(dsn), &amp;amp;gorm.Config{})
	if err != nil {
		fmt.Printf(&quot;データベースへの接続に失敗しました: %v\n&quot;, err)
		os.Exit(1)
	}

	fmt.Println(&quot;データベースに接続しました&quot;)
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;handlers フォルダ:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;HTTP ハンドラとリクエスト処理:
handlers フォルダは主に HTTP リクエストを処理し、それに対するレスポンスを生成するコードを含みます。&lt;/li&gt;
&lt;li&gt;ルーティング: リクエストのルーティングやエンドポイントの定義が handlers.go にあります。&lt;/li&gt;
&lt;li&gt;特定の機能の処理: 例えば、user_handler.go ではユーザー関連の処理が定義されています。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// handlers/handlers.go
package handlers

import (
	&quot;project-Backend/src/db&quot;
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;
)

type User struct {
	db.Model // ここで埋め込みを行う

	Name     string
	Age      int
	IsActive bool
}

func HandleRequests() {
	http.HandleFunc(&quot;/users&quot;, FetchUsers)
	log.Fatal(http.ListenAndServe(&quot;:8081&quot;, nil))
}

func FetchUsers(w http.ResponseWriter, r *http.Request) {
	db := db.DB

	var users []User
	db.Find(&amp;amp;users)

	profJSON, err := json.Marshal(users)
	if err != nil {
		http.Error(w, &quot;ユーザーデータのマーシャリングに失敗しました&quot;, http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, string(profJSON))
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;main.go:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;プログラムのエントリーポイントである main.go には、アプリケーションの起動や初期化といった主要な機能&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// main.go
package main

import (
	&quot;log&quot;

	&quot;project-Backend/src/db&quot;
	&quot;project-Backend/src/handlers&quot;

	&quot;github.com/joho/godotenv&quot;
)

func init() {
	err := godotenv.Load()
	if err != nil {
		log.Fatal(&quot;Error loading .env file&quot;)
	}

	db.InitDB()
}

func main() {
	handlers.HandleRequests()
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで分かりやすくなった。&lt;/p&gt;
&lt;h3&gt;handlers フォルダを詳細に&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;FetchUsers&lt;/code&gt;もついでに分けることにする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// handlers/user_handler.go
package handlers

import (
	&quot;project-Backend/src/db&quot;
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;net/http&quot;
)

type User struct {
	db.Model

	Name     string
	Age      int
	IsActive bool
}

func FetchUsers(w http.ResponseWriter, r *http.Request) {
	db := db.DB

	var users []User
	db.Find(&amp;amp;users)

	profJSON, err := json.Marshal(users)
	if err != nil {
		http.Error(w, &quot;ユーザーデータのマーシャリングに失敗しました&quot;, http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, string(profJSON))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// handlers/handlers.go
package handlers

import (
	&quot;log&quot;
	&quot;net/http&quot;
)

func HandleRequests() {
	http.HandleFunc(&quot;/users&quot;, FetchUsers)
	log.Fatal(http.ListenAndServe(&quot;:8081&quot;, nil))
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでそれぞれ管理しやすくなった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>情報収集のためにRSSを作成した。</title><link>https://blog.nove-b.dev/posts/create-rss-information-gathering</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-rss-information-gathering</guid><content:encoded>&lt;h2&gt;作ったもの&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;nove-b.github.io/feed/&quot;&gt;📰💬✨｜購読している記事とか、好きなサイトとか。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;気になるURLを&lt;code&gt;osmosfeed.yaml&lt;/code&gt;にまとめて、購読する&lt;code&gt;RSS Feed&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;情報過多で、時間がない中、常々欲しいと思っていたが、しっくりくるアプリがなく、自分で作ることにした。&lt;/p&gt;
&lt;p&gt;書いているブログが個人を象徴するポートフォリオになるように、購読している記事も個人を象徴する気がする。&lt;/p&gt;
&lt;p&gt;購読している記事をプロフィールに掲載するサービスもおもしろいかもしれない。&lt;/p&gt;
&lt;p&gt;さて、作り方だけれど、&lt;/p&gt;
&lt;h2&gt;osmosfeed&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/osmoscraft/osmosfeed&quot;&gt;osmosfeed&lt;/a&gt;を使えば簡単にできた。&lt;/p&gt;
&lt;p&gt;仕組みとしては&lt;code&gt;Github Action&lt;/code&gt;で購読しているサイトの新着記事を自動で取得してくれるというもの。&lt;/p&gt;
&lt;h3&gt;作り方&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/osmoscraft/osmosfeed#readme&quot;&gt;Readme&lt;/a&gt;に書いてある通りに進めていけば基本的に問題ない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Github Action&lt;/code&gt;でエラーが出たけど、こちらのリポジトリが参照している&lt;code&gt;Github Action&lt;/code&gt;のコアのリポジトリを参照にしたところ解決した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/osmoscraft/osmosfeed/issues/81&quot;&gt;build error aftermodified osmosfeed.yaml when Deploy to Github pages: Permission to &amp;lt;xxxx/xxx&amp;gt;.git denied to github-actions[bot]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Closeしていたけど、一応解決方法をコメントしておいた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go Langで新規登録と退会のWebAPIを作成したので、やったことをまとめてみる。</title><link>https://blog.nove-b.dev/posts/create-signup-unsubscribe-webapi-golang</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-signup-unsubscribe-webapi-golang</guid><content:encoded>&lt;h2&gt;いたるまで&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1124/&quot;&gt;Go Lang で WebAPI を作成するために、まずは Docker で MySQL を構築する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1125/&quot;&gt;Go Lang で WebAPI を作成するために、Golang で MySQL に接続する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1126/&quot;&gt;Go Lang で WebAPI を作成するために、Golang でサーバーを立ち上げる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1127/&quot;&gt;Go Lang で WebAPI を作成するために、Golang でエンドポイントにアクセスし DB からデータを取得する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://media.nove-web.com/1140/&quot;&gt;Go Lang で WebAPI を作成するために、Golang で DB のデータを取得する main ファイルをそれぞれの責務に分割する&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;ディレクトリ構成&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;.
├── db
├── db.go
├── handlers
│   ├── auth
│   │   ├── delete_user_handler.go
│   │   └── create_user_handler.go
│   └── handlers.go
├── models
│   └── user_model.go
└── main.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように作成した。&lt;/p&gt;
&lt;p&gt;簡単に説明すると、&lt;/p&gt;
&lt;h3&gt;db/db.go&lt;/h3&gt;
&lt;p&gt;データベースとの接続が行われる。&lt;/p&gt;
&lt;h3&gt;handlers/handlers.go&lt;/h3&gt;
&lt;p&gt;HTTP リクエストに対する処理を管理している。&lt;/p&gt;
&lt;h3&gt;handlers/auth/handlers.go&lt;/h3&gt;
&lt;p&gt;ユーザー作成・削除に対する処理を作成している。&lt;/p&gt;
&lt;h3&gt;handlers/models/user_model.go&lt;/h3&gt;
&lt;p&gt;ユーザーに関する構造体を定義している。 データーベースモデル。&lt;/p&gt;
&lt;h2&gt;処理を追いかける&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;---
// main.go
---

package main

import (
	&quot;log&quot;

	&quot;GiveAndTakeCollection-Backend/src/db&quot;
	&quot;GiveAndTakeCollection-Backend/src/handlers&quot;
	&quot;GiveAndTakeCollection-Backend/src/models&quot;

	&quot;github.com/joho/godotenv&quot;
)

func init() {
	err := godotenv.Load()
	if err != nil {
		log.Fatal(&quot;Error loading .env file&quot;)
	}

	db.InitDB()
	db.DB.AutoMigrate(&amp;amp;models.User{})
}

func main() {
	handlers.HandleRequests()
}


&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;データーベースと接続する&lt;/h2&gt;
&lt;h3&gt;プログラム初期化時に init 関数が実行&lt;/h3&gt;
&lt;p&gt;まずプログラム初期化時に&lt;code&gt;init&lt;/code&gt;関数が実行される。&lt;/p&gt;
&lt;p&gt;これは&lt;code&gt;Golang&lt;/code&gt;の特殊仕様。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;godotenv.Load()&lt;/code&gt;で&lt;code&gt;godotenv&lt;/code&gt;ライブラリを使用し、&lt;code&gt;.env&lt;/code&gt;を読み込む。&lt;/p&gt;
&lt;p&gt;エラーが出た際は&lt;code&gt;err&lt;/code&gt;にエラーオブジェクトをセットする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if err != nil&lt;/code&gt;は Go 言語においてエラー処理を行う際の一般的な書き方。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;env&lt;/code&gt;が読み込めなかった場合、&lt;code&gt;log.Fatal(&quot;Error loading .env file&quot;)&lt;/code&gt;が実行される。&lt;/p&gt;
&lt;p&gt;実行されることで、メッセージをログに記録し、それからプログラムを即座に終了する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;log.Fatal()&lt;/code&gt;は致命的なエラーが発生した場合に使われるログ出力関数らしい。&lt;/p&gt;
&lt;h3&gt;db.InitDB()が実行される&lt;/h3&gt;
&lt;p&gt;問題がなければ&lt;code&gt;db.InitDB()&lt;/code&gt;が実行される。&lt;/p&gt;
&lt;p&gt;こちらはインポートされた&lt;code&gt;&quot;GiveAndTakeCollection-Backend/src/db&quot;&lt;/code&gt;の&lt;code&gt;InitDB&lt;/code&gt;関数が呼ばれる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
// db/db.go
---
package db

import (
	&quot;fmt&quot;
	&quot;os&quot;

	&quot;gorm.io/driver/mysql&quot;
	&quot;gorm.io/gorm&quot;
)

var DB *gorm.DB


// 不要？
type Model struct {
	gorm.Model
}

func InitDB() {
	dsn := os.Getenv(&quot;DB_CONNECTION_STRING&quot;)
	if dsn == &quot;&quot; {
		fmt.Println(&quot;DB_CONNECTION_STRING 環境変数が設定されていません&quot;)
		os.Exit(1)
	}

	var err error
	DB, err = gorm.Open(mysql.Open(dsn), &amp;amp;gorm.Config{})
	if err != nil {
		fmt.Printf(&quot;データベースへの接続に失敗しました: %v\n&quot;, err)
		os.Exit(1)
	}

	fmt.Println(&quot;データベースに接続しました&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;先頭で&lt;code&gt;package db&lt;/code&gt;と定義しているため、&lt;code&gt;db.InitDB()&lt;/code&gt;で呼び出すことができる。&lt;/p&gt;
&lt;p&gt;このファイルではまず、&lt;code&gt;gorm.DB&lt;/code&gt;型のポインタ変数&lt;code&gt;DB&lt;/code&gt;を宣言している。これは&lt;code&gt;Gorm&lt;/code&gt;のデータベース接続を表す変数。&lt;/p&gt;
&lt;p&gt;ちなみに、ポインタ変数というのは「変数のメモリアドレスを格納するための特別な型の変数」ということらしい。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;変数にはデータそのものが格納されますが、ポインタ変数にはメモリアドレスが格納されます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;code&gt;Go&lt;/code&gt;では下記のように宣言する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var x int  // 通常の変数
var ptr *int  // int型のポインタ変数
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;詳細な使い方は調べる必要がある。&lt;/p&gt;
&lt;p&gt;あと&lt;code&gt;var DB *gorm.DB&lt;/code&gt;パッケージレベルで行う方がいいらしい。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;var DB
*gorm.DB の宣言が initDB 関数の中で行われる場合、その変数はローカル変数として initDB 関数のスコープ内にのみ存在します。この場合、他の関数やファイルから DB 変数にアクセスすることができなくなります。&lt;/p&gt;
&lt;p&gt;一般的に、データベース接続などのリソースはアプリケーション全体で共有されることが多いため、var
DB
*gorm.DB の宣言は関数の外、パッケージレベルで行われることがあります。これにより、他の関数やファイルから DB 変数にアクセスでき、アプリケーション内で一貫性のあるデータベース接続が確保されます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;話を戻して次に、&lt;code&gt;db.InitDB()&lt;/code&gt;の処理を追いかける。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	dsn := os.Getenv(&quot;DB_CONNECTION_STRING&quot;)
	if dsn == &quot;&quot; {
		fmt.Println(&quot;DB_CONNECTION_STRING 環境変数が設定されていません&quot;)
		os.Exit(1)
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;dsn&lt;/code&gt;という変数に、&lt;code&gt;os.Getenv(&quot;DB_CONNECTION_STRING&quot;)&lt;/code&gt;で取得した環境変数を格納する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;os.Getenv&lt;/code&gt;の戻り値の型は&lt;code&gt;string&lt;/code&gt;なので、もし環境変数が空文字であれば、エラーメッセージを標準出力し、プログラムを終了する。&lt;/p&gt;
&lt;p&gt;ちなみに引数は下記の通り。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;os.Exit(0): プログラムの正常な終了を示します。&amp;lt;br&amp;gt;
os.Exit(1): プログラムがエラーで終了したことを示します。&lt;/p&gt;
&lt;p&gt;一般的には非ゼロの終了コードはエラーを示す慣習とされています。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;環境変数が適切に設定されていた場合は下記コードが実行される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	var err error
	DB, err = gorm.Open(mysql.Open(dsn), &amp;amp;gorm.Config{})
	if err != nil {
		fmt.Printf(&quot;データベースへの接続に失敗しました: %v\n&quot;, err)
		os.Exit(1)
	}

	fmt.Println(&quot;データベースに接続しました&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここでは、まずエラー変数を定義し、&lt;code&gt;Gorm&lt;/code&gt;を使用して&lt;code&gt;MySQL&lt;/code&gt;データベースに接続する。&lt;/p&gt;
&lt;p&gt;成功すると&lt;code&gt;DB&lt;/code&gt;に接続が設定され、失敗するとエラーがエラー変数に格納される。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if err != nil { ... }&lt;/code&gt;でエラーチェックが実行され、エラーの場合はエラーメッセージを標準出力し、プログラムを終了する。&lt;/p&gt;
&lt;p&gt;問題がなければ、&lt;code&gt;データベースに接続しました&lt;/code&gt;が標準出力に表示される。&lt;/p&gt;
&lt;p&gt;ここまでで、データベースの接続が完了し、次に&lt;code&gt;main&lt;/code&gt;関数が呼ばれる。&lt;/p&gt;
&lt;h2&gt;HTTP リクエストを処理するためのルーティングとサーバーの起動&lt;/h2&gt;
&lt;h3&gt;main 関数が実行される&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	handlers.HandleRequests()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;main&lt;/code&gt;関数では上記の通り、handlers パッケージが呼ばれている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// handlers/handlers.go
package handlers

import (
	&quot;GiveAndTakeCollection-Backend/src/handlers/auth&quot;
	&quot;log&quot;
	&quot;net/http&quot;
)

func HandleRequests() {
	http.HandleFunc(&quot;/auth/new&quot;, auth.CreateUser)
	http.HandleFunc(&quot;/auth/delete&quot;, auth.DeleteUser)
	log.Fatal(http.ListenAndServe(&quot;:8081&quot;, nil))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;HandleRequests&lt;/code&gt;関数は、HTTP リクエストを処理するためのルーティングとサーバーの起動を行っている。&lt;/p&gt;
&lt;p&gt;これにより、&lt;code&gt;/auth/new&lt;/code&gt;へのリクエストは&lt;code&gt;auth.CreateUser&lt;/code&gt;関数で処理され、&lt;code&gt;/auth/delete&lt;/code&gt;へのリクエストは&lt;code&gt;auth.DeleteUser&lt;/code&gt;関数で処理されるようになる。&lt;/p&gt;
&lt;h3&gt;auth.CreateUser が呼ばれた時&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;auth.CreateUser&lt;/code&gt;は下記のようなコード構成になっている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package auth

import (
	&quot;GiveAndTakeCollection-Backend/src/db&quot;
	&quot;GiveAndTakeCollection-Backend/src/models&quot;
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;net/http&quot;

	&quot;golang.org/x/crypto/bcrypt&quot;
)

func CreateUser(w http.ResponseWriter, r *http.Request) {
	db := db.DB
	tx := db.Begin() // トランザクションを開始

	// リクエストからデータを取得
	var userData models.User
	err := json.NewDecoder(r.Body).Decode(&amp;amp;userData)
	if err != nil {
		fmt.Println(&quot;JSONデコードエラー:&quot;, err)
		http.Error(w, &quot;リクエストデータの解析に失敗しました&quot;, http.StatusBadRequest)
		return
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(userData.Password), bcrypt.DefaultCost)

	if err != nil {
		fmt.Printf(&quot;パスワードのハッシュ化に失敗しました: %s&quot;, err)
		http.Error(w, &quot;パスワードのハッシュ化に失敗しました&quot;, http.StatusInternalServerError)
		return
	}

	userData.Password = string(hashedPassword)

	// データベースに新しいユーザーを作成
	err = db.Create(&amp;amp;userData).Error
	if err != nil {
		fmt.Println(&quot;データベースエラー:&quot;, err)
		tx.Rollback()
		http.Error(w, &quot;ユーザーの作成に失敗しました&quot;, http.StatusInternalServerError)
		return
	}

	// トランザクションをコミットして確定
	tx.Commit()

	// レスポンスを返す
	w.WriteHeader(http.StatusCreated)
	fmt.Fprintf(w, &quot;ユーザーが作成されました&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CreateUser&lt;/code&gt;関数を追いかけると、まず&lt;code&gt;db := db.DB&lt;/code&gt;で db パッケージで定義したデータベース接続を取得する（&lt;code&gt;var DB *gorm.DB&lt;/code&gt;パッケージレベルで行っていたのはこのような場合のため）。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;tx := db.Begin()&lt;/code&gt;でトランザクションを開始する。&lt;/p&gt;
&lt;p&gt;トランザクションというのは、一貫性のないデータを作らないための処理のこと。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var userData models.User
	err := json.NewDecoder(r.Body).Decode(&amp;amp;userData)
	if err != nil {
		fmt.Println(&quot;JSONデコードエラー:&quot;, err)
		http.Error(w, &quot;リクエストデータの解析に失敗しました&quot;, http.StatusBadRequest)
		return
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次のブロックはまず、&lt;code&gt;userData&lt;/code&gt;という変数を作成する。 &lt;code&gt;models.User&lt;/code&gt;は型指定。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;err := json.NewDecoder(r.Body).Decode(&amp;amp;userData)&lt;/code&gt;では、&lt;code&gt;json.NewDecoder(r.Body)&lt;/code&gt;で HTTP リクエストのボディを読み込むためのデコーダー（変換機）を作成し、&lt;code&gt;.Decode(&amp;amp;userData)&lt;/code&gt;でデコーダーを使ってボディの内容を&lt;code&gt;userData&lt;/code&gt;という変数に変換（デコード）する。この操作は、JSON 形式のデータを Go の構造体（&lt;code&gt;models.User&lt;/code&gt;）に変換する役割を果たしている。&lt;/p&gt;
&lt;p&gt;もしエラーが出た際はエラーメッセージを標準出力し、HTTP レスポンスを生成してクライアントにエラーメッセージを返し、処理を終了させている。&lt;/p&gt;
&lt;p&gt;エラーがない場合は、この時点でユーザーの登録したいデータ（HTTP リクエストのボディ）が&lt;code&gt;userData&lt;/code&gt;に格納されている。&lt;/p&gt;
&lt;p&gt;その次に&lt;code&gt;userData&lt;/code&gt;のパスワード（ユーザーの入力したパスワード）をハッシュ化する処理が行われる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hashedPassword, err := bcrypt.GenerateFromPassword([]byte(userData.Password), bcrypt.DefaultCost)

if err != nil {
	fmt.Printf(&quot;パスワードのハッシュ化に失敗しました: %s&quot;, err)
	http.Error(w, &quot;パスワードのハッシュ化に失敗しました&quot;, http.StatusInternalServerError)
	return
}

// データベースに新しいユーザーを作成
userData.Password = string(hashedPassword)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これは&lt;code&gt;bcrypt&lt;/code&gt;の&lt;code&gt;Go&lt;/code&gt;パッケージを使用している。&lt;/p&gt;
&lt;p&gt;問題なく、ハッシュ化が行われれば、データベースにユーザーを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	err = db.Create(&amp;amp;userData).Error
	if err != nil {
		fmt.Println(&quot;データベースエラー:&quot;, err)
		tx.Rollback()
		http.Error(w, &quot;ユーザーの作成に失敗しました&quot;, http.StatusInternalServerError)
		return
	}

	// トランザクションをコミットして確定
	tx.Commit()

	// レスポンスを返す
	w.WriteHeader(http.StatusCreated)
	fmt.Fprintf(w, &quot;ユーザーが作成されました&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;err = db.Create(&amp;amp;userData).Error&lt;/code&gt;でデータベースに新規データを作成する。&lt;/p&gt;
&lt;p&gt;その際エラーが出たら&lt;code&gt;err&lt;/code&gt;オブジェクトに代入する。&lt;/p&gt;
&lt;p&gt;エラーがなければトランザクションをコミットし確定。&lt;/p&gt;
&lt;p&gt;成功のレスポンスを返し、ユーザー作成が完了した。&lt;/p&gt;
&lt;p&gt;ユーザー作成が出来たので、退会処理も同様に作成する。&lt;/p&gt;
&lt;h3&gt;auth.DeleteUser が呼ばれた時&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package auth

import (
	&quot;GiveAndTakeCollection-Backend/src/db&quot;
	&quot;GiveAndTakeCollection-Backend/src/models&quot;
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;time&quot;

	&quot;gorm.io/gorm&quot;
)

func DeleteUser(w http.ResponseWriter, r *http.Request) {
	db := db.DB
	tx := db.Begin() // トランザクションを開始

	// requestPayloadという構造体を作成する
	var requestPayload struct {
		// この構造体には UserID という名前のフィールドがあり、JSONのキーが user_id と対応している
		UserID uint `json:&quot;user_id&quot;`
	}
	// HTTPリクエストのボディをrequestPayloadにデコードする。結果、{&quot;user_id&quot;: 123}のようになる。
	err := json.NewDecoder(r.Body).Decode(&amp;amp;requestPayload)
	if err != nil {
		log.Printf(&quot;JSONデコードエラー: %v&quot;, err)
		http.Error(w, &quot;リクエストデータの解析に失敗しました&quot;, http.StatusBadRequest)
		return
	}

	var user models.User
	// `db.First` メソッドを使用して、データベースから最初に見つかったユーザーレコードを取得
	// &amp;amp;user は、ユーザーデータを取得するための構造体へのポインタ、データベースから取得した情報がこの構造体に格納される
	if err := db.First(&amp;amp;user, requestPayload.UserID).Error; err != nil {
		log.Printf(&quot;ユーザーが見つかりません: %v&quot;, err)
		tx.Rollback()
		http.Error(w, &quot;指定されたユーザーが見つかりません&quot;, http.StatusNotFound)
		return
	}

	// deleted_at フィールドに現在の日時をセット
	user.DeletedAt = gorm.DeletedAt{Time: time.Now()}

	// データベースを更新
	if err := db.Delete(&amp;amp;user).Error; err != nil {
		log.Printf(&quot;データベースエラー: %v&quot;, err)
		tx.Rollback()
		http.Error(w, &quot;ユーザーの退会に失敗しました&quot;, http.StatusInternalServerError)
		return
	}

	// トランザクションをコミットして確定
	if err := tx.Commit().Error; err != nil {
		log.Printf(&quot;トランザクションのコミットエラー: %v&quot;, err)
		http.Error(w, &quot;ユーザーの退会に失敗しました&quot;, http.StatusInternalServerError)
		return
	}

	// ログを使って重要なイベントを残す
	log.Printf(&quot;ユーザーが退会しました。ユーザーID: %d&quot;, requestPayload.UserID)

	// レスポンスを返す
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, &quot;ユーザーが退会しました&quot;)
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで退会処理もできた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go Langで新規登録のWebAPIを作成したので、認証周りをJWTで作成する。</title><link>https://blog.nove-b.dev/posts/create-registration-webapi-jwt-authentication-golang</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-registration-webapi-jwt-authentication-golang</guid><content:encoded>&lt;h2&gt;期待するもの&lt;/h2&gt;
&lt;p&gt;新規登録の&lt;code&gt;API&lt;/code&gt;を作成したので、次はログイン機能を作成したい。&lt;/p&gt;
&lt;p&gt;ログインは、メールアドレスとパスワードを送り一致したら、&lt;code&gt;token&lt;/code&gt;を取得する。&lt;/p&gt;
&lt;p&gt;で、&lt;code&gt;token&lt;/code&gt;を使って認証付きの&lt;code&gt;API&lt;/code&gt;を叩けるようになりたい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;token&lt;/code&gt;には&lt;code&gt;jwt&lt;/code&gt;を使用する。&lt;/p&gt;
&lt;h2&gt;jwtってなに？&lt;/h2&gt;
&lt;p&gt;これはどこかで調べてまとめる（気が向いた時）。&lt;/p&gt;
&lt;h2&gt;JWT認証を作成する&lt;/h2&gt;
&lt;h3&gt;パッケージのインストール&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;github.com/dgrijalva/jwt-go&lt;/code&gt;パッケージの情報が多かったので、それに従うことにする。長い物には巻かれるべきで間違いない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go get github.com/dgrijalva/jwt-go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;パッケージをインストールする。&lt;/p&gt;
&lt;h3&gt;Tokenを生成する&lt;/h3&gt;
&lt;p&gt;まず&lt;code&gt;jwt.go&lt;/code&gt;というファイルを作成する。&lt;/p&gt;
&lt;p&gt;今回は&lt;code&gt;auth&lt;/code&gt;フォルダの中に作成した。&lt;/p&gt;
&lt;p&gt;それでは書いていく。&lt;/p&gt;
&lt;p&gt;まずは、jwtを生成するためのシークレットキーを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var jwtKey = []byte(&quot;your_secret_key&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここでは任意の文字列（今回は&quot;your_secret_key&quot;）をバイト列に変換し、&lt;code&gt;jwtKey&lt;/code&gt;に代入している。&lt;/p&gt;
&lt;p&gt;バイト列というのがピンとこないので、&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fmt.Println&lt;/code&gt;で書き出しみると、&lt;code&gt;[121 111 117 114 95 115 101 99 114 101 116 95 107 101 121]&lt;/code&gt;となった。なんとなく理解した。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;このようにして文字列をバイト列に変換することは、多くの場面でデータの操作や処理に利用されます。JWTの署名などのセキュリティ関連の操作では、シークレットキーをバイト列として扱うことが一般的です。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことでした。&lt;/p&gt;
&lt;p&gt;次に、JWTのクレームを表す構造体である&lt;code&gt;Claims&lt;/code&gt;を定義する。&lt;/p&gt;
&lt;p&gt;これは任意のJSONデータっていう意味っぽい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Claims struct {
	Name string `json:&quot;name&quot;`
	jwt.StandardClaims
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;今回は&lt;code&gt;name&lt;/code&gt;を含めることにする。&lt;/p&gt;
&lt;p&gt;と思ったけど、ユニークで必要がありそうなので、ユーザーIDにした。&lt;/p&gt;
&lt;p&gt;下記のように変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Claims struct {
	UserID uint `json:&quot;user_id&quot;`
	jwt.StandardClaims
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に、&lt;code&gt;Token&lt;/code&gt;を作成する関数を作成する。&lt;/p&gt;
&lt;p&gt;コードの詳細はコメントアウトに書いた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func generateToken(userId uint) (string, error) {

	// トークンの有効期限を設定(この場合は15分)
	expirationTime := time.Now().Add(15 * time.Minute)

	// トークンのClaimsを構築
	claims := &amp;amp;Claims{
		UserID: userId, // ユーザーIDをトークンに含める
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expirationTime.Unix(), // トークンの有効期限を設定
		},
	}

	// 新しいJWTトークンを作成
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// トークンを署名して文字列に変換
	tokenString, err := token.SignedString(jwtKey)
	if err != nil {
		return &quot;&quot;, err
	}

	// : JWTトークンを文字列として表現したもの&amp;amp;エラーが発生しなかったことを示すための値を返却する
	return tokenString, nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで&lt;code&gt;Token&lt;/code&gt;を作成することができた。&lt;/p&gt;
&lt;p&gt;ログイン時にこの&lt;code&gt;Token&lt;/code&gt;を返却することにする。&lt;/p&gt;
&lt;h3&gt;Tokenを認証する&lt;/h3&gt;
&lt;p&gt;次に認証を行う関数を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func Authenticate(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Authorizationヘッダーからトークン文字列を取得します。
		tokenString := r.Header.Get(&quot;Authorization&quot;)

		// トークンが存在しない場合は、Unauthorizedエラーを返して処理を中断します。
		if tokenString == &quot;&quot; {
			http.Error(w, &quot;Unauthorized&quot;, http.StatusUnauthorized)
			return
		}

		// トークン文字列から&quot;Bearer &quot;を削除します。
		tokenString = strings.Replace(tokenString, &quot;Bearer &quot;, &quot;&quot;, 1)

		// JWTトークンをパースし、クレーム（Claims）を含むトークンオブジェクトを取得します。
		token, err := jwt.ParseWithClaims(tokenString, &amp;amp;Claims{}, func(token *jwt.Token) (interface{}, error) {
			return jwtKey, nil
		})

		// トークンのパースに失敗した場合は、Unauthorizedエラーを返して処理を中断します。
		if err != nil {
			http.Error(w, &quot;Unauthorized&quot;, http.StatusUnauthorized)
			return
		}

		// トークンのクレームを取得し、有効であるかを検証します。
		claims, ok := token.Claims.(*Claims)
		if !ok || !token.Valid {
			http.Error(w, &quot;Unauthorized&quot;, http.StatusUnauthorized)
			return
		}

		// 認証されたユーザーの情報をログに出力します。
		fmt.Printf(&quot;Authenticated user: %s\n&quot;, strconv.Itoa(int(claims.UserID)))

		// 次のハンドラ関数を呼び出します。
		next(w, r)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ちなみにこの関数の関数名が大文字始まりなのは下記の通り。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Go言語では、関数や変数が大文字で始まる場合には他のパッケージから参照可能（エクスポート可能）となりますが、小文字で始まる場合には同じパッケージ内からのみアクセス可能となります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;で、このコントローラーを下記のように噛ませる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	http.HandleFunc(&quot;/users&quot;, auth.Authenticate(FetchUsers))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで認証が必要になった。&lt;/p&gt;
&lt;p&gt;実際に叩くときは&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo4LCJleHAiOjE3MDMwODUxNzR9.bOJ6jYFLr3BneqtEhQdFb9b2y3lAubm3MpqXbzVQzQY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じでヘッダーを持たせる必要がある。&lt;/p&gt;
&lt;p&gt;これで&lt;code&gt;JWT&lt;/code&gt;認証ができるようになった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go Langで作成したログイン認証のjwtのアクセストークンが切れた時にどうするか</title><link>https://blog.nove-b.dev/posts/handle-expired-jwt-access-token-golang</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/handle-expired-jwt-access-token-golang</guid><content:encoded>&lt;h2&gt;アクセストークンの有効期限は短く&lt;/h2&gt;
&lt;p&gt;ログイン認証を作るうえで、アクセストークンの有効期限は短い方がいい、という情報を得た。&lt;/p&gt;
&lt;p&gt;アクセストークンが盗まれた時に、備えてのことらしい。&lt;/p&gt;
&lt;p&gt;例えば15分とか、って例で書かれていた。&lt;/p&gt;
&lt;p&gt;そうすると15分ごとにログインをし直させなければならない。&lt;/p&gt;
&lt;p&gt;それはユーザビリティ的にどうなのだろうか。という疑問が生まれた。&lt;/p&gt;
&lt;p&gt;それを解決するのがリフレッシュトークンらしい。&lt;/p&gt;
&lt;h2&gt;アクセストークンとリフレッシュトークン&lt;/h2&gt;
&lt;p&gt;リフレッシュトークンはアクセストークンを再発行するために必要になる。&lt;/p&gt;
&lt;p&gt;例えば、ログインをしアクセストークンを取得する。&lt;/p&gt;
&lt;p&gt;15分後、アクセストークンが切れた場合はリフレッシュトークンを使用し、アクセストークンを再発行する。&lt;/p&gt;
&lt;p&gt;その際、リフレッシュトークンも最新化する。&lt;/p&gt;
&lt;p&gt;これで15分ごとにユーザーがログインし直すという苦痛から解放することができる。&lt;/p&gt;
&lt;h2&gt;アクセストークンは危険で、リフレッシュトークンは安全なの？&lt;/h2&gt;
&lt;p&gt;アクセストークンもリフレッシュトークンも一緒に得ることができ、同じように保存をしておく必要がある。&lt;/p&gt;
&lt;p&gt;それなのにどうしてアクセストークンは危険で、リフレッシュトークンは安全なのだろうか。&lt;/p&gt;
&lt;p&gt;ってずっと疑問だったけど、社内の博士に聞き解決した。&lt;/p&gt;
&lt;h3&gt;確率の問題&lt;/h3&gt;
&lt;p&gt;アクセストークン、リフレッシュトークンが盗まれるのは通信中である。&lt;/p&gt;
&lt;p&gt;通信にアクセストークンを持たせて、15分間、何回通信をするだろうか。&lt;/p&gt;
&lt;p&gt;それに比べてリフレッシュトークンはアクセストークンが失われた時にしか使用されないので、リフレッシュトークンに比べて安全だと言える。&lt;/p&gt;
&lt;p&gt;ということ。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go Langで作成したAPIをSwagger UIで表示する</title><link>https://blog.nove-b.dev/posts/display-api-swagger-ui-golang</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/display-api-swagger-ui-golang</guid><content:encoded>&lt;p&gt;タイトルにあるように&lt;code&gt;Swagger&lt;/code&gt;で作成したいのであれば、&lt;code&gt;yaml&lt;/code&gt;を作成すればいい。&lt;/p&gt;
&lt;p&gt;だけど、そんなことをするのは面倒くさい。&lt;/p&gt;
&lt;p&gt;というのも&lt;code&gt;NestJs&lt;/code&gt;ではデコレーターを追加するだけで自動で&lt;code&gt;Swagger UI&lt;/code&gt;を作成してくれた。&lt;/p&gt;
&lt;p&gt;そこで&lt;code&gt;Go&lt;/code&gt;でも同様な手順で実現できるライブラリを探してみた。&lt;/p&gt;
&lt;h2&gt;swaggo/swag&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/swaggo/swag&quot;&gt;swaggo/swag&lt;/a&gt;を使えばできそうだったので試してみた。&lt;/p&gt;
&lt;h3&gt;インストール&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;go install github.com/swaggo/swag/cmd/swag@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;アノテーションを作成する&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt;にアノテーションを追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// @title sample api
// @version 1.0
// @description this is sample apigw

// @host localhost:18080
// @BasePath /api/v1

// @tag.name accounts
// @tag.description about accounts request
func main() {
	handlers.HandleRequests()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;記入後に&lt;code&gt;swag init&lt;/code&gt;を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── docs.go
├── swagger.json
└── swagger.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;すると上記ファイルたちが生成される。&lt;/p&gt;
&lt;h3&gt;UIで確認する&lt;/h3&gt;
&lt;p&gt;これがいまいちわかなかったので、&lt;a href=&quot;https://editor.swagger.io/&quot;&gt;https://editor.swagger.io/&lt;/a&gt;に生成された&lt;code&gt;yaml&lt;/code&gt;ファイルをコピペして見る方法にしているけど、localhost:18080/api/v1で見られるんだと思われる。&lt;/p&gt;
&lt;p&gt;...見れないので、要調査。&lt;/p&gt;
&lt;p&gt;⚠️ 違った。 localhost:18080/api/v1 上のURLは&lt;code&gt;BaseURL&lt;/code&gt;だった。&lt;/p&gt;
&lt;p&gt;まあ、問題ないので、いったん上記方法で行く。&lt;/p&gt;
&lt;p&gt;追記：2023.12.30
&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=Arjun.swagger-viewer&quot;&gt;Swagger Viewer&lt;/a&gt;VSCodeの拡張機能があった。&lt;/p&gt;
&lt;h3&gt;個別APIのアノテーションを作成する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// GetAccount
// @summary アカウントの情報を返します
// @description user_idを元にアカウント情報を返します
// @tags accounts
// @produce json
// @success 200
// @failure 401
// @router /accounts [get]
func FetchUserById(w http.ResponseWriter, r *http.Request) {
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じで、アノテーションを追加すればいける。&lt;/p&gt;
&lt;p&gt;詳細は&lt;a href=&quot;https://github.com/swaggo/swag?tab=readme-ov-file#declarative-comments-format&quot;&gt;https://github.com/swaggo/swag?tab=readme-ov-file#declarative-comments-format&lt;/a&gt;に詳しい。&lt;/p&gt;
&lt;p&gt;大枠はこれくらい。&lt;/p&gt;
&lt;p&gt;後は最適化していくだけ。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Hello New Blog</title><link>https://blog.nove-b.dev/posts/hello-new-blog</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/hello-new-blog</guid><description>WordPressを辞めてブログをHugoにした</description><content:encoded>&lt;p&gt;最近鳴りを潜めていたブログをリニューアルしたいという欲望が、新年早々むくむく頭をあげてきたので、欲望のままにリニューアルすることにした。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;今までのブログ歴&lt;/h2&gt;
&lt;p&gt;初めてブログを立ち上げた時は、&lt;code&gt;WordPress&lt;/code&gt;の無料テーマを使った。確かあれは新卒で入社したWebサイト制作会社を退職した時で、コードを書くことに飢えていた。そこでブログを立ち上げ、「実験だ」と、無料テーマをカスタマイズしては楽しんでいた。&lt;/p&gt;
&lt;p&gt;それから1年後くらいに&lt;code&gt;WordPress&lt;/code&gt;の自作テーマを作りたくなり、リニューアルした。リニューアルした後も色々新規ページを作って楽しんだりしていた。記事のメインは技術についてで、それなりに見てくれる人も多く、有難いことに副業の依頼もいただけたりした。&lt;/p&gt;
&lt;p&gt;徐々に&lt;code&gt;WordPress&lt;/code&gt;に慣れてくると、次に&lt;code&gt;WordPress&lt;/code&gt;以外のプラットフォームでブログを作りたいという欲求がむくむくと頭を上げ始めた。&lt;/p&gt;
&lt;p&gt;そこで当時話題になっていた&lt;code&gt;microCMS&lt;/code&gt;と&lt;code&gt;Netlify&lt;/code&gt;と&lt;code&gt;Nuxt2&lt;/code&gt;で静的ブログを作成した。これもまたいい経験であった。転職活動の時にいいポートフォリオになってくれたし、それなりの知見を得ることができた。&lt;/p&gt;
&lt;p&gt;そのあと、また&lt;code&gt;WordPress&lt;/code&gt;に戻り2度ほどテーマを作成し、拡張機能 (&lt;a href=&quot;https://wordpress.org/plugins/create-eye-catch-for-classic/&quot;&gt;Create Eye Catch For Classic&lt;/a&gt;) も作成した。&lt;/p&gt;
&lt;p&gt;そして今に至るのである。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;書いた記事は資産になるはずだがどこかに消えた&lt;/h2&gt;
&lt;p&gt;ということで今まで、5回ブログをリニューアルしている。テーマだけを変えればいいのだが、そのたびサーバーを変えているので、記事の記録はすべて引き継がれていない。これは自分が悪いのだが、エクスポートするのもそれなりに面倒くさいことはわかってほしい。&lt;/p&gt;
&lt;p&gt;そんな面倒なことはしたくないが、きっと今後もブログはリニューアルし続けるに違いない。そのたびに今までのように記事が失われるのは避けたいということで、&lt;code&gt;Github&lt;/code&gt;で記事を管理することにした。&lt;code&gt;Github&lt;/code&gt;で記事を管理し、それを&lt;code&gt;WordPress&lt;/code&gt;にポストする。これが最適解に思えたのだが、運用してみるとこれが何とも面倒くさい。&lt;/p&gt;
&lt;p&gt;特に編集するときが面倒くさい。&lt;/p&gt;
&lt;p&gt;まず&lt;code&gt;Github&lt;/code&gt;で変更し、そのあと修正を&lt;code&gt;WordPress&lt;/code&gt;の投稿画面でチェックする。問題がなければ公開する。なんとも面倒で仕方ない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Github&lt;/code&gt;で&lt;code&gt;commit&lt;/code&gt;するたびに記事が公開されればいいのに、という思いになり、静的サイトジェネレータを使うことにした。&lt;/p&gt;
&lt;p&gt;ヘッドレスCMSでもいいのだが、すべてのソースコードが&lt;code&gt;Github&lt;/code&gt;に集約されているので、管理画面をこれ以上増やしたくない。&lt;/p&gt;
&lt;p&gt;そういうことでこのブログを立ち上げることにした。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;ブログリニューアルした&lt;/h2&gt;
&lt;p&gt;っていうのも6回目となる。&lt;/p&gt;
&lt;p&gt;どうせまたリニューアルするけど、記事はそのまま資産にできる。&lt;/p&gt;
&lt;hr /&gt;
</content:encoded><author>nove-b</author></item><item><title>Install Nuxt3 | ERR! @parcel watcher</title><link>https://blog.nove-b.dev/posts/install-nuxt3</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/install-nuxt3</guid><description>仕事でNuxt3を使うことになったので、Nuxt3をインストールする</description><content:encoded>&lt;h2&gt;環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;windws11&lt;/li&gt;
&lt;li&gt;node =&amp;gt; v20.11.0&lt;/li&gt;
&lt;li&gt;npm =&amp;gt; 10.4.0&lt;/li&gt;
&lt;li&gt;nuxt =&amp;gt; 3.10.1&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;install&lt;/h2&gt;
&lt;p&gt;公式の手順に従っていく。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nuxt.com/docs/getting-started/installation&quot;&gt;Installation · Get Started with Nuxt&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx nuxi@latest init &amp;lt;project-name&amp;gt;
❯ Which package manager would you like to use?
● npm
○ pnpm
○ yarn
○ bun
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記を実行すると、エラーが発生した。&lt;/p&gt;
&lt;h3&gt;npm ERR! gyp ERR! cwd C:~\node_modules@parcel\watcher&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;npm WARN cleanup Failed to remove some directories [
npm WARN cleanup   [
npm WARN cleanup     &apos;C:\\project\\project-name\\node_modules&apos;,
npm WARN cleanup     [Error: EPERM: operation not permitted, scandir &apos;C:\project\project-name\node_modules\resolve\test\resolver\multirepo\packages\package-a&apos;] {
npm WARN cleanup       errno: -4048,
npm WARN cleanup       code: &apos;EPERM&apos;,
npm WARN cleanup       syscall: &apos;scandir&apos;,
npm WARN cleanup       path: &apos;C:\\project\\project-name\\node_modules\\resolve\\test\\resolver\\multirepo\\packages\\package-a&apos;
npm WARN cleanup     }
npm WARN cleanup   ],
npm WARN cleanup   [
npm WARN cleanup     &apos;C:\\project\\project-name\\node_modules\\@vercel&apos;,
npm WARN cleanup     [Error: EPERM: operation not permitted, rmdir &apos;C:\project\project-name\node_modules\@vercel\nft\node_modules\@rollup\pluginutils\dist&apos;] {
npm WARN cleanup       errno: -4048,
npm WARN cleanup       code: &apos;EPERM&apos;,
npm WARN cleanup       syscall: &apos;rmdir&apos;,
npm WARN cleanup       path: &apos;C:\\project\\project-name\\node_modules\\@vercel\\nft\\node_modules\\@rollup\\pluginutils\\dist&apos;
npm WARN cleanup     }
npm WARN cleanup   ]
npm WARN cleanup ]
npm ERR! code 1
npm ERR! path C:\project\project-name\node_modules\@parcel\watcher
npm ERR! command failed
npm ERR! command C:\WINDOWS\system32\cmd.exe /d /s /c node-gyp rebuild
npm ERR! gyp info it worked if it ends with ok
npm ERR! gyp info using node-gyp@10.0.1
npm ERR! gyp info using node@20.11.0 | win32 | x64
npm ERR! gyp info find Python using Python version 3.9.6 found at &quot;C:\Users\username\AppData\Local\Programs\Python\Python39\python.exe&quot;
npm ERR! gyp ERR! find VS
npm ERR! gyp ERR! find VS msvs_version not set from command line or npm config
npm ERR! gyp ERR! find VS VCINSTALLDIR not set, not running in VS Command Prompt
npm ERR! gyp ERR! find VS could not use PowerShell to find Visual Studio 2017 or newer, try re-running with &apos;--loglevel silly&apos; for more details
npm ERR! gyp ERR! find VS not looking for VS2015 as it is only supported up to Node.js 18
npm ERR! gyp ERR! find VS not looking for VS2013 as it is only supported up to Node.js 8
npm ERR! gyp ERR! find VS
npm ERR! gyp ERR! find VS **************************************************************
npm ERR! gyp ERR! find VS You need to install the latest version of Visual Studio
npm ERR! gyp ERR! find VS including the &quot;Desktop development with C++&quot; workload.
npm ERR! gyp ERR! find VS For more information consult the documentation at:
npm ERR! gyp ERR! find VS https://github.com/nodejs/node-gyp#on-windows
npm ERR! gyp ERR! find VS **************************************************************
npm ERR! gyp ERR! find VS
npm ERR! gyp ERR! configure error
npm ERR! gyp ERR! stack Error: Could not find any Visual Studio installation to use
npm ERR! gyp ERR! stack at VisualStudioFinder.fail (C:\project\project-name\node_modules\node-gyp\lib\find-visualstudio.js:113:11)
npm ERR! gyp ERR! stack at VisualStudioFinder.findVisualStudio (C:\project\project-name\node_modules\node-gyp\lib\find-visualstudio.js:69:17)
npm ERR! gyp ERR! stack at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
npm ERR! gyp ERR! stack at async createBuildDir (C:\project\project-name\node_modules\node-gyp\lib\configure.js:69:26)
npm ERR! gyp ERR! stack at async run (C:\project\project-name\node_modules\node-gyp\bin\node-gyp.js:81:18)
npm ERR! gyp ERR! System Windows_NT 10.0.22621
npm ERR! gyp ERR! command &quot;C:\\Users\\username\\AppData\\Local\\Volta\\tools\\image\\node\\20.11.0\\node.exe&quot; &quot;C:\\project\\project-name\\node_modules\\node-gyp\\bin\\node-gyp.js&quot; &quot;rebuild&quot;
npm ERR! gyp ERR! cwd C:\project\project-name\node_modules\@parcel\watcher
npm ERR! gyp ERR! node -v v20.11.0
npm ERR! gyp ERR! node-gyp -v v10.0.1
npm ERR! gyp ERR! not ok

npm ERR! A complete log of this run can be found in: C:\Users\username\AppData\Local\npm-cache\_logs\2024-02-13T10_14_47_279Z-debug-0.log

 ERROR  Error: Command failed with exit code 1: npm install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;エラーを見てみると&lt;code&gt;@parcel\watcher&lt;/code&gt; あたりが怪しい気がする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/@parcel/watcher&quot;&gt;@parcel/watcher&lt;/a&gt;はどうやらファイルの監視を行う&lt;code&gt;npm&lt;/code&gt;パッケージらしい。オプションで設定ができるように&lt;code&gt;Nuxt3&lt;/code&gt;に標準装備されているっぽい。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Set an alternative watcher that will be used as the watching service for Nuxt.
Nuxt uses chokidar-granular by default, which will ignore top-level
directories (like node_modules and .git) that are excluded from watching. You
can set this instead to parcel to use @parcel/watcher, which may improve
performance in large projects or on Windows platforms. You can also set this
to chokidar to watch all files in your source directory.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nuxt.com/docs/guide/going-further/experimental-features#watcher&quot;&gt;https://nuxt.com/docs/guide/going-further/experimental-features#watcher&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Nuxt のウォッチングサービスとして使用される代替のウォッチャーを設定します。Nuxt はデフォルトで chokidar-granular を使用しており、ウォッチから除外されたトップレベルのディレクトリ（node_modules や .git など）を無視します。代わりに @parcel/watcher を使用するようにこれを設定することができます。これにより、大規模なプロジェクトや Windows プラットフォームでのパフォーマンスが向上する場合があります。また、ソースディレクトリ内のすべてのファイルをウォッチするようにこれを chokidar に設定することもできます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;この時点で何も気にせずに&lt;code&gt;npm install&lt;/code&gt;をしていたら問題なく起動していたかもしれないけど、試してないのでわからない。&lt;/p&gt;
&lt;p&gt;「エラーが出た、気になる」ということで検索してみると、&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/77976536/running-into-errors-installing-nuxt3&quot;&gt;running into errors installing Nuxt3&lt;/a&gt;
&lt;a href=&quot;https://stackoverflow.com/questions/77893072/inint-nuxt-3-project-fails-with-npm-package&quot;&gt;Inint nuxt 3 project fails with npm package&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;同様のエラーに遭遇しているひとも結構いるっぽい。&lt;/p&gt;
&lt;h3&gt;解決方法&lt;/h3&gt;
&lt;p&gt;大本営のリポジトリでも、&lt;a href=&quot;https://github.com/nuxt/nuxt/issues/25478&quot;&gt;Unable to install with command failed sh -c node-gyp rebuild&lt;/a&gt;のように&lt;code&gt;issue&lt;/code&gt;標記されているが、&lt;code&gt;Nuxt&lt;/code&gt;の問題じゃないと言われている。で、その上の過程&lt;a href=&quot;https://github.com/unjs/nitro/issues/2123&quot;&gt;Unable to install with command failed sh -c node-gyp rebuild&lt;/a&gt;でもプルリクが出されている。&lt;/p&gt;
&lt;p&gt;で、色々たらい回しされ、&lt;a href=&quot;https://github.com/unjs/nitro/issues/2123&quot;&gt;Unable to install with command failed sh -c node-gyp rebuild&lt;/a&gt;で、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you add the following to package.json then do a clean install does it work?&lt;/p&gt;
&lt;p&gt;&quot;overrides&quot;: { &quot;@parcel/watcher&quot;: &quot;2.1.0&quot; },&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という希望が示されていたので、実行してみた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm i

&amp;gt; postinstall
&amp;gt; nuxt prepare

✔ Types generated in .nuxt                                                                                                                                                                                                                                19:37:24

added 732 packages, and audited 734 packages in 3m

120 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;インストールも成功し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm run dev -- -o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で無事にサーバーも起動した。&lt;/p&gt;
&lt;p&gt;なんとなく気分の良くないインストール体験だった。&lt;/p&gt;
&lt;p&gt;React主義だけど、より一層React主義になった。開発体験で挽回してくれることに期待している。&lt;/p&gt;
&lt;hr /&gt;
</content:encoded><author>nove-b</author></item><item><title>Hugo(ヒューゴ)でブログを立ち上げるまでにやったこと</title><link>https://blog.nove-b.dev/posts/create-hugo-blog</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/create-hugo-blog</guid><description>Hugo(ヒューゴ)でブログを立ち上げるまでにやったこと</description><content:encoded>&lt;p&gt;&lt;code&gt;Hugo&lt;/code&gt;でこのブログを立ち上げたので、&lt;code&gt;Hugo&lt;/code&gt;のインストールから&lt;code&gt;Github Page&lt;/code&gt;で公開するまで。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;windws11&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Hugo&lt;/h2&gt;
&lt;p&gt;そもそも&lt;code&gt;Hugo&lt;/code&gt;のことをよく知らずに技術選定をしてしまったので、ここでしっかり調べておくことにする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Hugo&lt;/code&gt;は&lt;code&gt;Go&lt;/code&gt;で記述された静的サイトジェネレータで
&lt;strong&gt;「ウェブサイトを構築するための世界最速のフレームワーク」&lt;/strong&gt; らしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gohugo.io/&quot;&gt;The world’s fastest framework for building websites | Hugo&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;静的サイトジェネレータ&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;静的サイトジェネレーターとは、生（未加工）データとテンプレート群を基に、完全に静的なHTML
Webサイトを生成するツールのことです。静的サイトジェネレーターは、基本的に個々のHTMLページをコーディングする作業を自動化し、それらのページをユーザーがすぐに使えるようにします。これらのHTMLページは事前作成されたものであるため、ユーザーはブラウザで即座に読み込むことができます。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cloudflare.com/ja-jp/learning/performance/static-site-generator/&quot;&gt;静的サイトジェネレーターとは？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;上記の通り、事前にHTMLを生成するのでパフォーマンスがいいのがメリットのひとつ。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Hugoのインストール&lt;/h2&gt;
&lt;p&gt;公式サイトに詳しい。
&lt;code&gt;Windows&lt;/code&gt;なので&lt;a href=&quot;https://gohugo.io/installation/windows/&quot;&gt;Windowsのインストール方法&lt;/a&gt;通りに行った。&lt;/p&gt;
&lt;p&gt;パッケージ管理システムの&lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolatey&lt;/a&gt;、&lt;a href=&quot;https://scoop.sh/&quot;&gt;Scoop&lt;/a&gt;と&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/package-manager/&quot;&gt;Winget&lt;/a&gt;を使うインストール方法が提供されていた。他にも2つインストール方法が記載されている。比較表があるのでわかりやすい。&lt;/p&gt;
&lt;h3&gt;パッケージ管理システム&lt;/h3&gt;
&lt;p&gt;ちなみにパッケージ管理システムとは、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;コンピュータのプログラムを一貫した方法でインストールやアンインストール、ライブラリなどの依存関係を解決する流れをツールによって管理を自動化するシステム&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;のこと。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;npm&lt;/code&gt;とか&lt;code&gt;Composer&lt;/code&gt;とかも言語のパッケージ管理ツールにあたる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Chocolatey&lt;/code&gt;が有名っぽいけど、インストール方法がぱっと見わからなかったので、&lt;code&gt;Scoop&lt;/code&gt;を使用することにした。&lt;/p&gt;
&lt;p&gt;調べると&lt;code&gt;Mac&lt;/code&gt;では&lt;code&gt;Homebrew&lt;/code&gt;一択っぽい。Windowsでは&lt;code&gt;winget&lt;/code&gt;が公式っぽく、インストールも必要なく使えて便利そうだった。&lt;/p&gt;
&lt;p&gt;インストール情報をエクスポートすることもできるので、パソコンの買い替え時とかにも重宝できそうだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.classmethod.jp/articles/use_windows_package_manager_winget/&quot;&gt;Windowsのパッケージマネージャー「winget」を使ってみた&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今思えば&lt;code&gt;winget&lt;/code&gt;にすれば良かったと思うけど、&lt;code&gt;Scoop&lt;/code&gt;を選択したので、それで進めていく。&lt;/p&gt;
&lt;h3&gt;Scoopでインストールする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;scoop install hugo-extended
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドを使用すれば、&lt;code&gt;hugo&lt;/code&gt;の拡張版をインストールすることができる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&apos;hugo-extended&apos; (0.122.0) was installed successfully!
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Hugoでサイトを構築する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Hugo&lt;/code&gt;でサイトを構築するのは簡単で、下記コマンドを叩くだけでいい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hugo new site site-name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記を実行した後に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hugo -D serve
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、サイトを確認することができる。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;テーマを選んで適応する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Hugo&lt;/code&gt;は沢山のテーマが提供されている。&lt;code&gt;Wordpress&lt;/code&gt;に通ずるものがある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://themes.gohugo.io/&quot;&gt;Hugo Themes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今回は一番上にあった&lt;a href=&quot;https://themes.gohugo.io/themes/hugo-papermod/&quot;&gt;PaperMod&lt;/a&gt;を採用することにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/adityatelange/hugo-PaperMod&quot;&gt;hugo-PaperMod&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;テーマを導入する&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;サブモジュールって？&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;外部の git リポジトリを、自分の git リポジトリのサブディレクトリとして登録し、特定の commit を参照する仕組み&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;どういうこと🤔?&lt;/p&gt;
&lt;p&gt;とりあえず、上記コマンドで&lt;code&gt;themes&lt;/code&gt;の中に&lt;code&gt;PaperMod&lt;/code&gt;がインストールされた。&lt;/p&gt;
&lt;p&gt;最後に&lt;code&gt;hugo.yaml&lt;/code&gt;に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;theme: PaperMod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を追加すればテーマが適用される。&lt;/p&gt;
&lt;p&gt;できたサイトが&lt;a href=&quot;https://nove-b.github.io/&quot;&gt;🦥 nove-b&lt;/a&gt;でリポジトリが&lt;a href=&quot;https://github.com/nove-b/nove-b.github.io&quot;&gt;こちら&lt;/a&gt;。&lt;/p&gt;
&lt;hr /&gt;
</content:encoded><author>nove-b</author></item><item><title>2024年2月に読んだ本まとめ</title><link>https://blog.nove-b.dev/posts/books-2024-2</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/books-2024-2</guid><description>2024年2月に読んだ本を軽くまとめてみる</description><content:encoded>&lt;p&gt;読む本をほとんどKindle
Unlimitedにしてからというもの読んだ本の記憶が残らないようになったしまった。&lt;/p&gt;
&lt;p&gt;そのため簡単にまとめておくことにした。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;廃遊園地の殺人 (斜線堂 有紀)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;プレオープン中に起きた銃乱射事件のため閉園に追い込まれたテーマパーク・イリュジオンランド。廃墟コレクターの資産家・十嶋庵(としまいおり)はかつての夢の国を二十年ぶりに解き放つ。狭き門をくぐり抜け、廃遊園地へと招かれた廃墟マニアのコンビニ店員・眞上永太郎(まがみえいたろう)を待っていたのは、『このイリュジオンランドは、宝を見つけたものに譲る』という十嶋からの伝言だった。それぞれに因縁を抱えた招待客たちは宝探しをはじめるが、翌朝串刺しになった血まみれの着ぐるみが見つかる。止まらない殺人、見つからない犯人、最後に真実を見つけ出すのは……&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/42E3gWV&quot;&gt;廃遊園地の殺人&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;なんか名前を聞いたことがある作家だと思ったら&lt;a href=&quot;https://amzn.to/3I49bLc&quot;&gt;キネマ探偵カレイドミステリー&lt;/a&gt;の作家さんだった。&lt;/p&gt;
&lt;p&gt;テンポが良いミステリで、それなりに先も気になり、楽しく読めた。&lt;/p&gt;
&lt;p&gt;水曜日のダウンタウンのトナッピーを思い出した。&lt;/p&gt;
&lt;p&gt;{{&amp;lt; youtube WSVf2eitR6s &amp;gt;}}&lt;/p&gt;
&lt;h2&gt;1984 (ジョージ・オーウェル)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1984年、世界は〈オセアニア〉〈ユーラシア〉〈イースタシア〉という3つの国に分割統治されていた。オセアニアは、ビッグ・ブラザー率いる一党独裁制。市中に「ビッグ・ブラザーは見ている」と書かれたポスターが張られ、国民はテレスクリーンと呼ばれる装置で24時間監視されていた。党員のウィンストン・スミスは、この絶対的統治に疑念を抱き、体制の転覆をもくろむ〈ブラザー連合〉に興味を持ちはじめていた。一方、美しい党員ジュリアと親密になり、隠れ家でひそかに逢瀬を重ねるようになる。つかの間、自由と生きる喜びを噛みしめるふたり。しかし、そこには、冷酷で絶望的な罠がしかけられていたのだった――。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/49DrjaM&quot;&gt;1984&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;読んだことある。&lt;/p&gt;
&lt;p&gt;ところどころ覚えている。でも結末とかストーリを全く覚えてなかった。&lt;/p&gt;
&lt;p&gt;たぶん、設定が強すぎる。&lt;/p&gt;
&lt;p&gt;読了はしていないので、3月に持ち越すことにする。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>WingetでWindowsにアプリをインストールする</title><link>https://blog.nove-b.dev/posts/winget-install-elk</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/winget-install-elk</guid><description>パッケージマネージャーを使用しアプリを管理する</description><content:encoded>&lt;h2&gt;環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;windws11&lt;/li&gt;
&lt;li&gt;winget =&amp;gt; v1.6.3482&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;パッケージマネージャーを使用する&lt;/h2&gt;
&lt;p&gt;この前、&lt;code&gt;Hugo&lt;/code&gt;をインストールする際にパッケージマネージャーである&lt;code&gt;Scoop&lt;/code&gt;を使用した。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chocolateyが有名っぽいけど、インストール方法がぱっと見わからなかったので、Scoopを使用することにした。調べるとMacではHomebrew一択っぽい。Windowsではwingetが公式っぽく、インストールも必要なく使えて便利そうだった。
&lt;a href=&quot;https://nove-b.github.io/posts/create-hugo-blog/&quot;&gt;Hugo(ヒューゴ)でブログを立ち上げるまでにやったこと&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;その際に、パッケージマネージャー（&lt;code&gt;Winget&lt;/code&gt;）の便利さを初めて知った。&lt;/p&gt;
&lt;p&gt;なんとインストールしたソフトウェアの情報を&lt;code&gt;json&lt;/code&gt;にして出力することができるらしい。&lt;/p&gt;
&lt;p&gt;だけでなく、インポートをすることで記載されたツールをインストールすることができるらしい。&lt;/p&gt;
&lt;p&gt;つまりこれを管理しておけば、パソコンを変えた時にソフトウェアの引継ぎができるとのこと。&lt;/p&gt;
&lt;p&gt;今更だけど、そろそろパソコンを買い替えたと思ったので、少しでも引き継げるように使用してみることにした。&lt;/p&gt;
&lt;h2&gt;Elkをインストールする&lt;/h2&gt;
&lt;p&gt;ちょうどマストドンの&lt;code&gt;Windows&lt;/code&gt;クライアントが欲しかったので、&lt;code&gt;Elk&lt;/code&gt;をインストールすることにした。&lt;/p&gt;
&lt;h3&gt;Wingetのバージョン確認&lt;/h3&gt;
&lt;p&gt;WingetはWindowsに標準でインストールされているので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;winget -v
v1.6.3482
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特に何もせずともバージョンを確認できる。&lt;/p&gt;
&lt;h3&gt;インストールしたいソフトウェアを検索&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt; winget search &quot;Elk&quot;

 名前         ID                  バージョン 一致              ソース
---------------------------------------------------------------------
TagIt CO Elk 9PCGNR99HGKQ        Unknown                      msstore
Elk          Elk.Elk             0.4.0                        winget
LDCad        RolandMelkert.LDCad 1.6d2                        winget
Obsidian     Obsidian.Obsidian   1.5.3      Tag: zettelkasten winget
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;インストールする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;winget install Elk.Elk
見つかりました Elk [Elk.Elk] バージョン 0.4.0
このアプリケーションは所有者からライセンス供与されます。
Microsoft はサードパーティのパッケージに対して責任を負わず、ライセンスも付与しません。
ダウンロード中 https://github.com/elk-zone/elk-native/releases/download/elk-native-v0.4.0/Elk_0.4.0_windows_x86_64.msi
  ██████████████████████████████  7.31 MB / 7.31 MB
インストーラーハッシュが正常に検証されました
パッケージのインストールを開始しています..
インストーラーハッシュが正常に検証されました
インストールが完了しました
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ID&lt;/code&gt;を使用してインストールする。&lt;/p&gt;
&lt;p&gt;ここから結構時間がかかったのは自身のパソコンの性能か、通信環境か、結構な時間がかかった。&lt;/p&gt;
&lt;h3&gt;アップグレードする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;winget upgrade
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、現在のバージョンと、利用可能なバージョンが表示される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;winget upgrade --all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のコマンドですべてのソフトウェアをアップグレードできる。&lt;/p&gt;
&lt;h3&gt;インストール情報をエクスポートする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;winget export --output C:{path}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;#2024-02-18 09:24:38：追記&lt;/h2&gt;
&lt;p&gt;エクスポートされなくて、色々試行錯誤した結果、ファイル名を指定していないことに気が付いた。&lt;/p&gt;
&lt;p&gt;正しくは、下記で無事に&lt;code&gt;json&lt;/code&gt;が作成された。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;winget export --output C:{path}\{file-name}.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで、インストールした情報をエクスポートできる。&lt;/p&gt;
&lt;p&gt;作成された&lt;code&gt;json&lt;/code&gt;を見ると、&lt;code&gt;winget&lt;/code&gt;を通してインストールした以外のソフトも含まれていた。&lt;/p&gt;
&lt;p&gt;よく分からないけれど、勝手にやってくれるらしい。&lt;/p&gt;
&lt;h3&gt;エクスポート情報をインポートする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;winget import --import-file C:{path}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これを実行すると、インストールされていないソフトウェアは自動的にインストールされらしい。また既にインストールされていてもバージョンが古い場合はアップグレードされるらしい。&lt;/p&gt;
&lt;p&gt;ただ、試していないのでわからない。&lt;/p&gt;
&lt;h2&gt;設定ファイルをGithubに&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Winget&lt;/code&gt;でエクスポートした&lt;code&gt;json&lt;/code&gt;を&lt;code&gt;Github&lt;/code&gt;に置いておけば、いろんな環境で情報を共有できるし、パソコンの買い替えも不便がなくなるかもしれない。&lt;/p&gt;
&lt;p&gt;この前聞いていいなあと思っていた盆栽とはこれのことだったのか。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe style=&quot;border-radius:12px&quot; src=&quot;https://open.spotify.com/embed/episode/3EE3uyFP2yxhud21L0l1jc?utm_source=generator&quot; width=&quot;100%&quot; height=&quot;352&quot; frameBorder=&quot;0&quot; allowfullscreen=&quot;&quot; allow=&quot;autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture&quot; loading=&quot;lazy&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>AngularでAPIリクエスト前後の処理を共通化する</title><link>https://blog.nove-b.dev/posts/angular-interceptor</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/angular-interceptor</guid><description>AngularでAPIコール前にAuthorizationを持たせる必要があったのでHttpInterceptorを使用してみた</description><content:encoded>&lt;h2&gt;環境&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;node =&amp;gt; v16.13.2
angular =&amp;gt; 15.0.4
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;AngularでリクエストヘッダーにAuthorizationを共通して持たせたい&lt;/h2&gt;
&lt;p&gt;とかレスポンスの&lt;code&gt;StatusCode&lt;/code&gt;を見て共通処理を書くと言ったAPIリクエスト前後の処理をどこで実装するのがいいのか調べてみた。&lt;/p&gt;
&lt;h2&gt;HttpInterceptor&lt;/h2&gt;
&lt;p&gt;どうやらドンピシャっぽいのがこれで、&lt;a href=&quot;https://angular.jp/api/common/http/HttpInterceptor#description&quot;&gt;ドキュメント&lt;/a&gt;によると&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Intercepts and handles an HttpRequest or HttpResponse.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;つまり、リクエストとレスポンスそれぞれに処理をできますよということ。まさに探していた機能に間違いない。&lt;/p&gt;
&lt;h2&gt;使ってみる&lt;/h2&gt;
&lt;h3&gt;リクエストに対して処理をする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import {
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from &quot;@angular/common/http&quot;;
import { Injectable } from &quot;@angular/core&quot;;
import { Observable } from &quot;rxjs&quot;;

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor() {}
  intercept(
    req: HttpRequest&amp;lt;any&amp;gt;,
    next: HttpHandler,
  ): Observable&amp;lt;HttpEvent&amp;lt;any&amp;gt;&amp;gt; {
    const newReq = req.clone({
      headers: req.headers.set(&quot;Authorization&quot;, &quot;Bearer &quot; + &quot;token&quot;),
    });
    // cloneされてヘッダーを付与したリクエストを次の処理に引き渡す
    return next.handle(newReq);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでリクエストヘッダーに&lt;code&gt;Bearer token&lt;/code&gt;という&lt;code&gt;Authorization&lt;/code&gt;が付与されたうえでリクエストが投げられる。&lt;/p&gt;
&lt;h3&gt;レスポンスに対して処理をする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import {
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from &quot;@angular/common/http&quot;;
import { Injectable } from &quot;@angular/core&quot;;
import { Observable, catchError } from &quot;rxjs&quot;;
import { MatDialog } from &quot;@angular/material/dialog&quot;;

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  constructor(public dialog: MatDialog) {}
  intercept(
    request: HttpRequest&amp;lt;any&amp;gt;,
    next: HttpHandler,
  ): Observable&amp;lt;HttpEvent&amp;lt;any&amp;gt;&amp;gt; {
    const req = request.clone();
    return next.handle(req).pipe(
      catchError((res) =&amp;gt; {
        if (400 &amp;lt;= res.status &amp;amp;&amp;amp; res.status &amp;lt; 500) {
          console.log(&quot;400以上500未満のエラーが発生しました。&quot;);
        }

        return next.handle(req).pipe();
      }),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでレスポンスの&lt;code&gt;status&lt;/code&gt;が400以上500未満の場合に限り&lt;code&gt;console&lt;/code&gt;が発火するようになった。これを使用すれば各&lt;code&gt;status&lt;/code&gt;に対する共通の処理を書くことができる。&lt;/p&gt;
&lt;h2&gt;app.module.ts にプロバイダー登録&lt;/h2&gt;
&lt;p&gt;それぞれ処理を書いたら&lt;code&gt;app.module.ts&lt;/code&gt;の&lt;code&gt;providers&lt;/code&gt;に登録する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
  ],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで無事に求めている動きをするようになった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavascriptのConsoleはGoLangでどう表現するのか</title><link>https://blog.nove-b.dev/posts/golang-for-console</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/golang-for-console</guid><description>Golangで出力の方法がいくつかあるようなので、どれが最適化調べてみた。</description><content:encoded>&lt;h2&gt;Golangの出力方法がたくさんある&lt;/h2&gt;
&lt;p&gt;いつも&lt;code&gt;Javascript&lt;/code&gt;をメインで使用している。&lt;code&gt;Javascript&lt;/code&gt;で最も使用するのは&lt;code&gt;Console&lt;/code&gt;オブジェクトに間違いない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Web/API/console&quot;&gt;console&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;デバックの際には本当にお世話になっている。なかでも&lt;code&gt;console.table&lt;/code&gt;には本当に感謝している。いつもありがとう。&lt;/p&gt;
&lt;p&gt;もう&lt;code&gt;Console&lt;/code&gt;がなくては生きていけない体になってしまったので、&lt;code&gt;Golang&lt;/code&gt;でも同様に出力しようとしたら、何やら書き方がたくさんあって困惑した。&lt;/p&gt;
&lt;h2&gt;Golangで出力する&lt;/h2&gt;
&lt;h3&gt;fmt.Printf()&lt;/h3&gt;
&lt;p&gt;第一引数に書式指定文字列を受け取り、第二引数以降に渡した値をフォーマットして出力&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fmt.Printf({書式指定}, {値})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;fmt.Println()&lt;/h3&gt;
&lt;p&gt;値を標準の書式で出力。 &lt;code&gt;fmt.Printf(%v, {値})&lt;/code&gt;と同じになる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fmt.Println({値})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;調べたらこれくらいしかなかった。じゃあなんで混乱したかというとコードを書いていて&lt;code&gt;log.Printf()&lt;/code&gt;というのが出てきたせいである。&lt;/p&gt;
&lt;h3&gt;log.Printf() / log.PrintIn()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;パッケージ ログは、単純なログ パッケージを実装します。これは、出力をフォーマットするためのメソッドを備えたタイプLoggerを定義します&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;つまりどういうことかよくわからないので、実装してみる。&lt;/p&gt;
&lt;h2&gt;fmt と log の違いを実装してみる。&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	fmt.Println(&quot;Hello, fmt&quot;)
	log.Println(&quot;Hello, log&quot;)
}
// Hello, fmt
// 2024/03/07 22:25:23 Hello, log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;log&lt;/code&gt;の方は日時のデータが付与された。&lt;/p&gt;
&lt;p&gt;使い方はよくわかないけど、ひとまず整理はできたので良しとする。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Golangのnet/httpでホットリロードの恩恵を受けたい</title><link>https://blog.nove-b.dev/posts/golang-hotreload-by-devcontainer</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/golang-hotreload-by-devcontainer</guid><description>Golangのnet/httpでホットリロードしたい</description><content:encoded>&lt;h2&gt;ホットリロードが欲しい&lt;/h2&gt;
&lt;p&gt;普段メインで&lt;code&gt;react&lt;/code&gt;とか&lt;code&gt;Angular&lt;/code&gt;を使用しているので、標準でホットリロードが搭載されていることが当然になっていた。&lt;/p&gt;
&lt;p&gt;しかし&lt;code&gt;Go&lt;/code&gt;の&lt;code&gt;net/http&lt;/code&gt;にはない。これが本当に開発体験に悪影響を及ぼしている。&lt;/p&gt;
&lt;p&gt;ということで、何とかできないか調べてみた。&lt;/p&gt;
&lt;h2&gt;Goのバージョン&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;go =&amp;gt; 1.21.4
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;DevContainerを使ってみる&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://qiita.com/Domao/items/03858530067b52986ca9&quot;&gt;Go net/httpサーバーのホットリロードにAirを使ってみた&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Devcontainerに airをインストールして、DevContainer上で実行する。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;色々調べた結果上記が１番楽そうだったので、やってみる。&lt;/p&gt;
&lt;p&gt;やり方は&lt;a href=&quot;https://qiita.com/Domao/items/03858530067b52986ca9&quot;&gt;上記の記事&lt;/a&gt;を引用する。&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;リポジトリ直下に .devcontainer フォルダ作成&lt;/li&gt;
&lt;li&gt;.devcontainerフォルダ内に 下記内容のdevcontainer.json を作成。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;{
	&quot;name&quot;: &quot;Go&quot;,
	&quot;image&quot;: &quot;mcr.microsoft.com/devcontainers/go:0-1-bullseye&quot;,
	&quot;features&quot;: {
		&quot;ghcr.io/devcontainers/features/docker-outside-of-docker:1&quot;: {
			&quot;moby&quot;: true,
			&quot;installDockerBuildx&quot;: true,
			&quot;version&quot;: &quot;latest&quot;,
			&quot;dockerDashComposeVersion&quot;: &quot;v2&quot;
		}
	},
	&quot;postCreateCommand&quot;: &quot;go install github.com/cosmtrek/air@latest&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;保存し、プロジェクトを再度開き直す&lt;/li&gt;
&lt;li&gt;DevContainerを開くかどうかVSCodeに確認されるので、DevContainerとして開き直す&lt;/li&gt;
&lt;li&gt;インストール完了後 プロンプト上で air と打って Airを立ち上げる&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;順序通りやったところ、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;DevContainerを開くかどうかVSCodeに確認されるので、DevContainerとして開き直す&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;の箇所で、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[+] Building 903.3s (2/3)
 =&amp;gt; [internal] load build definition from Dockerfile.extended              0.3s
 =&amp;gt; =&amp;gt; transferring dockerfile: 2.76kB                                     0.1s
 =&amp;gt; [internal] load .dockerignore                                          0.3s
 =&amp;gt; =&amp;gt; transferring context: 2B                                            0.0s
 =&amp;gt; resolve image config for docker.io/docker/dockerfile:1.4             902.4s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のようにとんでもなく時間がかかった結果諦めた。&lt;/p&gt;
&lt;p&gt;これは&lt;code&gt;Windows&lt;/code&gt;と&lt;code&gt;Docker&lt;/code&gt;問題🤔?&lt;/p&gt;
&lt;h2&gt;WSLで再トライ&lt;/h2&gt;
&lt;p&gt;ということで&lt;code&gt;WSL&lt;/code&gt;上に移して実行してみる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Windows&lt;/code&gt;上で実行するよりは早いけど、それでもめちゃくちゃ時間がかかった。&lt;/p&gt;
&lt;p&gt;で、実行してみたところ&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go.mod:3: invalid go version &apos;v1.21.4&apos;: must match format 1.23
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出たので、バージョンを&lt;code&gt;go 1.21.4&lt;/code&gt;から&lt;code&gt;go 1.21&lt;/code&gt;に変更し再度挑戦してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;building...
no Go files in /workspaces/ProjectName
failed to build, error: exit status 1
running...
/bin/sh: 1: /workspaces/ProjectName/tmp/main: not found
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;ホットリロードは確認できたけど...&lt;/h2&gt;
&lt;p&gt;次に上記エラーが出たので、&lt;code&gt;main.go&lt;/code&gt;を&lt;code&gt;/src&lt;/code&gt;から&lt;code&gt;root&lt;/code&gt;に移動した結果、ホットリロードが動いていることが確認できた。&lt;/p&gt;
&lt;p&gt;ただデーターベースに接続できなくなったし、やっぱり&lt;code&gt;/src&lt;/code&gt;の下に開発ファイルを置きたい。&lt;/p&gt;
&lt;p&gt;ここで時間使うのももったいないので、いったん諦める。戦略的撤退。&lt;/p&gt;
&lt;p&gt;ホットリロードが動くことは確認できたので、とりあえず満足した。&lt;/p&gt;
&lt;p&gt;いつかまた挑戦する。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>VSCodeのドットファイルをGithubで管理し常に最新を共有する</title><link>https://blog.nove-b.dev/posts/vscode-dotfiles-async</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/vscode-dotfiles-async</guid><description>VSCode</description><content:encoded>&lt;p&gt;パソコンがもっさりしている。どうやら買い替えの時期が近いらしい。&lt;/p&gt;
&lt;p&gt;そもそもキーボードもふたつのキーが機能していない。&lt;/p&gt;
&lt;p&gt;そういうわけで環境を色々整理し始めた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://localhost:1313/posts/winget-install-elk/&quot;&gt;WingetでWindowsにアプリをインストールする&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上の記事もそういう理由。&lt;/p&gt;
&lt;p&gt;今回はVSCodeの環境を&lt;code&gt;dotfiles&lt;/code&gt;で管理できるようにする。&lt;/p&gt;
&lt;h2&gt;dotfilesとは&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;dotfiles&lt;/code&gt;とは下記のこと。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;dotfilesとは、ホームディレクトリに置いてあるドット(.)から始まる設定ファイル (.bashrcとか)を管理しているリポジトリのことである。シェルやエディタの設定からアプリケーションの設定まで幅広いものが置かれている。&lt;/p&gt;
&lt;p&gt;引用：&lt;a href=&quot;https://qiita.com/yutkat/items/c6c7584d9795799ee164#dotfiles%E3%81%A8%E3%81%AF&quot;&gt;ようこそdotfilesの世界へ - Qiita&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;つまりこれを使用すれば、どのパソコンでも一瞬で同一の環境を作成することができる。&lt;/p&gt;
&lt;p&gt;会社のパソコンと自宅のパソコンの設定だって一緒にできる。&lt;/p&gt;
&lt;h2&gt;VSCodeでやってみる&lt;/h2&gt;
&lt;p&gt;そういうわけで、もっともよく使用するVSCodeでやってみることにした。&lt;/p&gt;
&lt;p&gt;管理するのは２つ。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;拡張機能&lt;/li&gt;
&lt;li&gt;環境設定&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;拡張機能&lt;/h3&gt;
&lt;p&gt;拡張機能は&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;code --list-extensions &amp;gt; extensions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でインストールした拡張機能の一覧を、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  C:\Users\name\.vscode\extensions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に一覧で書き出すことができる。&lt;/p&gt;
&lt;h3&gt;環境設定&lt;/h3&gt;
&lt;p&gt;環境設定は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Users\name\AppData\Roaming\Code\User
&amp;gt; keybindings.json
&amp;gt; settings.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に存在している。&lt;/p&gt;
&lt;p&gt;この3つをGit管理するようにする。&lt;/p&gt;
&lt;p&gt;https://qiita.com/miiina016/items/018331b36ecf57ed8973&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>GitBashが日本語を受け付けなかったので対応させた</title><link>https://blog.nove-b.dev/posts/gitbash-enable-japanese</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/gitbash-enable-japanese</guid><description>GitBashが日本語を受け付けなかったので対応させた</description><content:encoded>&lt;p&gt;会社のPCで&lt;code&gt;Git Bash&lt;/code&gt;に日本語を打つと何も表示されない。&lt;/p&gt;
&lt;p&gt;そのため、毎回毎回&lt;code&gt;export LC_ALL=ja_JP.utf8&lt;/code&gt;と記入していた。&lt;/p&gt;
&lt;p&gt;面倒なので起動時に日本語を受け付けるようにしたい。&lt;/p&gt;
&lt;h2&gt;.bash_profileを変更する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;user/username/.bash_profile&lt;/code&gt;に&lt;code&gt;export LC_ALL=ja_JP.utf8&lt;/code&gt;を追記すると実現できる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>2024年3月の月報</title><link>https://blog.nove-b.dev/posts/2024-3</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-3</guid><description>2024年3月に考えたこととか</description><content:encoded>&lt;p&gt;&lt;a href=&quot;https://nove-b.github.io/posts/books-2024-2/&quot;&gt;前回（3月）&lt;/a&gt;は読んだ本をまとめたけどそれ以外にも記憶しておいたほうがいいと思ったので、書いておくことにする。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;3月に読んだ本&lt;/h2&gt;
&lt;h3&gt;プログラミング経験者がGo言語を本格的に勉強する前に読むための本 (天田士郎)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;本書はタイトルの通り「Go言語を本格的に勉強する前に最低限抑えておくべき知識」をまとめた物です。何らかのプログラミング言語の経験者を想定しているため、未経験者や初心者の方はご注意ください。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3VyR200&quot;&gt;プログラミング経験者がGo言語を本格的に勉強する前に読むための本&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;いま作成しているアプリのバックエンドで&lt;code&gt;Golang&lt;/code&gt;に挑戦している。&lt;/p&gt;
&lt;p&gt;Chat-GPTを最大限に活用している。そのせいか、なんとなく学びきれてない感を拭い去れない。&lt;/p&gt;
&lt;p&gt;そこで体系的に学ぼうと手に取った。&lt;/p&gt;
&lt;p&gt;文法的のまとめのような本なので、体系的には学べなかった。&lt;/p&gt;
&lt;p&gt;次はハンズオン的な本を読もうと思った。&lt;/p&gt;
&lt;h2&gt;1984 (ジョージ・オーウェル)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1984年、世界は〈オセアニア〉〈ユーラシア〉〈イースタシア〉という3つの国に分割統治されていた。オセアニアは、ビッグ・ブラザー率いる一党独裁制。市中に「ビッグ・ブラザーは見ている」と書かれたポスターが張られ、国民はテレスクリーンと呼ばれる装置で24時間監視されていた。党員のウィンストン・スミスは、この絶対的統治に疑念を抱き、体制の転覆をもくろむ〈ブラザー連合〉に興味を持ちはじめていた。一方、美しい党員ジュリアと親密になり、隠れ家でひそかに逢瀬を重ねるようになる。つかの間、自由と生きる喜びを噛みしめるふたり。しかし、そこには、冷酷で絶望的な罠がしかけられていたのだった――。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/49DrjaM&quot;&gt;1984&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;まだ読んでいる。&lt;/p&gt;
&lt;p&gt;なんとなくページが進まない。&lt;/p&gt;
&lt;p&gt;面白くないわけじゃないんだけど、読み気が進まない。&lt;/p&gt;
&lt;p&gt;そして絶対に読んだことがある。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;プライベートとか仕事とか&lt;/h2&gt;
&lt;h3&gt;子育て&lt;/h3&gt;
&lt;p&gt;双子が1歳半になった。&lt;/p&gt;
&lt;p&gt;より人間らしくなってきて、ぐんぐん可愛くなってきている。&lt;/p&gt;
&lt;p&gt;同時に意思も強くなってきて、こちらの思い通りにならないことも増えてきた。&lt;/p&gt;
&lt;p&gt;滑り台が好きで、公園に行くと喜ぶ。&lt;/p&gt;
&lt;p&gt;最近は子どもの動画を編集するのにはまっている。&lt;/p&gt;
&lt;p&gt;Google
Photo のハイライト動画という機能で簡単に作れるので、お出かけした時はその日の動画を1分くらいにまとめている。&lt;/p&gt;
&lt;h3&gt;スマホがほしい&lt;/h3&gt;
&lt;p&gt;格安スマホ使っているのだが、そういう訳で画質に不満が募り始めたので、スマホの買い替えを検討している。&lt;/p&gt;
&lt;p&gt;Google Pixelに出戻りをするか、あと折りたたみスマホも気になっている。&lt;/p&gt;
&lt;h3&gt;PCのほうがほしい&lt;/h3&gt;
&lt;p&gt;ただそれよりもPCの買い替えが急務である。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ctrl&lt;/code&gt;キーがなくなって早１年、ずっと使ってきたが、&lt;code&gt;Alt&lt;/code&gt;キーも外れそうである。&lt;/p&gt;
&lt;p&gt;あと最近&lt;code&gt;Docker&lt;/code&gt;とか起動するともっさりしている。&lt;/p&gt;
&lt;p&gt;次は、Surface
10にする予定。どうやら6月に出るっぽいので、それまで我慢することにする。&lt;/p&gt;
&lt;h3&gt;目標達成率&lt;/h3&gt;
&lt;p&gt;もっさりしたPCで作っているアプリは進捗が芳しくない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Go&lt;/code&gt;の知識がなさすぎで思うように進まない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NestJS&lt;/code&gt;とかで作成しておけばよかったと思うけど、それだと成長が止まってしまうので、ここでしっかり&lt;code&gt;Go&lt;/code&gt;をマスターしたい所存。&lt;/p&gt;
&lt;p&gt;アプリ作成は今年の目標の1つである。数ある目標の中でも最優先タスクなので、6月くらいまでに達成したい。&lt;/p&gt;
&lt;p&gt;理想は&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ネイティブアプリをリリースする(6月)&lt;/li&gt;
&lt;li&gt;基本情報技術者資格を取る(8月)&lt;/li&gt;
&lt;li&gt;OSS活動にコントリビューとする(10月)&lt;/li&gt;
&lt;li&gt;Mastodonのサーバーを立ち上げる(12月)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とか。できるかしら。&lt;/p&gt;
&lt;p&gt;まあ、地道に頑張る。&lt;/p&gt;
&lt;h3&gt;仕事がまあ忙しい&lt;/h3&gt;
&lt;p&gt;進捗が芳しくないのは仕事に時間を取られているという原因もある。&lt;/p&gt;
&lt;p&gt;今は&lt;code&gt;Angular&lt;/code&gt;、&lt;code&gt;Vue&lt;/code&gt;、&lt;code&gt;NestJs&lt;/code&gt;の案件がメインである。&lt;/p&gt;
&lt;p&gt;その中でも多くの比重を占めているのが&lt;code&gt;NestJs&lt;/code&gt;の案件。&lt;/p&gt;
&lt;p&gt;実装者として参画しているんだけど、プロマネ的なこともしている。&lt;/p&gt;
&lt;p&gt;他人のコードの質を担保するのが本当に難しい。&lt;/p&gt;
&lt;p&gt;自分のコードは仕様に沿うように書いているので問題ないんだけど、他人のコードのレビューをするときはその人の考えたことを想像しつつ、コードを読み解く必要がある。&lt;/p&gt;
&lt;p&gt;難しいけど、まあ糧にはなるよね。&lt;/p&gt;
&lt;p&gt;っていうそんな感じで4月になっていた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Github ActionでGithubに草が生え続けていた</title><link>https://blog.nove-b.dev/posts/github-keeps-growing-green</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/github-keeps-growing-green</guid><description>Github Actionが毎日動き、草を生やし続けていたことに気が付いた</description><content:encoded>&lt;h2&gt;草が生い茂っている&lt;/h2&gt;
&lt;p&gt;自分自身の&lt;code&gt;Github&lt;/code&gt;プロフィールページは、たぶんだけれどそんなに多く訪れるものじゃない。個人で作ったプロジェクトの整理をしようと思い立ち、久々に訪れると、コミット履歴が青々と生い茂っていた。&lt;/p&gt;
&lt;p&gt;もちろん、勤勉に勉強しているつもりだが、毎日コミットできるほどに勤勉ではない。&lt;/p&gt;
&lt;p&gt;特に子どもが生まれてからパソコンを開けない日が増えた。&lt;/p&gt;
&lt;p&gt;いかに子どもたちの体力を消費させるかという基準で公園の選定と、保育園について調べる時間で、夜の自由時間は消える。&lt;/p&gt;
&lt;p&gt;そのため、最近は週の半分コミットできれば上出来といった具合なのだが、先述した通り、コミット履歴は青々と生い茂っている。&lt;/p&gt;
&lt;h2&gt;Githubの草を生やすことを目標にしている人種もいる&lt;/h2&gt;
&lt;p&gt;どうやら&lt;code&gt;Github&lt;/code&gt;の草を生やすことに執着している人もいるらしい。毎日草を生やしたいので、コミットするなんていう人が。&lt;/p&gt;
&lt;p&gt;理由としてはモチベーションアップとか、転職に役立つとか書いてあるけれど、&lt;code&gt;Github&lt;/code&gt;の草が転職に役立つような企業なのであれば、それは少し怪しい。&lt;/p&gt;
&lt;p&gt;毎日勉強しているという風に捉えてくれるのかもしれないけど、草が生えているから勉強しているわけではない。&lt;/p&gt;
&lt;p&gt;その一例が私のコミット履歴である。&lt;/p&gt;
&lt;p&gt;毎日やっていないけど、草が生い茂っている。&lt;/p&gt;
&lt;p&gt;決して毎日草を生やしたいなんていう目的で草を生やしているわけではない。&lt;/p&gt;
&lt;p&gt;この草は気が付いていたら生えていた雑草の様なものなので、引き抜きたいけれど、引き抜く方法がわからなので、もう生えてこないよう、除草剤をまくことにした。&lt;/p&gt;
&lt;h2&gt;原因はGithub Action&lt;/h2&gt;
&lt;p&gt;草が生えるには、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;リポジトリのデフォルトブランチへのコミット&lt;/li&gt;
&lt;li&gt;イシューを開く&lt;/li&gt;
&lt;li&gt;プルリクエストを提案する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上記の条件がある。&lt;/p&gt;
&lt;p&gt;確かに作業を行っていない日だろうと、思いついた時にissueを開くことはあったけど、決して毎日じゃない。そして毎日作業していないので、コミットもしていなければ、プルリクの提出もしていない。&lt;/p&gt;
&lt;p&gt;それじゃ、何が原因なのか。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/nove-b/nove-b.github.io/assets/68768186/cb44b94d-a5c9-413b-90f4-d7a3de22899e&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;調べてみると毎日１コミットが、&lt;code&gt;feed&lt;/code&gt;というリポジトリに行われていた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;feed&lt;/code&gt;というリポジトリは自作の&lt;code&gt;RSSリーダー&lt;/code&gt;で毎日&lt;code&gt;Github Action&lt;/code&gt;を使用し、記事を最新化している。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nove-b.github.io/feed/&quot;&gt;読みたい記事たち&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;間違いなく、これである。&lt;/p&gt;
&lt;p&gt;ここに仕込んだ&lt;code&gt;Github Action&lt;/code&gt;が毎日定期実行され、記事を最新化してくれ、その副産物として草まで生やしてくれていた。&lt;/p&gt;
&lt;p&gt;今回は草が生えているだけでよかったのだが、何かしら課金の絡んだ処理とかであった場合、恐ろしい。&lt;/p&gt;
&lt;p&gt;使わない定期実行はしっかり処理しようという教訓を得たのと、草を生やして転職に役立てたいという需要があるのであれば、そういう&lt;code&gt;Github Action&lt;/code&gt;を作っても面白いかもしれない？ という謎のアイデアが生まれた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>2024年4月の月報</title><link>https://blog.nove-b.dev/posts/2024-4</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-4</guid><description>2024年4月に考えたこととか</description><content:encoded>&lt;hr /&gt;
&lt;h2&gt;4月に読んだ本&lt;/h2&gt;
&lt;h3&gt;1984 (ジョージ・オーウェル)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1984年、世界は〈オセアニア〉〈ユーラシア〉〈イースタシア〉という3つの国に分割統治されていた。オセアニアは、ビッグ・ブラザー率いる一党独裁制。市中に「ビッグ・ブラザーは見ている」と書かれたポスターが張られ、国民はテレスクリーンと呼ばれる装置で24時間監視されていた。党員のウィンストン・スミスは、この絶対的統治に疑念を抱き、体制の転覆をもくろむ〈ブラザー連合〉に興味を持ちはじめていた。一方、美しい党員ジュリアと親密になり、隠れ家でひそかに逢瀬を重ねるようになる。つかの間、自由と生きる喜びを噛みしめるふたり。しかし、そこには、冷酷で絶望的な罠がしかけられていたのだった――。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/49DrjaM&quot;&gt;1984&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;やっと読み終えた。&lt;/p&gt;
&lt;p&gt;最後まで読んでもなんとなく読んだことあるなあ、くらいの感覚だった。&lt;/p&gt;
&lt;p&gt;つまり当時もそこまで思うところなかったんだろうなあ。&lt;/p&gt;
&lt;p&gt;当時としては画期的な設定だったのかもしれないけれど、今はよくあるだろうし、あまりにも理屈っぽい。&lt;/p&gt;
&lt;h3&gt;僕の好きな人が、よく眠れますように (角川文庫)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;僕が通う理科系大学のゼミに、北海道から院生の女の子が入ってきた。徐々に距離の近づく僕らには、しかし決して恋が許されない理由があった……『100回泣くこと』を超えた、あまりにせつない恋の物語。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3JHSWo3&quot;&gt;僕の好きな人が、よく眠れますように (角川文庫)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;再読、忘れちゃいけないんだけど、これ不倫のおはなし。&lt;/p&gt;
&lt;h3&gt;小市民シリーズ&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3wdrjQB&quot;&gt;春期限定いちごタルト事件 小市民シリーズ (創元推理文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4bdtxyg&quot;&gt;夏期限定トロピカルパフェ事件 小市民シリーズ (創元推理文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3JJQywQ&quot;&gt;秋期限定栗きんとん事件 上 小市民シリーズ (創元推理文庫)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;どうやら冬季限定（&lt;a href=&quot;https://amzn.to/3QmGQnY&quot;&gt;冬期限定ボンボンショコラ事件 〈小市民〉シリーズ (創元推理文庫)&lt;/a&gt;）が出るらしいということで、一気に読み返し中。&lt;/p&gt;
&lt;p&gt;調べると番外編（&lt;a href=&quot;https://amzn.to/4byGwLh&quot;&gt;巴里マカロンの謎 〈小市民〉シリーズ (創元推理文庫)&lt;/a&gt;）も出ていたらしい。&lt;/p&gt;
&lt;p&gt;久しぶりに読むけど、やっぱり面白い。&lt;/p&gt;
&lt;p&gt;ページをめくる手が止まらないので、どんどん口座からお金が引き落とされる。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;プライベートとか仕事とか&lt;/h2&gt;
&lt;h3&gt;土日は基本的に公園に&lt;/h3&gt;
&lt;p&gt;土日は基本的に外に行かないともたない。&lt;/p&gt;
&lt;p&gt;子どもたちの無尽蔵の体力と戦い抜くには家はあまりにも狭すぎる。&lt;/p&gt;
&lt;p&gt;ということで土日は決まって公園に行くのだが、人が多いと「抱っこ抱っこ」でこちらの体力が主に削られる。&lt;/p&gt;
&lt;p&gt;まあ、普段座ってばかりだから、歩くことは良いことなんだけど、他の子がぐんぐん歩いているのを見ると、少し羨ましい。&lt;/p&gt;
&lt;p&gt;とはいえ、いずれ抱っこすらさせてくれなくなるのだろうから、文句を言わずに抱っこしようと思う。&lt;/p&gt;
&lt;p&gt;たぶんきっと、子どもが親にくっついてくれる時期はあまりにも短い。&lt;/p&gt;
&lt;h3&gt;個人開発&lt;/h3&gt;
&lt;p&gt;やっとバックエンドの開発が終了した。&lt;/p&gt;
&lt;p&gt;いや、アプリ側と並走するので、終了したというより一段落したといったぐあい。&lt;/p&gt;
&lt;p&gt;現にアプリ側から叩き、&lt;code&gt;CORS&lt;/code&gt;エラーでつまった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CORS&lt;/code&gt;ってブラウザ間の問題じゃないの？&lt;/p&gt;
&lt;p&gt;よくわからいけど&lt;code&gt;expo&lt;/code&gt;で実行しているからかしら。&lt;/p&gt;
&lt;p&gt;そういったことを調べて、まとめて、理解して進みたいんだけど、それ以上に早く完成させたい。&lt;/p&gt;
&lt;p&gt;あまりにも時間がない。&lt;/p&gt;
&lt;p&gt;でもきっとしっかり調べてまとめた方が将来的にはためになるんだろう。&lt;/p&gt;
&lt;p&gt;木こりのジレンマ的な？&lt;/p&gt;
&lt;p&gt;調べてアウトプットしよう、5月の目標は5記事くらいは書きたい。&lt;/p&gt;
&lt;p&gt;ちなみに4月は1記事、うーん。記事書くことがすべてじゃないけど、もう少し書いていきたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>APIのメソッドPUTとPATCHは何が違うのか調べてみた</title><link>https://blog.nove-b.dev/posts/api-methods-put-or-patch</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/api-methods-put-or-patch</guid><description>APIを作成しているので、PUTとPATCHの違いを調べてみた</description><content:encoded>&lt;h2&gt;PUTとPATCHの違いをあまり気にしてこなかった&lt;/h2&gt;
&lt;p&gt;基本的にフロントエンドなので、仕様書に書かれているメソッドで&lt;code&gt;API&lt;/code&gt;と通信してきた。&lt;/p&gt;
&lt;p&gt;ただ今回、自身が作る側に回り、&lt;code&gt;PUT&lt;/code&gt;と&lt;code&gt;PATCH&lt;/code&gt;の違いがいまいちピンとこなかったので、調べてみた。&lt;/p&gt;
&lt;h2&gt;結論&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;PUT&lt;/code&gt;はリソースの完全な置き換えで、&lt;code&gt;PATCH&lt;/code&gt;はリソースの一部分のみを更新する場合とのこと。&lt;/p&gt;
&lt;p&gt;例えば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;John Doe&quot;,
  &quot;age&quot;: 30,
  &quot;email&quot;: &quot;john@example.com&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というデータがあり、31歳に変更する場合を考えてみる。&lt;/p&gt;
&lt;h3&gt;PUTの場合&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;PUT /users/123 HTTP/1.1
Host: example.com
Content-Type: application/json

{
  &quot;name&quot;: &quot;John Doe&quot;,
  &quot;age&quot;: 31,
  &quot;email&quot;: &quot;john@example.com&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;といった感じに変更した年齢以外もまるっと送る必要がある。&lt;/p&gt;
&lt;h3&gt;PATCHの場合&lt;/h3&gt;
&lt;p&gt;対して&lt;code&gt;PATCH&lt;/code&gt;の場合は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PATCH /users/123 HTTP/1.1
Host: example.com
Content-Type: application/json

{
  &quot;age&quot;: 31
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;となる。&lt;/p&gt;
&lt;h3&gt;どっちを使うべきか&lt;/h3&gt;
&lt;p&gt;まあ、この感じだと一部だけを更新したい場合は&lt;code&gt;PATCH&lt;/code&gt;を使用するべきなんだと思うけど、その場合はフォームの一部だけが変更されたという監視が必要になるので、それなりの工数がかかる。そのため&lt;code&gt;PUT&lt;/code&gt;でいいかなといった結論になりました。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Goで作成したローカルサーバーにReact NativeからアクセスしようとしたらTypeError: Network request failedになった</title><link>https://blog.nove-b.dev/posts/reactnative-fetch-error</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/reactnative-fetch-error</guid><description>Goで作成したローカルサーバーにReact NativeからアクセスしようとしたらTypeError: Network request failedになったので、調査してみた</description><content:encoded>&lt;h2&gt;API作成が一段落した&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Go&lt;/code&gt;の勉強で&lt;code&gt;API&lt;/code&gt;を作成してきたが、やっと一段落した。&lt;/p&gt;
&lt;p&gt;そこでアプリ側から叩こうとした結果、エラーが出たので原因を理由を調査してみた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Go&lt;/code&gt;で立ち上げたサーバ&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://localhost:8081/api/v1/endpoint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のローカルIPアドレス&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://172.19.176.1:8081/api/v1/endpoint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に&lt;code&gt;React Native&lt;/code&gt;で作成したアプリからアクセスしてみる。&lt;/p&gt;
&lt;h2&gt;ネットワークリクエストが失敗しました&lt;/h2&gt;
&lt;p&gt;結果、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TypeError: Network request failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出力された。&lt;/p&gt;
&lt;h3&gt;ファイアーウォールが関係している？&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://weblion303.net/2377&quot;&gt;【react-native】シュミレータでAPIアクセスを行う際にnetwork error&lt;/a&gt;の記事を参照するに、&lt;code&gt;CORS&lt;/code&gt;かしらって思ったけど、アプリで&lt;code&gt;CORS&lt;/code&gt;はちょっと違う気がする。&lt;/p&gt;
&lt;p&gt;アプリにドメイン存在しないので、どのドメインを許可すればいいのっていうことになる。&lt;/p&gt;
&lt;p&gt;で、色々調査していると、ファイアーウォールが関係している気がしてきた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Windows向けプログラムに搭載されているファイアウォール（パーソナルファイアウォール）機能は、ネットワークプリンターや他のコンピューターとの通信を遮断する場合があります。その場合は、該当する通信を許可するルールを作成することで、通信ができるようになります。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://eset-support.canon-its.jp/faq/show/235?site_domain=default&quot;&gt;https://eset-support.canon-its.jp/faq/show/235?site_domain=default&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ポートを開放すればいける感じかもしれないけど、せっかくだしサーバーにあげてみることにした。&lt;/p&gt;
&lt;p&gt;どうせいずれあげる必要があるしね。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>ZennのスクラップのようにGithub Issueに作業のログとかを残すようにした</title><link>https://blog.nove-b.dev/posts/log-as-gitthub-issue</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/log-as-gitthub-issue</guid><description>ZennのスクラップのようにGithub Issueに作業のログとかを残すようにした</description><content:encoded>&lt;p&gt;作業中に新しい知識とか詰まった箇所、エラーの記録を取りたいと思うことがある。今まではブログにずらずら書いていたけれど、結果、まとまりのない文章ができあがり、何にも活用することができないという状況が生まれていた。&lt;/p&gt;
&lt;h2&gt;ZennのScrapsを活用する？&lt;/h2&gt;
&lt;p&gt;そこで&lt;a href=&quot;Scraps&quot;&gt;Zenn&lt;/a&gt;を活用することを考えメリットデメリットを考えてみた。&lt;/p&gt;
&lt;h3&gt;メリット&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;公開することができるので、自身のブランディングに活用できる&lt;/li&gt;
&lt;li&gt;コメント機能で他人の知見をシェアしてもらうことができる&lt;/li&gt;
&lt;li&gt;結果的にほかの人の&lt;code&gt;Scraps&lt;/code&gt;を見るようになり知見が広まる&lt;/li&gt;
&lt;li&gt;他人の助けになることもある&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;デメリット&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;公開されるので、ソースコードにぼかしを入れる必要がある&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Scraps&lt;/code&gt;は&lt;code&gt;Git&lt;/code&gt;で管理ができない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;こうやって見るとメリットのほうが多いけど、デメリットが許容できなかった。ただこれが許容できないとなると、コンテンツの公開がされるサービスは使用できない。&lt;/p&gt;
&lt;h2&gt;GithubのIssue💡&lt;/h2&gt;
&lt;p&gt;そこで思いついたのが&lt;code&gt;Github&lt;/code&gt;の&lt;code&gt;Issue&lt;/code&gt;だった。&lt;/p&gt;
&lt;p&gt;そもそも&lt;code&gt;Scraps&lt;/code&gt;も&lt;code&gt;Issue&lt;/code&gt;を参考にしているだろうし、機能的には問題ない。&lt;/p&gt;
&lt;p&gt;しかもこのブログも&lt;code&gt;Github&lt;/code&gt;で管理されており、同リポジトリ内に作成すれば検索も強い。&lt;/p&gt;
&lt;p&gt;そういうことで&lt;code&gt;Github&lt;/code&gt;で管理することにした。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/issue-screen.jpg&quot; alt=&quot;実際の画像&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;プライベートリポジトリに&lt;/h2&gt;
&lt;p&gt;公開はしたくなかったので、リポジトリをプライベートに変更した。&lt;/p&gt;
&lt;p&gt;そのため&lt;code&gt;Github Pages&lt;/code&gt;が使えなくなったので、ホスティング先を&lt;code&gt;netlify&lt;/code&gt;に変更した。&lt;/p&gt;
&lt;p&gt;移行は&lt;a href=&quot;https://gohugo.io/hosting-and-deployment/hosting-on-netlify/&quot;&gt;Host on Netlify&lt;/a&gt;の通りやれば難なく完了できる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/&quot;&gt;https://blog.nove-b.dev/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;URLが少しダサくなったけど、カスタムドメインを適用するほどじゃないかなといった感じなので、このままいくことにした。&lt;/p&gt;
&lt;p&gt;これで少しでもレベルアップできるといい。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;☆カスタムドメインに対応した&lt;/strong&gt;
&lt;a href=&quot;https://blog.nove-b.dev/posts/cloudflare-registrar-netlify-subdomain/&quot;&gt;Cloudflare Registrarでドメインを登録し、Netlifyのサーバーにサブドメインを当てる&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Cloud RunでGoを動かしたい</title><link>https://blog.nove-b.dev/posts/api-by-go-on-gcp</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/api-by-go-on-gcp</guid><description>GolangでAPIを作成したのでCloud Runで動かしてみる</description><content:encoded>&lt;p&gt;&lt;code&gt;Gorm&lt;/code&gt;を使用し、&lt;code&gt;API&lt;/code&gt;を作成した。前回は&lt;code&gt;AWS&lt;/code&gt;と&lt;code&gt;NestJs&lt;/code&gt;だったので、今回は&lt;code&gt;GCP&lt;/code&gt;を使用してみることにした。&lt;/p&gt;
&lt;h2&gt;Cloud Run&lt;/h2&gt;
&lt;p&gt;今回は&lt;code&gt;Cloud Run&lt;/code&gt;を使用することにした。&lt;/p&gt;
&lt;p&gt;そもそも&lt;code&gt;Cloud Run&lt;/code&gt;とは、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;フロントエンド サービスやバックエンド サービス、バッチジョブの実行、ウェブサイトやアプリケーションのデプロイ、処理ワークロードのキューへの追加を行います。インフラストラクチャを管理する必要はありません。&lt;/p&gt;
&lt;p&gt;毎月 200 万リクエストは無料です。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;Amazon ECS&lt;/code&gt;と&lt;code&gt;AWS App Runner&lt;/code&gt;と比較されることが多いらしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zenn.dev/tokku5552/articles/diff-aws-google-cloud&quot;&gt;Amazon ECSとApp RunnerとCloud runの比較&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;特筆すべきは無料枠があることな気がする。&lt;/p&gt;
&lt;h2&gt;デプロイ&lt;/h2&gt;
&lt;p&gt;そんな&lt;code&gt;Cloud Run&lt;/code&gt;にデプロイしていく。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-go-service?hl=ja&quot;&gt;クイックスタート: Cloud Run に Go サービスをデプロイする&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;公式が丁寧なのでこれに沿っていく。&lt;/p&gt;
&lt;p&gt;ちなみに前提は下記の通りになる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Go&lt;/code&gt;で既に&lt;code&gt;API&lt;/code&gt;を作成している&lt;/li&gt;
&lt;li&gt;フレームワークは未使用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Go&lt;/code&gt;のバージョンは&lt;code&gt;go 1.21.4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ローカルでサーバーを立ち上げる時は&lt;code&gt;net/http&lt;/code&gt;を使用した。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;アカウント作成&lt;/h3&gt;
&lt;p&gt;まずはアカウントを作成する必要がある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://console.cloud.google.com/freetrial?hl=ja&amp;amp;facet_utm_source=google&amp;amp;facet_utm_campaign=%28organic%29&amp;amp;facet_utm_medium=organic&amp;amp;facet_url=https%3A%2F%2Fcloud.google.com%2Frun%2Fdocs%2Fquickstarts%2Fbuild-and-deploy%2Fdeploy-go-service&amp;amp;facet_id_list=%5B39300012%2C+39300023%2C+39300118%2C+39300196%2C+39300251%2C+39300318%2C+39300320%2C+39300324%2C+39300346%2C+39300354%2C+39300363%2C+39300373%2C+39300408%2C+39300422%2C+39300437%2C+39300473%2C+39300487%2C+39300496%2C+39300498%5D&amp;amp;_ga=2.101277705.966689526.1714917854-758618644.1700836939&quot;&gt;アカウントを作成する&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;作成後、
&lt;a href=&quot;https://console.cloud.google.com/projectselector2/home/dashboard?hl=ja&amp;amp;_ga=2.100680585.966689526.1714917854-758618644.1700836939&quot;&gt;プロジェクト セレクタ&lt;/a&gt;
ページで、&lt;code&gt;Google Cloud&lt;/code&gt; プロジェクトを作成する。&lt;/p&gt;
&lt;p&gt;プロジェクト名を作成するだけで作成が完了する。&lt;/p&gt;
&lt;p&gt;次に課金が有効になっていることを確認する必要がある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cloud.google.com/billing/docs/how-to/verify-billing-enabled?hl=ja#console&quot;&gt;課金が有効になっているか確認する&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;課金が有効になっていない場合は、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「このプロジェクトには請求先アカウントがありません」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;というポップアップが表示されるらしい。&lt;/p&gt;
&lt;h3&gt;Google Cloud CLI をインストール&lt;/h3&gt;
&lt;p&gt;ここで問題がないようであれば、&lt;code&gt;Google Cloud CLI&lt;/code&gt; をインストールする。&lt;/p&gt;
&lt;p&gt;以下、&lt;code&gt;Windows&lt;/code&gt;での方法になる。&lt;/p&gt;
&lt;p&gt;参考；&lt;a href=&quot;https://cloud.google.com/sdk/docs/install?hl=ja#windows&quot;&gt;インストール手順&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe?hl=ja&quot;&gt;Google Cloud CLI インストーラ&lt;/a&gt;をダウンロード。&lt;/p&gt;
&lt;p&gt;インストール後は画面の指示に従い、進めていく。&lt;/p&gt;
&lt;p&gt;全部、&lt;code&gt;Next☞&lt;/code&gt;でやったけど問題なさそうだった。&lt;/p&gt;
&lt;p&gt;インストールが完了するとログインを求められ、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;これで gcloud CLI での認証が完了しました。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;問題なければ上記のページに飛ばされる。&lt;/p&gt;
&lt;p&gt;同時にターミナル ウィンドウが開いて &lt;code&gt;gcloud init&lt;/code&gt; コマンドが実行される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; gcloud config set project PROJECT_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、&lt;code&gt;Cloud Run&lt;/code&gt;
サービスのデフォルト プロジェクトを設定するけど、なんで設定したかはまだわからない。&lt;/p&gt;
&lt;h3&gt;デプロイで連携する&lt;/h3&gt;
&lt;p&gt;次に既存のアプリを連携させる。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ソースコード ディレクトリで、次のコマンドを使用してソースからデプロイします。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gcloud run deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことだったので、実行した結果、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcloud run deploy
bash: gcloud: command not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;エラーになったので再起動して実装してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcloud run deploy
/c/Users/username/AppData/Local/Google/Cloud SDK/google-cloud-sdk/bin/gcloud: line 203: /c/Users/username/AppData/Local/Microsoft/WindowsApps/python3: Permission denied
/c/Users/username/AppData/Local/Google/Cloud SDK/google-cloud-sdk/bin/gcloud: line 203: /c/Users/username/AppData/Local/Microsoft/WindowsApps/python3: Permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーがでた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;VSCode&lt;/code&gt;の&lt;code&gt;Gitbash&lt;/code&gt;で起こるエラーっぽいので、コマンドプロンプトで実行したところうまく通った。&lt;/p&gt;
&lt;p&gt;このあと何回かデプロイを試したが何回もエラーで落ちる。&lt;/p&gt;
&lt;h3&gt;エラーとの戦い（データベースへの接続に失敗しました）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Google&lt;/code&gt;が用意したサンプルコードだとデプロイが成功するのに自身のアプリはデプロイできない。&lt;/p&gt;
&lt;p&gt;仕方ないので、コメントアウトをしつつ、デプロイを試していく。&lt;/p&gt;
&lt;p&gt;すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;データベースへの接続に失敗しました: dial tcp 127.0.0.1:3306: connect: connection refused&quot;
exit(1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで落ちていることが判明した。&lt;/p&gt;
&lt;p&gt;つまりデーターベースに接続できていない。&lt;/p&gt;
&lt;p&gt;ちょっと原因不明点が多すぎて原因究明できなかったので、また同じことが起きた時は原因まで調査するようにする。&lt;/p&gt;
&lt;h3&gt;Cloud SQLに接続するようにする&lt;/h3&gt;
&lt;p&gt;ローカルの&lt;code&gt;DB&lt;/code&gt;に接続できないのであれば、いずれ使用する予定だった&lt;code&gt;Cluod SQL&lt;/code&gt;であれば接続できるのでは？&lt;/p&gt;
&lt;p&gt;という風に思い、&lt;a href=&quot;https://blog.nove-b.dev/posts/gorm-connect-cloud-sql/&quot;&gt;GormでCloud SQLに接続する&lt;/a&gt;を行った。&lt;/p&gt;
&lt;h3&gt;無事にデプロイ&lt;/h3&gt;
&lt;p&gt;で、上記完了後に再デプロイした結果、無事にデプロイできました。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>GormでCloud SQLに接続する</title><link>https://blog.nove-b.dev/posts/gorm-connect-cloud-sql</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/gorm-connect-cloud-sql</guid><description>GormでCloud SQLに接続する</description><content:encoded>&lt;p&gt;&lt;code&gt;Cloud Run&lt;/code&gt;に&lt;code&gt;Go&lt;/code&gt;で作成した&lt;code&gt;API&lt;/code&gt;をデプロイしようと思ったところ、うまくいかなかった。&lt;/p&gt;
&lt;p&gt;調査してみたところ、データーベースに接続できずに落ちているっぽいとのこと。&lt;/p&gt;
&lt;p&gt;ちょっとなんでかわからないけど（今思い返せば、&lt;code&gt;Docker&lt;/code&gt;起動していた？ という不安がある）、ローカルの&lt;code&gt;DB&lt;/code&gt;に接続できないので、いずれ接続する予定だったので、&lt;code&gt;Cloud SQL&lt;/code&gt;に接続し、それで&lt;code&gt;Cloud Run&lt;/code&gt;にデプロイしてみようという風に思い立った。&lt;/p&gt;
&lt;h2&gt;Cloud SQLに登録する&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://cloud.google.com/sql/docs/mysql/connect-instance-cloud-run?hl=ja#console_2&quot;&gt;Cloud Run から Cloud SQL for MySQL に接続する&lt;/a&gt;がある。&lt;/p&gt;
&lt;p&gt;公式があるので、こちらを参考にする。&lt;/p&gt;
&lt;p&gt;なお、今回サーバーはローカル（&lt;code&gt;net/http&lt;/code&gt;）で起動することにする。&lt;/p&gt;
&lt;h2&gt;インスタンスを作成する&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Google Cloud コンソールで Cloud SQL の [インスタンス]
(https://console.cloud.google.com/sql?hl=ja&amp;amp;_ga=2.145632700.968950133.1716041931-758618644.1700836939)ページに移動する。&lt;/li&gt;
&lt;li&gt;インスタンスを作成 をクリック。&lt;/li&gt;
&lt;li&gt;[MySQL を選択] をクリック。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;インスタンスを作成するには、まず Compute Engine
API を有効にする必要があります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という警告が出るので、&lt;code&gt;API&lt;/code&gt;を有効にする。&lt;/p&gt;
&lt;p&gt;インスタンスID、パスワード、を登録。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;My SQL&lt;/code&gt;のバージョンを８にし、&lt;code&gt;Cloud SQL&lt;/code&gt; のエディションは&lt;code&gt;Enterprise&lt;/code&gt;にする。&lt;/p&gt;
&lt;p&gt;プリセットをいったん開発環境にして、リレージョンを東京、ゾーンをシングルに設定する。&lt;/p&gt;
&lt;p&gt;構成オプションを開き、とりあえず一番小さい&lt;code&gt;1 vCPU&lt;/code&gt;、&lt;code&gt;3.75 GB&lt;/code&gt;を選択してみる。&lt;/p&gt;
&lt;p&gt;で、インスタンスを作成する。&lt;/p&gt;
&lt;p&gt;構成オプションはとりあえず、最小で不満があればあげていく方法で問題ないらしい。&lt;/p&gt;
&lt;h2&gt;DBの作成&lt;/h2&gt;
&lt;p&gt;インスタンスのデータベースにいき、データーベースの作成をクリックする。&lt;/p&gt;
&lt;p&gt;今回インスタンスの作成をし、データーベースの作成をしていなかったので、エラーが出続け、悩まされた。&lt;/p&gt;
&lt;h2&gt;接続を試みる&lt;/h2&gt;
&lt;p&gt;まず接続をしてみたところ、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ go run main.go
2024/05/26 00:41:05 cloudsqlconn.NewDialer: failed to create default credentials: google: could not find default credentials. See https://cloud.google.com/docs/authentication/external/set-up-adc for more information
exit status 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出た。&lt;/p&gt;
&lt;p&gt;どうやら認証情報が見つかりませんとのこと。&lt;/p&gt;
&lt;p&gt;対象のディレクトリで&lt;code&gt;gcloud auth application-default login&lt;/code&gt;を実行し、ログインを完了させた。&lt;/p&gt;
&lt;p&gt;ソースコードは公式を参考に下記のように。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package db

import (
	&quot;context&quot;
	&quot;database/sql&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net&quot;
	&quot;os&quot;

	&quot;cloud.google.com/go/cloudsqlconn&quot;
	&quot;github.com/go-sql-driver/mysql&quot;
	gmysql &quot;gorm.io/driver/mysql&quot;
	&quot;gorm.io/gorm&quot;
)

var DB *gorm.DB

type Model struct {
	gorm.Model
}

func mustGetenv(k string) string {
	v := os.Getenv(k)
	if v == &quot;&quot; {
		log.Fatalf(&quot;Fatal Error in connect_connector.go: %s environment variable not set.&quot;, k)
	}
	return v
}

func InitDB() {

	var (
		dbUser                 = mustGetenv(&quot;DB_USER&quot;)                  // e.g. &apos;my-db-user&apos;
		dbPwd                  = mustGetenv(&quot;DB_PASS&quot;)                  // e.g. &apos;my-db-password&apos;
		dbName                 = mustGetenv(&quot;DB_NAME&quot;)                  // e.g. &apos;my-database&apos;
		instanceConnectionName = mustGetenv(&quot;INSTANCE_CONNECTION_NAME&quot;) // e.g. &apos;project:region:instance&apos;
		usePrivate             = os.Getenv(&quot;PRIVATE_IP&quot;)
	)
	d, err := cloudsqlconn.NewDialer(context.Background())
	if err != nil {
		fmt.Errorf(&quot;cloudsqlconn.NewDialer: %w&quot;, err)
		return
	}
	var opts []cloudsqlconn.DialOption
	if usePrivate != &quot;&quot; {
		opts = append(opts, cloudsqlconn.WithPrivateIP())
	}
	mysql.RegisterDialContext(&quot;cloudsqlconn&quot;,
		func(ctx context.Context, addr string) (net.Conn, error) {
			return d.Dial(ctx, instanceConnectionName, opts...)
		})

	dbURI := fmt.Sprintf(&quot;%s:%s@cloudsqlconn(localhost:3306)/%s?parseTime=true&quot;,
		dbUser, dbPwd, dbName)

	sqlDB, err := sql.Open(&quot;mysql&quot;, dbURI)
	if err != nil {
		log.Fatalf(&quot;sql.Open: %v&quot;, err)
	}

	// Open a connection to the database using the gorm package
	DB, err = gorm.Open(gmysql.New(gmysql.Config{
		Conn: sqlDB,
	}), &amp;amp;gorm.Config{})

	if err != nil {
		log.Fatalf(&quot;gorm.Open: %v&quot;, err)
	}

	fmt.Println(&quot;データベースに接続しました&quot;)
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで実行したところ、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;データベースに接続しました
2024/05/28 00:26:14 defaulting to port 8080
2024/05/28 00:26:14 listening on port 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事に接続できた。&lt;/p&gt;
&lt;h2&gt;課金具合が予想を超えている&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Cloud SQL&lt;/code&gt;の課金体系がいまいち理解できていない。&lt;/p&gt;
&lt;p&gt;ただコンソールを見る限り、想像を超える課金が行われている。&lt;/p&gt;
&lt;p&gt;使用していない時はインスタンスを停止してその場を凌ぐけど、しっかりと理解をしたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>2024年5月の月報</title><link>https://blog.nove-b.dev/posts/2024-5</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-5</guid><description>2024年5月に考えたこととか</description><content:encoded>&lt;hr /&gt;
&lt;h2&gt;5月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3wvHKI1&quot;&gt;秋期限定栗きんとん事件（下）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4byGwLh&quot;&gt;巴里マカロンの謎 〈小市民〉シリーズ (創元推理文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3QmGQnY&quot;&gt;冬期限定ボンボンショコラ事件 〈小市民〉シリーズ (創元推理文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3Vbt8HB&quot;&gt;でぃすぺる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3wL0vYp&quot;&gt;君は医者になれない　膠原病内科医・漆原光莉と血嫌い医学生 (メディアワークス文庫)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;春夏秋冬、小市民シリーズが遂に完結した。ただ最後、続きに希望が見えた気もするので、期待したい。そういえば、古典部シリーズも完結まで読んでないんだよなあ。昔読んでいたシリーズもので完結まで読み切ってないやつ、それなりにありそうな感じがする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3Vbt8HB&quot;&gt;でぃすぺる&lt;/a&gt;は、まあ、悪くなかった。あり得ない気もするけど、フィクションだしそれくらいいいよね、って感じ。ところどころ、本当に怖くなったりもした。アンリミテッドだし、おすすめ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3wL0vYp&quot;&gt;君は医者になれない&lt;/a&gt;はThe メディアワークスって言った感想。良くも悪くもキャラ文庫。&lt;/p&gt;
&lt;p&gt;さて、今後は月5冊まで本を買っていいことにしよう。それ以上はアンリミテッドにする。さすがにアンリミテッドだけで生きていくには、楽しみがなさすぎる。アンリミテッドなんて2冊読めば元取れるし、月7冊は確実に読むしね。&lt;/p&gt;
&lt;p&gt;絶賛読んでいる本。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4bZTIc0&quot;&gt;Goの基本的な文法を素早く理解したい人向けの本&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最近は時間がなくて本を読む時間もない。別にそれが悪いことではないんだけど、趣味が失われるような恐れはある。&lt;/p&gt;
&lt;p&gt;読書の時間を確保して、数少ない趣味を確保する必要がある。&lt;/p&gt;
&lt;h2&gt;旅行に行った&lt;/h2&gt;
&lt;p&gt;今月はゴールデンウイークを外し、旅行に行った。&lt;/p&gt;
&lt;p&gt;安全を期しディズニー前泊をしたことはあるけど、観光旅行は初。&lt;/p&gt;
&lt;p&gt;車にディスプレイを設置し、双子が絶対にぐずらない環境を作り、熱海に向かった。&lt;/p&gt;
&lt;p&gt;子どもたちには退屈だろうけど、まずは伊豆山神社に行き旅の安全を祈願し、その足で熱海駅に。&lt;/p&gt;
&lt;p&gt;お土産を買いパン屋でお昼ごはん。&lt;/p&gt;
&lt;p&gt;熱海の駅前商店街はいつみてもいい。あの廃れた感じが妙に旅情を誘う。&lt;/p&gt;
&lt;p&gt;次に親水公園で砂遊び。&lt;/p&gt;
&lt;p&gt;水気を含む砂を頭にかけて、頭がざらざらになっていた。&lt;/p&gt;
&lt;p&gt;最後に今宮神社に行き、この神社には梟が住み着いているという謎の情報を得た。&lt;/p&gt;
&lt;p&gt;そして今回のメインとも言えるリゾナーレ熱海に到着。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/01.jpg&quot; alt=&quot;夜景&quot; /&gt;&lt;/p&gt;
&lt;p&gt;星野リゾートは好きじゃないって言ってたけど、子連れにリゾナーレ熱海は最高だった。&lt;/p&gt;
&lt;p&gt;まず周りも子連れなので、負い目を感じる必要がない。お互い様だよね、て勝手に考え少し安心する。&lt;/p&gt;
&lt;p&gt;そして何より、アクティビティが豊富だった。&lt;/p&gt;
&lt;p&gt;プール、砂場、ボールプール、滑り台、そしてツリーハウス。&lt;/p&gt;
&lt;p&gt;退屈することなく、ぐっすり眠りについてくれた。&lt;/p&gt;
&lt;p&gt;ちなみにビュッフェは想像以上に大変だったけど、ふたりが食べれるものがあって良かった。&lt;/p&gt;
&lt;p&gt;子どもたちが寝静まった後、大浴場に。&lt;/p&gt;
&lt;p&gt;半露天で熱海の夜景を見つつ浸かるお湯は、とろけるほどリラックスできた。&lt;/p&gt;
&lt;p&gt;2日目はシャボテン公園でカピバラを見て、帰路に着く。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/02.jpg&quot; alt=&quot;カピバラ&quot; /&gt;&lt;/p&gt;
&lt;p&gt;シャボテン公園はもういいかしら。&lt;/p&gt;
&lt;p&gt;次はもう少し大きくなっているだろうし、グランパル公園に行くかな。&lt;/p&gt;
&lt;p&gt;そんなこんなで楽しい旅行だった。&lt;/p&gt;
&lt;h2&gt;目標完遂が黄色信号&lt;/h2&gt;
&lt;p&gt;てな感じでゴールデンウイークもあり、イベントもありで、目標としている6月リリースの個人開発が黄色信号に。&lt;/p&gt;
&lt;p&gt;なんとかして遅れを取り戻さないといけないんだけど、朝起きれないし、夜は眠い。&lt;/p&gt;
&lt;p&gt;5時に起きて、開発やる。&lt;/p&gt;
&lt;p&gt;って寝る前は思っているのに朝起きれない。&lt;/p&gt;
&lt;p&gt;どうしたものか、どうしたもこうしたもやらなくちゃいけないんだけど。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Expoのバージョンがシミュレーション用のスマホアプリとずれたのでアップグレードする</title><link>https://blog.nove-b.dev/posts/upgrade-expo-sdk</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/upgrade-expo-sdk</guid><description>Expoのバージョンがシミュレーション用のスマホアプリとずれたのでアップグレードする</description><content:encoded>&lt;p&gt;2年前から&lt;code&gt;react nativeで&lt;/code&gt;アプリを作成している。が、いろいろ（他のアプリ作ったり、仕事が忙しくなったり）あり放置気味で、重い腰を上げるかと「完成」を今年の目標に入れた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Go&lt;/code&gt;で&lt;code&gt;Api&lt;/code&gt;作成し、結合しようかと思ったところスマホの&lt;code&gt;Expoアプリ&lt;/code&gt;で開発中のアプリが開けなくなっていた。&lt;/p&gt;
&lt;p&gt;原因は&lt;code&gt;Expo&lt;/code&gt;のバージョンがずれていたこと。&lt;/p&gt;
&lt;p&gt;スマホのアプリのアップデートを自動にしているので、どうやら開発側とずれてしまっていたらしい。&lt;/p&gt;
&lt;p&gt;スマホアプリのバージョンを落としてもいいのだけれど、開発側のアップデートをすることにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.expo.dev/workflow/upgrading-expo-sdk-walkthrough/&quot;&gt;Expo SDK のアップグレード&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;まんま上記の通り実行すれば問題ない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install expo@latest
npx expo install --fix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで無事に開発を続行することができるようになった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Fabric.jsをAngularで最短で動かしてみる</title><link>https://blog.nove-b.dev/posts/fabric-on-angular</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/fabric-on-angular</guid><description>Fabric.jsをAngularで最短で動かしてみる</description><content:encoded>&lt;h2&gt;環境&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Angular: 15
Fabric.js: 5.3.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Fabric.jsとは？&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://fabricjs.com/&quot;&gt;http://fabricjs.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Canvas&lt;/code&gt;内に画像やテキストを配置したりすることのできるライブラリ。&lt;/p&gt;
&lt;p&gt;配置した要素の「移動」、「リサイズ」、「回転」など非常に自由度高く操作することができる。&lt;/p&gt;
&lt;p&gt;お絵描きアプリとかを作ることができる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://fabricjs.com/demos/&quot;&gt;色々なデモ&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;インストール&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ npm i fabric
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;betaでバージョン6が公開されており、5から6で破壊的な変更があるっぽい。&lt;/p&gt;
&lt;p&gt;つまり5を入れておくと、いずれ大規模な修正が必要になる可能性がある。&lt;/p&gt;
&lt;p&gt;けど、解説とかは5の方が多いし、6がまだbetaということで5を入れることにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fabricjs/fabric.js/issues/8299&quot;&gt;🧐 Breaking changes for fabric 6.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;次に定義ファイルも必要になったので&lt;code&gt;&quot;npm i @types/fabric&quot;: &quot;^5.3.7&quot;,&lt;/code&gt;でインストールした。&lt;/p&gt;
&lt;h2&gt;実装&lt;/h2&gt;
&lt;h3&gt;template&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;canvas width=&quot;300&quot; height=&quot;300&quot; #canvasEl&amp;gt; &amp;lt;/canvas&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずテンプレート側で&lt;code&gt;canvas&amp;gt;&lt;/code&gt;を作成する。&lt;/p&gt;
&lt;h3&gt;component&lt;/h3&gt;
&lt;p&gt;次に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; @ViewChild(&apos;canvasEl&apos;) canvasEl: ElementRef | undefined;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コンポーネント側で&lt;code&gt;canvas&lt;/code&gt;を取得し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ngAfterViewInit() {
  if(this.canvasEl) {
    const canvas = new fabric.Canvas(this.canvasEl.nativeElement);
    const rect = new fabric.Rect({
      top: 100,
      left: 100,
      width: 60,
      height: 70,
      fill: &apos;red&apos;,
    });
    canvas.add(rect);
  } else {
    throw new Error(&apos;Canvasの取得に失敗しました。&apos;)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fabric&lt;/code&gt;を呼び出す。&lt;/p&gt;
&lt;p&gt;これで画面表示まで行けた。&lt;/p&gt;
&lt;p&gt;ちなみに画面全体に&lt;code&gt;canvas&lt;/code&gt;を広げたい場合は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;canvas.setDimensions({width:number, height:number});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で実現できる。&lt;/p&gt;
&lt;p&gt;〇 追記&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/interact-on-angular/&quot;&gt;interactjsをAngularで最短で動かしてみる&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dom&lt;/code&gt;を動かしたかったというのがあるので、&lt;code&gt;Fabric.js&lt;/code&gt;ではなく&lt;code&gt;interact&lt;/code&gt;を採用した。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>WordPressから記事をHugoに大体移植した</title><link>https://blog.nove-b.dev/posts/wordress-to-hugo</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/wordress-to-hugo</guid><description>WordPressのアナリティクスを見たところ、PVが思ったよりあるので記事の引っ越しをした</description><content:encoded>&lt;h2&gt;意外と見られていた旧ブログ&lt;/h2&gt;
&lt;p&gt;ブログを&lt;code&gt;Hugo&lt;/code&gt;にリニューアルし、&lt;code&gt;WordPress&lt;/code&gt;の方はずっと放置していた。&lt;/p&gt;
&lt;p&gt;先日ふっと思い立ちこのブログにもアナリティクスを導入した。その時ちらっと見た&lt;code&gt;WordPress&lt;/code&gt;のアナリティクスの数字は自分の想像を遥かに絶するものだった。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/01.jpg&quot; alt=&quot;nove&quot; /&gt;&lt;/p&gt;
&lt;p&gt;さすがにこれはもったいないと、お引越しをすることにした。&lt;/p&gt;
&lt;p&gt;幸い&lt;code&gt;WordPress&lt;/code&gt;ブログなのだが、記事は&lt;code&gt;Git&lt;/code&gt;で管理していた（使わなかった...）。&lt;/p&gt;
&lt;p&gt;これ幸い、引っ越しを始める。&lt;/p&gt;
&lt;h2&gt;記事一覧の取得&lt;/h2&gt;
&lt;p&gt;まずは記事一覧の取得を行っていく。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WordPress&lt;/code&gt;の拡張機能である&lt;a href=&quot;https://ja.wordpress.org/plugins/export-all-urls/&quot;&gt;Export All URLs&lt;/a&gt;を使い、URLを出力した。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Post ID&lt;/th&gt;
&lt;th&gt;Title&lt;/th&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;th&gt;Categories&lt;/th&gt;
&lt;th&gt;Tags&lt;/th&gt;
&lt;th&gt;Published Date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;GithubActionを使用してエックスサーバーにデプロイする&lt;/td&gt;
&lt;td&gt;https://media.nove-web.com/42/&lt;/td&gt;
&lt;td&gt;Github&lt;/td&gt;
&lt;td&gt;Github, Github Action, Wordpress, エックスサーバー, 効率化&lt;/td&gt;
&lt;td&gt;2021/11/28 16:24&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;こんな感じの一覧が出力された。&lt;/p&gt;
&lt;p&gt;次に出力したタイトルをパスパラメータ―に変換していく。&lt;/p&gt;
&lt;p&gt;これが本当にしんどいけど、&lt;code&gt;Chat GPT&lt;/code&gt;が全部やってくれました。&lt;/p&gt;
&lt;h2&gt;記事ファイルをxmlに変換する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;WordPress&lt;/code&gt;の管理画面から&lt;code&gt;xml&lt;/code&gt;形式にエクスポートをする。&lt;/p&gt;
&lt;p&gt;エクスポートしたファイルを&lt;code&gt;xml-to-markdown&lt;/code&gt;というフォルダに格納し、&lt;code&gt;npx wordpress-export-to-markdown&lt;/code&gt;を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Path to WordPress export file? name.WordPress.2024-06-07.xml
? Path to output folder? output
? Create year folders? No
? Create month folders? No
? Create a folder for each post? No
? Prefix post folders/files with date? No
? Save images attached to posts? Yes
? Save images scraped from post body content? Yes
? Include custom post types and pages? No
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じに設定すると今までの記事がマークダウン形式に変換される。&lt;/p&gt;
&lt;p&gt;このパッケージを作ってくれた人には感謝しかない。&lt;/p&gt;
&lt;h2&gt;地道に作業していく。&lt;/h2&gt;
&lt;p&gt;まずはファイル名を先ほど、&lt;code&gt;GPT&lt;/code&gt;が作成してくれたパスパラメータ―に変換していく。&lt;/p&gt;
&lt;p&gt;これは力作業、時間を浪費するだけの作業。&lt;/p&gt;
&lt;p&gt;次にマークダウンの形式を&lt;code&gt;Hugo&lt;/code&gt;に合わせていく（そのままでも平気だった🤔?）&lt;/p&gt;
&lt;p&gt;最後に、最初に作ったエクセルを有効活用し、&lt;code&gt;.htaccess&lt;/code&gt;を作成していく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    # 環境変数の設定
    SetEnvIf Request_URI &quot;.*&quot; Ngx_Cache_NoCacheMode=off
    SetEnvIf Request_URI &quot;.*&quot; Ngx_Cache_AllCacheMode

    # 301リダイレクトの追加
    Redirect 301 /42/ https://blog.nove-b.dev/posts/new-name
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでお引越しが完了した。&lt;/p&gt;
&lt;p&gt;リアルタイムも常時、人がいるようになったので、これで完了した。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React Nativeでセキュアな環境にTokenを保存する</title><link>https://blog.nove-b.dev/posts/react-native-secure-token-storage</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/react-native-secure-token-storage</guid><description>API通信に必要となるJWTTokenをセキュアな環境にTokenを保存する</description><content:encoded>&lt;p&gt;要はブラウザ委のストレージのような機能をアプリでどう再現するかを調べてみた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iOS&lt;/code&gt;では &lt;code&gt;KeyChain&lt;/code&gt;、&lt;code&gt;Android&lt;/code&gt;では
&lt;code&gt;KeyStore&lt;/code&gt;という安全に重要情報を保存できる場所が用意されているらしい。&lt;/p&gt;
&lt;h2&gt;Expo Cliではreact-native-keychainが使えない。&lt;/h2&gt;
&lt;p&gt;で、React
Nativeでは&lt;a href=&quot;https://github.com/oblador/react-native-keychain&quot;&gt;react-native-keychain&lt;/a&gt;というプラグインで実現できるらしいが、&lt;code&gt;Expo Cli&lt;/code&gt;では使えないらしい。これは落とし穴だった。結構な時間を溶かした。&lt;/p&gt;
&lt;h2&gt;expo-secure-storeを使用しよう&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.expo.dev/versions/latest/sdk/securestore/&quot;&gt;公式サイト&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx expo install expo-secure-store
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でインストールする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;app.json&lt;/code&gt;に下記を追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;expo&quot;: {
    &quot;plugins&quot;: [
      [
        &quot;expo-secure-store&quot;,
        {
          &quot;faceIDPermission&quot;: &quot;Allow $(PRODUCT_NAME) to access your Face ID biometric data.&quot;
        }
      ]
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;実装&lt;/h2&gt;
&lt;p&gt;ログインボタンを押したときにアクセストークンを保存する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Button
  title=&quot;Log in&quot;
  onPress={async () =&amp;gt; {
    try {
      // ログイン処理
      // トークンを保存してメイン画面に遷移
      await SecureStore.setItemAsync(&quot;accessToken&quot;, &quot;userToken&quot;);
      navigation.navigate(&quot;Main&quot;);
    } catch (error) {
      console.error(&quot;SecureStore error: &quot;, error);
    }
  }}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;遷移先のページでチェックする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  async function getValueFor(key:string) {
    let result = await SecureStore.getItemAsync(key);
    if (result) {
      console.log(&quot;🔐 Here&apos;s your value 🔐 \n&quot; + result);
    } else {
      console.log(&apos;No values stored under that key.&apos;);
    }
  }
  useEffect(() =&amp;gt; {
    (async() =&amp;gt; {
      await getValueFor(&apos;accessToken&apos;)
    })()
  }, []);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;削除は&lt;code&gt;SecureStore.deleteItemAsync(key, options)&lt;/code&gt;で実装できる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Go &amp; Cloud Run &amp; Cloud SQLでWebAPIを作成したけど、公開する前に諦めた</title><link>https://blog.nove-b.dev/posts/go-cloud-run-cloud-sql-webapi-abandoned</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/go-cloud-run-cloud-sql-webapi-abandoned</guid><description>Cloud Run &amp; Cloud SQLが高すぎる</description><content:encoded>&lt;h2&gt;Cloud RunとCloud SQLの料金が予想を上回った&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Go&lt;/code&gt;の勉強をしたく、&lt;code&gt;WebAPI&lt;/code&gt;を作成することにした。特別難しいこともないただの&lt;code&gt;REST API&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;せっかくなのでアプリを作成しようということで、側は&lt;code&gt;react native&lt;/code&gt;で作成した。&lt;/p&gt;
&lt;p&gt;で、結合しているうちに料金が結構請求されていることに気が付いた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Cloud SQL&lt;/code&gt;が大体20日で4000円くらい。&lt;/p&gt;
&lt;p&gt;しかもここら辺はよくわからないのだが、インスタンスを停止しているにもかかわらず、料金が発生している気がする。&lt;/p&gt;
&lt;p&gt;調査して理解する必要がありそうなので、いつかまとめる。&lt;/p&gt;
&lt;p&gt;今は幸い無料期間でクレジットを消費しているだけだが、無料期間終了後は確実に払うことができない。&lt;/p&gt;
&lt;p&gt;つまり、現実できじゃない。&lt;/p&gt;
&lt;p&gt;ここは仕様検討で気が付くべきだった。&lt;/p&gt;
&lt;h2&gt;ここまでやったこと&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Cloud Run&lt;/code&gt; &amp;amp; &lt;code&gt;Cloud SQL&lt;/code&gt;でどうこうするのはいったん諦める。&lt;/p&gt;
&lt;p&gt;でもいつか使うかもしれなので、やったことをまとめておく。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/api-by-go-on-gcp/&quot;&gt;Cloud RunでGoを動かしたい&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/gorm-connect-cloud-sql/&quot;&gt;GormでCloud SQLに接続する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/connect-client-tool-to-cloud-sql/&quot;&gt;クライアントツールからCloud SQLのDBに接続したい&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これしかなかった。&lt;/p&gt;
&lt;p&gt;基本的にドキュメントが整備されているので、その通り実行すれば結果を得ることができた。&lt;/p&gt;
&lt;p&gt;ただ、料金体系が理解できていなので、そこらへんは整理したい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AWS&lt;/code&gt;も理解できていなので、こちらも理解したい。&lt;/p&gt;
&lt;h2&gt;fly.io&lt;/h2&gt;
&lt;p&gt;個人開発だとよく聞くし、ここを使ってみようと思っている。&lt;/p&gt;
&lt;p&gt;そのためには料金体系とかしっかり調べる必要がありそうだけど。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fly.io/plans&quot;&gt;Plan Pricing· Fly&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;料金表見る限り月額5ドルとのこと。&lt;/p&gt;
&lt;p&gt;無料プランはなくなったぽい、まあこのご時世だしこんなものか。&lt;/p&gt;
&lt;p&gt;本当は&lt;code&gt;Go&lt;/code&gt;での実績を作りたかったけど、&lt;code&gt;firebase&lt;/code&gt;で作成するか。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>クライアントツールからCloud SQLのDBに接続したい</title><link>https://blog.nove-b.dev/posts/connect-client-tool-to-cloud-sql</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/connect-client-tool-to-cloud-sql</guid><description>クライアントツールからCloud SQLのDBに接続したい</description><content:encoded>&lt;p&gt;&lt;code&gt;Cloud SQL&lt;/code&gt;にデータベースを作成したのでクライアントツールで確認したくなった。&lt;/p&gt;
&lt;p&gt;今回は&lt;code&gt;HeidiSQL&lt;/code&gt;で接続していく。&lt;/p&gt;
&lt;h2&gt;Cloud SQL Admin APIを有効にする&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1.2 接続設定を確認し、外部からの接続が許可されていることを確認します。これには、Cloud
SQL Admin
APIを有効にし、インスタンスのファイアウォール設定で必要なIPアドレスからの接続を許可する必要があります&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;参照元が不明だけど、&lt;code&gt;Cloud SQL Admin API&lt;/code&gt;を有効にする必要がある。&lt;/p&gt;
&lt;p&gt;有効にする方法は&lt;a href=&quot;https://cloud.google.com/sql/docs/mysql/admin-api?hl=ja&quot;&gt;Cloud SQL API を使用する&lt;/a&gt;にある通り。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://console.cloud.google.com/apiui/apiview/sqladmin/overview?hl=ja&quot;&gt;Google Cloud Platform Console&lt;/a&gt;
で、プロジェクトを選択します。&lt;/p&gt;
&lt;p&gt;API Manager コンポーネントで、[Google Cloud SQL API] をクリックします。&lt;/p&gt;
&lt;p&gt;Google Cloud SQL API コンポーネントで、[API を有効にする] を選択します。&lt;/p&gt;
&lt;p&gt;Google Cloud SQL API コンポーネントと
&lt;a href=&quot;https://console.cloud.google.com/apiui/apiview/sql_component/overview?hl=ja&quot;&gt;Google Cloud SQL&lt;/a&gt;
コンポーネントは違うことに注意してください。後者のコンポーネントは、Google
Cloud Platform Console と Cloud
SDK でインスタンスを管理するために有効にする必要があります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Cloud SQLインスタンスへの接続を許可する&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Google Cloud Consoleにログイン。&lt;/li&gt;
&lt;li&gt;ナビゲーションメニュー（左上の三本線）をクリックし、「SQL」を選択。&lt;/li&gt;
&lt;li&gt;接続したいCloud SQLインスタンスを選択。&lt;/li&gt;
&lt;li&gt;「接続」タブを選択。&lt;/li&gt;
&lt;li&gt;「公開IP」を設定。この設定がない場合は「公開IPの追加」ボタンをクリック。&lt;/li&gt;
&lt;li&gt;「ネットワーク」のセクションにある「承認済みネットワーク」までスクロール。&lt;/li&gt;
&lt;li&gt;「ネットワークの追加」ボタンをクリック。&lt;/li&gt;
&lt;li&gt;ネットワーク：接続を許可したいIPアドレスまたはIPレンジを入力。例えば、自分のPCのIPアドレスを許可する場合は、「203.0.113.0/32」のように入力（/32は単一のIPアドレスを意味する）。&lt;/li&gt;
&lt;li&gt;説明：任意の説明を入力（例：「自宅PC」）。&lt;/li&gt;
&lt;li&gt;「完了」ボタンをクリック。&lt;/li&gt;
&lt;li&gt;「保存」ボタンをクリックして設定を保存。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;これで、指定したIPアドレスから&lt;code&gt;Cloud SQL&lt;/code&gt;インスタンスへの接続が許可された。&lt;/p&gt;
&lt;p&gt;ちなみにIPアドレスは検索すればすぐにわかる。&lt;/p&gt;
&lt;h2&gt;HeidiSQLに必要情報を記載する&lt;/h2&gt;
&lt;p&gt;下記のように記載すれば接続できた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ネットワークタイプ: MySQL (TCP/IP)
ホスト名/IP: パブリック IP アドレス
ユーザー名: Cloud SQLのユーザー名
パスワード: Cloud SQLのパスワード
ポート: 3306
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>nove-b</author></item><item><title>interactjsをAngularで最短で動かしてみる</title><link>https://blog.nove-b.dev/posts/interact-on-angular</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/interact-on-angular</guid><description>interactjsをAngularで最短で動かしてみる</description><content:encoded>&lt;h2&gt;環境&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Angular: 15
interactjs: 1.10.27
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;interactjsとは？&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/taye/interact.js&quot;&gt;https://github.com/taye/interact.js&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;JavaScriptでドラッグ＆ドロップ、リサイズ、マルチタッチジェスチャー（慣性とスナッピング機能付き）を実装できるライブラリ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/taye&quot;&gt;色々なデモ&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;インストール&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm install interactjs
npm install --save-dev @interactjs/types
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でインストール。&lt;/p&gt;
&lt;h2&gt;実装&lt;/h2&gt;
&lt;h3&gt;template&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;draggable&quot;&amp;gt;Draggable Element&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずテンプレート側で&lt;code&gt;div&lt;/code&gt;を作成する。&lt;/p&gt;
&lt;h3&gt;component&lt;/h3&gt;
&lt;p&gt;次に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; @ViewChild(&apos;canvasEl&apos;) canvasEl: ElementRef | undefined;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コンポーネント側で&lt;code&gt;canvas&lt;/code&gt;を取得し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ngAfterViewInit() {
    const position = { x: 0, y: 0 }
    interact(&apos;.draggable&apos;).draggable({
      listeners: {
        start (event) {
          console.log(event.type, event.target)
        },
        move (event) {
          position.x += event.dx
          position.y += event.dy

          event.target.style.transform =
            `translate(${position.x}px, ${position.y}px)`
        },
      }
    })
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;interact&lt;/code&gt;を呼び出す。&lt;/p&gt;
&lt;p&gt;これで画面表示まで行けた。&lt;/p&gt;
&lt;p&gt;後は自由にカスタマイズしていける。&lt;/p&gt;
&lt;h2&gt;カスタマイズ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;要素を自由にカスタマイズしたかったので、&lt;code&gt;translate&lt;/code&gt;ではなく&lt;code&gt;absolute&lt;/code&gt;にした&lt;/li&gt;
&lt;li&gt;複数要素に対応&lt;/li&gt;
&lt;li&gt;ドラッグやリサイズはハンドルを使用する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とかいろいろ、やりたいことは結構実現できるカスタマイズ性の高いライブラリーだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/fabric-on-angular/&quot;&gt;Fabric.jsをAngularで最短で動かしてみる&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dom&lt;/code&gt;を動かしたかったというのがあるので、&lt;code&gt;Fabric.js&lt;/code&gt;ではなく&lt;code&gt;interact&lt;/code&gt;を採用した。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Cloudflare Registrarでドメインを登録し、Netlifyのサーバーにサブドメインを当てる</title><link>https://blog.nove-b.dev/posts/cloudflare-registrar-netlify-subdomain</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/cloudflare-registrar-netlify-subdomain</guid><content:encoded>&lt;h2&gt;最適なドメイン管理プラットフォームを探して&lt;/h2&gt;
&lt;p&gt;今までいくつかのドメイン管理プラットフォームを利用してきた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;エックスドメイン&lt;/li&gt;
&lt;li&gt;お名前ドットコム&lt;/li&gt;
&lt;li&gt;Google domains&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;エックスドメインは特に不満がない。&lt;/p&gt;
&lt;p&gt;Google domainsはよかったけど、サービス終了したので今後は使えない。&lt;/p&gt;
&lt;p&gt;で、問題はお名前ドットコム。&lt;/p&gt;
&lt;p&gt;ここ１年、メインのドメインを取得したんだけど、毎日のように膨大なメールが送られてくる。&lt;/p&gt;
&lt;p&gt;設定でオフにできるかもだけれど、そもそもこんなにメールを送ってくるのはどうなのだろうかということで乗り換えることにした。&lt;/p&gt;
&lt;p&gt;せっかくだし自身のドメインを新しくしようと思う。&lt;/p&gt;
&lt;p&gt;今まで&lt;code&gt;nove-web.com&lt;/code&gt;というドメインだったけど、&lt;code&gt;nove-b&lt;/code&gt;というドメインにしたい。&lt;/p&gt;
&lt;p&gt;そしてトップドメインは開発者らしく&lt;code&gt;dev&lt;/code&gt;にしたいということで、まずはなんら不満がないエックスドメインで探したが、どうやら&lt;code&gt;devドメイン&lt;/code&gt;を扱っていないということ。&lt;/p&gt;
&lt;h2&gt;Cloudflare Registrarでドメインを登録する&lt;/h2&gt;
&lt;p&gt;じゃあ、どこで購入しようと調べてみると&lt;code&gt;Cloudflare Registrar&lt;/code&gt;の評判が良さげだった。&lt;/p&gt;
&lt;p&gt;料金も、同様に&lt;code&gt;devドメイン&lt;/code&gt;を扱っているお名前ドットコムと比べると&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;登録&lt;/th&gt;
&lt;th&gt;更新&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;お名前ドットコム&lt;/td&gt;
&lt;td&gt;2,178円&lt;/td&gt;
&lt;td&gt;2,178円&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare Registrar&lt;/td&gt;
&lt;td&gt;$10.18（1,603.63 円）&lt;/td&gt;
&lt;td&gt;$10.18（1,603.63 円）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;Cloudflare Registrar&lt;/code&gt;の安い。&lt;/p&gt;
&lt;p&gt;どうやら卸売価格で提供されているのが強みらしい。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;登録料と更新料は卸売価格で提供ドメイン名の登録市場は、初回のドメイン名購入時には大幅割引価格を提供するものの、じょじょに追加料金を加算し、更新料も膨れ上がるような企業で占められています。&lt;/p&gt;
&lt;p&gt;Cloudflare
Registrarの場合、お客様に請求するのは弊社が支払うドメイン登録料のみで、その他の料金はかかりません。 値上げや想定外の料金は生じません。 Cloudflareのニ要素認証、マルチユーザーサポート、セキュリティ重視のカスタマーサポートチームといったセキュリティ機能でドメインの安全を確保し、安心してお使いいただけます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ありがたい。&lt;/p&gt;
&lt;p&gt;そういうわけで登録していくけど、特に難しいことはなかったので省略する。&lt;/p&gt;
&lt;h2&gt;Netlifyにで動くブログにサブドメインを当てる&lt;/h2&gt;
&lt;h3&gt;Cloudflare Registrarでの作業&lt;/h3&gt;
&lt;p&gt;次に&lt;code&gt;Netlify&lt;/code&gt;にアップしているこのブログにサブドメインを当てていく。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DNS&lt;/code&gt; &amp;gt; &lt;code&gt;Records&lt;/code&gt; &amp;gt; &lt;code&gt;DNS management for nove-b.dev&lt;/code&gt; &amp;gt; &lt;code&gt;Add Record&lt;/code&gt;
の順にページを移動し、&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;タイプ&lt;/th&gt;
&lt;th&gt;名前&lt;/th&gt;
&lt;th&gt;コンテンツ&lt;/th&gt;
&lt;th&gt;プロキシ ステータス&lt;/th&gt;
&lt;th&gt;TTL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;blog&lt;/td&gt;
&lt;td&gt;nove-b.netlify.app&lt;/td&gt;
&lt;td&gt;DNS のみ&lt;/td&gt;
&lt;td&gt;自動&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;のように登録した。&lt;/p&gt;
&lt;p&gt;これで、&lt;code&gt;blog.for nove-b.devをnove-b.netlify.app&lt;/code&gt;と紐づけ完了した。&lt;/p&gt;
&lt;p&gt;プロキシステータスをDNS のみ にすることで&lt;code&gt;Netlify&lt;/code&gt;のSSL証明書が正常に機能するようになるらしい。&lt;/p&gt;
&lt;h2&gt;Netlifyでの作業&lt;/h2&gt;
&lt;p&gt;次に&lt;code&gt;Netlify&lt;/code&gt;の管理画面にいき、&lt;code&gt;Domain management&lt;/code&gt; &amp;gt;
&lt;code&gt;Add a domain&lt;/code&gt;ボタンをクリックする。&lt;/p&gt;
&lt;p&gt;で、先ほど作成したドメインを追加する。&lt;/p&gt;
&lt;p&gt;最後に&lt;code&gt;Verify DNS configuration&lt;/code&gt;をクリックすることで、SSL証明書が有効になり、無事にブログが表示されるようになった。&lt;/p&gt;
&lt;h2&gt;そもそもDNSとは？&lt;/h2&gt;
&lt;p&gt;いまさらながら、&lt;code&gt;DNS&lt;/code&gt;について調べてみた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Domain Name System&lt;/code&gt;の略で、インターネット上でドメイン名とIPアドレスを結びつけるためのシステム。&lt;/p&gt;
&lt;p&gt;上でも設定したタイプはそのレコードがどのような情報を表しているかを示しているらしい。&lt;/p&gt;
&lt;p&gt;下記は代表的なもの一覧。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A (Address) レコード: ドメイン名に関連付けられたIPアドレスを示す。&lt;/li&gt;
&lt;li&gt;CNAME (Canonical Name) レコード: 他のドメイン名の別名を指定する。&lt;/li&gt;
&lt;li&gt;MX (Mail
Exchange) レコード: メールサーバーのホスト名を指定し、そのドメインがメールを受け取る際のルーティングを定義する。&lt;/li&gt;
&lt;li&gt;NS (Name
Server) レコード: ドメインのネームサーバーを指定し、ドメインに関連するDNS情報を提供するサーバーを指示する。&lt;/li&gt;
&lt;li&gt;TXT
(Text) レコード: 任意のテキストデータを格納し、主にドメイン認証やSPFレコードなどの用途に使用される。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;今回はすでに&lt;code&gt;Netlify&lt;/code&gt;が指定したドメインの別名を指定するという意味で&lt;code&gt;CNAME&lt;/code&gt;を使ったっぽい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Domain Name System&lt;/code&gt;という略と知り、急に親近感がわいてきた。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;それにしてもやっぱり独自ドメインはいい。&lt;/p&gt;
&lt;p&gt;やっと自分のブログになった気がする。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>HugoのPaperModにGA4を導入する</title><link>https://blog.nove-b.dev/posts/introduce-ga4-papermod-hugo</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/introduce-ga4-papermod-hugo</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/wordress-to-hugo/&quot;&gt;WordPressから記事をHugoに大体移植した&lt;/a&gt;で書いた通り、旧ブロブのアナリティクスをみると想像以上にアクセスがきていたので、このブログにリダイレクトするようにした。&lt;/p&gt;
&lt;p&gt;そのうえで、このブログでもPVを確認できるよう、GA4を導入した。&lt;/p&gt;
&lt;p&gt;まずは&lt;code&gt;hugo.yaml&lt;/code&gt;に下記を追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  googleAnalytics:
    id: G-**********
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に&lt;code&gt;/layouts/_internal/google_analytics.html&lt;/code&gt;を作成してテンプレートを追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{{- with site.Config.Services.GoogleAnalytics.ID }} {{- if hugo.IsProduction }}
{{- $ga4 := resources.GetRemote
&quot;https://cdn.jsdelivr.net/npm/@minimal-analytics/ga4/dist/index.js&quot; }} {{-
$track := resources.Get &quot;js/track.js&quot; }} {{- $opts := dict &quot;params&quot; (dict
&quot;trackingId&quot; . ) }} {{- $track = $track | js.Build $opts -}} {{- $stats := slice
$track $ga4 | resources.Concat &quot;js/analytics.js&quot; | minify | fingerprint }}
&amp;lt;script
  src=&quot;{{ $stats.RelPermalink }}&quot;
  integrity=&quot;{{ $stats.Data.Integrity }}&quot;
&amp;gt;&amp;lt;/script&amp;gt;
{{- end }} {{- end -}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最後に&lt;code&gt;assets/js/track.js&lt;/code&gt;を作成し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import params from &quot;@params&quot;;

window.minimalAnalytics = {
  trackingId: params.trackingId,
  autoTrack: true, // &amp;lt;-- init tracking
  defineGlobal: true,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という風に記述する。&lt;/p&gt;
&lt;p&gt;たったこれだけでトラッキングできるようになる。&lt;/p&gt;
&lt;p&gt;あとはGA4にリアルタイムで無事に集計できているか確認出来れば問題ない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavaScriptのnew Set() って何?? Arrayと何が異なるのか</title><link>https://blog.nove-b.dev/posts/javascript-new-set-vs-array</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/javascript-new-set-vs-array</guid><description>ChatGPTでコード生成したところ、new Set() というオブジェクトが出てきたので調べてみた</description><content:encoded>&lt;h2&gt;new Set()ってなに？&lt;/h2&gt;
&lt;p&gt;先日&lt;code&gt;ChatGPT&lt;/code&gt;でコード生成したところ、&lt;code&gt;new Set()&lt;/code&gt;というオブジェクトが登場した。&lt;/p&gt;
&lt;p&gt;そういえば使ったことあると思い調べてみると、&lt;a href=&quot;https://blog.nove-b.dev/posts/remove-duplicates-javascript-array/&quot;&gt;JavaScriptの配列で重複したものを削除し、ユニークな配列を作成する&lt;/a&gt;で使っていた。どうやら配列を削除するのに使っていたよう。&lt;/p&gt;
&lt;p&gt;実際に調べてみると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Set オブジェクトは値のコレクションです。 Set に重複する値は格納出来ません。Set 内の値はコレクション内で一意になります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;簡単に言うと「要素の重複を許可しない配列のこと」だと思う。&lt;/p&gt;
&lt;p&gt;じゃあ、配列と何が違うのか。&lt;/p&gt;
&lt;h2&gt;配列と何が違うのか&lt;/h2&gt;
&lt;p&gt;配列との違いは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重複を許さない&lt;/li&gt;
&lt;li&gt;インデックスでアクセスできない&lt;/li&gt;
&lt;li&gt;あとは追加とか削除とかのメソッドが異なる&lt;/li&gt;
&lt;li&gt;高次関数（map, filter, reduce）を使用できない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という点。&lt;/p&gt;
&lt;h3&gt;重複を許さない&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const setValue = new Set([1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]);
console.log(setValue);
// [LOG]: Set (6) {1, 2, 3, 4, 5, 6}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このように重複した値はなかったことになる。&lt;/p&gt;
&lt;h3&gt;インデックスでアクセスできない&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const setValue = new Set([1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]);
console.log(setValue[0]);
// Element implicitly has an &apos;any&apos; type because expression of type &apos;0&apos; can&apos;t be used to index type &apos;Set&amp;lt;number&amp;gt;&apos;.
// Property &apos;0&apos; does not exist on type &apos;Set&amp;lt;number&amp;gt;&apos;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じでエラーがでる。&lt;/p&gt;
&lt;h3&gt;追加とか削除とかのメソッドが異なる&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const setValue = new Set([1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]);

// 追加
setValue.add(7);

// 削除
setValue.delete(1);

console.log(setValue);
// [LOG]: Set (6) {2, 3, 4, 5, 6, 7}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じ。&lt;/p&gt;
&lt;h3&gt;高次関数（map, filter, reduce）を使用できない&lt;/h3&gt;
&lt;p&gt;これはそのままの意味なので使えないというだけ。&lt;/p&gt;
&lt;h2&gt;メリットは？&lt;/h2&gt;
&lt;p&gt;聞く限り重複を削除するときにしか使い道が見つからない。&lt;/p&gt;
&lt;p&gt;そこでメリットを調べてみた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;要素が含まれているかどうかを効率的に確認できるメソッド &lt;code&gt;has&lt;/code&gt;
があり、これは配列の &lt;code&gt;includes&lt;/code&gt; メソッドよりも高速に動作する&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とかなんとか要は配列よりも効率的であることが多いらしい。&lt;/p&gt;
&lt;p&gt;つまりパフォーマンスを上げる時は&lt;code&gt;Set&lt;/code&gt;を使うべきっぽい。&lt;/p&gt;
&lt;p&gt;ChatGPT曰く、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Set は、挿入や削除、存在確認の操作が平均的に O(1) の時間複雑度で行えます。これに対し、配列の操作は要素数に依存するため、最悪の場合 O(n) の複雑度となります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;...うーん、難しい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;includes&lt;/code&gt;と&lt;code&gt;has&lt;/code&gt;で考えると、&lt;code&gt;includes&lt;/code&gt;は配列内の全要素を順にチェックして指定した値を探すのに対し、&lt;code&gt;has&lt;/code&gt;はキーと値のペアを効率的に格納および検索するためのデータ構造であるはハッシュテーブルのように動作するため、要素の存在確認が早いとのこと。&lt;/p&gt;
&lt;p&gt;なるほど。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>nextjsで開発中にモックサーバーを立ち上げたいのでnext-swagger-docと@stoplight/prism-cliを比較してみた</title><link>https://blog.nove-b.dev/posts/nextjs-mock-server-next-swagger-doc-vs-prism-cli</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/nextjs-mock-server-next-swagger-doc-vs-prism-cli</guid><description>開発中にモックサーバーを立ち上げたかったので方法を調べてみた。</description><content:encoded>&lt;p&gt;フロントエンドを開発するときにバックエンドサーバ―の用意ができていない時がよくある。&lt;/p&gt;
&lt;p&gt;今までは側だけ作って待機していたが、せっかくなのでモックサーバーを立ち上げ、バックエンドができ次第、URLの向きを変え、完成！ という風に出来ればと思いモックサーバーの立ち上げを調べてみた。&lt;/p&gt;
&lt;h2&gt;json-server&lt;/h2&gt;
&lt;p&gt;まずは&lt;a href=&quot;https://www.npmjs.com/package/json-server&quot;&gt;json-server&lt;/a&gt;を使おうと思ったけど、同じエンドポイントで&lt;code&gt;Get&lt;/code&gt;、&lt;code&gt;Post&lt;/code&gt;が分けられなさそうということで不採用にした。けど、よくよく落ち着いて調べてみるとできるかもしれない。&lt;/p&gt;
&lt;p&gt;いつか機をみて使ってみたい。&lt;/p&gt;
&lt;p&gt;が、今回は上記の通り不採用した。&lt;/p&gt;
&lt;h2&gt;app/api&lt;/h2&gt;
&lt;p&gt;次に、そもそも&lt;code&gt;nextjs&lt;/code&gt;には&lt;code&gt;API&lt;/code&gt;を作る機能があるじゃないかと思いだし、それを活用することにした。&lt;/p&gt;
&lt;p&gt;ついでにAPI仕様書も作れればなおいいということで調べてみると、&lt;a href=&quot;https://www.npmjs.com/package/next-swagger-doc&quot;&gt;next-swagger-doc&lt;/a&gt;というものがあった。&lt;/p&gt;
&lt;p&gt;これでAPIを作成し、しかも&lt;code&gt;Swagger&lt;/code&gt;を作成できると舞い上がり実装してみた。&lt;/p&gt;
&lt;h3&gt;実装&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;npm i next-swagger-doc
npm i  swagger-ui-react
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずはインストールする。&lt;/p&gt;
&lt;p&gt;ちなみにバージョンは下記の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;next&quot;: &quot;14.2.3&quot;,
&quot;next-swagger-doc&quot;: &quot;^0.4.0&quot;,
&quot;react&quot;: &quot;^18&quot;,
&quot;swagger-ui-react&quot;: &quot;^5.17.14&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;lib/swagger.ts&lt;/code&gt;に下記をコピペする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { createSwaggerSpec } from &quot;next-swagger-doc&quot;;

export const getApiDocs = async () =&amp;gt; {
  const spec = createSwaggerSpec({
    apiFolder: &quot;app/api&quot;, // define api folder under app folder
    definition: {
      openapi: &quot;3.0.0&quot;,
      info: {
        title: &quot;Next Swagger API Example&quot;,
        version: &quot;1.0&quot;,
      },
      components: {
        securitySchemes: {
          BearerAuth: {
            type: &quot;http&quot;,
            scheme: &quot;bearer&quot;,
            bearerFormat: &quot;JWT&quot;,
          },
        },
      },
      security: [],
    },
  });
  return spec;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;※以降先頭行がファイル名になっている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app/api-doc/react-swagger.tsx

&apos;use client&apos;;

import SwaggerUI from &apos;swagger-ui-react&apos;;
import &apos;swagger-ui-react/swagger-ui.css&apos;;

type Props = {
  spec: Record&amp;lt;string, any&amp;gt;,
};

function ReactSwagger({ spec }: Props) {
  return &amp;lt;SwaggerUI spec={spec} /&amp;gt;;
}

export default ReactSwagger;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;app / api - doc / page.tsx;

import { getApiDocs } from &quot;@/lib/swagger&quot;;
import ReactSwagger from &quot;./react-swagger&quot;;

export default async function IndexPage() {
  const spec = await getApiDocs();
  return (
    &amp;lt;section className=&quot;container&quot;&amp;gt;
      &amp;lt;ReactSwagger spec={spec} /&amp;gt;
    &amp;lt;/section&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;app/api/hello/route.ts

/**
 * @swagger
 * /api/hello:
 *   get:
 *     description: Returns the hello world
 *     responses:
 *       200:
 *         description: Hello World!
 */
export async function GET(_request: Request) {
  // Do whatever you want
  return new Response(&apos;Hello World!&apos;, {
    status: 200,
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで完成したけど、これもじっと考えてみると、普通にAPI作っているのと何ら変わらないのではないか。&lt;/p&gt;
&lt;p&gt;ということに気が付いた。&lt;/p&gt;
&lt;p&gt;この労力を使うのではバックエンドサーバー作ったほうがよっぽど早い気がする。&lt;/p&gt;
&lt;p&gt;ということで不採用にした。&lt;/p&gt;
&lt;h2&gt;@stoplight/prism-cliを使うことにした。&lt;/h2&gt;
&lt;p&gt;結果的に、&lt;code&gt;@stoplight/prism-cli&lt;/code&gt;を使うことにした。&lt;/p&gt;
&lt;p&gt;これは作成された&lt;code&gt;Swagger&lt;/code&gt;からモックサーバーを立ち上げてくれるというもの。&lt;/p&gt;
&lt;p&gt;どうせAPI仕様書を作ってからバックエンドサーバーを作るので、それを&lt;code&gt;Swagger&lt;/code&gt;で作るという風にすればいい。&lt;/p&gt;
&lt;p&gt;そうすればバックエンドを作る前にその仕様書からモックサーバーを立ち上げることができるので、業務ストップがなくなる。&lt;/p&gt;
&lt;p&gt;使い方は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install @stoplight/prism-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でインストールし、&lt;code&gt;package.json&lt;/code&gt;に起動の記述を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;swaggerMock&quot;: &quot;prism mock sample.yml&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで、ルートに&lt;code&gt;sample.yml&lt;/code&gt;を作成するれば、それがモックサーバーとして起動される。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Hugo(Pagermod)で記事にGitのコミット履歴から最終更新日を付与する</title><link>https://blog.nove-b.dev/posts/git-last-updated-date-from-commit-history-with-hugo-pagermod</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/git-last-updated-date-from-commit-history-with-hugo-pagermod</guid><description>Hugo(Pagermod)で記事にGitのコミット履歴から最終更新日を付与する</description><content:encoded>&lt;h2&gt;レベルが低かろうと技術ブログという矜持を持つ&lt;/h2&gt;
&lt;p&gt;最終更新日を付与したい。&lt;/p&gt;
&lt;p&gt;というのも技術ブログにおいて更新日はとても大きな意味を持つ。&lt;/p&gt;
&lt;p&gt;ちゃんと更新されている記事であれば、たとえ公開日が古かろうと問題ない。&lt;/p&gt;
&lt;p&gt;ということで、このブログにも更新日を付与することにした。&lt;/p&gt;
&lt;h2&gt;HogoのテーマであるPagermodのカスタマイズ&lt;/h2&gt;
&lt;p&gt;当然、サブモジュールとしてインストールしたファイルをカスタマイズすると、本家の更新時に上書きされる。&lt;/p&gt;
&lt;p&gt;これはみんな大好き&lt;code&gt;wordpress&lt;/code&gt;と同様。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wordpress&lt;/code&gt;で子テーマを作るのと同様に、&lt;code&gt;Hugo&lt;/code&gt;では&lt;code&gt;サイト名\layouts\partials\&lt;/code&gt;というフォルダを用意して、そこにカスタマイズしたいファイルを持ってくる。&lt;/p&gt;
&lt;h2&gt;更新日を付与する&lt;/h2&gt;
&lt;p&gt;今回であれば、&lt;code&gt;post_meta.html&lt;/code&gt;に投稿日の記述等があったので、このファイルをカスタマイズする。&lt;/p&gt;
&lt;p&gt;そのため&lt;code&gt;\layouts\partials\post_meta.html&lt;/code&gt;を作成し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{{- if not .Date.IsZero -}} {{- $scratch.Add &quot;meta&quot; (slice (printf &quot;&amp;lt;span
  title=&quot;%s&quot;
  &amp;gt;%s&amp;lt;/span
&amp;gt;&quot; (.Date) (.Date | time.Format (default &quot;January 2, 2006&quot;
site.Params.DateFormat)))) }} {{- end }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という元記述を&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{{- if not .Date.IsZero -}}
{{- $scratch.Add &quot;meta&quot; (slice &quot;投稿日&quot; (.Date.Format (default &quot;2006-01-02&quot; .Site.Params.DateFormat)) &quot;更新日&quot; (.Lastmod.Format (default &quot;2006-01-02&quot;))) }}
{{- end }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;に変更した。ついでに日本語にした。&lt;/p&gt;
&lt;p&gt;最後に&lt;code&gt;hugo.yaml&lt;/code&gt;に&lt;code&gt;enableGitInfo: true&lt;/code&gt;を付与する。&lt;/p&gt;
&lt;p&gt;この設定は&lt;code&gt;build&lt;/code&gt;時に読み込まれるので、ローカルで開発している場合は一度サーバーを止め、再度&lt;code&gt;build&lt;/code&gt;しなおせば更新日が付与されていることが確認できる。&lt;/p&gt;
&lt;p&gt;実際に付与されている例 ↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/nextjs-mock-server-next-swagger-doc-vs-prism-cli/&quot;&gt;nextjsで開発中にモックサーバーを立ち上げたいのでnext-swagger-docと@stoplight/prism-cliを比較してみた&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>ネイティブアプリ作成を諦め、まずはウェブ版をリリースに注力することにした</title><link>https://blog.nove-b.dev/posts/web-release-focus-instead-of-native-app</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/web-release-focus-instead-of-native-app</guid><description>ネイティブアプリ作成を諦めた</description><content:encoded>&lt;h2&gt;ネイティブアプリを諦めた&lt;/h2&gt;
&lt;p&gt;さかのぼることはるか昔、まだ子どもが妻のおなかにいる頃。&lt;/p&gt;
&lt;p&gt;要は1年9か月前にネイティブアプリの作成を思いついた。&lt;/p&gt;
&lt;p&gt;それから幾星霜、まだネイティブアプリは完成していないし、モチベーションはすっかり下火になっている。&lt;/p&gt;
&lt;h2&gt;技術スタックを欲張った&lt;/h2&gt;
&lt;p&gt;理由はバックエンドにある。&lt;/p&gt;
&lt;p&gt;というより、技術スタックを欲張ったことにある。&lt;/p&gt;
&lt;p&gt;というのも今までは慣れた言語に1つ新しい言語を取り入れることで個人開発をしてきた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Nuxt&lt;/code&gt; + &lt;code&gt;firestore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Next&lt;/code&gt; + &lt;code&gt;firestore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Next&lt;/code&gt; + &lt;code&gt;Nest&lt;/code&gt; + &lt;code&gt;aws&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;といった具合に行ってきたのだが、今回は「&lt;code&gt;React Native&lt;/code&gt; + &lt;code&gt;Go&lt;/code&gt; +
&lt;code&gt;GCP&lt;/code&gt;」というすべて初めての言語で臨むことにした。&lt;/p&gt;
&lt;p&gt;わからないストレスをずっと感じつつプログラミングを進めていった結果、すべてそれなりの形にすることに成功した。&lt;/p&gt;
&lt;h2&gt;GCPにかかる料金で心が折れた&lt;/h2&gt;
&lt;p&gt;じゃあ、結合しようという時点で、&lt;code&gt;GCP&lt;/code&gt;にかかる料金を知り仰天し、心が折れた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/go-cloud-run-cloud-sql-webapi-abandoned/&quot;&gt;Go &amp;amp; Cloud Run &amp;amp; Cloud SQLでWebAPIを作成したけど、公開する前に諦めた&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GCP&lt;/code&gt;は無理だと知った時、もうモチベーションを保つことができなくなった。&lt;/p&gt;
&lt;h2&gt;すらすら書けないストレス&lt;/h2&gt;
&lt;p&gt;コードを書く時に、すらすら書ける言語と調べつつ書く言語だと心理的ストレスが全然違う。&lt;/p&gt;
&lt;p&gt;今は全ての言語が初めてで調べつつ書いているので、辛い。&lt;/p&gt;
&lt;p&gt;すらすらコードを書きとりあえず、モチベーションを上げ、最終的にネイティブアプリを完成させたい。&lt;/p&gt;
&lt;h2&gt;ただでは起きない&lt;/h2&gt;
&lt;p&gt;という理由があり、すらすら書けるWeb版の作成に着手しようと思い立った。&lt;/p&gt;
&lt;p&gt;ただそれだけだとつまらないので、今回はテストコードも書いてみうと思う。&lt;/p&gt;
&lt;p&gt;テストコードの勉強をしたいと思っていたのでちょうどいい。&lt;/p&gt;
&lt;p&gt;そして、最終的にネィティブアプリを作成するので、その時の労力を減らすためにここでAPIを作成しちゃおうと思う。&lt;/p&gt;
&lt;p&gt;決してただでは起きないように頑張る。&lt;/p&gt;
&lt;h2&gt;やること&lt;/h2&gt;
&lt;p&gt;じゃあ何をするのか。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Next&lt;/code&gt;でフロントエンドを実装する&lt;/li&gt;
&lt;li&gt;バックエンドは&lt;a href=&quot;https://supabase.com/&quot;&gt;Supabase&lt;/a&gt;を使ってみる。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app/api&lt;/code&gt;で&lt;a href=&quot;https://supabase.com/&quot;&gt;Supabase&lt;/a&gt;を&lt;code&gt;API&lt;/code&gt;にラップする&lt;/li&gt;
&lt;li&gt;テストコードをしっかり実装してみる&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;という風にしようと思う。&lt;/p&gt;
&lt;p&gt;それで&lt;code&gt;PWA&lt;/code&gt;にしようかなあ。&lt;/p&gt;
&lt;p&gt;その後ネイティブアプリ化するっていう目標。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Windows間のアプリ移行が簡単だった</title><link>https://blog.nove-b.dev/posts/windows-app-migration-is-easy</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/windows-app-migration-is-easy</guid><description>Windows間のアプリ移行が簡単だった</description><content:encoded>&lt;p&gt;会社のPCを新しくしてもらった。&lt;/p&gt;
&lt;p&gt;本当はSurfaceが良かったのだが、贅沢は言えない。&lt;/p&gt;
&lt;p&gt;それにSurfaceだけど、チップがArmベースに移行したということで、ちょっと口コミが良くない。&lt;/p&gt;
&lt;p&gt;個人で買うつもりだったけど、すこし迷いが生じている。&lt;/p&gt;
&lt;p&gt;ともかく会社のPCが新しくなった。&lt;/p&gt;
&lt;p&gt;で、そうすると移行作業が生じるのだが、非常に楽になっていた。&lt;/p&gt;
&lt;p&gt;今回、とにかく移行したいのはWindowsにインストールしたアプリとvscodeの拡張機能の2つ。&lt;/p&gt;
&lt;h2&gt;Windowsにインストールしたアプリを以降&lt;/h2&gt;
&lt;p&gt;wingetを使用したら、何とも簡単に移行できた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/winget-install-elk/&quot;&gt;WingetでWindowsにアプリをインストールする&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これの&lt;a href=&quot;https://blog.nove-b.dev/posts/winget-install-elk/#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%83%85%E5%A0%B1%E3%82%92%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B&quot;&gt;インストール情報をエクスポートする&lt;/a&gt;を実行すれば何の問題もなく移行できる。&lt;/p&gt;
&lt;h2&gt;vscodeの移行&lt;/h2&gt;
&lt;p&gt;こちらはプロファイルを使用する。&lt;/p&gt;
&lt;p&gt;vscode右下の歯車アイコンをクリックし、プロファイル（規定）をクリック、最後にプロファイルをエクスポートを選択し、エクスポートする。&lt;/p&gt;
&lt;p&gt;次にそれをインポートすれば、移行が完了する。&lt;/p&gt;
&lt;p&gt;新しいPCを迎え入れるストレスが減った。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>tailwindで定義した色をimportして使用する</title><link>https://blog.nove-b.dev/posts/tailwind-import-custom-colors</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/tailwind-import-custom-colors</guid><description>tailwindで定義した色をimportして使用する</description><content:encoded>&lt;p&gt;&lt;code&gt;tailwind&lt;/code&gt;の&lt;code&gt;config&lt;/code&gt;で定義した&lt;code&gt;primary&lt;/code&gt;の色とかを&lt;code&gt;tailwind&lt;/code&gt;のクラス以外で使用したい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import type { Config } from &quot;tailwindcss&quot;;

export const customColors = {
primary: &quot;#2563eb&quot;,
secondary: &quot;#4b5563&quot;,
danger: &quot;#cd2626&quot;,
success: &quot;#16a34a&quot;,
warning: &quot;#f59e0b&quot;,
};

const config: Config = {
theme: {
  extend: {
    colors: customColors,
  },
},
plugins: [],
};
export default config;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;みたいにすればいい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2024年6月】読書できず、目標も完遂できず、ウィルス性腸炎が猛威を振るう</title><link>https://blog.nove-b.dev/posts/2024-6</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-6</guid><description>2024年5月に考えたこととか</description><content:encoded>&lt;hr /&gt;
&lt;h2&gt;6月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4aOtQPy&quot;&gt;時をかけるゆとり (文春文庫)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;朝井リョウの&lt;a href=&quot;https://amzn.to/4aW2jvj&quot;&gt;正欲&lt;/a&gt;がすごいらしいと聞き、タイミングよくアンリミテッドになっていたので、&lt;a href=&quot;https://amzn.to/4aOtQPy&quot;&gt;時をかけるゆとり (文春文庫)&lt;/a&gt;を再読した。うーん、朝井リョウの小説は好きだけど、随筆は微妙かもしれない。文章もそれっぽく書いているけど、書ききれていないというかなんというか。空回りしているというかなんというか。エピソードは面白いんだけど。&lt;/p&gt;
&lt;p&gt;今月はこれ1冊のみだった。&lt;/p&gt;
&lt;p&gt;なんかダイヤのAをずっと読んでた気がする。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;ブログの改造&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/wordress-to-hugo/&quot;&gt;WordPressから記事をHugoに大体移植した&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/introduce-ga4-papermod-hugo/&quot;&gt;HugoのPaperModにGA4を導入する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/git-last-updated-date-from-commit-history-with-hugo-pagermod/&quot;&gt;Hugo(Pagermod)で記事にGitのコミット履歴から最終更新日を付与する&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;だいたいこれで落ち着いたかしら。&lt;/p&gt;
&lt;p&gt;後はしっかりアウトプットしていく。&lt;/p&gt;
&lt;h2&gt;今年の目標が今年の進行速度に敗れる&lt;/h2&gt;
&lt;p&gt;6月目標のネイティブアプリ作成。&lt;code&gt;Cloud SQL&lt;/code&gt;への接続まで完了はしたのでバックエンドの環境は整ったんだけど、テストしているとどんどんどんどん、課金されていく。多分これは本番運用に耐えられない。ということでマネードクターストップがかかった。&lt;code&gt;Go&lt;/code&gt;で&lt;code&gt;API&lt;/code&gt;作るっていう目的は達したので、まあ、良くやったといっていい気がする。&lt;/p&gt;
&lt;p&gt;ただリリースしない個人開発は何も成し遂げていないので、まずは最短でリリースを目指すために、&lt;code&gt;next&lt;/code&gt;と&lt;code&gt;supabase&lt;/code&gt;に構成を変更する。&lt;/p&gt;
&lt;p&gt;そのうえで、ネイティブアプリを作ることする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/web-release-focus-instead-of-native-app/&quot;&gt;ネイティブアプリ作成を諦め、まずはウェブ版をリリースに注力することにした&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;10月まで仕事が繁忙期を迎える&lt;/h2&gt;
&lt;p&gt;7,8,9と案件が山場を迎えるので、仕事にコミットしようと考えている。&lt;/p&gt;
&lt;p&gt;個人開発も勉強になるけど、仕事だって勉強になる。&lt;/p&gt;
&lt;p&gt;ということでウェブ版も少しお休みにして、今から3か月だけ仕事人間になる。&lt;/p&gt;
&lt;h2&gt;基本情報技術者試験を10月に受けるという宣言&lt;/h2&gt;
&lt;p&gt;個人開発はお休みするけど、隙間時間で勉強はできるので、基本情報技術者試験の勉強をすることにする。&lt;/p&gt;
&lt;p&gt;どのくらいで受かるかわからないけど、この3か月、時間の隙間で勉強していく。&lt;/p&gt;
&lt;p&gt;そして10月に必ず、試験を受ける。&lt;/p&gt;
&lt;p&gt;8月になったら申し込む（今すぐに申込できないところが決意の弱さを表している...）。&lt;/p&gt;
&lt;h2&gt;ロタウィルスが猛威を振るった&lt;/h2&gt;
&lt;p&gt;プライベートでは双子と妻が同時にロタウイルスの餌食になった。&lt;/p&gt;
&lt;p&gt;結果、何もできないポンコツがひとりぴんぴんしていた。&lt;/p&gt;
&lt;p&gt;何もできないので、ただ1週間会社を休み、おろおろしていた。&lt;/p&gt;
&lt;p&gt;ご飯くらい作れないとこの先どうしようないということをひどく痛感した。&lt;/p&gt;
&lt;p&gt;できることだけをやって家事している気になるなんて滑稽でしかない。&lt;/p&gt;
&lt;p&gt;時期を見て妻に師事しようと思う。&lt;/p&gt;
&lt;h2&gt;保活って話で聞くより、壮絶かもしれない&lt;/h2&gt;
&lt;p&gt;来年の4月から双子が保育園に通うことになる。&lt;/p&gt;
&lt;p&gt;きっと。&lt;/p&gt;
&lt;p&gt;きっとというのも保育園に入れるのが壮絶難しい。&lt;/p&gt;
&lt;p&gt;来年の4月からなのにもう見学が始まっているし、入れそうなところに見学行くとうーんとなる。&lt;/p&gt;
&lt;p&gt;行きたいと思っているところは、そもそも空きがないし、数枠あっても双子がその数枠を占められるのかっていうのが不安視される。&lt;/p&gt;
&lt;p&gt;しかも驚くべきことに双子には加点がない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ja.wikipedia.org/wiki/%E4%BF%9D%E8%82%B2%E5%9C%92%E8%90%BD%E3%81%A1%E3%81%9F%E6%97%A5%E6%9C%AC%E6%AD%BB%E3%81%AD!!!&quot;&gt;保育園落ちた日本死ね!!!&lt;/a&gt;、約10年前で他人事だったけど、自分事になってきた。&lt;/p&gt;
&lt;p&gt;というより10年間、対策はないのかしら。&lt;/p&gt;
&lt;p&gt;まあ、選ばなければ入れるし、そう考えるとそんなものか。&lt;/p&gt;
&lt;p&gt;ただ自分の子どものことなるとみんな熱くなるのは仕方ない。&lt;/p&gt;
&lt;p&gt;とりあえず、8月の「おかあさんといっしょスペシャルステージ」に当選したので、それを楽しみに8月まで保活する。&lt;/p&gt;
&lt;p&gt;とはいっても自分は見学に行くだけなんだけど、妻が色々動いてくれて頭が上がらない。&lt;/p&gt;
&lt;h2&gt;Surface Pro&lt;/h2&gt;
&lt;p&gt;買った。遂に。7月に届くので所感はその時。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>nextjsのプロジェクトでclass-variance-authorityを採用した</title><link>https://blog.nove-b.dev/posts/nextjs-project-class-variance-authority</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/nextjs-project-class-variance-authority</guid><description>class-variance-authorityってなに？</description><content:encoded>&lt;h2&gt;レビューは勉強になる&lt;/h2&gt;
&lt;p&gt;最近案件が立て込んでいるのは&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-6/&quot;&gt;6月のまとめ&lt;/a&gt;に書いたんだけど、結果いくつかのプロジェクトで実装ではなく、ただのレビューアーと化している。&lt;/p&gt;
&lt;p&gt;実装がしたいって今まで強く思っていた。&lt;/p&gt;
&lt;p&gt;実装が実力を伸ばす唯一の手段だと思っていたけど、レビューも真剣にやればすごい勉強になることに気が付いた。&lt;/p&gt;
&lt;p&gt;というのもレビューするには、まずコードをしっかり読まなければならないし、知らないプラグインとの出会いがあり、それを調べることで相当勉強になる。&lt;/p&gt;
&lt;p&gt;で、今回出会ったのが、&lt;code&gt;class-variance-authority&lt;/code&gt;というプラグイン。&lt;/p&gt;
&lt;h2&gt;class-variance-authorityとは??&lt;/h2&gt;
&lt;p&gt;簡単に言うと&lt;code&gt;variants&lt;/code&gt;を定義して条件分岐をわかりやすくするもの。&lt;/p&gt;
&lt;p&gt;公式にある&lt;code&gt;button&lt;/code&gt;コンポーネントの例がわかりやすい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React from &quot;react&quot;;
import { cva, type VariantProps } from &quot;class-variance-authority&quot;;

const button = cva(&quot;button&quot;, {
  variants: {
    intent: {
      primary: [
        &quot;bg-blue-500&quot;,
        &quot;text-white&quot;,
        &quot;border-transparent&quot;,
        &quot;hover:bg-blue-600&quot;,
      ],
      secondary: [
        &quot;bg-white&quot;,
        &quot;text-gray-800&quot;,
        &quot;border-gray-400&quot;,
        &quot;hover:bg-gray-100&quot;,
      ],
    },
    size: {
      small: [&quot;text-sm&quot;, &quot;py-1&quot;, &quot;px-2&quot;],
      medium: [&quot;text-base&quot;, &quot;py-2&quot;, &quot;px-4&quot;],
    },
  },
  compoundVariants: [{ intent: &quot;primary&quot;, size: &quot;medium&quot;, class: &quot;uppercase&quot; }],
  defaultVariants: {
    intent: &quot;primary&quot;,
    size: &quot;medium&quot;,
  },
});

export interface ButtonProps
  extends React.ButtonHTMLAttributes&amp;lt;HTMLButtonElement&amp;gt;,
    VariantProps&amp;lt;typeof button&amp;gt; {}

export const Button: React.FC&amp;lt;ButtonProps&amp;gt; = ({
  className,
  intent,
  size,
  ...props
}) =&amp;gt; &amp;lt;button className={button({ intent, size, className })} {...props} /&amp;gt;;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/joe-bell/cva/blob/main/examples/react-with-tailwindcss/src/components/button/button.tsx&quot;&gt;https://github.com/joe-bell/cva/blob/main/examples/react-with-tailwindcss/src/components/button/button.tsx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今まで自分が実装したときは&lt;code&gt;jsx&lt;/code&gt;のほうに条件をいろいろ書いてコードが読みにくくなっていたけど、これならコードが整理されてわかりやすい。&lt;/p&gt;
&lt;h2&gt;懸念点があった&lt;/h2&gt;
&lt;p&gt;懸念点は&lt;code&gt;prettier&lt;/code&gt;が効くのか、そして&lt;code&gt;vscode&lt;/code&gt;の拡張機能が正常に動くかという点だった。&lt;/p&gt;
&lt;p&gt;でもそれも公式でしっかり解消されていた。&lt;/p&gt;
&lt;h3&gt;prettier&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;tailwind&lt;/code&gt;のフォーマットが行われるよう&lt;code&gt;prettier-plugin-tailwindcss&lt;/code&gt;というプラグインを入れている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tailwindlabs/prettier-plugin-tailwindcss&quot;&gt;prettier-plugin-tailwindcss&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;で、これが&lt;code&gt;variants&lt;/code&gt;に書くと効かないことが分かった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tailwindlabs/tailwindcss/discussions/7558#discussioncomment-7345390&quot;&gt;https://github.com/tailwindlabs/tailwindcss/discussions/7558#discussioncomment-7345390&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ここで議論されており、解決されていた。&lt;/p&gt;
&lt;p&gt;この通り行った結果、うまく動いた。&lt;/p&gt;
&lt;h3&gt;Tailwind CSS IntelliSense&lt;/h3&gt;
&lt;p&gt;これは自動で&lt;code&gt;tailwind&lt;/code&gt;の補完、つまり予測を出してくれる&lt;code&gt;vscode&lt;/code&gt;の拡張機能。&lt;/p&gt;
&lt;p&gt;これを効くようにするには、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;tailwindCSS.experimental.classRegex&quot;: [
    [&quot;cva\\(([^)]*)\\)&quot;, &quot;[\&quot;&apos;`]([^\&quot;&apos;`]*).*?[\&quot;&apos;`]&quot;],
    [&quot;cx\\(([^)]*)\\)&quot;, &quot;(?:&apos;|\&quot;|`)([^&apos;]*)(?:&apos;|\&quot;|`)&quot;]
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という風に設定すればいい。で、再起動をする。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;うん、勉強になった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>tailwind-mergeというプラグインはなぜ入れるのか</title><link>https://blog.nove-b.dev/posts/why-use-tailwind-merge-plugin</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/why-use-tailwind-merge-plugin</guid><description>tailwind-merge is 何 ?</description><content:encoded>&lt;p&gt;&lt;a href=&quot;https://azukiazusa.dev/blog/tailwind-css-libs/#tailwind-merge&quot;&gt;Tailwind CSS を使う時に一緒に入れたいライブラリ&lt;/a&gt;が参考になった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;px-4&lt;/code&gt;と&lt;code&gt;py-6&lt;/code&gt;というクラスを持つコンポーネントに&lt;code&gt;p-10&lt;/code&gt;というクラスを渡した場合、&lt;code&gt;CSS カスケード&lt;/code&gt;により、&lt;code&gt;p-10&lt;/code&gt;というスタイルは無視される。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CSS カスケード&lt;/code&gt;というのは、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;異なるソースから来るプロパティ値を組み合わせる方法を定義するアルゴリズム&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;のこと。&lt;/p&gt;
&lt;p&gt;で、今回は詳細度で&lt;code&gt;p-10&lt;/code&gt;は無視される。&lt;/p&gt;
&lt;p&gt;ただコンポーネントで上書きしようとしたスタイルが無視されるのは困る。&lt;/p&gt;
&lt;p&gt;そこで必要となるのが、&lt;code&gt;tailwind-merge&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dcastil/tailwind-merge&quot;&gt;tailwind-merge&lt;/a&gt;はコンフリクトした
&lt;code&gt;Tailwind CSS&lt;/code&gt;のクラス名を取り除きつつ結合するライブラリで、上記では後から指定された&lt;code&gt;p-10&lt;/code&gt;により、&lt;code&gt;px-4&lt;/code&gt;と&lt;code&gt;py-6&lt;/code&gt;というクラスが結果からとりの結果から取り除かれる。&lt;/p&gt;
&lt;p&gt;結果、意図した挙動をするコンポーネントができあがる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Surface(第11世代)を実際に買うまで悩んだこと</title><link>https://blog.nove-b.dev/posts/deliberations-before-buying-surface-11th-gen</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/deliberations-before-buying-surface-11th-gen</guid><description>Surface(第11世代)を実際に買うまで悩んだこと</description><content:encoded>&lt;h2&gt;Surfaceに片思い&lt;/h2&gt;
&lt;p&gt;遡ること、2年前前の2022年。Surfaceが欲しく家電量販店に通った。欲しくて欲しくてどうしよもなかったのだが懸念点がいくつかあり、決め手に欠けた。&lt;/p&gt;
&lt;p&gt;例えば、Surfaceを象徴するキックスタンドとタブレットモード。&lt;/p&gt;
&lt;p&gt;キックスタンドは狭い机で操作しにくいとか、膝上で操作できないとかいろいろな口コミが、購入を留まらせた。&lt;/p&gt;
&lt;p&gt;またタブレットモードもそうで、そもそもタブレットとして使うには重すぎるし、&lt;code&gt;winndows&lt;/code&gt;のタブレットモードは使いにくいと思うって言われており、もっともだと思った。&lt;/p&gt;
&lt;p&gt;そして購入に至らなかった最大の理由は、使用していたgramが十分に役割を果たしていてくれていた点。まだバリバリの現役だった。&lt;/p&gt;
&lt;p&gt;それから2年の月日が経ち、gramの動きがもっさりとし、たまに動かなくなるよになった。なにより、キーボードのいくつかのキーが紛失していた。&lt;/p&gt;
&lt;h2&gt;買い替え時が訪れた&lt;/h2&gt;
&lt;p&gt;パソコンの買い替え時が訪れた。&lt;/p&gt;
&lt;p&gt;2年の月日が経とうが、ずっとSurfaceが欲しかった。&lt;/p&gt;
&lt;p&gt;これは買わなきゃ後悔するということで購入を決意した。決意したのだが、値段を見ると決意は簡単に揺らいだ。&lt;/p&gt;
&lt;p&gt;最低20万7680円でタイプカバーをつけると23万くらいになる。&lt;/p&gt;
&lt;p&gt;うーん、高い。ということでさらに3か月悩むことになった。&lt;/p&gt;
&lt;h2&gt;名乗りを上げる候補者たち&lt;/h2&gt;
&lt;p&gt;その間に富士通のFMV LOOXも候補にあがってきた。&lt;/p&gt;
&lt;p&gt;すこしスペックは落ちるけど、最低限は担保しているように思える。&lt;/p&gt;
&lt;p&gt;ただ、FMV LOOXはバッテリー35Wh（surfaceは48Wh）なので見送ることにした。&lt;/p&gt;
&lt;p&gt;持ち運ぶ前提なのでバッテリーは重視したい。&lt;/p&gt;
&lt;p&gt;それに、FMV
LOOXは画面の縦横比が16対9なのもマイナスポイントになった。コーディングをするので縦長のほうが好ましく、この点もSurfaceが勝っている。&lt;/p&gt;
&lt;p&gt;唯一、本体の重さが599gというのは非常に魅力的だった。&lt;/p&gt;
&lt;p&gt;次のバージョンに期待しつつ見送る。&lt;/p&gt;
&lt;h2&gt;コスパのASUSが台頭する&lt;/h2&gt;
&lt;p&gt;なんて迷っているとASUSがProArt PZ13
HT5306というSurfaceと同じようなセパレート型のパソコンを出すことが発表された。&lt;/p&gt;
&lt;p&gt;コスパに定評のあるASUSだしバッテリー容量も70whとずば抜けている。&lt;/p&gt;
&lt;p&gt;期待しかないのだが、稼働中のgramがそれまで待てないほど消耗しきっているので、タイミングが合わなかったということで泣く泣く見送った。けど、次回以降の候補になるので、注視したい。&lt;/p&gt;
&lt;h2&gt;surfaceの懸念点 vs 思い&lt;/h2&gt;
&lt;p&gt;色々見送ったけど、そもそもSurfaceの懸念点がなくなったわけじゃなく、なんなら11世代はチップがARMになるとのことで、懸念点が増える一方だった。&lt;/p&gt;
&lt;p&gt;でも2年間欲しかったという気持ちを尊重して購入にいたった。&lt;/p&gt;
&lt;h2&gt;結果&lt;/h2&gt;
&lt;p&gt;買ってみると予想以上に良かった。&lt;/p&gt;
&lt;p&gt;何よりパソコン感がない。&lt;/p&gt;
&lt;p&gt;今までパソコンを持ち歩くとき、すこし後ろめたさがあった。&lt;/p&gt;
&lt;p&gt;パソコン持ち歩くってなにごと？ みたいに思われやしないかと不安だったけど、Surfaceなら持ち歩いていても何も違和感ない。&lt;/p&gt;
&lt;p&gt;裸で持ち歩いているけど、タブレット持ち歩いているのと何ら変わらない。&lt;/p&gt;
&lt;p&gt;それにパソコンを開く抵抗も減った。&lt;/p&gt;
&lt;p&gt;持ち歩くとき同様、パソコンは開くときもそれなりに心理的ハードルがある。話しつつ調べごとをする時に、パソコンを開くのは少し大仰な気がするけど、Surfaceならすっと開ける。何ならたぶんスタイリッシュに開くことができる（願望）。&lt;/p&gt;
&lt;p&gt;心配したキーボードの操作性も特に問題ない。なにより、gramのようにキーがなくなっても交換できるという利点がある。&lt;/p&gt;
&lt;p&gt;いい買い物をした。今のところ不満点はなく、購入してよかったと思える。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2024年7月】読書できず、仕事に追われている</title><link>https://blog.nove-b.dev/posts/2024-7</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-7</guid><description>2024年7月に考えたこととか</description><content:encoded>&lt;hr /&gt;
&lt;h2&gt;7月に読んだ本&lt;/h2&gt;
&lt;p&gt;ない、何も読めなかった。&lt;/p&gt;
&lt;p&gt;正直時間を作り出そうと思えばできた気がするけど、なんとなく手に取れなかった。&lt;/p&gt;
&lt;p&gt;読まないといけないものではないけど、心のゆとりがなくなっている１つの指標ではあるので、すこし考えなおしたい。&lt;/p&gt;
&lt;p&gt;どんだけ軽い本でもいいので、8月は1冊は読みたい。&lt;/p&gt;
&lt;p&gt;趣味を失うことは恐ろしい。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Surfaceを購入した&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/deliberations-before-buying-surface-11th-gen/&quot;&gt;Surface(第11世代)を実際に買うまで悩んだこと&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;悩みに悩んだけど、買ってよかったと思っている。&lt;/p&gt;
&lt;p&gt;この記事で触れたProArth PZ13 HT5306はまだ販売していないよう。&lt;/p&gt;
&lt;p&gt;待たなくてよかった。&lt;/p&gt;
&lt;p&gt;1ヶ月近く使ったけど、満足している。&lt;/p&gt;
&lt;p&gt;ただまだ家でしか使ってないので、小さいテーブルで発生するキックスタンドの問題には直面していない。&lt;/p&gt;
&lt;h2&gt;9月まで仕事が繁忙期を迎える&lt;/h2&gt;
&lt;p&gt;なかなか忙しい。&lt;/p&gt;
&lt;p&gt;８月９月と家族の誕生日、そして保活とイベントが盛りだくさんなのだが、そこらへんが疎かになっているので、家庭に危機感を持たないといけない。&lt;/p&gt;
&lt;p&gt;うまくバランスをとるか、ここは一気に仕事にけりをつけるか悩みどこだけど、今回の案件的にバランスが取れるような感じではないので、少しでも早く終わらせられるように全力で取り組む。&lt;/p&gt;
&lt;p&gt;案件的には学びもあり、楽しくはある。&lt;/p&gt;
&lt;p&gt;ただやっぱり家で仕事するのはどうなんだろう。&lt;/p&gt;
&lt;p&gt;自分は楽しいからいいけど、家族的にはそんなことないだろうし、理想は家に仕事を持ち込まないことだと思う。&lt;/p&gt;
&lt;p&gt;少し遅く帰ってもいいけど、家族が起きている時間は家族を優先するべきだよね。&lt;/p&gt;
&lt;p&gt;早く起きてやるとか。すこし考え直さないといけない。&lt;/p&gt;
&lt;h2&gt;目標を変えるというのは悪手でしかない&lt;/h2&gt;
&lt;p&gt;という風に、最近はずっと忙しいのだが、不思議なことに忙しいとやりたいことがたくさん生まれる。&lt;/p&gt;
&lt;p&gt;たとえば今年の目標の１つであるマストドンのサーバーを無性に立ち上げたくなったりとか。&lt;/p&gt;
&lt;p&gt;でも10月に基本情報をとるって決めているので、まずはそこからクリアしたい。&lt;/p&gt;
&lt;p&gt;勉強できていなので、クリアできるかわからないけど、１つづつ消化していくのが一番いい。&lt;/p&gt;
&lt;h2&gt;8月から10月までの生き方&lt;/h2&gt;
&lt;p&gt;ということで、この記事を書いているのがすでに10日で8月の1/3を終えているのだが、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;家族が起きている時間は仕事をしない(家のことが終わり次第ok)&lt;/li&gt;
&lt;li&gt;10月の基本情報に向け、勉強する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これが10月までの生き方でマストドンのサーバーは基本情報が終わり次第着手していく。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2024年8月、9月】とにかく仕事に追われる</title><link>https://blog.nove-b.dev/posts/2024-9</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-9</guid><description>2024年8月、9月に考えたこととか</description><content:encoded>&lt;h2&gt;デスマーチから帰還する&lt;/h2&gt;
&lt;p&gt;気がついたら10月になっていた。&lt;/p&gt;
&lt;p&gt;ここ最近、納期に追われて更新すらできなかった。&lt;/p&gt;
&lt;p&gt;8月から始まったデスマーチは9月中の納品を目指し壮絶を極めた。&lt;/p&gt;
&lt;h3&gt;反省点が多い&lt;/h3&gt;
&lt;p&gt;何故デスマーチになったのか、後述するように会社都合でもあるのだが、自身の反省も多くある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;useSWR&lt;/code&gt; をラップしてCURDに対応させたこと&lt;/li&gt;
&lt;li&gt;&lt;code&gt;form&lt;/code&gt;内の&lt;code&gt;value&lt;/code&gt;定義をミスったこと&lt;/li&gt;
&lt;li&gt;コンポーネントを共通化しすぎたこと&lt;/li&gt;
&lt;li&gt;共通処理をうまくまとめられなかったこと&lt;/li&gt;
&lt;li&gt;プルリクのマージレベルを下げたこと&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;あげだすときりがない。これにスケジュールの反省点もある。&lt;/p&gt;
&lt;p&gt;これは重要なので今度まとめる。&lt;/p&gt;
&lt;h3&gt;裁量労働制という奴隷制度と文化祭前の高揚感&lt;/h3&gt;
&lt;p&gt;壮絶を極めたので、毎日帰宅は日をまたぎ、土日もほぼ出勤した。&lt;/p&gt;
&lt;p&gt;しかしいくら仕事をこなしても裁量労働制なので残業が出るわけでもない。&lt;/p&gt;
&lt;p&gt;しかもこの納期、会社の決算前に売り上げを上げたいという、こちら提示の納期なので、なぜか自分の会社に首を絞めれるという摩訶不思議な案件だった。&lt;/p&gt;
&lt;p&gt;積る不満はいくつもあるが、案件としてはとても楽しかった。&lt;/p&gt;
&lt;p&gt;立ち上げたサーバーに入り操作することも、バックエンドの人といろいろ最適解を探りつつ、勉強しつつ進めていくのがとても楽しかった。&lt;/p&gt;
&lt;p&gt;色々なことを犠牲にしたが、その分成長できたし、わいわい楽しくできたと感じている。&lt;/p&gt;
&lt;p&gt;脱落者がいないのもいい結果だった。&lt;/p&gt;
&lt;h2&gt;仕事は家庭を犠牲にする&lt;/h2&gt;
&lt;p&gt;さて、色々なことを犠牲にしたと書いたが、特に犠牲になったは家族である。&lt;/p&gt;
&lt;p&gt;日をまたいで帰る日は既にみんな就寝し、寝顔を見ることしかできない。&lt;/p&gt;
&lt;p&gt;普段、家事を沢山しているわけではないが、この間ほぼなにも手伝えずで、妻がワンオペで乗り越えてくれた。&lt;/p&gt;
&lt;p&gt;忙しく帰れないせいで妻が飲み会に行けなかったり、しかもすっかりそのことを忘れていたりと散々迷惑をかけた。&lt;/p&gt;
&lt;p&gt;申し訳ないし、感謝してもしきれない。&lt;/p&gt;
&lt;p&gt;その分給料とか還元されるものがないので、やっぱり少し納得いかない気もする。&lt;/p&gt;
&lt;h3&gt;みんな1歳歳をとった&lt;/h3&gt;
&lt;p&gt;家族の誕生日が8月末と9月初めに集中している。&lt;/p&gt;
&lt;p&gt;さすがに誕生日に、とくに双子の誕生日に仕事に行っているわけにはいけないと、メンバーには申し訳ないが、家族写真撮影とアンパンマンミュージアムに行った。&lt;/p&gt;
&lt;h3&gt;カレーパンマン好きは遺伝する&lt;/h3&gt;
&lt;p&gt;双子のうち娘のほうがなぜかカレーパンマン好きで「かれー」とよく言っている。&lt;/p&gt;
&lt;p&gt;あるいはカレーが好きなだけかもしれないけれど、どうやら世間的にカレーパンマンが好きな人は少数派らしく、妻に自分もカレーパンマン好きだったことを言うと驚いていた。&lt;/p&gt;
&lt;p&gt;そんなことまで遺伝するものなのか、と。&lt;/p&gt;
&lt;p&gt;そんなカレーパンマンに抱きしめれられてご満悦の娘と、いつもの姿からは想像できない素早さで動く息子を見ていると、やっぱりたくさん家に帰って、長い間子供たちを見ていたいと思うようになる。もちろんその分大変なことも多いのだけれど。&lt;/p&gt;
&lt;p&gt;案件が終わった今、少しでもいろんなところに行き、たくさん思い出を作りたいと改めて思った。&lt;/p&gt;
&lt;p&gt;今年はあと、昭和記念公園に行って、箱根に旅行に行きたい。&lt;/p&gt;
&lt;p&gt;あと、おかあさんといっしょのファミリーコンサートのリセールにも当選したいし、ディズニーランドの予約もせねばならん。&lt;/p&gt;
&lt;p&gt;来年からは妻の育休が明け、好きに遊びに行けなくなるに違いないので、それまでに存分に家族で楽しみたい。&lt;/p&gt;
&lt;p&gt;ーー、のはやまやまなのだが、保活も仕事同様に壮絶を極め、いろいろ時間を浪費している。&lt;/p&gt;
&lt;h3&gt;保活について&lt;/h3&gt;
&lt;p&gt;まず、うちは双子なので当然、２人分の枠が必要になる。&lt;/p&gt;
&lt;p&gt;だがしかし、多くの保育園は１～２人という募集要項で、運よく2人だとしても双子で埋めていいものかという疑問が残る。&lt;/p&gt;
&lt;p&gt;いや入れるのなら入るのだが、それが不利に働かないかと不安になる。&lt;/p&gt;
&lt;p&gt;考えられることを国はしてくれているんだろうけれど、保活壮絶すぎるでしょう。&lt;/p&gt;
&lt;p&gt;文句を言っても仕方ない。引き続き頑張る。&lt;/p&gt;
&lt;h2&gt;8月９月に読んだ本&lt;/h2&gt;
&lt;p&gt;毎月まとめている読んだ本だが、そんな通りなので、全然本が読めなかった。&lt;/p&gt;
&lt;p&gt;8月と9月で1冊。しかもそれがあまり面白くなかった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3BVv3sg&quot;&gt;かなりや荘浪漫 廃園の鳥たち (PHP文芸文庫) &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ログによると&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;なんか、序章って感じ。何も始まってない、シリーズぽいけど、もう読まなくていいかな&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;っていう感想だったらしい。&lt;/p&gt;
&lt;p&gt;10月は本を読む。&lt;/p&gt;
&lt;p&gt;今のままだとキンドルアンリミテッドに入っている意味がないし、なによりずっと大好きだった趣味を失いたくない。&lt;/p&gt;
&lt;h2&gt;Mastodonのクライアントアプリ&lt;/h2&gt;
&lt;p&gt;Trunksというアプリを見つけ、使い始めた。&lt;/p&gt;
&lt;p&gt;これが良いのだけれど、唯一の欠点が絵文字リアクションに対応していない。&lt;/p&gt;
&lt;p&gt;なので、絵文字リアクションに対応したクライアントアプリを作りたい。&lt;/p&gt;
&lt;p&gt;そしてそもそも自分のサーバーを建てたい。&lt;/p&gt;
&lt;p&gt;まずは自分のサーバーを建てようと思う。&lt;/p&gt;
&lt;p&gt;これは必ず今年中に実現する。と宣言してみる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>マストドンでおひとり様サーバーを立ち上げた</title><link>https://blog.nove-b.dev/posts/mastodon-solo-server-setup</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/mastodon-solo-server-setup</guid><description>サーバーの知識０でなんとかサーバー立ち上げまでこぎつけた</description><content:encoded>&lt;h2&gt;おひとり様サーバーに憧れる&lt;/h2&gt;
&lt;p&gt;2023年の11月。&lt;/p&gt;
&lt;p&gt;つまりおおよそ1年前からMastodonを使用してきた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3BOfm6x&quot;&gt;ハロー・ワールド&lt;/a&gt;という本を読み、オープンソースのSNSという響きに憧れ開始した。&lt;/p&gt;
&lt;p&gt;そのレベルの解像度なので何も考えずに有名で汎用的な&lt;a href=&quot;https://fedibird.com/&quot;&gt;https://fedibird.com/&lt;/a&gt;にお邪魔させてもらってきた。&lt;/p&gt;
&lt;p&gt;それから1年経ち、なんだかんだ呟いたりしているうちに、自分のサーバーを持ちたくなった。&lt;/p&gt;
&lt;h2&gt;サーバーの立ち上げに興味を持つ&lt;/h2&gt;
&lt;p&gt;いままでいくつかサービスを公開してきた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vercel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;firebase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aws&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cloud run&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上記のようなサービスを使ってきたが、&lt;code&gt;vercel&lt;/code&gt;、&lt;code&gt;firebase&lt;/code&gt;は&lt;code&gt;github&lt;/code&gt;にデプロイするだけでサイトが公開されるし、&lt;code&gt;aws&lt;/code&gt;と&lt;code&gt;cloud run&lt;/code&gt;はコピペするだけでなんとか乗り切ってきた。&lt;/p&gt;
&lt;p&gt;つまりサーバー何もわからない、エンジニアなのに。&lt;/p&gt;
&lt;p&gt;これじゃいけないということで、&lt;code&gt;vps&lt;/code&gt;を借りて好き勝手出来る環境を作ってみようと思い立ち、それならMastodonを運用するのがいいじゃないかと天啓をひらめいた。&lt;/p&gt;
&lt;p&gt;思い立ったが吉日、&lt;code&gt;vps&lt;/code&gt;を借りて立ち上げてみた。&lt;/p&gt;
&lt;h2&gt;MastodonをエックスサーバーVPSで立ち上げる&lt;/h2&gt;
&lt;h3&gt;そもそも必要な要件がわからない&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;vps&lt;/code&gt;を選ぶうえでいくつか候補があったけど、過去のブログでレンタルサーバーとしてお世話になったエックスサーバーを使うことにした。&lt;/p&gt;
&lt;p&gt;前述したとおり、サーバー何もわからないので、「メモリ」「vCPU」「NVMe
SSD」とかどのくらいを選べば適正に運用できるかがわからない。&lt;/p&gt;
&lt;p&gt;調べてもよくわからないので、運用しつつ見定めていくことにした。&lt;/p&gt;
&lt;p&gt;ということでとりあえず最小の2GBプランにしてみる。&lt;/p&gt;
&lt;p&gt;2GBプランは&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;メモリ 2GB&lt;/li&gt;
&lt;li&gt;vCPU 3コア&lt;/li&gt;
&lt;li&gt;NVMe SSD 50GB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;それぞれ簡単に調べてみた感じ、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;メモリ（RAM）
役割: サーバーが一時的にデータを保存する場所です。たくさんの人が同時にWebサイトにアクセスしてもスムーズに動くようにします。
メリット: メモリが多いと、Webサイトが速くなり、同時に多くのアクセスを処理できます。
2. vCPU（仮想CPU）
役割: サーバーの頭脳で、リクエストを処理したり、ページを作ったりする仕事をします。
メリット: vCPUが多いと、Webサイトの処理が速くなり、アクセスが増えても遅くなりにくくなります。
3. NVMe SSD
役割: サーバーのデータ（ファイルや画像など）を保存する場所で、データの読み書きが速いです。
メリット: NVMe SSDが多いと、Webページの表示が速くなり、データベースも素早く動作します。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;うーん、メモリとCPUの違いがよくわからない、いつか誰かに教えてもらいたい。&lt;/p&gt;
&lt;h3&gt;ドメインを用意しておく&lt;/h3&gt;
&lt;p&gt;よくわからないけど&lt;code&gt;vps&lt;/code&gt;は契約したので、次はドメインを作成する。&lt;/p&gt;
&lt;p&gt;このブログもサブドメインで運用しているので、同じようにサブドメインを作成し運用することにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cloudflare.com/ja-jp/products/registrar/&quot;&gt;Cloudflare Registrar&lt;/a&gt;でサブドメインを作成する。&lt;/p&gt;
&lt;p&gt;ドメインのページに行き、DNS 管理で&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;タイプ&lt;/th&gt;
&lt;th&gt;名前&lt;/th&gt;
&lt;th&gt;コンテンツ&lt;/th&gt;
&lt;th&gt;プロキシステータス&lt;/th&gt;
&lt;th&gt;TTL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;social&lt;/td&gt;
&lt;td&gt;VPS情報のIPアドレス&lt;/td&gt;
&lt;td&gt;DNSのみ&lt;/td&gt;
&lt;td&gt;自動&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;のように登録する。&lt;/p&gt;
&lt;p&gt;ちなみにプロキシステータスが何かよくわかないけど、のブログはDNSのみに設定されていたので合わせた。&lt;/p&gt;
&lt;p&gt;プロキシ済みにすると&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;この動作により、Cloudflare はアプリケーションへのすべてのリクエストを最適化、キャッシュ、保護できるだけでなく、オリジンサーバーをDDoS 攻撃から保護できます ↗。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことらしく、どうしてDNS のみにしたんだろうと&lt;a href=&quot;https://blog.nove-b.dev/posts/cloudflare-registrar-netlify-subdomain/&quot;&gt;過去のブログ&lt;/a&gt;を検索すると&lt;code&gt;Netlify&lt;/code&gt;は&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;プロキシステータスをDNS のみ にすることでNetlifyのSSL証明書が正常に機能するようになるらしい。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という経緯があったらしい。忘れていた。&lt;/p&gt;
&lt;p&gt;後日これを書いている時、これを機にMastodonのほうをプロキシ済みにしよう安全だし、と思い変更したらサイトが落ちた。&lt;/p&gt;
&lt;p&gt;つまりDNSのみじゃないといけないらしい。&lt;/p&gt;
&lt;p&gt;そんなこんなでドメインの作成までが完了した。&lt;/p&gt;
&lt;h3&gt;Mastodonをインストールしていく&lt;/h3&gt;
&lt;p&gt;基本的に、公式が丁寧すぎるので従っていけば問題なく表示できる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://vps.xserver.ne.jp/support/manual/man_server_app_use_mastodon.php&quot;&gt;Mastodonアプリイメージを利用する&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただ初心者過ぎていくつか詰まったのでそこだけまとめておく。&lt;/p&gt;
&lt;h4&gt;公式の方法でサーバーに接続できないのでvsCodeを使用した&lt;/h4&gt;
&lt;p&gt;VPS管理画面のコンソールか&lt;code&gt;Tera Term&lt;/code&gt;を使ってサーバーに接続しファイルの編集とかを行う必要があるのだが、慣れてなさすぎてファイルの編集が難しいということでvsCodeから接続することにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh&quot;&gt;Remote - SSH&lt;/a&gt;という拡張機能を使い接続する。&lt;/p&gt;
&lt;p&gt;リモートエクスプローラーを開き歯車から&lt;code&gt;C:\Users\{username}\.ssh\config&lt;/code&gt;を開き、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host サーバー名
  HostName IPアドレス
  User root
  Port 22  # SSHポート番号 (通常22)
IdentityFile ダウンロードしたSSH Keyのパス
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように記述すればリモート接続できるようになった。&lt;/p&gt;
&lt;p&gt;これでvsCodeでコードの編集とかをできるようになる。&lt;/p&gt;
&lt;p&gt;結果的に便利になった気がするので良かった。&lt;/p&gt;
&lt;h4&gt;GmailのSMTPが使えなくなっていた&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;2024年9月30日よりGmailのSMTPサーバー（smtp.google.com）でパスワードを利用した認証が利用できなくなる&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;パスワードを利用した認証っていうのがよくわからないけど、うまくいかなかったので今回はメールを使用しないことにした。&lt;/p&gt;
&lt;p&gt;どんな不便が発生するかわからないけど、おひとり様サーバーなのでいらないはず。&lt;/p&gt;
&lt;h4&gt;Adminっていうユーザー名にしてしまった。&lt;/h4&gt;
&lt;p&gt;管理者を作りますかという質問に脳死で答えていたら、&lt;/p&gt;
&lt;p&gt;https://social.nove-b.dev/@admin&lt;/p&gt;
&lt;p&gt;というユーザー名にしてしまった。&lt;/p&gt;
&lt;p&gt;別にいいんだけれどダサいので変更したい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@x {ipアドレス}:/# su - mastodon
mastodon@x {ipアドレス}:~$ cd ~/live
mastodon@x {ipアドレス}:~/live$ RAILS_ENV=production bundle exec rails console
user = Account.find_by(username: &apos;admin&apos;)
user.username = &apos;新しいユーザー名&apos;  # または他の許可された形式
user.save!
mastodon@x {ipアドレス}:~/live$ exit
root@x {ipアドレス}:/# sudo systemctl restart mastodon-*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記で無事変更できた。&lt;/p&gt;
&lt;h2&gt;おひとり様サーバーデビュー&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/social.nove-b.dev.png&quot; alt=&quot;実際の画像&quot; /&gt;&lt;/p&gt;
&lt;p&gt;運用していく、楽しみもあるけど、不安も多い。&lt;/p&gt;
&lt;p&gt;ともかくデビューには成功した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://social.nove-b.dev/@nove_b&quot;&gt;@nove_b@social.nove-b.dev&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;もしかするとサーバーが崩壊してすぐにいなくなるかもしれないですが、もしよろしければフォローしてください。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>マストドンのfaviconを変更する</title><link>https://blog.nove-b.dev/posts/mastodon-change-favicon</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/mastodon-change-favicon</guid><description>マストドンのfaviconを変更する</description><content:encoded>&lt;p&gt;せっかくのおひとり様サーバーなので好き勝手実験したいということでまずは&lt;code&gt;favicon&lt;/code&gt;を変更することにした。&lt;/p&gt;
&lt;p&gt;エックスサーバーVPSのMastodonアプリイメージを使用したので、どこに&lt;code&gt;mastodon&lt;/code&gt;本体があるかわからなかったが、色々検索した結果、&lt;code&gt;/home/mastodon/live/&lt;/code&gt;に存在することが分かった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Remote - SSH&lt;/code&gt;を使用し、対象のディレクトリに移動後、&lt;code&gt;favicon&lt;/code&gt;を置き換え、&lt;code&gt;sudo systemctl restart mastodon-*&lt;/code&gt;を実行。&lt;/p&gt;
&lt;p&gt;確認するけど、変更されていない。&lt;/p&gt;
&lt;p&gt;ソースを見ると&lt;code&gt;favicon&lt;/code&gt;は変更されているけど、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;link href=&apos;/favicon.ico&apos; rel=&apos;icon&apos; type=&apos;image/x-icon&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/favicon-16x16-c58fdef40ced38d582d5b8eed9d15c5a.png&apos; rel=&apos;icon&apos; sizes=&apos;16x16&apos; type=&apos;image/png&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/favicon-32x32-249409a6d9f300112c51af514d863112.png&apos; rel=&apos;icon&apos; sizes=&apos;32x32&apos; type=&apos;image/png&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/favicon-48x48-c1197e9664ee6476d2715a1c4293bf61.png&apos; rel=&apos;icon&apos; sizes=&apos;48x48&apos; type=&apos;image/png&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-57x57-c9dca808280860c51d0357f6a3350f4d.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;57x57&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-60x60-bb247db195d9ee9d8c687b2b048508d9.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;60x60&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-72x72-799d90b81f5b28cea7355a0c0b356381.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;72x72&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-76x76-015d73d770413d121873193153ae4ab5.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;76x76&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-114x114-211e68807b8d15707666a8d326d338b1.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;114x114&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-120x120-4c4e647d758bf1b2f47a53e2165a01d2.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;120x120&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-144x144-ff3110f7772743bdd0c1c47fb7b2d4e0.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;144x144&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-152x152-b12cbb1baaf4a6111d0efd391fd829c9.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;152x152&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-167x167-6f21a68f6a05a8b5cf25b1729e553728.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;167x167&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-180x180-a75559a0af48064c1b7c71b81f3bf7c6.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;180x180&apos;&amp;gt;
&amp;lt;link href=&apos;/packs/media/icons/apple-touch-icon-1024x1024-db6849588b44f525363c37b65ef0ac66.png&apos; rel=&apos;apple-touch-icon&apos; sizes=&apos;1024x1024&apos;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;favicon.ico&lt;/code&gt;以外にも複数の画像を読み込んでいるらしいことが分かった。&lt;/p&gt;
&lt;p&gt;仕方がないので全ファイル分作成し、同様の画像名にし、置換。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl restart mastodon-*&lt;/code&gt;を実行し無事に&lt;code&gt;favicon&lt;/code&gt;が反映されていることを確認した。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Mastodonをアップデートするたびに更新されるので、意味ない気がする。&lt;/p&gt;
&lt;p&gt;変更した後に気が付いたけど、まあいいや。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b/113334955593169076/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b/113334977285416957/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>appearance-noneってなにか真剣に調べてみた</title><link>https://blog.nove-b.dev/posts/what-appearance-none</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/what-appearance-none</guid><description>とりあえず使っていたappearance-noneに歩み寄る</description><content:encoded>&lt;h2&gt;appearance-noneはOS レベルのスタイル制御するもの&lt;/h2&gt;
&lt;p&gt;ウェブフォームのスタイル設定はOSレベルで設定されている。&lt;/p&gt;
&lt;p&gt;そのため、コントロールの見た目のカスタマイズの問題の一部となっていた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;appearance-none&lt;/code&gt;は適用したコントロールがシステムレベルのスタイルを使用することを可能な限り止め、 CSS を使用して自分でスタイルを構築できるようにするプロパティ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/ja/docs/Learn/Forms/Advanced_form_styling&quot;&gt;フォームへの高度なスタイル設定&lt;/a&gt;ほぼこれに書いてあること、そのまま。&lt;/p&gt;
&lt;h3&gt;CSSの上書きと何が違うのか&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;appearance-none&lt;/code&gt;では ボタンやフォーム要素のデフォルトスタイルを即座に取り除き、開発者がカスタマイズするベースを作ることができる。上書きだと個別に上書きするのは手間がかかかるので、その点便利なプロパティとのこと。&lt;/p&gt;
&lt;p&gt;なんとなく使っていたので、はじめてその有用性に気が付いた。&lt;/p&gt;
&lt;h2&gt;ポエム 木こりのジレンマ&lt;/h2&gt;
&lt;p&gt;最近というか今更というか、木こりのジレンマなる寓話を思い出した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ある日、森で一生懸命に木を切っている木こりがいました。彼は朝から晩まで休むことなく木を切っており、疲れ果てています。それでも、木を切るのにとても時間がかかっているため、彼はさらに焦っていました。

そこへ通りがかった旅人が木こりに話しかけました。

「あなたの斧はとても鈍くなっているようですね。少し休んで、斧を研いだ方がいいですよ。」

木こりはその言葉にイライラして答えました。

「そんな時間はない！見ての通り、木を切らなければならないんだ！斧を研ぐ暇なんてないんだ！」

旅人は木こりにもう一度諭しました。

「でも、斧が鋭くなれば、木をもっと早く、もっと簡単に切れるはずですよ。少し休んで斧を研いだ方が、結果的に仕事が早く終わるでしょう。」

木こりは依然として目の前の仕事に集中しすぎて、斧を研ぐことの重要性に気づかず、疲れ果てたまま非効率に仕事を続けました。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この寓話は、効率的に物事を進めるためには、短期的な忙しさに囚われず、道具や方法を改善する時間を取ることの重要性を説いている。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;そしてこれの話がとても心に響いた。&lt;/p&gt;
&lt;p&gt;プログラミング中、忙しい時は特にその場しのぎの解決策に飛びつき、特に考えることなく実装する。&lt;/p&gt;
&lt;p&gt;結果的にその案件は完遂するけど、身につくものをいくつか取りこぼしている。&lt;/p&gt;
&lt;p&gt;なのでこれからは、気になったことはどんどん調べ、ここに備忘録として残していく。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>TypeScriptで一回unknwonに変換するのはどういう意味があるのか</title><link>https://blog.nove-b.dev/posts/ad-unknown-as</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/ad-unknown-as</guid><description>unknwonの謎を調べてみた</description><content:encoded>&lt;h2&gt;as unknown as ?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;as soon as&lt;/code&gt;は「できるだけ早く」で、中学生の時、喉が擦り切れるほどむやみに連呼していた記憶がある。&lt;/p&gt;
&lt;p&gt;おかげさまで、この意味を30歳超えても忘れていない。&lt;/p&gt;
&lt;p&gt;だが、&lt;code&gt;as unknown as&lt;/code&gt;は知らなかった。&lt;/p&gt;
&lt;h2&gt;そもそもunknownってなに？&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;unknown&lt;/code&gt;は型が分からないときに使用するらしい。&lt;/p&gt;
&lt;p&gt;つまりそれって&lt;code&gt;any&lt;/code&gt;ではと思うし、間違っていない。&lt;/p&gt;
&lt;p&gt;その両方ともどのような値も代入することができる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const any1: any = null;
const any2: any = undefined;
const any3: any = true;
const any4: any = 0.8;
const any5: any = &quot;Comment allez-vous&quot;;
const any6: any = {
  x: 0,
  y: 1,
  name: &quot;origin&quot;,
};
const unknown1: unknown = null;
const unknown2: unknown = undefined;
const unknown3: unknown = true;
const unknown4: unknown = 0.8;
const unknown5: unknown = &quot;Comment allez-vous&quot;;
const unknown6: unknown = {
  x: 0,
  y: 1,
  name: &quot;origin&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://typescriptbook.jp/reference/statements/any-vs-unknown&quot;&gt;サバイバルTypeScript&lt;/a&gt;からの引用。&lt;/p&gt;
&lt;p&gt;違いは型チェックをするしないかという点らしい。&lt;/p&gt;
&lt;p&gt;つまり&lt;code&gt;any&lt;/code&gt;を使用するとはコンパイル時には気が付けないのに対し、&lt;code&gt;unknown&lt;/code&gt;型は一貫して&lt;code&gt;TypeScript&lt;/code&gt;がプロパティ、メソッドへのアクセスを行わせない。結果的にコンパイルを実行することができず、意図しないランタイム時のエラーを防止することができる。&lt;/p&gt;
&lt;p&gt;例えば、下記コードでは&lt;code&gt;&apos;unknownValue&apos; is of type &apos;unknown&apos;.&lt;/code&gt;というエラーが出る。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let unknownValue: unknown = {
  x: 0,
};
unknownValue.x = &quot;hello&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;any&lt;/code&gt;よりも厳格な型らしいので、&lt;code&gt;unknown&lt;/code&gt;を使ったほうが良いのだろうか。&lt;/p&gt;
&lt;h2&gt;unknownは理解した、ではas unknown asはなに&lt;/h2&gt;
&lt;p&gt;ちなみにこの構文(&lt;code&gt;as ○○ as&lt;/code&gt;)のことを型アサーションっていうらしい。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TypeScriptには、型推論を上書きする機能があります。その機能を型アサーション (type
assertion)と言います。&lt;/p&gt;
&lt;p&gt;TypeScriptコンパイラーはコードをヒントに型を推論してくれます。その型推論は非常に知的ですが、場合によってはコンパイラーよりもプログラマーがより正確な型を知っている場合があります。そのような場合は、型アサーションを用いるとコンパイラーに型を伝えることができます。型アサーションはコンパイラに「私を信じて！私のほうが型に詳しいから」と伝えるようなものです。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ただ、型アサーションを使用してもコンパイルエラーが出るときがある。&lt;/p&gt;
&lt;p&gt;例えば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const num = 123;
const str: string = num as string;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これは&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Conversion of type &apos;number&apos; to type &apos;string&apos; may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to &apos;unknown&apos; first.(2352)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが出る。&lt;/p&gt;
&lt;p&gt;これは&lt;code&gt;number型をstring型にするのは間違いです。お互いの型に共通する部分が少なすぎるからです&lt;/code&gt;というエラーらしい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TypeScript&lt;/code&gt;は無茶な上書きはできないように設計されているのだが、それでも自分の書いた型アサーションが正しいという場合は&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const num = 123;
const str: string = num as unknown as string;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このように一度&lt;code&gt;unknown&lt;/code&gt;型を経由することエラーを出さずに型推論を上書きすることができる。&lt;/p&gt;
&lt;h2&gt;サバイバルTypeScriptの警告&lt;/h2&gt;
&lt;p&gt;最後に参考にした&lt;a href=&quot;https://typescriptbook.jp/reference/values-types-variables/type-assertion-as&quot;&gt;サバイバルTypeScript&lt;/a&gt;に教訓が載っていたのでそのまま載せておく。&lt;/p&gt;
&lt;h3&gt;大いなる力には大いなる責任が伴う&lt;/h3&gt;
&lt;p&gt;型アサーションには、コンパイラーの型推論を上書きする強力さがあります。そのため、プログラマーは型アサーションによってバグを産まないように十分注意する必要があります。型に関することはできるだけ、コンパイラーの型推論に頼ったほうが安全なので、型アサーションは、やむを得ない場合にのみ使うべきです。&lt;/p&gt;
&lt;p&gt;型アサーションを使う必要が出てきたら、それよりも先に、型ガードやユーザー定義型ガードで解決できないか検討してみるとよいでしょう。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>TypeScriptで出てきたRecordってなに</title><link>https://blog.nove-b.dev/posts/what-record-typescript</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/what-record-typescript</guid><description>TypeScriptをChatGPTに書いてもらっていたら知らないワードとまた出会った</description><content:encoded>&lt;p&gt;ChatGPTにコードを書いてもらっていると知らない書き方と出会うことができ、勉強になる。&lt;/p&gt;
&lt;p&gt;ChatGPTに書いてもらうことは悪いことばかりじゃないと最近は思うようにしている。&lt;/p&gt;
&lt;p&gt;ちょっと前までは反骨心から使ってなかったけど、そう思うようになってからはどんどん活用している。&lt;/p&gt;
&lt;p&gt;ただChatGPTを使って学習したことを活用する機会はChatGPTに奪われているけど。&lt;/p&gt;
&lt;h2&gt;Recordってなに&lt;/h2&gt;
&lt;p&gt;そんなChatGPTが提案してきたコードに&lt;code&gt;Record&lt;/code&gt;という型があったので、どういう型なのか調べてみた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Record&amp;lt;Keys,
Type&amp;gt;はプロパティのキーがKeysであり、プロパティの値がTypeであるオブジェクトの型を作るユーティリティ型です。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;例えば、キーがstringで値がnumberのインデックス型を定義するには、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type StringNumber = Record&amp;lt;string, number&amp;gt;;
const value: StringNumber = { a: 1, b: 2, c: 3 };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;キーが&lt;code&gt;firstName&lt;/code&gt;、&lt;code&gt;middleName&lt;/code&gt;、&lt;code&gt;familyName&lt;/code&gt;で、値が文字列になるオブジェクトの型を定義するには、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Person = Record&amp;lt;&quot;firstName&quot; | &quot;middleName&quot; | &quot;lastName&quot;, string&amp;gt;;
const person: Person = {
  firstName: &quot;Robert&quot;,
  middleName: &quot;Cecil&quot;,
  lastName: &quot;Martin&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じで使用することができる。&lt;/p&gt;
&lt;p&gt;ただ、2つ目の例のように&lt;code&gt;Key&lt;/code&gt;が確定している型に関しては&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface Person {
  firstName: string;
  middleName: string;
  lastName: string;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と何が違うのか。&lt;/p&gt;
&lt;h2&gt;結果的には同じ構造&lt;/h2&gt;
&lt;p&gt;上記だと同様の型定義になる。&lt;/p&gt;
&lt;p&gt;ただ&lt;code&gt;interface &lt;/code&gt;のほうが拡張性が高く、&lt;code&gt;Record&lt;/code&gt;のほうが簡潔に書けるけど、具体的なプロパティ名や構造を明示しにくいとのこと。&lt;/p&gt;
&lt;p&gt;じゃあ、&lt;code&gt;Record&lt;/code&gt;はいつ使うのか。&lt;/p&gt;
&lt;h3&gt;Recordの使い道&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Record は多くのキーが同じ型を持つ場合、簡潔に型を定義する時&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;type WeeklySchedule = Record&amp;lt;&quot;Monday&quot; | &quot;Tuesday&quot; | &quot;Wednesday&quot; | &quot;Thursday&quot; | &quot;Friday&quot;, string&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;動的なキーの集合に対して一律の型を定義したい時&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;type ApiResponse&amp;lt;T&amp;gt; = Record&amp;lt;string, T&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じで動的なキーの型付けや簡潔なオブジェクト型定義が必要なときに使えるらしい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2024年10月】人間的生活を取り戻した</title><link>https://blog.nove-b.dev/posts/2024-10</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-10</guid><description>2024年10月に考えたこととか</description><content:encoded>&lt;hr /&gt;
&lt;h2&gt;10月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/48fRx3s&quot;&gt;失恋覚悟のラウンドアバウト&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;15日にデスマーチから帰還し、読書を再開した。&lt;/p&gt;
&lt;p&gt;なんか馬鹿馬鹿しい本が読みたいと手に取った本で、期待通りに馬鹿馬鹿しかった。&lt;/p&gt;
&lt;p&gt;今の自分にはちょうどいい。&lt;/p&gt;
&lt;h2&gt;ブログを再開&lt;/h2&gt;
&lt;p&gt;忙しさにかまけて、というより更新したくても更新できなかったこのブログを、再活性化している。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-9/&quot;&gt;【2024年8月、9月】とにかく仕事に追われる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/mastodon-solo-server-setup/&quot;&gt;マストドンでおひとり様サーバーを立ち上げた&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/mastodon-change-favicon/&quot;&gt;マストドンのfaviconを変更する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/what-appearance-none/&quot;&gt;appearance-noneってなにか真剣に調べてみた&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/ad-unknown-as/&quot;&gt;TypeScriptで一回unknwonに変換するのはどういう意味があるのか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;TypeScript%E3%81%A7%E5%87%BA%E3%81%A6%E3%81%8D%E3%81%9FRecord%E3%81%A3%E3%81%A6%E3%81%AA%E3%81%AB&quot;&gt;TypeScriptで出てきたRecordってなに&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;10月15日から更新を再開し、結構活動的に書いてきた。&lt;/p&gt;
&lt;p&gt;というのもやっぱりアウトプットするべきだと再認識した。&lt;/p&gt;
&lt;p&gt;アウトプットするということではなく、アウトプットするために調べることが重要で、&lt;a href=&quot;https://blog.nove-b.dev/posts/what-appearance-none/&quot;&gt;appearance-noneってなにか真剣に調べてみた&lt;/a&gt;でも書いたけど、木こりのジレンマの寓話のように、一見遠回りに思えてもそれが後に生きてくることが、勉強においては多分にある気がする。&lt;/p&gt;
&lt;p&gt;そういうわけで精力的にブログを書いていきたい。&lt;/p&gt;
&lt;h2&gt;ひっそりと終わるブログ&lt;/h2&gt;
&lt;p&gt;そんな中、ワードプレスで作成したブログがサーバーの更新日を迎える。&lt;/p&gt;
&lt;p&gt;2年間くらいお世話になったけど、記事の管理を&lt;code&gt;GitHub&lt;/code&gt;にしたいがためにさよならしたブログで、更新はしないため一生のお別れになる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/media-nove-web-com.png&quot; alt=&quot;サイトトップ&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/media-nove-web-com-first.png&quot; alt=&quot;最初の記事&quot; /&gt;&lt;/p&gt;
&lt;p&gt;記事効率化のためにワードプレスのプラグインを作成したりとなかなか楽しい経験だった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nove-b/create-eye-catch-for-classic&quot;&gt;create-eye-catch-for-classic&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;初！ 公開したプラグインに要望が届く&lt;/h3&gt;
&lt;p&gt;そういえば、そんなプラグインに&lt;code&gt;issue&lt;/code&gt;が上がっていた。&lt;/p&gt;
&lt;p&gt;公開しているプラグインに&lt;code&gt;issue&lt;/code&gt;が上がるのは初めてなのでテンションが上がるけど、やらないとという焦燥感がある。&lt;/p&gt;
&lt;p&gt;できるかわからなし、もうサイトも閉じ、プラグイン更新する熱量もないけどせっかくなので対応してあげたい。&lt;/p&gt;
&lt;p&gt;使ってもらえているのはシンプルにうれしい。&lt;/p&gt;
&lt;h2&gt;マストドンのサーバーを立ち上げる&lt;/h2&gt;
&lt;p&gt;忙しい仕事から抜け出し、ぽっと自分時間ができたので、いの一番にマストドンのサーバーを立ち上げた。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b/113325372536161415/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/mastodon-solo-server-setup/&quot;&gt;マストドンでおひとり様サーバーを立ち上げた&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;レンタルサーバーを借りることはよくあったけど、&lt;code&gt;vps&lt;/code&gt;を借りたのは初めてでまだ何もわかっていない。&lt;/p&gt;
&lt;p&gt;ただフルスタックになるにはこの領域の理解も深めなくてはいけないので、いっぱい試行錯誤してみる。&lt;/p&gt;
&lt;p&gt;実験的な場にしたい。&lt;/p&gt;
&lt;p&gt;ただSNSとして使うのであれば、お金を払いSNSをしているというわけのわからない状況になるので頑張る。&lt;/p&gt;
&lt;h2&gt;今年の目標１つクリア&lt;/h2&gt;
&lt;p&gt;マストドンのサーバーを立ち上げたことで今年の目標を1つクリアしたことになる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ] ネイティブアプリをリリースする&lt;/li&gt;
&lt;li&gt;[ ] 基本情報技術者資格を取る&lt;/li&gt;
&lt;li&gt;[ ] OSS活動にコントリビューとする&lt;/li&gt;
&lt;li&gt;[x] Mastodonのサーバーを立ち上げる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最後まで達成できそうもないので、次はネイティブアプリリースにする。&lt;/p&gt;
&lt;p&gt;ちょうどいいので、マストドンのクライアントをリリースしたい。&lt;/p&gt;
&lt;p&gt;今年中はきついと思うけど、リリースまでもっていきたい。&lt;/p&gt;
&lt;h2&gt;やることが多い&lt;/h2&gt;
&lt;p&gt;目標クリアにささげられる時間もあんまりない。&lt;/p&gt;
&lt;p&gt;子どもができて、仕事が増えて、明らかに自分に使える時間が減った。&lt;/p&gt;
&lt;p&gt;つまり今後はどうやって時間の濃度を高めていくかにかかっている。&lt;/p&gt;
&lt;p&gt;とは言え、自身の集中力の低さはわかっている。&lt;/p&gt;
&lt;p&gt;どうすればいいのか、やっぱりポモドーロとかテクニックを取り入れる必要があるのかしら。&lt;/p&gt;
&lt;p&gt;11月はとりあえずポモドーロを実行してみるか、そうしよう。&lt;/p&gt;
&lt;h3&gt;ポモドーロのルール&lt;/h3&gt;
&lt;p&gt;せっかくのなのでここに明確にしておく。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1クールを25分
&lt;ul&gt;
&lt;li&gt;1クールで終わらせる量をあらかじめ定めてクールに入る&lt;/li&gt;
&lt;li&gt;終わっていようと終ってなかろうと25分でクールは切る&lt;/li&gt;
&lt;li&gt;クール中に他の事、連絡も含めほかのやることは禁止&lt;/li&gt;
&lt;li&gt;やることが終わったらクール完了&lt;/li&gt;
&lt;li&gt;クール完了後は飲み物を飲む（なんとなく）&lt;/li&gt;
&lt;li&gt;5分間の休憩は何をしてもいいけど、5分を決して超えないようにする&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;何ポモドーロしたかは記録しておく。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ちょっとこれで11月は試してみる。&lt;/p&gt;
&lt;p&gt;どこにポモドーロした回数を記録しておくかは別で考える必要がある。&lt;/p&gt;
&lt;p&gt;アプリがあるならそれを活用するのもいいかもしれない。&lt;/p&gt;
&lt;p&gt;11月の月報にはいい知らせを載せられるようにしたい。&lt;/p&gt;
&lt;h2&gt;コロナにかかった&lt;/h2&gt;
&lt;p&gt;そういえば、コロナにかかった。&lt;/p&gt;
&lt;p&gt;家族全員で39度出して寝込んだ。&lt;/p&gt;
&lt;p&gt;とは言え、特別辛いわけでもなく1日で完治した。&lt;/p&gt;
&lt;p&gt;ちょうど土日を挟んだので、みんなで21時に寝て、8時に起きて、13時～16時まで昼寝するという何ともいい生活を送らせてもらった。&lt;/p&gt;
&lt;p&gt;ただ、いろいろな予定がキャンセルになったり、やっぱり感染症なんてかかるものじゃない。&lt;/p&gt;
&lt;p&gt;2年前にコロナになり、2年ぶりの風邪がコロナだった。&lt;/p&gt;
&lt;p&gt;風邪ひかないことが取り柄なのにコロナだけは防ぎきれないらしい、つまりコロナはやばい。&lt;/p&gt;
&lt;h2&gt;Happy Halloween 👻&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/github.png&quot; alt=&quot;Githubの草&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GitHub&lt;/code&gt;もハロウィーン仕様だった。&lt;/p&gt;
&lt;p&gt;そういうわけで、Happy Halloween 👻！&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>JavascriptでEnumをより保守性高く使う方法</title><link>https://blog.nove-b.dev/posts/javascript-enum-maintainability-tips</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/javascript-enum-maintainability-tips</guid><description>Enumを扱い等式を使用する際、どのように扱えばいいか調べてみた</description><content:encoded>&lt;p&gt;例えば&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
enum Example {
  緑茶
  麦茶
  紅茶
  珈琲
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という&lt;code&gt;Enum&lt;/code&gt;を使って比較をする時に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if(key === +Example.緑茶)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という比較を書くか&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if(Example[key] === &quot;緑茶&quot;)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という風に書くかどっちがいいのかがわからなかったので調べてみた。&lt;/p&gt;
&lt;h2&gt;if(key ===Example.緑茶)のほうが保守性が高い&lt;/h2&gt;
&lt;p&gt;理由としては、まず&lt;code&gt;Example.緑茶&lt;/code&gt;という風に書くことで型推論が効きタイポが起きにくくなる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Example[key] === &quot;緑茶&quot;&lt;/code&gt;と書くときは型推論が効かないので、青茶って書いても何も教えてれない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (Example[key] === &quot;青茶&quot;) {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こう書いてもエラーが出ない。&lt;/p&gt;
&lt;p&gt;これ以外にメリットがありそうだったけど、これが最大のメリットな気がする。&lt;/p&gt;
&lt;p&gt;そういうことで&lt;code&gt;Enum&lt;/code&gt;を直接比較したほうが良い。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Mastodonのおひとり様サーバーにおける連合タイムライン</title><link>https://blog.nove-b.dev/posts/mastodon-other-servers</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/mastodon-other-servers</guid><content:encoded>&lt;h2&gt;連合がない&lt;/h2&gt;
&lt;p&gt;おひとり様サーバーを立ち上げたのは過去に書いたのだが、フォロワーを探すために連合を見に行った。&lt;/p&gt;
&lt;p&gt;当時（といっても１か月もいかないくらい前）連合とはmastodonに投稿されるすべての呟きが忙しく流れるところという認識だった。というのもかつていたサーバーの連合は絶え間なく呟きが投稿されていたからである。&lt;/p&gt;
&lt;p&gt;しかしどうしたものか、自サーバーの連合はタイムラインと大差ない。&lt;/p&gt;
&lt;p&gt;うまくサーバーが立ち上げれていないのか、はたまたそういうものなのか。&lt;/p&gt;
&lt;p&gt;そもそも前にいたサーバーの連合も日本語だらけで海外の投稿がなかった気がする。&lt;/p&gt;
&lt;p&gt;つまり連合は「mastodonに投稿されるすべての呟き」じゃない......？&lt;/p&gt;
&lt;h2&gt;連合は同一サーバーに所属する人のコミュニティが反映される&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.joinmastodon.org/ja/user/network/&quot;&gt;ドキュメント&lt;/a&gt;を探っていたところ、下記情報に遭遇した。&lt;/p&gt;
&lt;blockquote&gt;
&lt;h2&gt;公開タイムラインに流れるコン​​テンツの閲覧&lt;/h2&gt;
&lt;p&gt;興味のありそうなコンテンツを発見できるように、Mastodonはすべての公開投稿を見る手段を提供しています。とはいっても、全部のサーバー間で包括的にステータスが共有されているわけではないため、すべての公開投稿を見る方法はありません。連合タイムラインを閲覧すると、あなたのいるサーバーが認識しているすべての公開投稿を表示できます。サーバーが投稿を認識する方法はさまざまですが、その大部分は、同じサーバー上にいる他のユーザーがフォローしている人々の投稿でしょう。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;簡単に言うと、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同じサーバーのユーザーがフォローしている他のサーバーのユーザー&lt;/li&gt;
&lt;li&gt;同じサーバーのユーザーがブーストをした相手ユーザーによる投稿&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;が連合には表示されるらしい。&lt;/p&gt;
&lt;p&gt;そのため、自分しかいないサーバーであるおひとり様サーバーの場合、連合はタイムラインと同じ情報になる。&lt;/p&gt;
&lt;p&gt;だから以前のサーバーにも日本語投稿が多かったのかと腑に落ちた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>nextjsのLinkコンポーネントは事前にプリフェッチしているらしい</title><link>https://blog.nove-b.dev/posts/nexr-link-prefetch</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/nexr-link-prefetch</guid><content:encoded>&lt;p&gt;新規開発中のWebアプリケーションで、一覧ページのネットワークタブを何気なく確認したら、画面に表示されているリストの各詳細ページがすべてリクエストされていることに気付き、驚いた。&lt;/p&gt;
&lt;p&gt;「実装ミスかしら」とぞっと総毛だって実装を見直してみるが、特段へんてこな記述は見つけられない。&lt;/p&gt;
&lt;p&gt;ただ&lt;code&gt;next/link&lt;/code&gt;を&lt;code&gt;map&lt;/code&gt;で回しているだけである。&lt;/p&gt;
&lt;p&gt;だいたいこういうときは&lt;code&gt;next&lt;/code&gt;のお節介が原因のことが多い。&lt;/p&gt;
&lt;p&gt;そういうわけで、&lt;code&gt;next/link&lt;/code&gt;を調べてみると案の定&lt;code&gt;prefetch&lt;/code&gt;というオプションがあり、デフォルトが&lt;code&gt;true&lt;/code&gt;となっていた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ビューポート内にある &amp;lt;Link /&amp;gt;
はすべてプリロードされます (初期状態やスクロール中)。prefetch={false} を渡すことでプリフェッチは無効になります。prefetch が false に設定されている場合でも、ホバー時にはプリフェッチが行われます。&lt;a href=&quot;https://nextjs-ja-translation-docs.vercel.app/docs/basic-features/data-fetching#getstaticprops-static-generation&quot;&gt;静的生成&lt;/a&gt;を使用しているページでは、ページ遷移を高速化するためにデータと一緒に JSON ファイルがプリロードされます。プリフェッチは本番環境での&amp;gt; み有効です。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;基本的に気にしなくてもいい気がするけど、サーバーに負荷をかけるので&lt;code&gt;false&lt;/code&gt;にしても問題ない気がする。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;prefetch が false に設定されている場合でも、ホバー時にはプリフェッチが行われます&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とあるので&lt;code&gt;false&lt;/code&gt;にしたところで、そこまでページ遷移のユーザー体験を損なわないと思われる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;next&lt;/code&gt;は本当にお節介で裏側で色々なことをしてくれる。しっかり理解しないと思わぬ副作用を生むことがあるのでドキュメントを読むことを心掛けたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>良質な記事を書くという目的意識のためにOFUSEを導入する</title><link>https://blog.nove-b.dev/posts/introduction-ofuse</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/introduction-ofuse</guid><content:encoded>&lt;p&gt;ブログにOFUSEを導入することにした。&lt;/p&gt;
&lt;p&gt;OFUSEとは簡単に言うと投げ銭サービスで、クリエーターとかが簡単に寄付を受け付けることができるプラットフォームのこと。&lt;/p&gt;
&lt;p&gt;公式に下記のような説明がある。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OFUSEは、「ファンの応援でクリエイターの創作活動を支えたい」という想いから生まれたファンレターサービスです。あらゆるクリエイターが、Web上での創作活動や情報発信を通じて継続的に価値を生み出してゆける仕組みをつくり、ファンとクリエイターをつなぎます。&lt;/p&gt;
&lt;p&gt;現在、中心的な機能である「支援付きレター」（1文字2円のファンレター）に加え、投稿への「支援付きコメント」（1文字2円のコメント）や月額で支援できる「メンバーシップ」をご利用いただけ、応援金額の90%をクリエイターの皆様へお届けしております。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;他にも有名なサービスで&lt;a href=&quot;https://buymeacoffee.com/&quot;&gt;Buy Me a Coffee&lt;/a&gt;がある。こちらはよくGithubとかで見る。個人的には投げ銭というばこっちのサイトが頭に浮かぶし、なんとなくかっこいい。&lt;/p&gt;
&lt;p&gt;けど、今回はOFUSEを導入することにした。&lt;/p&gt;
&lt;h2&gt;なぜ投げ銭サービスを導入するのか&lt;/h2&gt;
&lt;p&gt;そもそもなぜ投げ銭サービスを導入するのかだけど、大前提としてこのブログで儲けようなんて微塵も思っていないし、儲けられるなんて思っていない。&lt;/p&gt;
&lt;p&gt;儲けたいのであれば過去に月１万とかを生んでくれた商品レビューブログを復活させるし、アドセンスを表示しまくる。&lt;/p&gt;
&lt;p&gt;けどこのサイトはそういうサイトじゃない。あくまでも自分のアウトプット用、あるいは記録用で、後で見返せばいいなくらいのスタンスで更新している。&lt;/p&gt;
&lt;p&gt;そうしないと更新が続かないと思って、そういうスタンスをとってきた。&lt;/p&gt;
&lt;p&gt;けど最近は少しづつ読まれることも意識するようにしたいと思うようになってきた。&lt;/p&gt;
&lt;p&gt;それが本質ではないけど、どうせ書くのであれば誰かが読んでいい記事だと唸るような記事が書ければいい。そのために時間を費やすことはないけれど、結果的にそうなれば幸せである。&lt;/p&gt;
&lt;p&gt;とは言え、唸る記事がもし書けたところで投げ銭してくれる人なんでいないと思うし、自分有益な記事を読み感謝こそすれど投げ銭なんてしたことがない。&lt;/p&gt;
&lt;p&gt;あくまでもこれは投げ銭サービスのリンクを張っているぞという自分への戒めである。投げ銭のリンク張っているんだから少しくらいいい記事書くように意識しようぜ、といったところ。&lt;/p&gt;
&lt;p&gt;ただ何度も言うけど、このブログは自分のためのアウトプットで記事更新が億劫にならないレベルで書いていくつもり。&lt;/p&gt;
&lt;p&gt;かけれる保険は掛けておく。&lt;/p&gt;
&lt;h2&gt;なんでOFUSEにしたのか&lt;/h2&gt;
&lt;p&gt;前述したように同様のサービスであるBuy Me a Coffeeの方が洒落ていてかっこいい。&lt;/p&gt;
&lt;p&gt;ただ自分が寄付する側だった時に、海外サービスを使用するのは少し抵抗がある。安全性とか信頼性とかではなく、通貨の単位が異なることに不安を感じる。&lt;/p&gt;
&lt;p&gt;あと使えるクレジットカードのサービスとかもなんか制限がありそうな気がする。すごい偏見なんだけど。&lt;/p&gt;
&lt;p&gt;それに海外の人が読むことなんてあり得ないので、それなら国産サービスにしたほうニーズに合っている。&lt;/p&gt;
&lt;p&gt;まあ、そういうわけで投げ銭サービスを取り入れてみた。これが少しでも記事更新、質向上になればと考えている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Github Actionでprettierを実行したい</title><link>https://blog.nove-b.dev/posts/github-action-prettier</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/github-action-prettier</guid><content:encoded>&lt;p&gt;フォーマットを書けるのが面倒くさい。&lt;/p&gt;
&lt;p&gt;このブログはマークダウンで書かれていて、コミットする前に必ず&lt;code&gt;prettier --write&lt;/code&gt;を実行しようと心に誓ったけど、まったくというほど実行されずにきた。そしてたまに思いだしたように実行し、毎回あげだされる差分に驚いてきた。&lt;/p&gt;
&lt;p&gt;エンジニアとして対策しないのかという話だけれど、以前対策を試み&lt;code&gt;Github Action&lt;/code&gt;を登録したけれどうまく動かず、そもそも最悪フォーマットしなくても問題ないので時間かけるのもどうだろうかと&lt;code&gt;issue&lt;/code&gt;に登録して寝かせていた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Close&lt;/code&gt;されずにずっと残り続ける&lt;code&gt;issue&lt;/code&gt;は心を蝕む......、なんてことはないけれど少し気持ち悪い。&lt;/p&gt;
&lt;p&gt;そこで時間をかけてもいいので、解決することを最優先課題にしてみた。&lt;/p&gt;
&lt;p&gt;そういうわけで色々なサイトを巡回し調べた結果、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Format Markdown
on:
  push:
    branches:
      - main

permissions:
  contents: write

jobs:
  format:
    runs-on: ubuntu-latest
    steps:
      - name: Check out the repository
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: &quot;18&quot;

      - name: Install Prettier
        run: npm install -g prettier

      - name: Format Markdown files
        run: prettier --write &quot;**/*.md&quot;

      - name: Push changes
        run: |
          git config --global user.name &quot;github-actions[bot]&quot;
          git config --global user.email &quot;github-actions[bot]@users.noreply.github.com&quot;
          git stash  # 現在の変更を一時保存
          git pull origin main  # リモートの変更を取得
          git stash pop  # 保存した変更を復元
          git add .  # 変更をステージング
          git commit -m &quot;Format markdown files&quot; || echo &quot;No changes to commit&quot;
          git push origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で実現できた。&lt;/p&gt;
&lt;p&gt;やっていることは以下の通りで、シンプル。&lt;/p&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ワークフローのトリガー設定&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;ブランチにプッシュされたときにこのワークフローが実行されます。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;リポジトリのチェックアウト&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;actions/checkout@v3&lt;/code&gt;アクションを使ってリポジトリの全体（過去の履歴も含む）を取得します。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Node.jsのセットアップ&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;actions/setup-node@v3&lt;/code&gt;アクションを使い、Node.jsのバージョン18をインストールします。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prettierのインストール&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm install -g prettier&lt;/code&gt;を使って、Markdownフォーマット用のツールであるPrettierをグローバルにインストールします。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Markdownファイルのフォーマット&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prettier --write &quot;**/*.md&quot;&lt;/code&gt;コマンドで、リポジトリ内のすべてのMarkdownファイル（&lt;code&gt;*.md&lt;/code&gt;）をフォーマットします。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;変更のプッシュ&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以下の手順でフォーマットした変更をリモートの&lt;code&gt;main&lt;/code&gt;ブランチにプッシュします：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git stash&lt;/code&gt;で現在の変更を一時的に保存。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git pull origin main&lt;/code&gt;でリモートの最新変更を取得。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash pop&lt;/code&gt;で保存した変更を再適用。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add .&lt;/code&gt;で変更をステージング。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git commit&lt;/code&gt;で変更をコミット（変更がない場合はスキップ）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push origin main&lt;/code&gt;で変更をリモートにプッシュ。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;過去の試行錯誤を見るに、&lt;code&gt;Token&lt;/code&gt;とかを生成したりしているし、参考サイトには&lt;code&gt;Token&lt;/code&gt;を生成している記事も多かった。&lt;/p&gt;
&lt;p&gt;ただ、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GitHub
Actionsでは、GITHUB_TOKENがデフォルトで自動的に適用される。このトークンはGitHubによって自動的に生成され、ワークフローのすべてのジョブで利用可能になっている。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Github&lt;/code&gt;の方でアップデートがされたのか、そのおかげかしら？&lt;/p&gt;
&lt;p&gt;過去の自分が何に躓いていたのかはわからないけれど、うまくいってよかった。&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE] &amp;gt;
&lt;a href=&quot;/post/fix-same-lastmodl&quot;&gt;Hugoブログで最終更新日がすべて同じになっていたのを修正した&lt;/a&gt;で更新した。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><author>nove-b</author></item><item><title>next startで実行される環境変数をそれぞれ違うファイルから呼び出したい</title><link>https://blog.nove-b.dev/posts/next-start-env-cmd</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/next-start-env-cmd</guid><content:encoded>&lt;p&gt;&lt;code&gt;nextjs&lt;/code&gt;でタグマネージャーを導入する際に、本番環境、検証環境、開発環境といった環境ごとにコンテナのIDを指定することにした。&lt;/p&gt;
&lt;p&gt;ただ&lt;code&gt;nextjs&lt;/code&gt;では用意された&lt;code&gt;env&lt;/code&gt;と適応コマンドがすでに割りついているっぽい。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;環境ファイル&lt;/th&gt;
&lt;th&gt;役割&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.env.local&lt;/td&gt;
&lt;td&gt;next dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.env.development&lt;/td&gt;
&lt;td&gt;next dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.env.production&lt;/td&gt;
&lt;td&gt;next build/next start&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://zenn.dev/yuji/articles/cb4f2562cf70ae&quot;&gt;Next.jsで環境ファイル(env)別ビルドを行う&lt;/a&gt;
参考：&lt;a href=&quot;https://github.com/vercel/next.js/issues/12772&quot;&gt;Add support for custom environments&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今回は、同じ&lt;code&gt;next start&lt;/code&gt;で3つの環境を作成したいけど、前述の通りそれだと&lt;code&gt;.env.production&lt;/code&gt;しか呼び出すことができない。&lt;/p&gt;
&lt;p&gt;そこで&lt;a href=&quot;https://www.npmjs.com/package/env-cmd&quot;&gt;env-cmd&lt;/a&gt;を使用する。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;#Using custom env file path To use a custom env filename or path, pass the
flag. This is a major breaking change from prior versions &amp;lt; 9.0.0-f&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とあるように、アプリをビルド/実行するときに特定の.envファイルを選択することができるパッケージ。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.env.prod
.env.stag
.env.local
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と3つの&lt;code&gt;Env&lt;/code&gt;を用意し下記のような&lt;code&gt;Script&lt;/code&gt;を作成すれば、それぞれの&lt;code&gt;Script&lt;/code&gt;ごとに対応する&lt;code&gt;Env&lt;/code&gt;を読みに行ってくれる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &quot;prod&quot;: &quot;env-cmd -f .env.prod next build &amp;amp;&amp;amp; next start&quot;,
    &quot;stag&quot;: &quot;env-cmd -f .env.stag next build &amp;amp;&amp;amp; next start&quot;,
    &quot;local&quot;: &quot;env-cmd -f .env.local next build &amp;amp;&amp;amp; next start&quot;,
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>nove-b</author></item><item><title>【2024年11月】2024年の目標はきっと無理</title><link>https://blog.nove-b.dev/posts/2024-11</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-11</guid><description>2024年11月に考えたこととか</description><content:encoded>&lt;hr /&gt;
&lt;h2&gt;11月に読んだ本&lt;/h2&gt;
&lt;p&gt;読書はそれなにできた気がする。&lt;/p&gt;
&lt;p&gt;読んだ本は下記の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4fcNUhz&quot;&gt;新装版 タイム・リープ〈上〉　あしたはきのう (メディアワークス文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3AGTrxA&quot;&gt;新装版 タイム・リープ〈下〉　あしたはきのう (メディアワークス文庫)&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;タイムリープものの金字塔らしく、新装版が出るのも納得できた。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3UKxCEk&quot;&gt;オカシナ記念病院 (角川文庫)&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;現代医療をブラックユーモアで切った作品。主張しなく、最後も意外な終わり方でよかった。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3Zj1hHv&quot;&gt;聖なる怠け者の冒険 (朝日文庫)&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;再読、ほとんど忘れてた。主人公がほとんどぐうたらしている稀有な小説。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3CDmy5K&quot;&gt;君が夏を走らせる（新潮文庫）&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;これは泣く。子どもできてから子ども可愛くて仕方ない。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3VdlT1b&quot;&gt;ある男&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;絶賛読んでいる途中で面白い。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;キンドルアンリミテッドが980円なので相当得していることになる。サブスクって損することが多い気がするけどアンリミテッドは有効活用できている。最近読みたいと思える本がアンリミテッドになってくれて嬉しい。&lt;/p&gt;
&lt;h2&gt;保活Done！&lt;/h2&gt;
&lt;p&gt;さて、ついに保活が終了した。入れるか入れないかはさておき、とりあえず申し込みはした。申し込み後に申し込み状況を電話で教えてくれる制度があり、活用してみた結果、2人(たぶん)の募集に対して4人の応募があったらしい。うちは双子なので厳しい戦いになる。さらに、聞いた日の消印有効なのでさらに増えている可能性もある。&lt;/p&gt;
&lt;p&gt;落ちたらたぶん、第2希望はさらに厳しそうだったので、第3志望の幼稚園になる。&lt;/p&gt;
&lt;p&gt;そうするとお金がきつい。幼稚園は高い。教材費とかなんとか色々とかさむ。&lt;/p&gt;
&lt;p&gt;とは言えもうできることはないので待つしかない。悶々と1月中旬まで待ち続ける。&lt;/p&gt;
&lt;p&gt;資料とかいろいろ読み込み、保育課に何度も電話してくれた妻には感謝しかない。&lt;/p&gt;
&lt;h2&gt;秋の終わりに&lt;/h2&gt;
&lt;p&gt;そんな事をしているうちに秋が終わった。葉が色づいて、車が凍るようになった。今年の秋は一瞬だった。意識しないと秋に気が付かないくらい暖かく、急に寒くなった。&lt;/p&gt;
&lt;p&gt;せっかくなので紅葉が綺麗な昭和記念公園に行った。子どもの成長は凄まじく、ボールを蹴って遊んでたし、ふわふわドームでジャンプをしていた。自分はどんどん衰えているのに、子どもはどんどん成長していく。その事実がうれしくもあり、少し怖い。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/koyo.jpg&quot; alt=&quot;紅葉&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;冬の訪れ&lt;/h2&gt;
&lt;p&gt;冬の訪れとともにクリスマスがやってくる。昨年、てんやわんやして買ったクリスマスツリーを出した。毎年少しづつオーナメントを買っていく。昨年寒そうだったツリーもだいぶ賑やかになった。今年は子どもたちが喧嘩しながら飾り付けをしてくれた。何度も言うようだけど、子どもの成長はすごい。昨年買いそびれた念願のツリートップを飾り付け、あとはクリスマスを待つのみになった。&lt;/p&gt;
&lt;p&gt;クリスマスが来ると正月がくる。そうすると当然、今年が終わり来年になる。それは避けられない事実でどんなに首を振っても強制的に来年になる。&lt;/p&gt;
&lt;h2&gt;散々な結果に終わりそうな2024年の目標&lt;/h2&gt;
&lt;p&gt;さて、じゃ今年の目標はどうだったというと、4件たてた目標のうち現時点で1件しか達成できていない。はたして、取り組みが悪いのか、あるいは目標の立て方が悪いのか。&lt;/p&gt;
&lt;p&gt;そんななか、残り3つのうち1つであるネイティブアプリをリリースする、という目標に遅ればせながら着手した。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b/113537241015233243/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mastodon&lt;/code&gt;のクライアントを&lt;code&gt;react native&lt;/code&gt;で作成することにする。作りたいものはすでに頭の中にあるので、あとはそれを形にしていく作業になる。&lt;/p&gt;
&lt;p&gt;ただ形にする時間があまりにも少ない。時間が全く足りない。みんなが勉強したり、何かを作っている事実に焦りを感じる。&lt;/p&gt;
&lt;p&gt;そこで、朝早起きをして勉強をすることにした。ただ冬の早起きは誰もが知るように辛い。実際11月は起きれない日が続いたし、何回か遅刻しかけた。そんな中、sleep
as androidというアプリにであった。&lt;/p&gt;
&lt;p&gt;これが自分ニーズとぴったりとハマった。&lt;/p&gt;
&lt;p&gt;目覚ましアプリに求めていたのは&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;スマートウォッチのバイブが活用できる&lt;/li&gt;
&lt;li&gt;スマホ自体は音が鳴らない&lt;/li&gt;
&lt;li&gt;起きれるまで止まらない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;そしてこれのニーズに答えてくれたのがsleep as android。&lt;/p&gt;
&lt;p&gt;これの設定でCAPTCHAをQRコードにして、スヌーズをオフにすると、朝起きてスマホでQRコードを読み取るまでスマートウォッチが振動し続ける。&lt;/p&gt;
&lt;p&gt;QRコードを洗面室の鏡の裏に貼り付けたので、寝室を出なくちゃいけなく、そのまま顔を洗い、目覚めるといった非人間的行動を強制される。&lt;/p&gt;
&lt;p&gt;最初は3問の計算問題を解かないと止まらない四則演算にしていたが、計算を終え満足して二度寝することが多発したので、プライドを捨ててQRコードにした。結果、起きれるようになった。&lt;/p&gt;
&lt;p&gt;たぶん、これが続けば朝活できるようになり、少しは時間を使えるようになる気がする。&lt;/p&gt;
&lt;p&gt;そこで少しでも開発できればいいなって明るい12月を思い描いている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>2024年12月時点でのReact Native開発環境の構築手順</title><link>https://blog.nove-b.dev/posts/environment-construction-react-native-2024-12</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/environment-construction-react-native-2024-12</guid><content:encoded>&lt;p&gt;毎回React
Nativeの環境構築に苦労するので、2024年現時点でしっくりした環境構築の方法を残しておく。&lt;/p&gt;
&lt;h2&gt;立ち上げるアプリの環境&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;    &quot;expo&quot;: &quot;~52.0.11&quot;,
    &quot;react-native&quot;: &quot;0.76.3&quot;,
    &quot;eslint&quot;: &quot;^8.57.0&quot;,
    &quot;eslint-config-expo&quot;: &quot;~8.0.1&quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Expoでアプリを立ち上げる&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npx create-expo-app@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でプロジェクトを作成すると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Creating an Expo project using the default template.

To choose from all available templates pass in the --template arg:
  $ npx create-expo-app --template

To choose from all available examples pass in the --example arg:
  $ npx create-expo-app --example

√ What is your app named? ... my-app
✔ Downloaded and extracted project files.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のようにデフォルトで作成される。&lt;/p&gt;
&lt;p&gt;しばらくすると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;✅ Your project is ready!

To run your project, navigate to the directory and run one of the following npm commands.

- cd my-app
- npm run android
- npm run ios # you need to use macOS to build the iOS project - use the Expo app if you need to do iOS development without a Mac
- npm run web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;インストールが完了し、buildコマンドが表示される。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;npm run start&lt;/code&gt;を実行して、ExpoアプリでQRコードを読み込めば、アプリが表示される。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image01.png&quot; alt=&quot;lサンプルアプリ&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Tailwind React Native Classnamesを導入する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;react native&lt;/code&gt;のスタイリングに勉強コストをかけたくないので、&lt;code&gt;Tailwind&lt;/code&gt;のように直感的に書けるクラスを採用する。&lt;/p&gt;
&lt;p&gt;以前は、&lt;a href=&quot;https://www.nativewind.dev/&quot;&gt;NativeWind&lt;/a&gt;を使っていたのだけれど、環境構築に手間がかかるので、今回は&lt;a href=&quot;https://www.npmjs.com/package/twrnc&quot;&gt;twrnc(Tailwind React Native Classnames)&lt;/a&gt;を使うことにした。&lt;/p&gt;
&lt;p&gt;まず、&lt;code&gt;npm install twrnc&lt;/code&gt;でインストールし、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import tw from &apos;twrnc&apos;;

...
&amp;lt;Text style={tw`text-md text-red-500`}&amp;gt;Hello Tailwind React Native Classnames&amp;lt;/Text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これだけでスタイリングをすることができた。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image01.png&quot; alt=&quot;Tailwind React Native Classnames&quot; /&gt;&lt;/p&gt;
&lt;p&gt;あとはTailwind CSS IntelliSenseでうまく補完できれば最高なので調べてみる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jaredh159/tailwind-react-native-classnames/issues/321&quot;&gt;No VS Code intellisense #321&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jaredh159/tailwind-react-native-classnames/discussions/124#discussioncomment-8841211&quot;&gt;Tailwind intellisense/auto-complete support #124&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;issueとdiscussionが上がっていた。&lt;/p&gt;
&lt;p&gt;これの通り、まずは&lt;code&gt;setting.json&lt;/code&gt;の&lt;code&gt;tailwindCSS.experimental&lt;/code&gt;に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &quot;tw`([^`]*)&quot;,
    [&quot;tw.style\\(([^)]*)\\)&quot;, &quot;&apos;([^&apos;]*)&apos;&quot;],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を追加し、&lt;code&gt;tailwind.config.js&lt;/code&gt;を作成する。中身は下記のように空で問題ない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/** @type {import(&apos;tailwindcss&apos;).Config} */
module.exports = {
  content: [],
  theme: {
    extend: {},
  },
  plugins: [],
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、再起動で予測変換が効くようになった。&lt;/p&gt;
&lt;h2&gt;コードフォーマットを導入する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Eslint&lt;/code&gt;、&lt;code&gt;Prettier&lt;/code&gt;を導入したい。&lt;/p&gt;
&lt;p&gt;前回は&lt;code&gt;npm&lt;/code&gt;でインストールしたが、いろいろ調べてみると&lt;a href=&quot;https://reactnative.dev/contributing/how-to-contribute-code#coding-style&quot;&gt;コードの貢献方法&lt;/a&gt;にあるように&lt;code&gt;Prettier&lt;/code&gt;が標準っぽく書かれている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;私たちは、JavaScript コードのフォーマットに Prettier を使用しています。これにより、Prettier のエディター統合を通じて、または手動で を実行して、フォーマットの問題を自動的に修正できるため、時間と労力を節約できますyarn
run
prettier。また、コード内に存在する可能性のあるスタイルの問題を検出するために、リンターも使用します。 を実行して、コード スタイルのステータスを確認できますyarn
run lint。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;実際&lt;code&gt;package.json&lt;/code&gt;を見ると&lt;code&gt;script&lt;/code&gt;に&lt;code&gt;lint&lt;/code&gt;とあるので、まずは実行してみた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
...

√ No ESLint config found. Install and configure ESLint in this project? ... yes
ESLint is required to lint your project. Installing eslint@^8.57.0, eslint-config-expo@~8.0.1

› Installing 2 other packages using npm
› Using ~8.0.1 instead of ~8.0.1 for eslint-config-expo because this version was explicitly provided. Packages excluded from dependency validation should be listed in expo.install.exclude in package.json. Learn more: https://docs.expo.dev/more/expo-cli/#configuring-dependency-validation
&amp;gt; npm install
npm warn deprecated @humanwhocodes/config-array@0.13.0: Use @eslint/config-array instead
npm warn deprecated @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
npm warn deprecated eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.

added 157 packages, and audited 1362 packages in 12s

190 packages are looking for funding
  run `npm fund` for details

5 low severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
✔ Installed eslint@^8.57.0, eslint-config-expo@~8.0.1

ESlint has been configured 🎉

&amp;gt; npx eslint .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そうすると&lt;code&gt;ESLint&lt;/code&gt;をプロジェクトに追加されるかを聞かれ、続行すると&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        &quot;eslint&quot;: &quot;^8.57.0&quot;,
        &quot;eslint-config-expo&quot;: &quot;~8.0.1&quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;がインストールされた。&lt;/p&gt;
&lt;p&gt;ただこれだと&lt;code&gt;Prettier&lt;/code&gt;がインストールされてない。つまり&lt;code&gt;Prettier&lt;/code&gt;は標準じゃない？&lt;/p&gt;
&lt;p&gt;よくわからないけど、&lt;code&gt;Prettier&lt;/code&gt;もインストールする。&lt;/p&gt;
&lt;p&gt;&lt;s&gt;手順は公式の&lt;a href=&quot;https://docs.expo.dev/guides/using-eslint/&quot;&gt;Use ESLint and Prettier&lt;/a&gt;を参考にした。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;summary&amp;gt;公式を参考にした方法（できなかった）&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx expo install -- --save-dev prettier eslint-config-prettier eslint-plugin-prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に、&lt;code&gt;eslintrc.js &lt;/code&gt;を修正する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module.exports = {
  extends: [&apos;expo&apos;, &apos;prettier&apos;],
  plugins: [&apos;prettier&apos;],
  rules: {
    &apos;prettier/prettier&apos;: &apos;error&apos;,
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で&lt;code&gt;npm run lint&lt;/code&gt;を実行すると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
C:\dev\lazylink\hooks\useColorScheme.web.ts
   1:37  error  Replace `&apos;react&apos;` with `&quot;react&quot;`                prettier/prettier
   2:52  error  Replace `&apos;react-native&apos;` with `&quot;react-native&quot;`  prettier/prettier
  20:10  error  Replace `&apos;light&apos;` with `&quot;light&quot;`                prettier/prettier

C:\dev\lazylink\hooks\useThemeColor.ts
   6:24  error  Replace `&apos;@/constants/Colors&apos;` with `&quot;@/constants/Colors&quot;`          prettier/prettier
   7:32  error  Replace `&apos;@/hooks/useColorScheme&apos;` with `&quot;@/hooks/useColorScheme&quot;`  prettier/prettier
  11:66  error  Insert `,`                                                          prettier/prettier
  13:37  error  Replace `&apos;light&apos;` with `&quot;light&quot;`                                    prettier/prettier

C:\dev\lazylink\scripts\reset-project.js
  77:182  error  Insert `,`  prettier/prettier

C:\dev\lazylink\tailwind.config.js
  1:44  error  Delete `␍`  prettier/prettier
  2:19  error  Delete `␍`  prettier/prettier
  3:15  error  Delete `␍`  prettier/prettier
  4:11  error  Delete `␍`  prettier/prettier
  5:16  error  Delete `␍`  prettier/prettier
  6:5   error  Delete `␍`  prettier/prettier
  7:15  error  Delete `␍`  prettier/prettier
  8:3   error  Insert `⏎`  prettier/prettier

✖ 196 problems (196 errors, 0 warnings)
  196 errors and 0 warnings potentially fixable with the `--fix` option.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように大量のerror がでてきた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm run lint --fix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で潰せると思ったけど、潰れない。試しに&lt;code&gt;npx prettier --write .&lt;/code&gt;でやるとうまく整形できた。&lt;/p&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;p&gt;結局下記の方法にした。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&quot;lint&quot;: &quot;expo lint &amp;amp;&amp;amp; npx prettier --write .&quot;&lt;/code&gt;という風に&lt;code&gt;Script&lt;/code&gt;を編集した。&lt;/p&gt;
&lt;p&gt;無事に&lt;code&gt;ESLint&lt;/code&gt;と&lt;code&gt;prettier&lt;/code&gt;が動いているのを確認した。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Expoアプリの+not-found.tsxファイルの正体と「+」の意味</title><link>https://blog.nove-b.dev/posts/expo-plus-not-found-file</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/expo-plus-not-found-file</guid><content:encoded>&lt;p&gt;&lt;code&gt;Expo&lt;/code&gt;で&lt;code&gt;react native&lt;/code&gt;のアプリを作成する時、インストール時のディレクトリ構成で&lt;code&gt;+not-found.tsx&lt;/code&gt;とかいう謎のファイルがあった。たぶんというか確実に404ページではあるんだろうけれど、&lt;code&gt;+&lt;/code&gt;が付いている。&lt;/p&gt;
&lt;h2&gt;Expoアプリのファイルにある「+」の意味&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.expo.dev/develop/file-based-routing/#not-found-routes&quot;&gt;Not found routes&lt;/a&gt;のように公式には、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Expo
Router は、404 のルートを処理するために使用される特別なファイル +not-found.tsxを提供します。このルート ファイルは、ネストされたレベルからのすべての一致しないルートと一致します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一致しないルートとは、アプリのルーティング構成で定義されていないURLやパスにユーザーがアクセスした場合、そのアクセスに対応するページが見つからない状態のことを言うらしい。&lt;/p&gt;
&lt;p&gt;つまり&lt;code&gt;+&lt;/code&gt;は404ページのためにあるようなものと言っても過言じゃない？&lt;/p&gt;
&lt;p&gt;過言かもしれないけれど、今はその理解で満足することにする。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React NativeでMastodon認証を実装した</title><link>https://blog.nove-b.dev/posts/auth-mastodon-react-native</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/auth-mastodon-react-native</guid><description>React NativeでMastodon認証を実装した</description><content:encoded>&lt;p&gt;Mastodonnのクラインアント用ネイティブアプリを&lt;code&gt;React Native&lt;/code&gt;と&lt;code&gt;Expo&lt;/code&gt;で作成している。&lt;/p&gt;
&lt;p&gt;バージョンは下記の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &quot;expo&quot;: &quot;~52.0.11&quot;,
    &quot;react-native&quot;: &quot;0.76.3&quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実装自体はできたんだけれど、正直いろいろと理解が足りていないので、整理してみる。&lt;/p&gt;
&lt;h2&gt;インストールしたPackage&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&quot;expo-auth-session&quot;: &quot;^6.0.1&quot;,
&quot;expo-secure-store&quot;: &quot;^14.0.0&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;expo-auth-session&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;ブラウザベースの認証を処理するための API&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b/113674167224507515/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;最初は認証時にWebViewを開いて認証に成功したらリダイレクトURIを用いてアプリ画面に戻すという仕組みを実装しようとしたんだけれど、そもそもリダイレクトURIがわからない。&lt;code&gt;Expo&lt;/code&gt;の開発用URLを指定してみたけど、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;java.io.IOException: Remote update request not successful
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という謎のエラーが出てアプリ側に戻らない。&lt;/p&gt;
&lt;p&gt;そしてタスク管理でアプリに戻ると認証が成功しているという謎の現象が発生した。&lt;/p&gt;
&lt;p&gt;色々悩んでいたけど&lt;code&gt;expo-auth-session&lt;/code&gt;
を使用したらリダイレクトURIの作成をいい感じにやってくれた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.expo.dev/versions/latest/sdk/auth-session/&quot;&gt;Expo AuthSession&lt;/a&gt;には&lt;code&gt;expo-crypto&lt;/code&gt;
と一緒にインストールする必要があるって書いてあったけど、インストールしていない。今のところ問題はないので気にしないでおく。&lt;/p&gt;
&lt;h3&gt;expo-secure-store&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.expo.dev/versions/latest/sdk/securestore/&quot;&gt;Expo SecureStore&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Expo&lt;/code&gt;用のローカルストレージ。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 保存
await SecureStore.setItemAsync(&quot;key&quot;, value);

// 参照
await SecureStore.getItemAsync(&quot;key&quot;);

// 削除
await SecureStore.deleteItemAsync(&quot;kye&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、一通りの作業ができる。&lt;/p&gt;
&lt;h2&gt;認証に用いたMastodon API&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;${instanceUrl}/api/v1/apps&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.joinmastodon.org/methods/apps/&quot;&gt;クライアント アプリケーションを登録&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;${instanceUrl}/oauth/authorize?&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.joinmastodon.org/methods/oauth/&quot;&gt;OAuth トークンを生成および管理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;${instanceUrl}/oauth/token&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.joinmastodon.org/methods/oauth/#token&quot;&gt; API 呼び出し中に使用するアクセス トークンを取得&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;認証までのフロー&lt;/h2&gt;
&lt;h3&gt;アプリケーションを登録&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.joinmastodon.org/methods/apps/&quot;&gt;クライアント アプリケーションを登録&lt;/a&gt;APIを叩く。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Body&lt;/code&gt;に&lt;code&gt;client_name&lt;/code&gt;、&lt;code&gt;redirect_uris&lt;/code&gt;、&lt;code&gt;scopes&lt;/code&gt;、&lt;code&gt;website&lt;/code&gt;が必要になる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;client_name&lt;/code&gt;はアプリ名を指定し、&lt;code&gt;redirect_uris&lt;/code&gt;は&lt;code&gt;expo-auth-session&lt;/code&gt;を使用し作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redirect_uris: AuthSession.makeRedirectUri({
  native: &quot;{APPNAME}://redirect&quot;,
}),
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;scopes&lt;/code&gt;は&lt;a href=&quot;https://docs.joinmastodon.org/api/oauth-scopes/&quot;&gt;権限&lt;/a&gt;を指定し、&lt;code&gt;website&lt;/code&gt;はアプリのウェブサイトをインプットする。&lt;/p&gt;
&lt;p&gt;成功すると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;id&quot;: &quot;563419&quot;,
  &quot;name&quot;: &quot;Test Application&quot;,
  &quot;website&quot;: &quot;https://app.example&quot;,
  &quot;scopes&quot;: [&quot;read&quot;, &quot;write&quot;, &quot;push&quot;],
  &quot;redirect_uri&quot;: &quot;urn:ietf:wg:oauth:2.0:oob&quot;,
  &quot;redirect_uris&quot;: [&quot;urn:ietf:wg:oauth:2.0:oob&quot;],
  &quot;client_id&quot;: &quot;TWhM-tNSuncnqN7DBJmoyeLnk6K3iJJ71KKXxgL1hPM&quot;,
  &quot;client_secret&quot;: &quot;ZEaFUFmF0umgBX1qKJDjaU99Q31lDkOU8NutzTOoliw&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;が取得できる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;client_id&lt;/code&gt;、&lt;code&gt;client_secret&lt;/code&gt;は後ほど使用する。関数をまたいで使用するので、&lt;code&gt;expo-secure-store&lt;/code&gt;に保存した。&lt;/p&gt;
&lt;h3&gt;認証画面を開く&lt;/h3&gt;
&lt;p&gt;取得した&lt;code&gt;client_id&lt;/code&gt;を用い、認証URLを作成しブラウザで開く。&lt;/p&gt;
&lt;p&gt;その際、&lt;code&gt;expo-web-browser&lt;/code&gt;を使用した。&lt;a href=&quot;https://docs.expo.dev/versions/latest/sdk/webbrowser/&quot;&gt;Expo WebBrowser&lt;/a&gt;だけどインストールした記憶がないので、たぶん標準で入っていた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;react-native-webview&lt;/code&gt;とは異なり、ネイティブなブラウザモーダルを使用するらしい。&lt;/p&gt;
&lt;p&gt;使い分けの参考は下記の通り。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;要素&lt;/th&gt;
&lt;th&gt;expo-web-browser&lt;/th&gt;
&lt;th&gt;react-native-webview&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;利用シーン&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;外部リンクを簡単に開く場合&lt;/td&gt;
&lt;td&gt;ウェブページをアプリの一部として組み込む場合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;操作性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;操作不可&lt;/td&gt;
&lt;td&gt;DOM操作やイベントリスニングが可能&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UIの統合性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;外部ブラウザ風のUI（独立性あり）&lt;/td&gt;
&lt;td&gt;アプリ内に統合されたUI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;インストールの必要性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;不要（Expoに標準搭載）&lt;/td&gt;
&lt;td&gt;必要（個別にインストール）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;パフォーマンス&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;高速（ネイティブブラウザ）&lt;/td&gt;
&lt;td&gt;やや劣る可能性あり&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;で、&lt;code&gt;expo-web-browser&lt;/code&gt;には&lt;a href=&quot;https://docs.expo.dev/versions/latest/sdk/webbrowser/#webbrowseropenauthsessionasyncurl-redirecturl-options&quot;&gt;認証フローのメソッド&lt;/a&gt;がある。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const result = await WebBrowser.openAuthSessionAsync(
  authUrl, // 認証を開始するURL
  redirectUri, // 認証後にリダイレクトされるURL
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記メソッドを実行すると下記フローが走る。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;認証プロバイダーとのやり取り:&amp;lt;br&amp;gt; &lt;code&gt;authUrl&lt;/code&gt;に指定したプロバイダー（例:
GoogleやTwitter）に接続し、ユーザーが認証情報を入力できる画面を表示。&lt;/li&gt;
&lt;li&gt;リダイレクトハンドリング:&amp;lt;br&amp;gt;
認証が成功すると、プロバイダーは&lt;code&gt;redirectUri&lt;/code&gt;にリダイレクト。&amp;lt;br&amp;gt;
アプリはそのリダイレクトURLを受け取り、アクセストークンや認証コードを抽出して利用。&lt;/li&gt;
&lt;li&gt;ネイティブモーダルの使用:&amp;lt;br&amp;gt;&lt;code&gt;WebBrowser.openAuthSessionAsync&lt;/code&gt;は、ネイティブの認証モーダル（Safari
View ControllerやChrome Custom
Tabs）を使用するため、認証が安全かつシームレスに行える。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;アクセストークンの取得&lt;/h3&gt;
&lt;p&gt;認証が完了したら、認証結果に含まれる&lt;code&gt;code&lt;/code&gt;を用い、アクセストークンを取得する。その際、先ほど保存した&lt;code&gt;client_id&lt;/code&gt;、&lt;code&gt;client_secret&lt;/code&gt;を&lt;code&gt;Body&lt;/code&gt;に含める。成功後したら認証が成功したということなので、取得したアクセストークンを&lt;code&gt;expo-secure-store&lt;/code&gt;に保存して、アクセストークンを持っている人用のページにリダイレクトする。&lt;/p&gt;
&lt;h2&gt;ルートに関係ないディレクトがルートに紐づく問題&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;app&lt;/code&gt;以下に&lt;code&gt;model&lt;/code&gt;という型フォルダを作成したら、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;./model/App.ts&quot; is missing the required default export. Ensure a React component is exported as default.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが吐き出された。どうやら&lt;code&gt;React native&lt;/code&gt;はファイル構造に基づいてルートを自動生成するらしい。&lt;/p&gt;
&lt;p&gt;しかしこれはルート判定してほしくない。除外判定の仕方がわからなかったので、&lt;code&gt;app&lt;/code&gt;と同階層に&lt;code&gt;src&lt;/code&gt;を作成しそこに格納した。&lt;/p&gt;
&lt;p&gt;これが正しいかはわからない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>ExpoとReact Nativeで作成したアプリのAPKを作成する</title><link>https://blog.nove-b.dev/posts/expo-react-native-apk</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/expo-react-native-apk</guid><content:encoded>&lt;p&gt;作成中のマストドンクライアントアプリの1つの機能が完成したので実機で活用したいという思いが生まれ、&lt;code&gt;apk&lt;/code&gt;を作成することにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.expo.dev/build/setup/&quot;&gt;最初のビルドを作成する&lt;/a&gt;を参考にして進めていき、無事に&lt;code&gt;apk&lt;/code&gt;を作成することに成功した。&lt;/p&gt;
&lt;h2&gt;EAS CLIをインストール&lt;/h2&gt;
&lt;p&gt;ドキュメントが充実しているので、問題なくできるだろうと踏んでいたのだが、最初で壁にぶつかった。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install -g eas-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というコマンドで&lt;code&gt;EAS CLI&lt;/code&gt;をインストールするのだが、なぜうまくインストールされない。&lt;/p&gt;
&lt;p&gt;なんか&lt;code&gt;Volta&lt;/code&gt;の権限でうまく入らなかったので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;C:\\Program Files\\Volta\\npm.exe&quot; install -g eas-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を管理者権限で実行したら成功した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Windows\System32&amp;gt;eas --version
eas-cli/14.2.0 win32-x64 node-v20.15.0
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;npm install -g eas-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;npm install -g eas-cli&lt;/code&gt;ではシステムの&lt;code&gt;PATH&lt;/code&gt;にあるデフォルトの&lt;code&gt;npm&lt;/code&gt;を使うけど、&lt;code&gt;&quot;C:\\Program Files\\Volta\\npm.exe&quot; install -g eas-cli&lt;/code&gt;は&lt;code&gt;Volta&lt;/code&gt;で管理している&lt;code&gt;npm&lt;/code&gt;を使用するという違いがあるらしい。&lt;/p&gt;
&lt;h2&gt;ログインする&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;PS C:\dev\appname&amp;gt; eas login
Log in to EAS with email or username (exit and run eas login --help to see other login options)
√ Email or username ... email
√ Password ... ********
Logged in
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;プロジェクトを構成する&lt;/h2&gt;
&lt;p&gt;AS
Build 用に Android または iOS プロジェクトを構成するためにコマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PS C:\dev\appname&amp;gt; eas build:configure
EAS project not configured.
√ Would you like to automatically create an EAS project for @username/appname? ... yes
✔ Created @username/appname: https://expo.dev/accounts/username/projects/appname on Expo
✔ Linked local project to EAS project xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
💡 The following process will configure your iOS and/or Android project to be compatible with EAS Build. These changes only apply to your local project files and you can safely revert them at any time.

√ Which platforms would you like to configure for EAS Build? » All

√ Generated eas.json. Learn more: https://docs.expo.dev/build-reference/eas-json/

🎉 Your project is ready to build.

- Run eas build when you are ready to create your first build.
- Once the build is completed, run eas submit to upload the app to app stores.
- Learn more about other capabilities of EAS Build: https://docs.expo.dev/build/introduction
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Android エミュレーターとデバイス用の APK をビルドする&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.expo.dev/build-reference/apk/#configuring-a-profile-to-build-apks&quot;&gt;APK を作成するためのプロファイルの設定&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;eas.json&lt;/code&gt;を下記のように変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;build&quot;: {
    &quot;preview&quot;: {
      &quot;android&quot;: {
        &quot;buildType&quot;: &quot;apk&quot;
      }
    },
    &quot;preview2&quot;: {
      &quot;android&quot;: {
        &quot;gradleCommand&quot;: &quot;:app:assembleRelease&quot;
      }
    },
    &quot;preview3&quot;: {
      &quot;developmentClient&quot;: true
    },
    &quot;preview4&quot;: {
      &quot;distribution&quot;: &quot;internal&quot;
    },
    &quot;production&quot;: {}
  }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そのうえで下記コマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PS C:\dev\appname&amp;gt; eas build -p android --profile preview
We detected that you are building for the &quot;internal&quot; distribution. Resolving the environment for environment variables used during the build to &quot;preview&quot;. Set the &quot;environment&quot; field in the build profile if you want to specify the environment manually.
No environment variables with visibility &quot;Plain text&quot; and &quot;Sensitive&quot; found for the &quot;preview&quot; environment on EAS servers.

📝  Android application id Learn more: https://expo.fyi/android-package
√ What would you like your Android application id to be? ... com.username.appname
No remote versions are configured for this project, versionCode will be initialized based on the value from the local project.
✔ Initialized versionCode with 1.
✔ Using remote Android credentials (Expo server)
√ Generate a new Android Keystore? ... yes
Detected that you do not have keytool installed locally.
✔ Generating keystore in the cloud...
✔ Created keystore

Compressing project files and uploading to EAS Build. Learn more: https://expo.fyi/eas-build-archive
✔ Compressed project files 1s (7.7 MB)
✔ Uploaded to EAS 1s
⌛️ Computing the project fingerprint is taking longer than expected...
⏩ To skip this step, set the environment variable: EAS_SKIP_AUTO_FINGERPRINT=1
✔ Computed project fingerprint

Build details: https://expo.dev/accounts/username/projects/appname/builds/xxxxxxxxxxxxxxxxxxxxx

Waiting for build to complete. You can press Ctrl+C to exit.
✔ Build finished

QRコードが表示される


🤖 Open this link on your Android devices (or scan the QR code) to install the app:
https://expo.dev/accounts/username/projects/appname/builds/xxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;iOSシミュレーター用のビルド&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.expo.dev/build-reference/simulators/#configuring-a-profile-to-build-for-simulators&quot;&gt;APK を作成するためのプロファイルの設定&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;eas.json&lt;/code&gt;を下記のように変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;build&quot;: {
    &quot;preview&quot;: {
      &quot;ios&quot;: {
        &quot;simulator&quot;: true
      }
    },
    &quot;production&quot;: {}
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そのうえで下記コマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; eas build -p ios --profile preview
We detected that you are building for the &quot;internal&quot; distribution. Resolving the environment for environment variables used during the build to &quot;preview&quot;. Set the &quot;environment&quot; field in the build profile if you want to specify the environment manually.
No environment variables with visibility &quot;Plain text&quot; and &quot;Sensitive&quot; found for the &quot;preview&quot; environment on EAS servers.

📝  iOS Bundle Identifier Learn more: https://expo.fyi/bundle-identifier
√ What would you like your iOS bundle identifier to be? ... com.username.appname
No remote versions are configured for this project, buildNumber will be initialized based on the value from the local project.
✔ Initialized buildNumber with 1.

Compressing project files and uploading to EAS Build. Learn more: https://expo.fyi/eas-build-archive
✔ Compressed project files 1s (7.7 MB)
✔ Uploaded to EAS 1s
✔ Computed project fingerprint

Build details: https://expo.dev/accounts/username/projects/appname/builds/xxxxxxxxxxxxxxx

Waiting for build to complete. You can press Ctrl+C to exit.
✔ Build finished

QRコードが表示される

🍏 Open this link on your iOS devices (or scan the QR code) to install the app:
https://expo.dev/accounts/username/projects/appname/builds/xxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt; iOS&lt;/code&gt;はシミュレーターようなので実機での確認はできなかった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2024年12月】2024年が終わりを迎える</title><link>https://blog.nove-b.dev/posts/2024-12</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-12</guid><description>2024年12月に考えたこととか</description><content:encoded>&lt;hr /&gt;
&lt;h2&gt;12月に読んだ本&lt;/h2&gt;
&lt;p&gt;読んだ本は下記の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3OGbUh9&quot;&gt;四畳半タイムマシンブルース【電子特典付き】 四畳半シリーズ (角川文庫) &lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;久々に四畳半のシリーズ読んだらやっぱり楽しかった。大学生時代しか楽しめない本だと思っていたけど、まだまだ現役だった。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4ix6a76&quot;&gt;夜空に泳ぐチョコレートグラミー（新潮文庫）&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;デビュー作なの？筆力と言い、構成と言い、化け物すぎる。久々に衝撃の読者体験だった👏👏&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3ZU9W3i&quot;&gt;八月の御所グラウンド (文春e-book)&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;面白かった。大学生×歴史で読みたい万城目学が一気に読めた。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4fqX1ui&quot;&gt;六人の嘘つきな大学生 (角川文庫)&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;思っていたより散りばめられてた。それにしても&lt;a href=&quot;https://amzn.to/3VMsP5L&quot;&gt;何者&lt;/a&gt;といい就活は物語を生む。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3BymFPY&quot;&gt;キネマの神様 (文春文庫)&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;再読だけど、感動した。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;箱根に行く&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/hanaori.jpg&quot; alt=&quot;はなおり&quot; /&gt;&lt;/p&gt;
&lt;p&gt;2歳 2ヶ月。今年2度目の旅行は妻の両親を連れ箱根に行った。冬晴れで気温も丁度よく、快適な旅行日和だった。彫刻の森を散歩し、ガラスの森美術館でクリスマス気分を味わった。双子の片方（重い方）は「ばあばばあば」と抱っこせがみ、ずっと抱っこで歩く姿を見て大変辛そうだなと思った。&lt;/p&gt;
&lt;p&gt;宿は「はなをり」にした。口コミがとてもよく、ランキングにも登場するので結構期待したんだけど、そんなに良くなかった。子どもと旅行に行くのであれば、迷わず星野リゾートにするのが一番いい。個人的に好きではないけど、子供連れという条件が付けば間違いない。&lt;/p&gt;
&lt;p&gt;2日目はロープウェイに乗って、箱根元宮に行き、海賊船に乗って箱根神社に行った。最近乗り物に興味出てきたので、たくさん乗せてあげようという魂胆だったが、初見で謎すぎたのか、そこまで反応を示さなかった。双子の片方（重い方）は「ばあばばあば」と抱っこせがみ、ずっと抱っこで歩く姿を見て大変辛そうだなと思った（2日連続）。特に2日目は階段が多く、本当に......。&lt;/p&gt;
&lt;h2&gt;良く喋る&lt;/h2&gt;
&lt;p&gt;ばあばばあばと言うように2歳の誕生日を迎え、急に喋りだすようになった。家に帰れば「おかーり」と言ってくれるし、ほどほどに会話が成り立つようになった。そうなると急に可愛さが増す。ずっと一緒にいるわけじゃないのでわからないことも多いけど、喋れるようになって泣いて怒ることが減った気がする。たぶん、ずっと表現ができずに泣いていたのか、泣くことだけが唯一の表現方法だったのか。&lt;/p&gt;
&lt;p&gt;夜も布団でよく寝てくれるようになった。絵本を2冊読み、「げんこつ山」と「きんらきらぽん」を歌ったら寝るという謎のルーティンができた。泣いて抱っことかなく、あまりにすんなり寝てくれるので、自分も思わず寝落ちしてしまうことが増えた。&lt;/p&gt;
&lt;h2&gt;2回目のクリスマス&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/xmas.jpg&quot; alt=&quot;クリスマス&quot; /&gt;&lt;/p&gt;
&lt;p&gt;今年のクリスマスは平日だったので、前の日曜日におこなった。おこなったといっても自分は何もできない。料理もできなければ、ケーキも作れないので、ただただ申し訳ない気持ちでおいしくいただいた。子どもたちもおいしそうにケーキをを頬ばり幸せな気持ちになった。&lt;/p&gt;
&lt;p&gt;最近は親の真似で写真を撮りたがり、スマホを奪おうとするので、プレゼントはキッズカメラにした。子どもの撮った写真を見ることができるので、1つの思い出になる気がする。&lt;/p&gt;
&lt;h2&gt;結局ポッドキャストに戻ってきた&lt;/h2&gt;
&lt;p&gt;ずっと仕事中とか運転中にポッドキャストを聞いてきたんだけど、一部ポッドキャストに配信していない動画等があり、youtubeを見るようになった。youtubeは広告だらけなので、有料版に登録した。お金払っているのでyoutubeをたくさん見ないといけないという貧乏魂が燃え、すべてのコンテンツをyoutubeで見るようになり、他のコンテンツを見なくなった。&lt;/p&gt;
&lt;p&gt;ただなんとなくポッドキャストの方がコンテンツの質がいい気がする。そこで結局ポッドキャストに戻ってきた。来年はオーディブルとか試してみようかと思っている。&lt;/p&gt;
&lt;h2&gt;引き続きマストドンのクライアントを作成している&lt;/h2&gt;
&lt;p&gt;先月、作ろうと決意したマストドンのクライアントアプリを作っている。着手できる時間が限られているので、全然進まないけど、止まってはいない。ネイティブアプリ作成の概念がよくわからず苦労することもあるけど、書いているコードが&lt;code&gt;React Native&lt;/code&gt;なのでそこまで苦痛じゃない。リリースがいつになるか見当もつかないほどのんびりペースだけど、熱量は変わらずあるので悪い状況じゃない。ただリリースまでたどり着かないと最悪なのでまずは最低限でリリースしたいと思っている。&lt;/p&gt;
&lt;h2&gt;今年が終わる&lt;/h2&gt;
&lt;p&gt;また今年が終わる。何も成し遂げていないけど、歳を重ねる。何もないけど2024年もまとめようと思っている。&lt;/p&gt;
&lt;p&gt;2024年まとめも書こうと思っているので、少し適当になったけど、なんとか書ききった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>2024年を振り返ってみる</title><link>https://blog.nove-b.dev/posts/2024-all</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2024-all</guid><content:encoded>&lt;h2&gt;年が明けた、2024 + 1&lt;/h2&gt;
&lt;p&gt;去年に引き続き、また年が明けた。そして去年に引き続き、ジャニーズのカウントダウンは開催されなかった。すると当然のように毎年祝っていた堂本光一の誕生日を意識することなく、新年を迎えることになった。&lt;/p&gt;
&lt;p&gt;ちょっとしたことで世界はガラッと変わる。テレビから何人かの有名人が消え、M1の審査員もガラッと変わった。&lt;/p&gt;
&lt;p&gt;変わらないものはないなんて言うけど、時間の進み具合は多分変わっていない。去年も今年も同じくらいの時が経ち、年が明ける。そしてたぶん来年も同じくらいの時が経てば、年が明ける。&lt;/p&gt;
&lt;p&gt;それでもどうしてか、歳を取るにつれ、１年が短くなっている。小学生の時は５分休みでドッチボールができるくらいだったのに、いまは５分じゃ何もできない。１分の密度が明らかに変わってしまった。天才じゃないので１分１秒を大切にしていかなくちゃいけないのに、１分１秒をドブに捨ててきたことに気がついた。&lt;/p&gt;
&lt;p&gt;年が明け、そのことに気が付いたのであれば、今年もまた年を重ねた意味があったのかもしれない。&lt;/p&gt;
&lt;h2&gt;桃鉄と年末&lt;/h2&gt;
&lt;p&gt;年末から年始にかけて、恒例のようになった桃鉄大会が妻と繰り広げられている。テレビも見たいというので、昔使っていたテレビを引っ張りだし、桃鉄用に使っている。つまりリビングに２台のテレビがある。どう考えたっておかしな状況であるんだけれど、年末年始はそれを許してくれる高揚感がある。桃鉄は毎年100年で行うんだけれど、完走したことがない。2024～2025年、今年こそは完走したいものである。&lt;/p&gt;
&lt;p&gt;正解は１年後に。&lt;/p&gt;
&lt;h2&gt;2024年を振り返る&lt;/h2&gt;
&lt;p&gt;さて、そういうわけで今年を振り返ることにする。なんて、書き出して思ったけど、驚くべきことに、今年のことをなんにも覚えていない。&lt;/p&gt;
&lt;p&gt;仕方がないので、書いたブログを読み直した。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GO&lt;/code&gt;でブログをリプレースして以降、毎月の振り返りを書いているので３月スタートになっていた。&lt;/p&gt;
&lt;h2&gt;月ごとの振り返り&lt;/h2&gt;
&lt;p&gt;1月と2月はそういうわけで記録がない故に記憶もない。……、本当に何も覚えていない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-3/&quot;&gt;2024年3月の月報&lt;/a&gt;
&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-4/&quot;&gt;2024年4月の月報&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;3月と4月はネイティブアプリ作成していたらしい。今年の目標に掲げていたので、それを達成できるように頑張っていたらしい。ただこれは達成できなかったので、結果的に無駄な頑張りだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-5/&quot;&gt;2024年5月の月報&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;5月は熱海旅行に行った。観光旅行は初めてだったので不安と期待があったけど、楽しかった。星野リゾートリゾナーレは子連れに良いという教訓を得た。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-6/&quot;&gt;【2024年6月】読書できず、目標も完遂できず、ウィルス性腸炎が猛威を振るう&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;6月は自分を除く皆がロタウイルスに感染した。子どもは本当にいろいろ病気になる。まあ、そうやって強くなっていくので仕方ないけれど、保育園入園後が恐ろしい。保活もこの月から本格的に開始した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-7/&quot;&gt;【2024年7月】読書できず、仕事に追われている&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;7月からは仕事が忙しくなった。反省点も多く、勉強になった案件だった。ただ何より楽しかった。なんでこんなに仕事してるんだって思うこともあったけど、要件的にも楽しい案件だった。このときは9月には終わると思ってたけど、10月まで仕事漬けになった。&lt;/p&gt;
&lt;p&gt;そんな中でSurfaceを購入してた。割高だとは思うけど、なかなかいい買い物をしたと思っている。ただフラグシップモデルを買うともう後戻りできないんだよなあ。次はジェネリックを賢く買いたい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-9/&quot;&gt;【2024年8月、9月】とにかく仕事に追われる&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;9月は双子と妻の誕生日があった。アンパンマンミュージアムに行くことができた。カレーカレーとはしゃぐ子どもは可愛かった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-10/&quot;&gt;【2024年10月】人間的生活を取り戻した&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;10月は仕事が終わり、自分の時間を作れるようになったのでMastodonのサーバーを立ち上げた。今年の目標の1つだったので、少し肩の荷がおりた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-11/&quot;&gt;【2024年11月】2024年の目標はきっと無理&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;11月は無事に保活も完了した。結果を待ちなので完了してはいないんだけど、やれることはやったので、あとは待つことしかできない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2024-12/&quot;&gt;【2024年12月】2024年が終わりを迎える&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;12月は本格的にアプリを作り始めた。いろいろ悩んだけど、&lt;code&gt;react native&lt;/code&gt;を採用して、本当に少しづつ進めている。あと箱根旅行に行った。結果今年は2回旅行に行けた。来年は妻の育休が終わるので、それまでに色々遊びに行きたい。&lt;/p&gt;
&lt;h2&gt;今年買って良かったもの&lt;/h2&gt;
&lt;p&gt;恒例なのでまとめておく。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4fIecrf&quot;&gt;[Secrid]セクリッド シークリッド スリムウォ- レット Slim Wallet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4h5hpCt&quot;&gt;Coperta 【保育士が推薦】ヒップシート だっこひも&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3DB3kOv&quot;&gt;Surface Pro（第 11 世代）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3W2cFFB&quot;&gt;QCY Crossky C30 イヤーカフ イヤホン&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;意外と少なかった。ただ買った商品も少ないので、当たり率は高かったと思ってる。&lt;/p&gt;
&lt;p&gt;特にコスパ最強だったのはイヤホン。今までイヤーカフ型のambieを使っていた。イヤーカフ型の先駆けだし、首掛けワイヤレス×1個、フルワイヤレス×2個とお世話になったけど、QCY
Crossky
C30のほうが圧倒的にコスパが良い。料金は3分の1で、ambieより音質がいい。そういうわけで、今後はQCY
Crossky
C30を選ばないわけにはいかなくなった。イヤフォン業界にイヤーカフ型のながら聞きという、風穴を開けてくれたambieには感謝してもしきれない。ありがとう、ambie。ということで乗り換えた。&lt;/p&gt;
&lt;p&gt;フラグシップモデルということで言えば、サーフェスも購入した。満足できる買い物だったけど、やっぱりコスパ悪い気がする。せっかくWindowsOSで多くの種類から選ぶことができるので、他の企業も追いつけ追い越せで、セパレート型のパソコンジャンルで切磋琢磨して、どんどんコスパの良いパソコンを出して欲しいと願ってやまない。&lt;/p&gt;
&lt;h2&gt;今年の目標と来年の目標&lt;/h2&gt;
&lt;p&gt;まず年始に考えた目標は、ほとんど達成できなかった。ずっと時間がないって言ってたけど、そういう問題じゃない気もしている。&lt;/p&gt;
&lt;p&gt;そもそも達成できると考えて目標を立てているのだろかということ立ち返って考えてみると、決してそんなことないことに気がつく。&lt;/p&gt;
&lt;p&gt;今年たてた目標はできればやりたいという願望にしか過ぎない。&lt;/p&gt;
&lt;p&gt;そこで来年は目標を一つに絞ることにする。で、達成できたら次の目標を立てる。そのうえで来年は大小限らず5つの目標を達成できるようにする。&lt;/p&gt;
&lt;p&gt;まず記念すべき1つ目はアプリをリリースする。目標は4月まで。&lt;/p&gt;
&lt;p&gt;達成できるように頑張る。&lt;/p&gt;
&lt;p&gt;さて、よろしく2025年、ありがとう、2024年。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React Nativeで無限スクロールのタイムラインを作成した</title><link>https://blog.nove-b.dev/posts/react-native-infinite-scroll-timeline</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/react-native-infinite-scroll-timeline</guid><content:encoded>&lt;p&gt;Mastodonのクライアントアプリを作るうえで最もコアな機能であるタイムラインを作成した。無限スクロールを実装するためにいろいろと調べたりしたのでまとめておく。&lt;/p&gt;
&lt;h2&gt;FlatListが優秀&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://reactnative.dev/docs/flatlist&quot;&gt;FlatList&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完全なクロスプラットフォーム。&lt;/li&gt;
&lt;li&gt;オプションの水平モード。&lt;/li&gt;
&lt;li&gt;設定可能なビューアビリティ コールバック。&lt;/li&gt;
&lt;li&gt;ヘッダーのサポート。&lt;/li&gt;
&lt;li&gt;フッターのサポート。&lt;/li&gt;
&lt;li&gt;セパレーターのサポート。&lt;/li&gt;
&lt;li&gt;引っ張って更新します。&lt;/li&gt;
&lt;li&gt;スクロールの読み込み。&lt;/li&gt;
&lt;li&gt;ScrollToIndex のサポート。&lt;/li&gt;
&lt;li&gt;複数列のサポート。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という多くの機能をサポートしているリストコンポーネント。&lt;/p&gt;
&lt;p&gt;今回はタイムラインの無限スクロールを実現したいということで、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;リストを引っ張り更新&lt;/li&gt;
&lt;li&gt;リストのそこについたら再フェッチ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上記２つが実現できればいい。&lt;/p&gt;
&lt;p&gt;そしてその２つは&lt;code&gt;FlatList&lt;/code&gt;に標準搭載されている。&lt;/p&gt;
&lt;h3&gt;リストを引っ張り更新&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;onRefresh&lt;/code&gt; という&lt;code&gt;Props&lt;/code&gt;が用意されている。&lt;/p&gt;
&lt;p&gt;このイベントで最新情報を取得し、&lt;code&gt;useState&lt;/code&gt;を更新すればいい。&lt;/p&gt;
&lt;h3&gt;リストのそこについたら再フェッチで無限スクロール&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;onEndReached&lt;/code&gt;という &lt;code&gt;Props&lt;/code&gt;が用意されている。&lt;/p&gt;
&lt;p&gt;このイベントで最新情報を取得し、&lt;code&gt;useState&lt;/code&gt;を更新すればいい。&lt;/p&gt;
&lt;p&gt;その際スクロールのタイミングで重複のデータが&lt;code&gt;set&lt;/code&gt;されることがあった。重複チェックをすることで解決した。&lt;/p&gt;
&lt;p&gt;また&lt;code&gt;onEndReachedThreshold&lt;/code&gt;という&lt;code&gt;Props&lt;/code&gt;を使った。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;onEndReachedThreshold: 0 ~
1の間の数値でどのくらいの距離でonEndReachedを呼び出すかを決められます。0が一番近くで、1が一番遠いです。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という記事を参照したのだけれど、公式の&lt;code&gt;Props&lt;/code&gt;には明記されていなかった。&lt;/p&gt;
&lt;p&gt;機能しているかを確認する必要がある。&lt;/p&gt;
&lt;p&gt;##その他、実装した機能&lt;/p&gt;
&lt;h3&gt;ボトムメニューのタブクリックでFlatListのトップにスクロールする&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const flatListRef = useRef&amp;lt;FlatList&amp;lt;Interface&amp;gt;&amp;gt;(null);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;レンダリング時にドムを取得しておき、タブクリックで書きイベントを発火させる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (flatListRef.current) {
  flatListRef.current.scrollToOffset({ animated: true, offset: 0 });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;スクロールバーを非表示にする&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;showsVerticalScrollIndicator&lt;/code&gt;という&lt;code&gt;Props&lt;/code&gt;を&lt;code&gt;false&lt;/code&gt;にする。&lt;/p&gt;
&lt;h2&gt;まだ実装していないけど試したい機能&lt;/h2&gt;
&lt;h3&gt;List~~~Componentを活用する&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ListEmptyComponent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ListFooterComponent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ListHeaderComponent&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特に&lt;code&gt;ListFooterComponent&lt;/code&gt;は無限スクロール時の読み込みに使えそうなのでUI改善で使っていきたい。&lt;/p&gt;
&lt;p&gt;たぶんこれくらい。&lt;/p&gt;
&lt;p&gt;使った&lt;code&gt;Props&lt;/code&gt;は以下の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        ref={flatListRef}
        data={timeline}
        keyExtractor={(item) =&amp;gt; item.id}
        onEndReached={onEndReached}
        onEndReachedThreshold={1}
        onRefresh={onRefresh}
        refreshing={refreshing}
        extraData={timeline}
        showsVerticalScrollIndicator={false}
        renderItem={({ item, index }) =&amp;gt; {}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>nove-b</author></item><item><title>useStateの型、Dispatch&lt;SetStateAction&lt;T&gt;&gt; についてとジェネリック型</title><link>https://blog.nove-b.dev/posts/typescript-react-usestate-dispatch-generic</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/typescript-react-usestate-dispatch-generic</guid><content:encoded>&lt;h2&gt;useStateの型&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;useState&lt;/code&gt;の状態管理関数を&lt;code&gt;Props&lt;/code&gt;で渡すとき、受け取る側は&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dispatch&amp;lt;SetStateAction&amp;lt;T&amp;gt;&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という方で受け取ることになる。&lt;/p&gt;
&lt;h2&gt;ジェネリクスのメリットがいまいち&lt;/h2&gt;
&lt;p&gt;関係ないけどずっと気になっていた「ジェネリクスのメリットがいまいちピンとこない件」について、ついでに調べてみることにした。&lt;/p&gt;
&lt;p&gt;例えば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 文字列を入力し、文字列を出力する関数
const returnText = (input: string): string =&amp;gt; {
  return input;
};

// 数値を入力し、数値を出力する関数
const returnNumber = (input: number): number =&amp;gt; {
  return input;
};

console.log(returnText(&quot;hello world&quot;), &quot;returnText&quot;);
console.log(returnNumber(0), &quot;returnNumber&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という関数が存在した時、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const returnTextOrNumber = (input: string | number): string | number =&amp;gt; {
  return input;
};

console.log(returnTextOrNumber(&quot;hello world&quot;), &quot;returnTextOrNumber&quot;);
console.log(returnTextOrNumber(0), &quot;returnTextOrNumber&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じにまとめたくなる。&lt;/p&gt;
&lt;p&gt;これをジェネリック型にすると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const returnTextOrNumberGeneric = &amp;lt;T extends string | number&amp;gt;(input: T): T =&amp;gt; {
  return input;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じになる。&lt;/p&gt;
&lt;h3&gt;型ガードが必要&lt;/h3&gt;
&lt;p&gt;同じように感じるけど、&lt;code&gt;returnTextOrNumber&lt;/code&gt;の場合は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const a: string | number = returnTextOrNumber(&quot;hello world&quot;);
const b: string | number = returnTextOrNumber(0);

console.log(a.length);
// Property &apos;length&apos; does not exist on type &apos;string | number&apos;.
// Property &apos;length&apos; does not exist on type &apos;number&apos;

console.log(b + 1);
// Operator &apos;+&apos; cannot be applied to types &apos;string | number&apos; and &apos;number&apos;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;string&lt;/code&gt;と&lt;code&gt;number&lt;/code&gt;のどちらが返ってくる確定していないので、コンパイルエラーが出る。&lt;/p&gt;
&lt;p&gt;実行するためには&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (typeof a === &quot;string&quot;) {
  console.log(a.length);
}
if (typeof b === &quot;number&quot;) {
  console.log(b + 1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように型ガードする必要がある。&lt;/p&gt;
&lt;h3&gt;コンパイラーをだませる&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const b: string | number = returnTextOrNumber(0) as string;
console.log(b.length);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;bは0なので&lt;code&gt;length&lt;/code&gt;が存在しないが、&lt;code&gt;as string&lt;/code&gt;で強制的に文字列とコンパイラーと認識させられる。&lt;/p&gt;
&lt;p&gt;これはコード的負の遺産になる。&lt;/p&gt;
&lt;h3&gt;ジェネリック型は堅牢でコード量が少ない&lt;/h3&gt;
&lt;p&gt;対照的にジェネリック型である&lt;code&gt;returnTextOrNumberGeneric &lt;/code&gt;の場合は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const a = returnTextOrNumberGeneric&amp;lt;string&amp;gt;(&quot;hello world&quot;);
const b = returnTextOrNumberGeneric&amp;lt;number&amp;gt;(0);

console.log(a.length);
console.log(b + 1);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;関数実行時に入出力共に型を指定し確定できるので、コンパイルエラーがでない。&lt;/p&gt;
&lt;p&gt;また&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const b = returnTextOrNumberGeneric&amp;lt;number&amp;gt;(0) as string;
// Conversion of type &apos;number&apos; to type &apos;string&apos; may be a mistake because neither type sufficiently overlaps with the other. If this // was intentional, convert the expression to &apos;unknown&apos; first.(2352)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;強制的に異なる方でコンパイラーを納得させようとしても不可能になり、堅牢制が向上した。&lt;/p&gt;
&lt;p&gt;実際に整理してみるとジェネリック型の恩恵がよくわかった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React Nativeで動的にナビゲーションヘッダー文言を設定する方法</title><link>https://blog.nove-b.dev/posts/react-native-dynamic-navigation-header</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/react-native-dynamic-navigation-header</guid><content:encoded>&lt;h2&gt;実現コード&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;const navigation = useNavigation();
useLayoutEffect(() =&amp;gt; {
  if (response &amp;amp;&amp;amp; navigation) {
    navigation.setOptions({
      title: `${response}`,
    });
  }
}, [navigation, response]);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;useLayoutEffectって？&lt;/h2&gt;
&lt;p&gt;実装していて、&lt;code&gt;useLayoutEffect&lt;/code&gt;っていう&lt;code&gt;hooks&lt;/code&gt;が聞き覚えなさ過ぎて、&lt;code&gt;react native&lt;/code&gt;専用の&lt;code&gt;hooks&lt;/code&gt;だと思っていたけど、調べると&lt;code&gt;react&lt;/code&gt;が用意している&lt;code&gt;hooks&lt;/code&gt;らしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ja.react.dev/reference/react/useLayoutEffect&quot;&gt;useLayoutEffect&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;useLayoutEffect は &lt;a href=&quot;https://ja.react.dev/reference/react/useEffect&quot;&gt;useEffect&lt;/a&gt;
の一種ですが、ブラウザが画面を再描画する前に実行されます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことで、さらに、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;useLayoutEffect はパフォーマンスを低下させる可能性があります。可能な限り
&lt;a href=&quot;https://ja.react.dev/reference/react/useEffect&quot;&gt;useEffect&lt;/a&gt;
を使用することを推奨します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことだった。できる限り使わないでほしいとのことなので知らなくても無理はなかったかもしれない。&lt;/p&gt;
&lt;p&gt;今回は、&lt;code&gt;useLayoutEffect&lt;/code&gt;を使用することで、タイトルが描画される前に処理が実行されるため、新しいタイトルが即座に反映されるようになっている。&lt;/p&gt;
&lt;p&gt;ただこのコードだと、&lt;code&gt;response&lt;/code&gt;が取得されるまでは元のタイトルが表示されるので、&lt;code&gt;response&lt;/code&gt;が&lt;code&gt;false&lt;/code&gt;の時の条件を付与する必要があるということにいまさら気が付いた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>AngularプロジェクトでPlaywrightを導入しTypeScriptで自動E2Eテストを実行する</title><link>https://blog.nove-b.dev/posts/angular-playwright-typescript-e2e-testing</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/angular-playwright-typescript-e2e-testing</guid><content:encoded>&lt;h2&gt;E2E（イーツーイー）&lt;/h2&gt;
&lt;p&gt;英語の「End-to-End（エンドツーエンド）」の略で、「端から端まで」を意味する。
&lt;code&gt;E2E&lt;/code&gt;テストはユーザーの視点からアプリケーション全体の動作を確認し、機能の一貫性と信頼性を保証する手法すること。&lt;/p&gt;
&lt;h2&gt;E2Eテストの自動化&lt;/h2&gt;
&lt;p&gt;自動化するツールはいくつかあり、それぞれメリットデメリットがあるっぽい。下記は [&lt;a href=&quot;https://tech.techtouch.jp/entry/e2e-testing-tool&quot;&gt;ブラウザ拡張のE2Eテストを検討してみた（Playwright、Puppeteer、Cypress）&lt;/a&gt;とChatGPTの情報を混ぜ合わせた、メリットデメリット表。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;項目&lt;/th&gt;
&lt;th&gt;Playwright&lt;/th&gt;
&lt;th&gt;Puppeteer&lt;/th&gt;
&lt;th&gt;Cypress&lt;/th&gt;
&lt;th&gt;Selenium&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;サポートブラウザ&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Chromium, Chrome, Edge, Firefox, Webkit (Safari)&lt;/td&gt;
&lt;td&gt;Chrome, Firefox&lt;/td&gt;
&lt;td&gt;Chrome, Edge, Firefox, Electron&lt;/td&gt;
&lt;td&gt;Chrome, Edge, Firefox, Safari, IE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;テストツールの有無&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🟡 (Jest を使えば可能)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🟡 (外部ライブラリが必要)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;複数タブ / ウィンドウ&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🛑&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shadow DOM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🟡 (aria または pierce セレクタを使えば可能)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🟡 (限定的なサポート)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ブラウザ拡張&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🟡&lt;/td&gt;
&lt;td&gt;🟡 (一部サポート)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;要素の特定&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;🟡&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🟡&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;要素の自動待機&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🟡&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🛑 (手動で記述が必要)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;スクリーンショット&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;動画&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🛑&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🛑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;実行速度&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🟡 (ブラウザ依存でやや遅い)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;これだけ見ると&lt;code&gt;Playwright&lt;/code&gt;が有望な気がする。気になるのは&lt;strong&gt;要素の特定&lt;/strong&gt;なので調べてみた結果、&lt;code&gt;Puppeteer&lt;/code&gt;と&lt;code&gt;Cypress&lt;/code&gt;は&lt;code&gt;jQuery&lt;/code&gt;、&lt;code&gt;javascript&lt;/code&gt;での記述で取得できるけど、&lt;code&gt;Playwright&lt;/code&gt;は独特な記法になるということだったので、特段問題なさそうだった。&lt;/p&gt;
&lt;h2&gt;Playwrightをインストールする&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm install -D @playwright/test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;長いプロジェクトで&lt;code&gt;node&lt;/code&gt;のバージョンが&lt;code&gt;v16.13.2&lt;/code&gt;だったので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;m WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: &apos;@playwright/test@1.49.1&apos;,
npm WARN EBADENGINE   required: { node: &apos;&amp;gt;=18&apos; },
npm WARN EBADENGINE   current: { node: &apos;v16.13.2&apos;, npm: &apos;8.1.2&apos; }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: &apos;playwright@1.49.1&apos;,
npm WARN EBADENGINE   required: { node: &apos;&amp;gt;=18&apos; },
npm WARN EBADENGINE   current: { node: &apos;v16.13.2&apos;, npm: &apos;8.1.2&apos; }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: &apos;playwright-core@1.49.1&apos;,
npm WARN EBADENGINE   required: { node: &apos;&amp;gt;=18&apos; },
npm WARN EBADENGINE   current: { node: &apos;v16.13.2&apos;, npm: &apos;8.1.2&apos; }
npm WARN EBADENGINE }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;しっかり怒られた。&lt;/p&gt;
&lt;p&gt;これを機に&lt;code&gt;node&lt;/code&gt;のバージョンを上げることにする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ node -v
v22.13.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;色々な依存関係を解消しつつ、最新&lt;code&gt;LTS&lt;/code&gt;まで上げた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;node_modules&lt;/code&gt;を最新化し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx playwright install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Playwright&lt;/code&gt;を初期化する。大量のエラーが吐き出され、TLS/SSL 証明書の検証に失敗した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export NODE_TLS_REJECT_UNAUTHORIZED=0
npx playwright install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を実行する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NODE_TLS_REJECT_UNAUTHORIZED&lt;/code&gt;は、&lt;code&gt;Node.js&lt;/code&gt;が
&lt;code&gt;HTTPS&lt;/code&gt;通信を行う際に使用する環境変数で、&lt;code&gt;0&lt;/code&gt;にすると、サーバー証明書の有効性が検証されなくなる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Chromium&lt;/code&gt;、&lt;code&gt;Firefox&lt;/code&gt;、&lt;code&gt;Webkit&lt;/code&gt;、&lt;code&gt;FFMPEG&lt;/code&gt;がインストール完了した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to &apos;0&apos; makes TLS connections and HTTPS requests insecure by disabling certificate verification.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という警告が出ていたので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export NODE_TLS_REJECT_UNAUTHORIZED=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でサーバー証明書を再度有効にした。&lt;/p&gt;
&lt;h2&gt;Playwrightのテストファイルを実行まで&lt;/h2&gt;
&lt;h3&gt;テストファイルの作成&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;tests/&lt;/code&gt;にテストファイルを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { test, expect } from &apos;@playwright/test&apos;;

test(&apos;ホームページが正しく表示されることを確認する&apos;, async ({ page }) =&amp;gt; {
  // アプリケーションのURL
  await page.goto(&apos;http://localhost:4200&apos;);

  // タイトルが表示されていることを確認
  await expect(page).toHaveTitle(/Angular App/);

  // テキストが表示されているか確認
  const header = page.locator(&apos;h1&apos;);
  await expect(header).toHaveText(&apos;Welcome to Angular App!&apos;);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;トライする&lt;/h3&gt;
&lt;p&gt;上記を&lt;code&gt;npx playwright test&lt;/code&gt;で実行したところ、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ReferenceError: describe is not defined

   at src\app\template\sheet\sheet.component.spec.ts:5

  3 | import { SheetComponent } from &apos;./sheet.component&apos;;
  4 |
&amp;gt; 5 | describe(&apos;SheetComponent&apos;, () =&amp;gt; {
    | ^
  6 |   let component: SheetComponent;
  7 |   let fixture: ComponentFixture&amp;lt;SheetComponent&amp;gt;;
  8 |
    at Object.&amp;lt;anonymous&amp;gt; (C:\dev\path\sheet.component.spec.ts:5:1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というエラーが大量にでた。どうやら、標準のユニットテストと混合しているらしい。&lt;/p&gt;
&lt;h3&gt;エラーと格闘し成功まで&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;tests/&lt;/code&gt;以下に置いていることが影響している気がしたので、&lt;code&gt;tests/e2e&lt;/code&gt;以下にファイルを置いて再実行したところ、何も変わらない。&lt;/p&gt;
&lt;p&gt;色々調べてみた感じ、&lt;code&gt;playwright.config.ts&lt;/code&gt;が不足しているようだったので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { PlaywrightTestConfig } from &apos;@playwright/test&apos;;

// PlaywrightTestConfig型で設定オブジェクトを定義
// この型定義により、設定オブジェクトの構造が保証され、TypeScriptの補完機能が利用可能
const config: PlaywrightTestConfig = {
  // テストファイルが配置されているディレクトリを指定
  // ./tests 以下のすべての .spec.ts ファイルがテスト対象となる
  testDir: &apos;./tests/e2e&apos;,

  // テストのタイムアウト時間を30秒（30000ミリ秒）に設定
  // 1つのテストケースがこの時間を超えると、タイムアウトエラーが発生
  timeout: 30000,

  // テスト失敗時の再試行回数を2回に設定
  // テストが失敗した場合、最大2回まで再実行される
  retries: 2,

  // テスト実行時の共通設定
  use: {
    // テスト実行時のベースURLを設定
    // page.goto(&apos;/path&apos;)とした場合、http://localhost:4200/path にアクセスする
    baseURL: &apos;http://localhost:4200&apos;,

    // トレース（実行ログ）の設定
    // &apos;on-first-retry&apos;: 最初の再試行時にのみトレースを記録
    // トレースには実行時のスクリーンショットやネットワークリクエストなどが含まれる
    trace: &apos;on-first-retry&apos;,

    // スクリーンショットの設定
    // &apos;only-on-failure&apos;: テストが失敗した場合のみスクリーンショットを保存
    screenshot: &apos;only-on-failure&apos;,
  },

  // テストを実行するブラウザプロジェクトの設定
  // 複数のブラウザでテストを実行することで、クロスブラウザテストが可能
  projects: [
    {
      // Chromeブラウザでのテスト設定
      name: &apos;Chrome&apos;,
      use: {
        // Chromiumベースのブラウザを使用
        // Chromium は Chrome の開発版で、テスト自動化に適している
        browserName: &apos;chromium&apos;,
      },
    },
    {
      // Firefoxブラウザでのテスト設定
      name: &apos;Firefox&apos;,
      use: {
        browserName: &apos;firefox&apos;,
      },
    },
    {
      // Safariブラウザでのテスト設定
      // WebKitはSafariのエンジンを使用
      name: &apos;Safari&apos;,
      use: {
        browserName: &apos;webkit&apos;,
      },
    },
  ],
  // レポートを作成する
  reporter: [
    [&apos;html&apos;, { open: &apos;always&apos; }],
    [&apos;json&apos;, { outputFile: &apos;test-results/results.json&apos; }],
  ],
};

// 設定オブジェクトをエクスポート
// この設定は npx playwright test コマンド実行時に自動的に読み込まれる
export default config;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ルートに追加したところ、テストを通すことができた。そしてレポートの&lt;code&gt;HTML&lt;/code&gt;が作成されるので、結果を見ることができる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Playwrightで実装で調べたことをとりあえずメモした（動画撮影、APIレスポンス、SignalR）</title><link>https://blog.nove-b.dev/posts/playwright-video-api-signalr</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/playwright-video-api-signalr</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/angular-playwright-typescript-e2e-testing/&quot;&gt;AngularプロジェクトでPlaywrightを導入しTypeScriptで自動E2Eテストを実行する&lt;/a&gt;で詰まったことを調べてみた雑記帳のようなもの。&lt;/p&gt;
&lt;h2&gt;テストケースを動画で撮影し、ダウンロードする&lt;/h2&gt;
&lt;p&gt;テストした結果を動画で残して起きたかったので、撮影しダウンロードする方法を調べてみた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;test(&apos;テストケースを動画で撮影し、ダウンロードする&apos;, async ({ browser }) =&amp;gt; {

  // ブラウザ名を取得（小文字に変換）
  const browserName = browser.browserType().name();

 // テスト名（スペースをアンダースコアに変換）
  const testName = &apos;test_name&apos;;

  // 動画保存用のディレクトリパスを生成
  const videoDir = path.join(&apos;videos&apos;, `${browserName}_${testName}_${今日の日付取得関数}`);

  // コンテキストを作成する際にビデオ録画を設定
  const context = await browser.newContext({
    recordVideo: {
      dir: videoDir, // 録画ファイルを保存するディレクトリ
      size: { width: 1280, height: 720 } // ビデオサイズを設定（オプション）
    }

    // ここで必要なテストを実行する


   // テスト終了時にコンテキストをクローズ（これによりビデオ録画も終了）
  await context.close();
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;複数のテストファイルを順次実行する&lt;/h2&gt;
&lt;p&gt;デフォルトではPlaywrightは並列実行するらしいので、直列実行するためのコマンドを叩くようにする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx playwright test --workers=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そのうえで、テストファイルがアルファベット順で実行される仕様らしいので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1_test_login
2_test_acoount_change
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;認証情報を保持する&lt;/h2&gt;
&lt;p&gt;順次実行したいのも、ログインしたうえで処理を実行したいからであり、そのためにテストファイルをまたぎ認証情報を保持しておく必要がある。&lt;/p&gt;
&lt;p&gt;ログイン処理実行後に認証情報を保存する処理を行い、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;test(&apos;ログインページが正しく動いている確認テスト&apos;, async ({ browser }) =&amp;gt; {

    ...テスト実施

    // 認証情報を保存
    const storageStatePath = path.resolve(&apos;./storageState.json&apos;);
    await page.context().storageState({ path: storageStatePath });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;認証情報を使用したいファイルで&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;test.use({
  storageState: path.resolve(&quot;./storageState.json&quot;), // 保存した認証情報を使用
});

test(&quot;認証情報を使うテスト&quot;, async ({ page }) =&amp;gt; {});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように使用する。&lt;/p&gt;
&lt;h2&gt;APIのレスポンスを使用する&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// API レスポンスを待つ
const [response] = await Promise.all([
  page.waitForResponse(
    (response) =&amp;gt;
      response.url().includes(&quot;/api/endpoint&quot;) &amp;amp;&amp;amp; response.status() === 200,
  ),
]);

// レスポンスの内容を取得
const responseData = await response.json();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特別変わった書き方ではない。&lt;/p&gt;
&lt;p&gt;ちなみに中の値にアクセスする前に、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;expect(response.value).not.toBeUndefined();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記のように&lt;code&gt;Undefined&lt;/code&gt;チェックをすることができる。&lt;/p&gt;
&lt;h2&gt;SignalRのテストをする&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// ページにアクセス
await page.goto(&quot;http://localhost:4200/#/dummy&quot;);

// SignalRライブラリを動的にロード
await page.evaluate(async () =&amp;gt; {
  return new Promise((resolve, reject) =&amp;gt; {
    const script = document.createElement(&quot;script&quot;);
    script.src =
      &quot;https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/7.0.0/signalr.min.js&quot;;
    script.onload = resolve;
    script.onerror = reject;
    document.head.appendChild(script);
  });
});

// SignalRライブラリがグローバルに利用可能か確認
await page.waitForFunction(() =&amp;gt; &quot;signalR&quot; in window);

// SignalR接続の開始
const signalRConnection = await page.evaluate(async () =&amp;gt; {
  try {
    const connection = new window.signalR.HubConnectionBuilder()
      .withUrl(&quot;http://xxx.xx.xxx.xxx:xxxx/SignalR&quot;, {
        skipNegotiation: true,
        transport: window.signalR.HttpTransportType.WebSockets,
      })
      .withAutomaticReconnect([0, 1000, 5000])
      .build();

    let connectionState: string | null = null;

    // 再接続処理
    connection.onreconnecting((error) =&amp;gt; {
      connectionState = &quot;reconnecting&quot;;
      console.log(&quot;再接続中:&quot;, error?.message || &quot;No error message&quot;);
    });

    // 再接続成功時
    connection.onreconnected((connectionId) =&amp;gt; {
      connectionState = &quot;reconnected&quot;;
      console.log(&quot;再接続成功。ID:&quot;, connectionId);
    });

    // 接続終了時
    connection.onclose((error) =&amp;gt; {
      connectionState = &quot;closed&quot;;
      console.log(&quot;接続終了:&quot;, error?.message || &quot;No error message&quot;);
    });

    // 接続の開始
    console.log(&quot;SignalR接続開始...&quot;);
    await connection.start();
    connectionState = &quot;connected&quot;;
    console.log(&quot;SignalR接続完了。ID:&quot;, connection.connectionId);

    connection.on(&quot;Message&quot;, async (response) =&amp;gt; {
      console.log(&quot;ResidentProgramDataAdded メッセージを受信:&quot;, response);

      // SignalRで受信したデータについてのテストをする
      console.log(response);
      expect(response === &quot;xxx&quot;).toBe(true);

      // テストクリア
      expect(true).toBe(true);
    });

    return {
      success: true,
      connectionId: connection.connectionId,
      state: connectionState,
    };
  } catch (err: any) {
    console.error(&quot;SignalR接続エラー:&quot;, err);
    return {
      success: false,
      error: err.message,
      state: &quot;setup_failed&quot;,
    };
  }
});
console.log(&quot;SignalR接続結果:&quot;, signalRConnection);

if (!signalRConnection.success) {
  console.error(&quot;接続失敗:&quot;, signalRConnection.error);
  throw new Error(`SignalR接続失敗: ${signalRConnection.error}`);
}

expect(signalRConnection.success).toBe(true);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;どうやって&lt;code&gt;SignalR&lt;/code&gt;と接続すればいいかわからなかった。
&lt;code&gt;CDN&lt;/code&gt;で接続すればうまくいったので、正解かわからないけどそのように実装した。&lt;/p&gt;
&lt;p&gt;これも認証のようにグローバルに受信できるようにしたいけど、いまは接続確認するまで。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>無料の翻訳API、みんなの自動翻訳を使ってみた</title><link>https://blog.nove-b.dev/posts/free-translation-api-minnano-auto-translate</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/free-translation-api-minnano-auto-translate</guid><content:encoded>&lt;p&gt;マストドンのクライアントアプリに翻訳機能を追加するため、「みんなの自動翻訳」というAPIを見つけたので試してみた。&lt;/p&gt;
&lt;h2&gt;最初に実装結果&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b/113854236337930111/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;br /&amp;gt;ただ書いた通り翻訳の精度がどれほどのものかは英語が読めないのでわからない。&lt;/p&gt;
&lt;p&gt;今更だけどせっかくなので、ほかの翻訳サイトで試してみようと思い、threadsのwhitehouseのアカウントに行ったら削除されていた。トランプ政権要職であるイーロンの商売敵だし、仕方ないとは言え、驚くべき仕事の速さ。&lt;/p&gt;
&lt;p&gt;最後の投稿だけ残っていたのでそれで試してみる。&lt;/p&gt;
&lt;p&gt;原文は下記の通り。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;President Joe Biden, Vice President Kamala Harris, First Lady Jill Biden, and
Second Gentleman Douglas Emhoff gather on the North Portico of the White House
for the final time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;みんなの自動翻訳は&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ジョー・バイデン大統領、カマラ・ハリス副大統領、ジル・トレーシー・ジェイコブズ大統領夫人、ダグラス・エンホフ第二紳士が、最後にホワイトハウスの北ポルティコに集まります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;DeepLは&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ジョー・バイデン大統領、カマラ・ハリス副大統領、ジル・バイデン大統領夫人、ダグラス・エムホフ副大統領夫人がホワイトハウスの北ポルティコに集合。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Google翻訳は&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ジョー・バイデン大統領、カマラ・ハリス副大統領、ジル・バイデン大統領夫人、ダグラス・エムホフ二等紳士が最後にホワイトハウスの北柱廊玄関に集まる。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ChatGPTは&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ジョー・バイデン大統領、カマラ・ハリス副大統領、ジル・バイデン大統領夫人、ダグラス・エムホフセカンドジェントルマンが、ホワイトハウスの北ポルチコで最後の時間を共に過ごしました。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;こうやってみるとChatGPTが圧倒的に良い翻訳だと思うけど、みんなの自動翻訳も意図は伝わるので問題はない。&lt;/p&gt;
&lt;h2&gt;みんなの自動翻訳とは？&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://mt-auto-minhon-mlt.ucri.jgn-x.jp/&quot;&gt;自動翻訳をみんなで育てるサイトみんなの自動翻訳＠TexTra®&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;話題のニューラル機械翻訳(NMT)、最新の自動翻訳研究に基づく、「高精度自動翻訳エンジン」とのこと。&lt;/p&gt;
&lt;p&gt;つまり、テキストの翻訳を行う際に、従来のルールベースや統計的機械翻訳（SMT）と異なり、ニューラルネットワークを使って文脈や意味を考慮した高精度な翻訳を実現できるということらしい。&lt;/p&gt;
&lt;p&gt;提供元は国立研究開発法人情報通信研究機構 先進的音声翻訳研究開発推進センターで公式サイトに行くと翻訳アプリとかもリリースしていた。全く知らなかったけど、国の研究でこんなことをしていたのかと驚いた。&lt;/p&gt;
&lt;h3&gt;特徴&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;一般的なWeb翻訳と同様、誰でも簡単にお使いいただけます。&lt;/li&gt;
&lt;li&gt;日本語・英語・中国語・韓国語の４言語を中心に多言語に対応。&lt;/li&gt;
&lt;li&gt;ブログ・レシピ・エッセイ・新聞などの一般的な文章はもちろん、特許・論文・マニュアルなどの&lt;/li&gt;
&lt;li&gt;専門分野の長文翻訳も得意です。&lt;/li&gt;
&lt;li&gt;面倒なインストールは不要︕ 翻訳エディタのご利用が可能です。&lt;/li&gt;
&lt;li&gt;翻訳をサポートする便利なツールが満載︕
&lt;ul&gt;
&lt;li&gt;MS Word、Excel、PowerPoint上のテキストを自動翻訳するアドイン。&lt;/li&gt;
&lt;li&gt;Firefox、Thunderbird、Chrome上での自動翻訳、辞書引きのアドイン。&lt;/li&gt;
&lt;li&gt;Trados上での翻訳、辞書引き機能を提供するアドイン。&lt;/li&gt;
&lt;li&gt;TexTra Clipboard︓クリップボードにコピーしたテキストを翻訳するアプリ。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;自動翻訳、辞書引き、用語検索、類似文検索の機能をWeb APIとして公開しています。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://mt-auto-minhon-mlt.ucri.jgn-x.jp/data/MJH-TexTra-Flyer.pdf?20240123_01&quot;&gt;引用元&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;使用する上での注意点&lt;/h2&gt;
&lt;p&gt;アプリ作成する上で気になることを調べてみた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;商用利用は禁止&lt;/li&gt;
&lt;li&gt;1日500回までのアクセス&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上記を考えると本番運用は難しそうに感じる。参考にDeepL API
Freeは1ヶ月あたり50万文字まで無料とのこと。&lt;/p&gt;
&lt;p&gt;ちなみに参考のDeepL API
Freeとコスパで比較すると、マストドンの最大文字数500で計算で&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1日500回までのアクセスの場合、1ヶ月で15,000回のリクエストが可能。&lt;/li&gt;
&lt;li&gt;1ヶ月あたり50万文字の制限の場合、1ヶ月で1,000回のリクエストが可能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;なので「みんなの自動翻訳」のほうがコスパはいい。&lt;/p&gt;
&lt;p&gt;DeepL API Freeは商用利用可能なので本番で運用するならこちらにする必要があるけど。&lt;/p&gt;
&lt;h2&gt;使い方&lt;/h2&gt;
&lt;p&gt;みんなの自動翻訳APIは認証が必要になる。&lt;/p&gt;
&lt;p&gt;なのでサーバー側で叩いく必要がある。丁寧にサンプルコード（&lt;code&gt;PHP&lt;/code&gt;、&lt;code&gt;Node.js&lt;/code&gt;、&lt;code&gt;Python3&lt;/code&gt;、&lt;code&gt;Java&lt;/code&gt;、&lt;code&gt;C#&lt;/code&gt;、&lt;code&gt;VB&lt;/code&gt;）があったので、それを参考にする。&lt;/p&gt;
&lt;p&gt;サーバーを用意するのは面倒だったので&lt;code&gt;Next&lt;/code&gt;の&lt;code&gt;app/api&lt;/code&gt;で&lt;code&gt;nodejs&lt;/code&gt;を実行し、エンドポイントを作成した。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/app/api/translate/route.ts&lt;/code&gt;を用意してそこに書く。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { NextResponse } from &quot;next/server&quot;;

export async function POST(req: Request) {
  try {
    const body = await req.json();
    if (!body || !body.text) {
      return NextResponse.json(
        { error: &quot;Text is required for translation&quot; },
        { status: 400 },
      );
    }

    const { text } = body;
    const url = &quot;https://mt-auto-minhon-mlt.ucri.jgn-x.jp&quot;;
    const key = &quot;xxxxxxxxxxxxxxxxxx&quot;;
    const secret = &quot;xxxxxxxxxxxxxxxxxx&quot;;
    const name = &quot;xxxxxxxxxxxxxxxxxx&quot;;
    const api_name = &quot;mt&quot;;
    const api_param = &quot;generalNT_en_ja&quot;;

    let access_token = null;

    // アクセストークン取得
    const tokenResponse = await fetch(`${url}/oauth2/token.php`, {
      method: &quot;POST&quot;,
      body: new URLSearchParams({
        grant_type: &quot;client_credentials&quot;,
        client_id: key,
        client_secret: secret,
      }),
    });

    if (!tokenResponse.ok) {
      throw new Error(&quot;Failed to fetch access token&quot;);
    }

    const tokenData = await tokenResponse.json();
    access_token = tokenData.access_token;

    if (!access_token) {
      return NextResponse.json(
        { error: &quot;Access token not found&quot; },
        { status: 400 },
      );
    }

    // APIリクエストの形式を修正
    const apiResponse = await fetch(`${url}/api/`, {
      method: &quot;POST&quot;,
      headers: {
        &quot;Content-Type&quot;: &quot;application/x-www-form-urlencoded&quot;,
      },
      body: new URLSearchParams({
        access_token: access_token,
        key: key, // API Key
        api_name: api_name,
        api_param: api_param,
        name: name, // ログインID
        type: &quot;json&quot;, // レスポンスタイプ
        text: text, // 翻訳テキスト
      }),
    });

    if (!apiResponse.ok) {
      throw new Error(&quot;API request failed&quot;);
    }

    const apiData = await apiResponse.json();

    const response = NextResponse.json(apiData);
    response.headers.set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
    response.headers.set(&quot;Access-Control-Allow-Methods&quot;, &quot;GET, POST, OPTIONS&quot;);
    response.headers.set(
      &quot;Access-Control-Allow-Headers&quot;,
      &quot;Content-Type, Authorization&quot;,
    );
    return response;
  } catch (error: unknown) {
    // エラーがオブジェクトかどうかをチェック
    if (error instanceof Error) {
      const response = NextResponse.json(
        { error: `Error: ${error.message}` },
        { status: 500 },
      );
      response.headers.set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
      return response;
    } else {
      const response = NextResponse.json(
        { error: &quot;Unknown error occurred&quot; },
        { status: 500 },
      );
      response.headers.set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
      return response;
    }
  }
}

// OPTIONS メソッド対応
export async function OPTIONS() {
  const response = new NextResponse(null, { status: 204 });
  response.headers.set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
  response.headers.set(&quot;Access-Control-Allow-Methods&quot;, &quot;GET, POST, OPTIONS&quot;);
  response.headers.set(
    &quot;Access-Control-Allow-Headers&quot;,
    &quot;Content-Type, Authorization&quot;,
  );
  return response;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特筆すべきこともないので、これで&lt;code&gt;build&lt;/code&gt;して&lt;code&gt;body&lt;/code&gt;を持たせたうえでエンドポイントを叩けば期待する翻訳テキストが返却される。&lt;/p&gt;
&lt;p&gt;言語の判定とか多言語用のAPIがどれかわからなかったので、それを使えばマストドンの&lt;code&gt;Status&lt;/code&gt;をみて多言語対応もできそうな感じだった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Amazon Cognitoについて調べてみた</title><link>https://blog.nove-b.dev/posts/amazon-cognito-overview</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/amazon-cognito-overview</guid><content:encoded>&lt;p&gt;業務で使用する可能性があるので、簡単に概念的な部分を調べてみた。&lt;/p&gt;
&lt;h2&gt;Amazon CognitoにはAWSが提供するユーザー認証サービス&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/jp/cognito/&quot;&gt;cognito&lt;/a&gt;はコグニートと読み、&lt;code&gt;AWS&lt;/code&gt;が提供するユーザー認証サービスのこと。&lt;/p&gt;
&lt;h2&gt;多様な認証サービス&lt;/h2&gt;
&lt;p&gt;同様のサービスに&lt;code&gt;Firebase Authentication&lt;/code&gt;とか&lt;code&gt;Auth0&lt;/code&gt;がある。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;code&gt;AWS&lt;/code&gt;の代表的なものだけでも&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS Identity and Access Management (IAM)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS Directory Service&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS Single Sign-On (以下、SSO)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Amazon Cognito&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;など多くのサービスがある。&lt;/p&gt;
&lt;p&gt;それぞに向き不向きがあるとのことで、生成AI（嘘が含まれている可能性がある）にユースケース等をまとめてもらった。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;項目&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AWS SSO&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Amazon Cognito&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AWS IAM&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AWS Directory Service&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;目的&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;組織内のユーザーに対する認証・認可を一元管理する&lt;/td&gt;
&lt;td&gt;一般ユーザーに対する認証・認可を提供&lt;/td&gt;
&lt;td&gt;AWSリソースへのアクセスを制御する&lt;/td&gt;
&lt;td&gt;マネージド型のActive Directoryサービスを提供し、AWSとADの連携を可能にする&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;主な対象&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;組織内の従業員や社内システム利用者&lt;/td&gt;
&lt;td&gt;不特定多数の一般ユーザー&lt;/td&gt;
&lt;td&gt;AWSアカウントのIAMユーザー、ロール、サービス&lt;/td&gt;
&lt;td&gt;Active Directoryを使用している企業&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;主要機能&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;- 複数のAWSアカウントへのSSO&amp;lt;br&amp;gt;- Active Directoryとの連携&amp;lt;br&amp;gt;- 外部アプリケーション（例: Office 365）へのSSO&amp;lt;br&amp;gt;- AWS Organizationsとの統合&lt;/td&gt;
&lt;td&gt;- ユーザープール（ユーザー認証）&amp;lt;br&amp;gt;- IDプール（認可とAWSリソースへのアクセス権限付与）&amp;lt;br&amp;gt;- Cognito Sync（データのデバイス間共有）&lt;/td&gt;
&lt;td&gt;- ユーザー、グループ、ロールによるアクセス管理&amp;lt;br&amp;gt;- AWSリソースのポリシーベースのアクセス制御&amp;lt;br&amp;gt;- MFAのサポート&lt;/td&gt;
&lt;td&gt;- Microsoft Active Directory (AD) の管理&amp;lt;br&amp;gt;- AWSリソースとADの統合&amp;lt;br&amp;gt;- ドメインコントローラーの提供&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Organizationsとの連携&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;マスターアカウントでAWS SSOを有効にすることで、複数アカウントの統合管理が可能&lt;/td&gt;
&lt;td&gt;不可&lt;/td&gt;
&lt;td&gt;ポリシーを使用してマルチアカウント環境を管理可能&lt;/td&gt;
&lt;td&gt;不可&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active Directory連携&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS Managed Microsoft ADやAzure ADなどの外部ディレクトリサービスと統合可能&lt;/td&gt;
&lt;td&gt;不可&lt;/td&gt;
&lt;td&gt;AWS Managed Microsoft ADを使用したアクセス管理が可能&lt;/td&gt;
&lt;td&gt;Active Directoryそのものの管理が可能&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;認証対象の規模&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;組織内ユーザー向け（数百〜数千の規模）&lt;/td&gt;
&lt;td&gt;不特定多数（デフォルトで最大20,000,000ユーザー）&lt;/td&gt;
&lt;td&gt;AWSアカウントに関連するIAMユーザーとロール&lt;/td&gt;
&lt;td&gt;組織内のActive Directoryユーザー&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;トークンの種類&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;不適用（SSOによる直接ログイン）&lt;/td&gt;
&lt;td&gt;- IDトークン（認証）&amp;lt;br&amp;gt;- 一時クレデンシャル（認可）&lt;/td&gt;
&lt;td&gt;一時クレデンシャル（STSトークン）&lt;/td&gt;
&lt;td&gt;不適用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;主なユースケース&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;- 複数AWSアカウントへの一元的アクセス&amp;lt;br&amp;gt;- AWS上のファイルシステム（例: Amazon FSx）へのアクセス&amp;lt;br&amp;gt;- Office 365などの外部アプリケーションへのSSO&lt;/td&gt;
&lt;td&gt;- サーバーレスアプリケーションの認証（例: API Gateway）&amp;lt;br&amp;gt;- 認証不要なアプリケーションのAWSリソースアクセス&amp;lt;br&amp;gt;- ソーシャルログイン（Facebook, Google, Appleなど）&lt;/td&gt;
&lt;td&gt;- AWSリソースへのアクセス制御&amp;lt;br&amp;gt;- リソースレベルのポリシー適用&amp;lt;br&amp;gt;- セキュリティの詳細な管理&lt;/td&gt;
&lt;td&gt;- AWSと社内Active Directoryの統合&amp;lt;br&amp;gt;- ADベースの認証でAWSリソースにアクセス&amp;lt;br&amp;gt;- Windowsファイルシステムの管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;特徴的な機能&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;- シングルサインオンの利便性とセキュリティ向上&amp;lt;br&amp;gt;- AWSコンソールにログインせずにアプリケーション利用可能&lt;/td&gt;
&lt;td&gt;- ユーザー登録機能（セルフサービス）&amp;lt;br&amp;gt;- ゲストユーザーへの限定的なアクセス権付与&amp;lt;br&amp;gt;- 複数デバイス間でのデータ同期&lt;/td&gt;
&lt;td&gt;- ポリシーベースで細かいアクセス制御が可能&amp;lt;br&amp;gt;- AWS CLIやSDKでの柔軟な認証管理&lt;/td&gt;
&lt;td&gt;- ADサービスのマネージド運用&amp;lt;br&amp;gt;- AWSリソースとの完全統合&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Amazon Cognitoと他サービスの違い&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;対象ユーザーが一般ユーザー向け&lt;/li&gt;
&lt;li&gt;ソーシャルログインとの連携&lt;/li&gt;
&lt;li&gt;ユーザープールとIDプールの役割分担&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Cognitoは認証（ユーザープール）と認可（IDプール）を明確に分けている&lt;/li&gt;
&lt;li&gt;ユーザープール: アプリケーションのユーザーを認証し、IDトークンを発行。&lt;/li&gt;
&lt;li&gt;IDプール: 認証済みのユーザーやゲストにAWSリソースのアクセス権を付与するための一時クレデンシャルを発行。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;大規模ユーザー向け設計&lt;/li&gt;
&lt;li&gt;デバイス間のデータ同期&lt;/li&gt;
&lt;li&gt;認証を必要としないアクセスのサポート&lt;/li&gt;
&lt;li&gt;エンドユーザー向けのUIカスタマイズ&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Amazon
Cognitoは、外部ユーザー認証を中心に、ソーシャルログインや大規模ユーザー管理、デバイス間のデータ同期など、アプリケーションの開発者にとって必要な機能を幅広くサポートしている。&lt;/p&gt;
&lt;p&gt;ちなみに認証とは、その人が誰であるかを判別すること。認可とは、その人が何を許可されているかを判別すること。&lt;/p&gt;
&lt;h2&gt;参考になりそうなサイトとかをまとめてみた&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://aws.amazon.com/jp/cognito/&lt;/li&gt;
&lt;li&gt;https://d1.awsstatic.com/webinars/jp/pdf/services/20200630_AWS_BlackBelt_Amazon%20Cognito.pdf&lt;/li&gt;
&lt;li&gt;https://dev.classmethod.jp/articles/krsk-amazon-cognito-20250120/&lt;/li&gt;
&lt;li&gt;https://techblog.insightedge.jp/entry/cognito-auth&lt;/li&gt;
&lt;li&gt;https://dev.classmethod.jp/articles/get-started-with-amazon-cognito-now-1/&lt;/li&gt;
&lt;li&gt;https://zenn.dev/toccasystems/articles/aws-cognito-trial&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>nove-b</author></item><item><title>React NativeのFlatListで要素がデバイスの高さ分存在しないときに、onEndReachedが発火する問題を解決する</title><link>https://blog.nove-b.dev/posts/react-native-flatlist-onendreached-trigger-issue-solution</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/react-native-flatlist-onendreached-trigger-issue-solution</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/react-native-infinite-scroll-timeline/&quot;&gt;React Nativeで無限スクロールのタイムラインを作成した&lt;/a&gt;んだけど、対象のコンテンツがデバイスの高さ以上になるコンテンツ数を持っていないときに、発生する必要のない無限スクロールイベントが無限で発生する事象が起きたので対処法を実装した。&lt;/p&gt;
&lt;p&gt;まずはデバイスの高さを取得する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const screenHeight = Dimensions.get(&quot;window&quot;).height;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に&lt;code&gt;FlatList&lt;/code&gt;ののコンテンツサイズ変更時に&lt;code&gt;setContentHeight&lt;/code&gt;を利用し、リストの高さを更新する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const [contentHeight, setContentHeight] = useState(0);

...(中略)

     onContentSizeChange={(width, height) =&amp;gt; {
     setContentHeight(height);
  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、リストの高さがデバイスの高さより大きければ、スクロール可能（onEndReachedが発火してもいい）ので&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const hasMoreContent = contentHeight &amp;gt; screenHeight;

...(中略)
    onEndReached={hasMoreContent ? onEndReached : null}
  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という風に実装できる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年1月】ディズニーランドと星野リゾート1955と猛禽類のそらジロー</title><link>https://blog.nove-b.dev/posts/2025-1</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-1</guid><content:encoded>&lt;h2&gt;1月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4hvvZ6v&quot;&gt;電球交換士の憂鬱&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/40nXCsg&quot;&gt;もしも徳川家康が総理大臣になったら&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;毎年のごとく1月はイベントが多く、本が読めない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/40nXCsg&quot;&gt;もしも徳川家康が総理大臣になったら&lt;/a&gt;は無料だからという理由で、なにも期待せずに手に取ったところ、とても面白かった。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;良いか。仕事と思うな。祭りと思え。祭りならば気も浮き立ち、頭も回る。役目を思わば、気は重くなる。祭りを今からやるのじゃ！歌え！舞え！狂え！今から祭りを始めようぞ！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;「それはわしの仕事ではにゃー。それをやるのは三成じゃ」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;フィクションなんだけど、天下を取る人はやっぱりすごいと思わされた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/4hvvZ6v&quot;&gt;電球交換士の憂鬱&lt;/a&gt;は相変わらずの吉田篤弘でほっとした。&lt;/p&gt;
&lt;p&gt;2冊読めば元が取れる&lt;a href=&quot;https://www.amazon.co.jp/kindle-dbs/hz/signup?tag=nove0822-22&quot;&gt;Kindle Unlimited&lt;/a&gt;で読書しているので今月も得した。&lt;/p&gt;
&lt;h2&gt;1月が終わる&lt;/h2&gt;
&lt;p&gt;ついこの間、年が明けたというのに、もう1月が終わろうとしている。1月はイベントが比較的多いので、特に時間が過ぎるのがはやい。&lt;/p&gt;
&lt;p&gt;1日、2日はお互いの実家に帰省した。妻の実家にはプラレールが所狭しに広がっており、楽しそうに遊んでいた。&lt;/p&gt;
&lt;p&gt;3日、大山詣りに行く予定が、子どもに蕁麻疹が出て次の日に延期する。それ以降、たまに2人とも蕁麻疹が出るようになった。全身に広がるわけじゃないんだけど、ぽつりぽつりとまばらにでる。蕁麻疹なのか？皮膚科にもらった塗り薬を塗れば直るんだけど、すこし心配ではある。&lt;/p&gt;
&lt;p&gt;大山はきつかった。2歳のくせに外では抱っこをねだるので、ずっと抱っこで登る羽目になった。想定内ではあったんだけど辛かった。正月の不摂生がここで一気に解消された。&lt;/p&gt;
&lt;p&gt;5日には高校の友達と新年会をした。久々の東京でちょっと怖かったけど、ロマンスカーは快適でいい気分転換になった。しかしみんな離れ離れになったので集まるのが面倒くさい。&lt;/p&gt;
&lt;p&gt;友達の1人が22日連続忘年会＆新年会って言ってて、まだ高校生から卒業してなかった。広告代理店の宿命なのかもしれないけど、自由に楽しそうに生きていて少し羨ましかった。たぶん、自分には向かないけど。&lt;/p&gt;
&lt;h2&gt;桃鉄は50年を突破した&lt;/h2&gt;
&lt;p&gt;年末年始恒例で3が日を超えると自然とやらなくなる桃鉄大会だけど、今年は絶賛継続中で遂に50年を突破した。毎日、子どもの寝かしつけ、家事が完了後の開催なので12時から始まるのでずっと寝不足気味ではあるんだけど、楽しいのでまあいいことにする。1日2年できるかどうかなので、2月中には終わると思っている。&lt;/p&gt;
&lt;h2&gt;希望する保育園に受かった&lt;/h2&gt;
&lt;p&gt;運よく、希望する保育園に受かった。3/5だったので、運良くと言っていい気がする。公立なので例年2枠なんだけど、今年は退園する子がいるのか3枠あったらしく、双子をなんとかねじ込めた。日本の悪口を言わずに済みそうで良かった。&lt;/p&gt;
&lt;p&gt;抽選中も妻が第一希望の保育園の園庭開放に連れて行ってくれていたんだけど、「保育園決まるといいですね」という思わせぶりな声をかけてもらっていたらしい。果たして先生たちは知っていたのかどうかすごい気になる。&lt;/p&gt;
&lt;h2&gt;ディズニーランドに行く&lt;/h2&gt;
&lt;p&gt;去年は前泊で、今年は後泊にした。というのも前泊だと、遊んでいる間も帰る時間が気になって仕方ないし、前泊中もホテルで次の日のことを考えてそわそわする。&lt;/p&gt;
&lt;p&gt;そういうわけで後泊にしたけど、これが正解だった。&lt;/p&gt;
&lt;p&gt;当日5時に起きて、準備して、子どもたちを起こさないように着替えさせようとしたら普通に起きた。寝かせたままチャイルドシートに乗せる計画はここで破綻する。&lt;/p&gt;
&lt;p&gt;ただ宿泊するホテルに着くまで泣かずに車に乗ってくれていたので助かった。&lt;/p&gt;
&lt;p&gt;8:10に宿泊する星野リゾート 1955 東京ベイに到着。ランドに車を停めてもいいけど、1955の方が安いので、1955に停めた。&lt;/p&gt;
&lt;p&gt;そのままシャトルバスでランドに向かう。全員座れるくらいの混雑具合だったので、双子用ベビーカーも邪魔にならなかった。&lt;/p&gt;
&lt;p&gt;1955は基本的にいいホテルだったけど、遠いのがマイナスポイント。結局20分くらいかかった。&lt;/p&gt;
&lt;p&gt;ついてすぐに、プライマリティパスを取って、シンデレラ城のショーと美女と野獣に課金した。待ち時間が耐えられないので、課金できるものは課金する覚悟で行ったので、後悔はしていない。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/bizyoyazyu.jpg&quot; alt=&quot;城&quot; /&gt;&lt;/p&gt;
&lt;p&gt;結果的に、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ウェスタンリバー鉄道&lt;/li&gt;
&lt;li&gt;ジャングルクルーズ：ワイルドライフ・エクスペディション&lt;/li&gt;
&lt;li&gt;イッツ・ア・スモール・ワールド&lt;/li&gt;
&lt;li&gt;美女と野獣 “魔法のものがたり”&lt;/li&gt;
&lt;li&gt;プーさんのハニーハント&lt;/li&gt;
&lt;li&gt;ミッキーのフィルハーマジック&lt;/li&gt;
&lt;li&gt;ミニーの家&lt;/li&gt;
&lt;li&gt;ミニーのスタイルスタジオ&lt;/li&gt;
&lt;li&gt;イッツ・ア・スウィーツ・フル・タイム&lt;/li&gt;
&lt;li&gt;Reach for the Stars&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;と結構満喫した。&lt;/p&gt;
&lt;p&gt;帰りのバスは激混みで、双子用ベビーカーは邪魔だったはずなので、申し訳ない。しかも抱っこで寝ちゃったので、荷物とベビーカーと力の抜けた子どもで、その日一番つらかった。車窓から花火が見えたけど、誰も見ていなかった。みんな疲れた顔をしていて、夢の国から出てきたことを実感した。&lt;/p&gt;
&lt;p&gt;そんな状況だったので、1955のQRコードチェックインは本当に助かった。双子はそのまま寝ちゃったので、状況を整理して、すぐに寝た。なぜかすごい夜泣きしてつらかった。&lt;/p&gt;
&lt;p&gt;次の日、ホテルからの景色がオーシャンビューであることに気が付いた。何のためのオーシャンビューなのかわからないけど、朝日を堪能した。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/sea.jpg&quot; alt=&quot;海&quot; /&gt;&lt;/p&gt;
&lt;p&gt;1955は奇麗だし、星野リゾート安定の土足禁止だし、安いし、控えめに言っていいホテルだった。&lt;/p&gt;
&lt;p&gt;朝、せっかくなのでということでレストランでバイキングを食べて、セカンドルームでゆっくりして、チェックアウトした。&lt;/p&gt;
&lt;h2&gt;そらジローと対面する&lt;/h2&gt;
&lt;p&gt;妻の育休が終わるまでにそらジローに会いたいねという話をしていた。というより、木原さんのお天気コーナーに子どもと出たいという話をしていた。&lt;/p&gt;
&lt;p&gt;そこで行くことにした。&lt;/p&gt;
&lt;p&gt;その日お天気コーナーがあることを確認し、1955を出て汐留に向かう。ここで誤算が生じる。双子の１人が車でお昼寝しなかった。&lt;/p&gt;
&lt;p&gt;そのため、お天気コーナー中ずっとぐずっているという醜態を晒した。&lt;/p&gt;
&lt;p&gt;もういいね、疲れたといいながら家に帰ることになった。&lt;/p&gt;
&lt;p&gt;そらジローは大きかった。たぶんあれは、猛禽類に違いない。&lt;/p&gt;
&lt;h2&gt;個人開発は順調に自分用にできあがっている&lt;/h2&gt;
&lt;p&gt;まだリリースしていないけど、毎日45分だけ個人開発の時間を取れるように頑張っている。15分だけとかの方が多いけど、少しでも進めるように頑張っている。そういうわけで進む具合はよくないけど、停滞はしていない。&lt;/p&gt;
&lt;p&gt;そして自分が使う分には問題レベルまで出来上がている。&lt;/p&gt;
&lt;p&gt;そろそろリリースしたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>エックスサーバーVPSのMastodonイメージを使用したソロインスタンスに新規ユーザーを追加した</title><link>https://blog.nove-b.dev/posts/add-new-user-to-mastodon-solo-instance-on-exserver-vps</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/add-new-user-to-mastodon-solo-instance-on-exserver-vps</guid><content:encoded>&lt;p&gt;エックスサーバーVPSのMastodonイメージを使用したソロインスタンスを使用して、Mastodonを運用している。&lt;/p&gt;
&lt;p&gt;3か月ほど運用してみて、ローカルタイムラインが機能していなということに気が付いた。&lt;/p&gt;
&lt;p&gt;趣味サーバーであれば、ローカルタイムラインには趣味が合う投稿で溢れているのだろうけれど、ソロインスタンスは自身の投稿しかない。&lt;/p&gt;
&lt;p&gt;そこでもう１つアカウントを追加し、その子に&lt;code&gt;Bot&lt;/code&gt;として働いてもらうことにした。&lt;/p&gt;
&lt;p&gt;色々試行錯誤してサーバーに不要なものをたくさんインストールしてしまったので、今後のことを考え、うまくいった方法をまとめておく。&lt;/p&gt;
&lt;p&gt;色々調べて実行したけど、うまくいかないことも多く、エックスサーバーVPSのMastodonイメージが特殊なのかもしれないと考えているけど、言い訳かもしれない。&lt;/p&gt;
&lt;h2&gt;コンソールからユーザーを追加する&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Accountモデルの新しいインスタンスを作成し、データベースに保存する
# &apos;rss_feed&apos; というユーザー名と &apos;rss feed&apos; という表示名を持つアカウントを作成
account = Account.create(
  username: &apos;rss_feed&apos;,     # ユーザー名を &apos;rss_feed&apos; に設定
  display_name: &apos;rss feed&apos;  # 表示名を &apos;rss feed&apos; に設定
)

# Userモデルの新しいインスタンスを作成（まだデータベースには保存しない）
user = User.new(
  email: &apos;example@mail.com&apos;,         # ユーザーのメールアドレス
  password: &apos;password&apos;,              # パスワード（仮のもの）
  password_confirmation: &apos;password&apos;, # パスワード確認（同じ値を指定）
  account: account                   # 先ほど作成した Account インスタンスを紐付け
)

# 招待IDを設定（最初の招待データを使用）
# Mastodonのユーザー登録では招待制を使用することがあるため、招待コードを紐付ける
user.invite_id = Invite.first.id

# ユーザーを承認済みに設定（管理者の承認が必要な場合に手動で承認を行う）
user.approved = true

# 利用規約に同意したことを示すフラグを設定
user.agreement = true

# ユーザーのメールアドレス確認を完了したことを示す
user.confirmed_at = Time.now

# メール確認をスキップ（通常は確認メールを送るが、この処理では省略）
user.skip_confirmation!

# ユーザーをデータベースに保存（バリデーションを強制的に通す）
user.save!

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;理解してないのでChat GPTにコメントアウトを書いてもらった。&lt;/p&gt;
&lt;p&gt;試行錯誤したので、本当にこの通りだったか曖昧だけど、だいたいこんな感じだった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>PM2を使ってMastodonのBotを作成した</title><link>https://blog.nove-b.dev/posts/mastodon-bot-with-pm2</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/mastodon-bot-with-pm2</guid><content:encoded>&lt;p&gt;前回に引き続き、ソロインスタンスのローカルタイムラインをRSS
Feedとして活用したいという思いで、今回は追加したアカウンをBotとして機能するようにした。&lt;/p&gt;
&lt;h2&gt;Botをどこで動かすのか&lt;/h2&gt;
&lt;p&gt;Mastodonを触るうえでディレクトリ構成に悩む。今回もどこで動かすか迷ったうえ、&lt;code&gt;/home/mastodon/以下&lt;/code&gt;に作成することにした。&lt;/p&gt;
&lt;h2&gt;投稿する仕組みを作成する&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;import axios from &quot;axios&quot;;
import Parser from &quot;rss-parser&quot;;
import dotenv from &quot;dotenv&quot;;
import fs from &quot;fs&quot;;

dotenv.config();

const parser = new Parser();
const MASTODON_API_URL = &quot;https://instanceURL/api/v1/statuses&quot;;
const ACCESS_TOKEN = process.env.MASTODON_ACCESS_TOKEN;

const rssUrls = [&quot;https://blog.nove-b.dev/index.xml&quot;];

const POSTED_URLS_FILE = &quot;posted_urls.json&quot;;

// 投稿済みURLを読み込む
function loadPostedUrls(): Set&amp;lt;string&amp;gt; {
  try {
    if (!fs.existsSync(POSTED_URLS_FILE)) {
      console.log(
        `File ${POSTED_URLS_FILE} does not exist. Creating a new one.`,
      );
      fs.writeFileSync(POSTED_URLS_FILE, JSON.stringify([], null, 2), &quot;utf8&quot;);
      console.log(`${POSTED_URLS_FILE} successfully created.`);
    }
    const data = fs.readFileSync(POSTED_URLS_FILE, &quot;utf8&quot;);
    return new Set(JSON.parse(data));
  } catch (error) {
    console.error(&quot;Error loading posted URLs:&quot;, error);
    return new Set();
  }
}

// 投稿済みURLを保存する
function savePostedUrls(postedUrls: Set&amp;lt;string&amp;gt;) {
  try {
    fs.writeFileSync(
      POSTED_URLS_FILE,
      JSON.stringify([...postedUrls], null, 2),
      &quot;utf8&quot;,
    );
    console.log(`Updated ${POSTED_URLS_FILE}`);
  } catch (error) {
    console.error(&quot;Error saving posted URLs:&quot;, error);
  }
}

async function fetchAndPost() {
  try {
    const postedUrls = loadPostedUrls();

    for (const url of rssUrls) {
      const feed = await parser.parseURL(encodeURI(url));
      if (feed.items.length === 0) {
        console.log(`No items found in RSS feed: ${url}`);
        continue;
      }

      let hasNewPost = false;

      for (const post of feed.items) {
        if (!post.link || postedUrls.has(post.link)) {
          continue;
        }

        const status = `🎉 ${post.title} 🎉\n🔗 ${post.link}`;
        try {
          const response = await axios.post(
            MASTODON_API_URL,
            { status, visibility: &quot;public&quot; },
            {
              headers: {
                Authorization: `Bearer ${ACCESS_TOKEN}`,
                &quot;Content-Type&quot;: &quot;application/json&quot;,
              },
            },
          );
          console.log(`Successfully posted: ${post.title}`, response.data);
        } catch (error: any) {
          console.error(
            &quot;Error posting to Mastodon:&quot;,
            error.response?.data || error.message,
          );
        }
        postedUrls.add(post.link);
        hasNewPost = true;
      }

      if (hasNewPost) {
        savePostedUrls(postedUrls);
      }
    }
  } catch (error) {
    console.error(&quot;Error fetching or posting RSS:&quot;, error);
  }
}

// 定期実行（30分ごと）
setInterval(fetchAndPost, 30 * 60 * 1000);

// 初回実行
fetchAndPost();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;npx tsc&lt;/code&gt;でビルドして、&lt;code&gt;node dist/index.js&lt;/code&gt;で実行で投稿されることを確認した。&lt;/p&gt;
&lt;h2&gt;PM2で永続化し、Botとして機能させる&lt;/h2&gt;
&lt;h3&gt;PM2とは？&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;PM2 は、アプリケーションを 24 時間 365 日オンラインで管理および維持するのに役立つデーモン プロセス マネージャーです。
&lt;a href=&quot;https://pm2.keymetrics.io/&quot;&gt;https://pm2.keymetrics.io/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これで常時、&lt;code&gt;js&lt;/code&gt;を動かして&lt;code&gt;Bot&lt;/code&gt;化することができた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// pm2のインストール
npm install -g pm2
// pm2でBotを起動
pm2 start {path}/index.js --env MASTODON_ACCESS_TOKEN={access_token}
// pm2で起動したBotを自動起動設定
pm2 startup
pm2 save
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;pm2 list&lt;/code&gt;で起動しているか確認することもできる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────┬─────────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name                │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼─────────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 1  │ rss-mastodon-bot    │ default     │ 1.0.0   │ fork    │ 141470   │ 69s    │ 0    │ online    │ 0%       │ 60.7mb   │ root     │ disabled │
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ちなみに削除は、&lt;code&gt;pm2 delete rss-mastodon-bot&lt;/code&gt;で実行できる。&lt;/p&gt;
&lt;h2&gt;Chat GPTにお世話になりすぎている&lt;/h2&gt;
&lt;p&gt;今回もまたChat
GPTにいろいろ聞いた。理解しきれていないので、カスタマイズしつつ理解を深めていきたい。&lt;/p&gt;
&lt;p&gt;&amp;lt;br /&amp;gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b_feed/113934904948672020/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Mastodonのソロインスタンスでローカルタイムラインを情報収集で活用する</title><link>https://blog.nove-b.dev/posts/mastodon-solo-instance-local</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/mastodon-solo-instance-local</guid><content:encoded>&lt;h2&gt;ソロインスタンスはタイムラインを有効活用できない&lt;/h2&gt;
&lt;p&gt;Mastodonには3つのタイムラインがある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;連合タイムライン&lt;/li&gt;
&lt;li&gt;ローカルライムライン&lt;/li&gt;
&lt;li&gt;ホームタイムライン&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;それぞれ下記のような特徴があるのだけれど、&lt;/p&gt;
&lt;h3&gt;連合タイムライン&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;自分がログインしているサーバーと、連合しているサーバーの、公開範囲が「公開」の投稿が全て流れるタイムライン&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;ローカルタイムライン&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;自分がログインしているサーバーの、公開範囲が「公開」の投稿&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;が流れるタイムラインのこと&lt;/p&gt;
&lt;h3&gt;ホームタイムライン&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;自分の投稿とフォローしているユーザーの投稿、フォローしているハッシュタグの付いた投稿、それからフォローしているユーザーがブーストした投稿&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;が流れるタイムラインのこと&lt;/p&gt;
&lt;p&gt;参考:&lt;a href=&quot;https://note.com/tukinekitune/n/ndca6a88ddd66&quot;&gt;Mastodonのタイムラインいろいろ【Fedibird】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ソロインスタンスだと少し趣が異なる。&lt;/p&gt;
&lt;h2&gt;ソロインスタンスの場合ホームタイムラインしか機能しない&lt;/h2&gt;
&lt;p&gt;ソロインスタンスの場合は、&lt;/p&gt;
&lt;p&gt;連合タイムラインとホームタイムラインは同じ情報になる。&lt;/p&gt;
&lt;p&gt;詳細は&lt;a href=&quot;https://blog.nove-b.dev/posts/mastodon-other-servers/&quot;&gt;Mastodonのおひとり様サーバーにおける連合タイムライン&lt;/a&gt;で過去に調べた通り。&lt;/p&gt;
&lt;p&gt;で、ローカルタイムラインはソロインスタンスなので、当然自分の投稿のみになる。&lt;/p&gt;
&lt;p&gt;つまりアカウントページ等で見える投稿一覧と変わらない。&lt;/p&gt;
&lt;p&gt;結果、ソロインスタンスだとホームタイムラインしか機能しない。&lt;/p&gt;
&lt;p&gt;それがどうにももったいないと感じたので活用できないかと調べてみたところ、RSS
Feedとして活用しているインスタンスを発見した。&lt;/p&gt;
&lt;h2&gt;ローカルタイムラインをRSS Feedにするということ&lt;/h2&gt;
&lt;p&gt;確かにそうすることで、ローカルタイムラインは興味のあるRSSと自身の投稿になり、有用なタイムラインになる。&lt;/p&gt;
&lt;p&gt;さらにそれ用のツールもあるらしかった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.itmedia.co.jp/news/articles/1707/14/news051.html&quot;&gt;マストドンを共有フィードリーダーにするbot「Monesi」&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただ更新がされていないようだったので、今回は自前で実装した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/add-new-user-to-mastodon-solo-instance-on-exserver-vps/&quot;&gt;エックスサーバーVPSのMastodonイメージを使用したソロインスタンスに新規ユーザーを追加した&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/mastodon-bot-with-pm2/&quot;&gt;PM2を使ってMastodonのBotを作成した&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;結果的に大満足で、&lt;/p&gt;
&lt;p&gt;今はタイムラインより、ローカルタイムラインに訪れる機会のほうが増えた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://social.nove-b.dev/public/local&quot;&gt;ローカルタイムライン&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;後は投稿のカスタマイズ、RSSのURLリストを外部ファイル化する、&lt;code&gt;PM2&lt;/code&gt;を辞めるっていうのが課題。&lt;/p&gt;
&lt;p&gt;引き続き、改善していく。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>WordpressをDockerで起動する</title><link>https://blog.nove-b.dev/posts/wordpress-docker-setup</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/wordpress-docker-setup</guid><content:encoded>&lt;p&gt;個人開発が完了し、やることがなくなったので&lt;a href=&quot;https://github.com/nove-b/create-eye-catch-for-classic/issues/1&quot;&gt;記事公開時に自動でアイキャッチ画像をアップロードしたい #1 &lt;/a&gt;このIssueの解決を試みることにした。&lt;/p&gt;
&lt;p&gt;そこで開発環境にアクセスしようとしたけど、パソコンを変えたので&lt;a href=&quot;https://localwp.com/&quot;&gt;Local - Local WordPress development made simple&lt;/a&gt;をインストールしなくちゃいけないことに気が付いた。&lt;/p&gt;
&lt;p&gt;ただ何となく、本当になんとなく気が進まなかったので&lt;code&gt;Docker&lt;/code&gt;で環境構築することにした。&lt;/p&gt;
&lt;h2&gt;DockerでWorspressを起動する&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.jp/compose/wordpress.html&quot;&gt;クィックスタート: Compose と WordPress&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;しっかりとドキュメントが整備されていたので、それ通りやるだけ。&lt;/p&gt;
&lt;p&gt;まずは&lt;code&gt;docker-compose.yml&lt;/code&gt; ファイルを生成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - &quot;8000:80&quot;
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
volumes:
  db_data:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、&lt;code&gt;docker-compose up -d&lt;/code&gt;で実行する。&lt;/p&gt;
&lt;p&gt;すると下記内容のエラーが出た。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/c/dev/wordpress
$ docker-compose up -d
time=&quot;2025-02-10T07:49:35+09:00&quot; level=warning msg=&quot;C:\\dev\\wordpress\\docker-compose.yml: the attribute `version` is obsolete, it will be ignoed, please remove it to avoid potential confusion&quot;
[+] Running 0/2
 - db Pulling                                                                                                                                                                                            3.1s
 - wordpress Pulling                                                                                                                                                                                     3.1s
no matching manifest for linux/arm64/v8 in the manifest list entries
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;エラーの内容としては&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;使用している Docker イメージに linux/arm64/v8 の対応がないためです。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことらしい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; - image: mysql:5.7
 +  image: mysql:8.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mysql:5.7&lt;/code&gt; は &lt;code&gt;arm64&lt;/code&gt;
へのサポートが十分ではないということなので、&lt;code&gt;mysql:8.0&lt;/code&gt;を試してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker-compose up -d
time=&quot;2025-02-10T07:52:13+09:00&quot; level=warning msg=&quot;C:\\dev\\wordpress\\docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion&quot;
[+] Running 35/2
 ✔ wordpress Pulled                                                                                                                                                                                     43.4s
 ✔ db Pulled                                                                                                                                                                                            69.3s
[+] Running 4/4
 ✔ Network wordpress_default        Created                                                                                                                                                              0.1s
 ✔ Volume &quot;wordpress_db_data&quot;       Created                                                                                                                                                              0.0s
 ✔ Container wordpress-db-1         Started                                                                                                                                                              0.5s
 ✔ Container wordpress-wordpress-1  Started
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事に通った。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://localhost:8000&lt;/code&gt;に行けば開ける。&lt;/p&gt;
&lt;p&gt;そろそろ着手する。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;(2025/2/15)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;にversionの記載はいらないと指摘をもらったので修正した。&lt;/p&gt;
&lt;p&gt;どうやら&lt;code&gt;docker-compose.yml&lt;/code&gt;も非推奨らしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://qiita.com/mai_llj/items/a91bb375af68a1c88469&quot;&gt;そのdocker-compose.yaml、正しいですか？&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Hugoブログで最終更新日がすべて同じになっていたのを修正した </title><link>https://blog.nove-b.dev/posts/fix-same-lastmod</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/fix-same-lastmod</guid><content:encoded>&lt;h2&gt;最終更新日が１分前&lt;/h2&gt;
&lt;p&gt;記事を更新したのでブログを訪れ適当に記事を読んでいると、すべての最終更新時間が同じことに気が付いた。&lt;/p&gt;
&lt;p&gt;どうやら記事の&lt;code&gt;meta&lt;/code&gt;データに&lt;code&gt;lastmod&lt;/code&gt;を入れると最終更新日が更新されるらしいけど、毎回そんなことをしたくない。&lt;/p&gt;
&lt;h2&gt;Gitを使用する&lt;/h2&gt;
&lt;p&gt;そこで調べていると&lt;code&gt;Git&lt;/code&gt;の情報で取れるらしいという知識を得た。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hugo.toml&lt;/code&gt;で下記設定にする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;enableGitInfo = true [frontmatter] lastmod = [&quot;lastmod&quot;, &quot;:git&quot;, &quot;:fileModTime&quot;,
&quot;:default&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でビルドしたけど、すべての記事が最終更新１分前で変わらず。&lt;/p&gt;
&lt;p&gt;色々調査し、ビルド時にオプション付けるといけるらしいということで実行したけど、最終更新１分前で変わらず。&lt;/p&gt;
&lt;h2&gt;Gitの情報を見てみる&lt;/h2&gt;
&lt;p&gt;さすがにおかしいので、昔の&lt;code&gt;.md&lt;/code&gt;のコミット履歴を調べたら1分前だった。&lt;/p&gt;
&lt;p&gt;なんでそなことになったのか潰していくと、どうやら&lt;code&gt;Github Action&lt;/code&gt;でコードフォーマットをしているのだが、それが問題っぽいということに行き当たった。&lt;/p&gt;
&lt;p&gt;実際にGithub Actionを消したら無事に、最終更新日がばらけてくれた。&lt;/p&gt;
&lt;h2&gt;Github Actionを修正する&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/post/github-action-prettier/&quot;&gt;Github Actionでprettierを実行したい&lt;/a&gt;で作成した&lt;code&gt;Action Flow&lt;/code&gt;を修正する。&lt;/p&gt;
&lt;p&gt;前&lt;code&gt;Action Flow&lt;/code&gt;では全ファイルに対しフォーマットをかけていたので変更されたファイルのみをフォーマットするように修正した。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;新バージョン（上）&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} -- &apos;*.md&apos;)
if [[ -n &quot;$CHANGED_FILES&quot; ]]; then
  echo &quot;$CHANGED_FILES&quot; | xargs prettier --write
else
  echo &quot;No Markdown files changed. Skipping formatting.&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;旧バージョン（下）&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;prettier --write &quot;**/*.md&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そのほかにも修正してスリム化した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Format Markdown
on:
  push:
    branches:
      - main

permissions:
  contents: write

jobs:
  format:
    runs-on: ubuntu-latest
    steps:
      - name: Check out the repository
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: &quot;18&quot;

      - name: Install Prettier
        run: |
          npm install -g prettier

      - name: Create .prettierrc
        run: |
          echo &apos;{&quot;overrides&quot;: [{&quot;files&quot;: &quot;*.md&quot;, &quot;options&quot;: {&quot;proseWrap&quot;: &quot;always&quot;}}]}&apos; &amp;gt; .prettierrc

      - name: Format only changed Markdown files
        run: |
          CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} -- &apos;*.md&apos;)
          if [[ -n &quot;$CHANGED_FILES&quot; ]]; then
            echo &quot;$CHANGED_FILES&quot; | xargs prettier --write
          else
            echo &quot;No Markdown files changed. Skipping formatting.&quot;
          fi

      - name: Commit changes
        run: |
          git config --global user.name &quot;github-actions[bot]&quot;
          git config --global user.email &quot;github-actions[bot]@users.noreply.github.com&quot;
          git add .
          git diff --cached --quiet || (git commit -m &quot;Format markdown files&quot; &amp;amp;&amp;amp; git push origin main)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;結果、うまくいった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Hugoのテーマ「Github Style Plus」のローカル検索をFuse.jsで最適化した。</title><link>https://blog.nove-b.dev/posts/optimized-local-search-performance</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/optimized-local-search-performance</guid><content:encoded>&lt;h2&gt;github-stylingというテーマに変更した&lt;/h2&gt;
&lt;p&gt;このブログは&lt;a href=&quot;https://github.com/MeiK2333/github-style&quot;&gt;github-style&lt;/a&gt;から&lt;code&gt;Clone&lt;/code&gt;された&lt;a href=&quot;https://github.com/kurt-liao/github-style-plus&quot;&gt;github-style-plus&lt;/a&gt;を&lt;code&gt;fork&lt;/code&gt;してカスタマイズした&lt;a href=&quot;https://github.com/nove-b/github-styling&quot;&gt;github-styling&lt;/a&gt;というテーマを使用している。&lt;/p&gt;
&lt;p&gt;名前の通りデザインをGithubに寄せたブログテーマで絶大な人気はなさそうだし、Githubのデザイン変更に追従するのは辛そうだし、オプションも少なそうだっだけど、個人でカスタマイズしてくのであれば問題なそうだったので採用してみた。&lt;/p&gt;
&lt;p&gt;結果、個人的に使い慣れた、見慣れたデザインになったのでまあ良かったと思っている。&lt;/p&gt;
&lt;p&gt;テーマ変更時にディレクトの変更を余儀なくされ、&lt;code&gt;netlify&lt;/code&gt;のリダイレクト設定が必要になったりと面倒ではあったが、躓くことなくテーマ変更できた。&lt;/p&gt;
&lt;p&gt;とはいえ、それなりに時間を食うので、このテーマとは長く付き合いたいと思っている。&lt;/p&gt;
&lt;p&gt;ただ前述したようにいくらかカスタマイズしなくちゃいけない部分があり、中でも致命的だったのがローカル検索の遅さだった。&lt;/p&gt;
&lt;h2&gt;ローカル検索に1分かかる&lt;/h2&gt;
&lt;p&gt;個人的にGithubの最大使いやすさは検索性能の高さだと思っている。&lt;/p&gt;
&lt;p&gt;コード検索とか本当に重宝している。&lt;/p&gt;
&lt;p&gt;それに比べてこのテーマの検索は遅すぎた。&lt;/p&gt;
&lt;p&gt;ブログは過去のナレッジが詰まっているので頻繁に検索したい、けどそのたびに1分かかるのは辛い。&lt;/p&gt;
&lt;p&gt;ということで改善することにした。&lt;/p&gt;
&lt;p&gt;実際の改善前が下記動画で、実際には1分20秒かかっている。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;old.gif&quot; alt=&quot;改善前のローカル検索&quot; /&gt;&lt;/p&gt;
&lt;p&gt;ネットワークタブをみると全ファイルを 見に行っていることがわかった。&lt;/p&gt;
&lt;h2&gt;github-style-plusのローカル検索を解読する&lt;/h2&gt;
&lt;p&gt;実際に全ファイルを見に行っているのが下記のソースになる&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fetch(
  `${host.indexOf(&quot;localhost&quot;) &amp;gt; -1 ? &quot;http://&quot; : &quot;https://&quot;}${host}/index.xml`,
)
  .then((resp) =&amp;gt; resp.text())
  .then(async (res) =&amp;gt; {
    parser = new DOMParser();
    xmlDoc = parser.parseFromString(res, &quot;text/xml&quot;);
    const linkResult = xmlDoc.getElementsByTagName(&quot;link&quot;);
    const titleResult = xmlDoc.getElementsByTagName(&quot;title&quot;);
    const arr = [];

    const matched = [];
    await (async function searchLink() {
      for (let i = 0; i &amp;lt; linkResult.length; i++) {
        await fetch(linkResult[i].textContent).then((resp) =&amp;gt;
          resp.text().then((res) =&amp;gt; {
            const pureText = stripHtml(res);
            if (pureText.indexOf(keyword) &amp;gt;= 0) {
              matched.push(i);
            }
          }),
        );
      }
    })();
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まず、自身の&lt;a href=&quot;https://blog.nove-b.dev/index.xml&quot;&gt;&lt;code&gt;index.xml&lt;/code&gt;&lt;/a&gt;を取得し全URLの件数を取得する。&lt;/p&gt;
&lt;p&gt;その件数で&lt;code&gt;for&lt;/code&gt;を回し、全URLのコンテンツを取り出しキーワードが含まれているかをチェックしている。&lt;/p&gt;
&lt;p&gt;で含まれていたら&lt;code&gt;matched&lt;/code&gt;に格納し、&lt;code&gt;matched&lt;/code&gt;を使用し&lt;code&gt;Dom&lt;/code&gt;を生成している。&lt;/p&gt;
&lt;p&gt;いま200記事あるので、それを全部見に行くとなると、それはそれなりに時間がかかるに決まっている。&lt;/p&gt;
&lt;h2&gt;改善する&lt;/h2&gt;
&lt;p&gt;改善後は下記のようになった。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;new.gif&quot; alt=&quot;改善後のローカル検索&quot; /&gt;&lt;/p&gt;
&lt;p&gt;検索の高速化を調べていると&lt;a href=&quot;https://www.fusejs.io/&quot;&gt;&lt;code&gt;Fuse.js&lt;/code&gt;&lt;/a&gt;がヒットした。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Powerful, lightweight fuzzy-search library, with zero dependencies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下記のように実装しなおした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script src=&quot;https://cdn.jsdelivr.net/npm/fuse.js@7.1.0&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずは&lt;code&gt;Fuse.js&lt;/code&gt;を読み込む。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const fetchIndex = async () =&amp;gt; {
  const response = await fetch(
    `${host.indexOf(&quot;localhost&quot;) &amp;gt; -1 ? &quot;http://&quot; : &quot;https://&quot;}${host}/index.xml`,
  );
  const xmlText = await response.text();
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xmlText, &quot;text/xml&quot;);
  const items = Array.from(xmlDoc.getElementsByTagName(&quot;item&quot;));

  searchIndex = items.map((item) =&amp;gt; ({
    title: item.getElementsByTagName(&quot;title&quot;)[0].textContent,
    link: item.getElementsByTagName(&quot;link&quot;)[0].textContent,
    content: item.getElementsByTagName(&quot;description&quot;)[0]?.textContent || &quot;&quot;,
  }));

  fuse = new Fuse(searchIndex, {
    keys: [&quot;title&quot;, &quot;content&quot;],
    threshold: 0.3,
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に&lt;code&gt;fuse&lt;/code&gt;を定義する。&lt;/p&gt;
&lt;p&gt;これで特定のキーワードを&lt;code&gt;title&lt;/code&gt;と&lt;code&gt;content&lt;/code&gt;から検索できるようになる。やっていることは改善前と変わらずに、&lt;code&gt;index.xml&lt;/code&gt;から&lt;code&gt;title&lt;/code&gt;と&lt;code&gt;link&lt;/code&gt;と&lt;code&gt;description&lt;/code&gt;を取得している。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;threshold&lt;/code&gt;はあいまい検索の閾値らしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.fusejs.io/api/options.html&quot;&gt;オプション&lt;/a&gt;は他にもあった。&lt;/p&gt;
&lt;p&gt;で、下記コードのように検索ワードを&lt;code&gt;search&lt;/code&gt;に渡せば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const results = fuse.search(query).map((res) =&amp;gt; res.item);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fetchIndex&lt;/code&gt;で返した&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;title&lt;/li&gt;
&lt;li&gt;link&lt;/li&gt;
&lt;li&gt;content&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;が取得できるので、それで&lt;code&gt;Dom&lt;/code&gt;を生成すればいい。&lt;/p&gt;
&lt;p&gt;この方法なら初回に&lt;code&gt;index.xml&lt;/code&gt;を取得するだけで検索が実装できる。&lt;/p&gt;
&lt;p&gt;これでブログを頻繁に検索できるようになり、自身のナレッジに手軽にアクセスできるようになった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nove-b/github-styling/blob/875529f5d32a17fc2acd495e4aacbf85b5eb9794/layouts/partials/script.html&quot;&gt;全コードはこちら&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;そもそも改善前も&lt;code&gt;description&lt;/code&gt;を使えば&lt;code&gt;fetch&lt;/code&gt;する必要がなかったかもしれない。&lt;/p&gt;
&lt;p&gt;あるいはもしかするとこの方法だと&lt;code&gt;tag&lt;/code&gt;が取得できないので、あえて全URLのHTMLを見に行っていたのかもしれない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Google CloudでNode.jsを起動する</title><link>https://blog.nove-b.dev/posts/node-google-cloud</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/node-google-cloud</guid><content:encoded>&lt;p&gt;&lt;code&gt;Node.js&lt;/code&gt;をできる限り安く動かしたいという思いでクラウドサービスを探していたところ、Google
Cloudで特定の条件であれば無料利用できそうということを知ったので、サーバーの立ち上げから&lt;code&gt;Node.js&lt;/code&gt;の実行までを行った。&lt;/p&gt;
&lt;h2&gt;Google Cloudの無料枠&lt;/h2&gt;
&lt;p&gt;コンピューティングエンジンの無料枠は下記の通り。&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;e2-micro 以下の米国リージョンのいずれかで、毎月 1 つの非プリエンプティブVM インスタンス:
&lt;ul&gt;
&lt;li&gt;オレゴン：us-west1&lt;/li&gt;
&lt;li&gt;アイオワ州:us-central1&lt;/li&gt;
&lt;li&gt;サウスカロライナ州:us-east1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;30 GB/月の標準永続ディスク&lt;/li&gt;
&lt;li&gt;北米からすべての地域（中国とオーストラリアを除く）への毎月1GBの送信データ転送&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;詳細は&lt;a href=&quot;https://cloud.google.com/free/docs/free-cloud-features#compute&quot;&gt;ここ&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;コンピューティングエンジン&lt;/h2&gt;
&lt;p&gt;そもそもコンピューティングエンジンがなんなのかというと、公式には下記のように書かれている。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Compute
Engine は、Google のインフラストラクチャ上で仮想マシンを作成して実行できる、コンピューティングおよびホスティング サービスです。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;みんな大好きAWSでいうところのES2と同じ。&lt;/p&gt;
&lt;h2&gt;Google Cloudのコンピューティングエンジンでインスタンスを立ち上げる&lt;/h2&gt;
&lt;p&gt;Google Cloudにログインし、サイドメニューからCompute Engineを選択する。&lt;/p&gt;
&lt;p&gt;VM インスタンスを選択し、インスタンスの作成をする。&lt;/p&gt;
&lt;p&gt;で、前述した無料枠の条件に適するように選択する。&lt;/p&gt;
&lt;p&gt;次にネットワーキングタブでファイアウォールの&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[x] HTTP トラフィックを許可する&lt;/li&gt;
&lt;li&gt;[x] HTTPS トラフィックを許可する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;にチェックを入れる。&lt;/p&gt;
&lt;p&gt;ここにチェックを入れずに作成したせいで接続ができずに苦労した。&lt;/p&gt;
&lt;p&gt;これでインスタンスの立ち上げが完了。&lt;/p&gt;
&lt;p&gt;&lt;s&gt;この方法で立ち上げて2日間経つけど請求が来ていないので無料枠での運用は問題がなさそうだった。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;なんか請求発生している気がするので、しっかり確認する必要がありそう。&lt;/p&gt;
&lt;h2&gt;ブラウザからアクセスできるようにする&lt;/h2&gt;
&lt;p&gt;VM インスタンスのSSHをクリックすればブラウザ上でコンソールが起動するので、そこでコマンドを実行していく。&lt;/p&gt;
&lt;h3&gt;nginxをインストール&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;nginx&lt;/code&gt;をインストールして起動する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install nginx -y
sudo service nginx start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでインスタンスの外部 IPに訪問すれば下記のような画面が表示される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Welcome to nginx!
If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;nodeアプリを立ち上げる&lt;/h2&gt;
&lt;h3&gt;Gitをインストール&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Git&lt;/code&gt;上の&lt;code&gt;Node.js&lt;/code&gt;アプリを動かしたいのでまずは&lt;code&gt;Git&lt;/code&gt;をインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install git -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Advanced Package Tool&lt;/code&gt;を最新にし、&lt;code&gt;Git&lt;/code&gt;をインストール。&lt;/p&gt;
&lt;p&gt;次に&lt;code&gt;Node.js&lt;/code&gt;をインストールしたいんだけど、パッケージツールに&lt;code&gt;Volta&lt;/code&gt;を使用しているので先に&lt;code&gt;Volta&lt;/code&gt;をインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl https://get.volta.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Volta&lt;/code&gt;は&lt;code&gt;package.json&lt;/code&gt;に記載している&lt;code&gt;Node.js&lt;/code&gt;を自動でインストールしてくれるので、結果的に&lt;code&gt;Node.js&lt;/code&gt;のインストールは完了したことになる。&lt;/p&gt;
&lt;p&gt;最後に&lt;code&gt;Git&lt;/code&gt;上の&lt;code&gt;Node.js&lt;/code&gt;アプリを&lt;code&gt;Clone&lt;/code&gt;する。&lt;/p&gt;
&lt;h2&gt;Node.jsを起動する&lt;/h2&gt;
&lt;p&gt;次に、Nginxをリバースプロキシとして設定し、HTTPリクエストをNode.jsアプリ（ポート3000）に転送する設定をする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/etc/nginx/sites-available/default&lt;/code&gt;を下記に変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    # サーバーがリッスンするポートを指定（HTTPの標準ポート80）
    listen 80;

    # サーバーのホスト名やIPアドレスを指定
    # ここでは「外部IP」へのリクエストを処理する
    server_name 外部IP;

    # ルートパス（&quot;/&quot;）へのリクエストを処理
    location / {
        # リクエストをリバースプロキシし、ポート3000で動作するローカルのNode.jsアプリに転送
        proxy_pass http://localhost:3000; # Node.js アプリが動作しているポート

        # クライアントの &quot;Host&quot; ヘッダーをそのままバックエンド（Node.js）に渡す
        proxy_set_header Host $host;

        # クライアントの実際のIPアドレスを &quot;X-Real-IP&quot; ヘッダーとしてバックエンドに渡す
        proxy_set_header X-Real-IP $remote_addr;

        # クライアントの元のIPアドレスを &quot;X-Forwarded-For&quot; ヘッダーとしてバックエンドに渡す
        # プロキシを経由した場合でも、すべての経由したIPアドレスがリストされる
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # クライアントがHTTPかHTTPSのどちらでアクセスしたかをバックエンドに伝える
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;理解が追い付かなかったとのでChat GPTにコメントアウトを書いてもらった。&lt;/p&gt;
&lt;p&gt;よくわからないけど、&lt;code&gt;/&lt;/code&gt;にアクセスが来た時、&lt;code&gt;http://localhost:3000&lt;/code&gt;に転送してくれるらしい。&lt;/p&gt;
&lt;p&gt;そういうわけなので、Nginxを再起動して設定を適用し&lt;code&gt;Node.js&lt;/code&gt;を起動したら、アプリが表示された。&lt;/p&gt;
&lt;h2&gt;独自ドメインとLet&apos;s Encrypt の無料SSL証明書を取得する&lt;/h2&gt;
&lt;p&gt;独自ドメインの取得と設定は省略する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install certbot python3-certbot-nginx -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記は下記のプラグインをインストールする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;certbot&lt;/code&gt; → Let&apos;s Encrypt の無料SSL証明書を取得・更新するためのツール。
&lt;code&gt;python3-certbot-nginx&lt;/code&gt; → CertbotがNginxと統合できるようにするプラグイン。&lt;/p&gt;
&lt;p&gt;次にLet&apos;s Encrypt の無料SSL証明書を取得する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo certbot --nginx -d example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最後に、自動更新を設定する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo certbot renew --dry-run
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Nginx の設定で HTTP から HTTPS へリダイレクト&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sudo nano /etc/nginx/sites-available/default&lt;/code&gt;で&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen 80;  # HTTPリクエストを受け付けるポート
    server_name {domain};  # この設定が適用されるドメイン名

    # HTTPアクセスをHTTPSにリダイレクト
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;  # HTTPSリクエストを受け付けるポート
    server_name {domain};  # この設定が適用されるドメイン名

    # Let&apos;s Encryptで取得したSSL証明書のパスを指定
    ssl_certificate /etc/letsencrypt/live/{domain}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/{domain}/privkey.pem;

    # サポートするTLSのバージョンを指定（TLS1.2およびTLS1.3のみを許可）
    ssl_protocols TLSv1.2 TLSv1.3;

    # 安全な暗号スイートを指定（脆弱なアルゴリズムを排除）
    ssl_ciphers HIGH:!aNULL:!MD5;

    # ドキュメントルート（公開ディレクトリ）の設定
    root /var/www/html;

    # デフォルトのインデックスファイルを指定
    index index.html index.htm index.nginx-debian.html;

    # ルートパス（/）へのリクエストを処理
    location / {
        # リクエストされたURIが存在する場合はそのファイルを提供
        # ディレクトリとして存在する場合はそのディレクトリを開く
        # どちらにも該当しない場合は404エラーを返す
        try_files $uri $uri/ =404;
    }

    # /search-items へのリクエストをNode.jsアプリ（ポート3000）に転送
    location /search-items {
        proxy_pass http://127.0.0.1:3000;  # ローカルのNode.jsアプリへリクエストを転送

        # クライアントのホスト情報を転送
        proxy_set_header Host $host;

        # クライアントのIPアドレスを転送
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # クライアントのプロトコル情報（http/https）を転送
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように修正して&lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;で再起動する。&lt;/p&gt;
&lt;p&gt;これも理解しきれていないので、コメントアウトを書いもらった。&lt;/p&gt;
&lt;h2&gt;Node.jsを常時起動したい&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/post/mastodon-bot-with-pm2/&quot;&gt;PM2を使ってMastodonのBotを作成した&lt;/a&gt;で&lt;code&gt;PM2&lt;/code&gt;を使いアプリケーションの永続化をしたところ、&lt;code&gt;systemd &lt;/code&gt;のほうが良いと思うと言われたので、今回は&lt;code&gt;systemd&lt;/code&gt;を使ってみた。&lt;/p&gt;
&lt;p&gt;まずはサービスファイルを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/systemd/system/node.service
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
# サービスの説明（任意）
Description=My Node.js App
# このサービスはネットワークが起動した後に起動する
After=network.target

[Service]
# Node.js の実行ファイル（Volta 経由）を使用してアプリを起動
ExecStart=/home/{username}/.volta/bin/node /home/{path}/app.js
# 作業ディレクトリを指定（相対パス解決のため）
WorkingDirectory=/home/{path}
# アプリが異常終了した場合でも自動で再起動
Restart=always
# 実行するユーザーを指定（セキュリティ上、root ではなく専用ユーザーを使う）
User={username}
# 環境変数 NODE_ENV を production に設定
Environment=NODE_ENV=production
# 環境変数を .env ファイルから読み込む
EnvironmentFile=/home/{path}/.env
# 標準出力を syslog に記録
StandardOutput=syslog
# 標準エラー出力も syslog に記録
StandardError=syslog
# syslog に記録する際の識別子（ログ確認時に `node-app` で検索可能）
SyslogIdentifier=node-app

[Install]
# `systemctl enable node-app` で OS 起動時に自動起動させるためのターゲット
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;systemctl コマンド一覧&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;コマンド&lt;/th&gt;
&lt;th&gt;役割&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl daemon-reload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;systemd の設定を再読み込み&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl enable node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OS 起動時に node を自動起動する&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl disable node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OS 起動時の自動起動を無効にする&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl start node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;node を今すぐ起動&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl stop node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;node を今すぐ停止&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl restart node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;node を再起動&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl reload node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;設定を変更してプロセスを再読込&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;node の現在の状態を確認&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl list-units --type=service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;起動中のサービス一覧を表示&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl list-unit-files --type=service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;すべてのサービス一覧を表示&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl is-active node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;node が動作中か確認&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl is-enabled node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;node の自動起動設定を確認&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl kill node&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;node のプロセスを強制終了&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo journalctl -u node --no-pager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;node のログを確認&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;上記のようなコマンドがあるので、サービスを登録 して起動する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl enable node
sudo systemctl start node
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>nove-b</author></item><item><title>Kindle Unlimitedの検索が使いにくいので、好きな作家の対象本を一覧表示するサービスを作った</title><link>https://blog.nove-b.dev/posts/kindle-unlimited-search-service</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/kindle-unlimited-search-service</guid><content:encoded>&lt;h2&gt;Kindle Unlimitedの検索が使いにくい！&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Kindle
Unlimited&lt;/strong&gt;は、読書好きにとって最高のサブスクリプションサービスのひとつです。&lt;/p&gt;
&lt;p&gt;毎月7～8冊ほど読むため、利用することで&lt;strong&gt;月に¥2,500～¥3,000ほどお得&lt;/strong&gt;になっています。しかし、便利な一方で、&lt;strong&gt;検索のしにくさ&lt;/strong&gt;が大きな課題でした。&lt;/p&gt;
&lt;p&gt;Googleのサジェストに「&lt;strong&gt;Kindle
Unlimited 検索しにくい&lt;/strong&gt;」と出るくらいなので、同じ不満を持つ人は多いはずです。&lt;/p&gt;
&lt;p&gt;特に、&lt;strong&gt;Kindle
Unlimitedの対象本だけを簡単に検索する&lt;/strong&gt;のが難しく、フィルターをかけたり、余計な操作が必要になったりと手間がかかります。&lt;/p&gt;
&lt;p&gt;そんな中、Qiitaで&lt;a href=&quot;https://qiita.com/muranet/items/4bb0c89f6c2da44185a9&quot;&gt;「kindle unlimited検索を作ってみた」&lt;/a&gt;という記事を発見しました。&lt;/p&gt;
&lt;p&gt;これは非常に便利なツールで、今まで読んだQiita記事の中で&lt;strong&gt;一番役に立った&lt;/strong&gt;と言っても過言ではありません。しかし、使い続けるうちに「&lt;strong&gt;自分は特定の作家の本しか検索していない&lt;/strong&gt;」ということに気が付きました。&lt;/p&gt;
&lt;h2&gt;好きな作家のKindle Unlimited対象本を簡単に探したい&lt;/h2&gt;
&lt;p&gt;自分が本当に欲しいのは、&lt;strong&gt;特定の作家のKindle
Unlimited対象本を簡単に一覧表示できるサービス&lt;/strong&gt;でした。&lt;/p&gt;
&lt;p&gt;Amazonの検索URLをブックマークする方法もありますが、それでは使い勝手が悪い。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;「エンジニアなら、ないものは作ろう！」&lt;/strong&gt;
ということで、思い立って開発しました。&lt;/p&gt;
&lt;h2&gt;Kindle Unlimited対象本検索ツールを開発！&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;service.gif&quot; alt=&quot;📚【無料で読める】好きな作家の本を検索！Kindle Unlimited対応作品一覧&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kindle-unlimited-search.nove-b.dev/&quot;&gt;📚【無料で読める】好きな作家の本を検索！Kindle Unlimited対応作品一覧&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;このサービスでは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;好きな作家のKindle Unlimited対象本を簡単に検索&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;シンプルで直感的なUI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;すぐに使える無料ツール&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;を提供しています。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kindle Unlimitedの検索が使いにくいと感じている方は、ぜひ試してみてください！&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;まとめ&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Kindle
Unlimitedの検索が不便&lt;/strong&gt;と感じている方のために、好きな作家の対象本を簡単に検索できるツールを作成しました。&lt;/p&gt;
&lt;p&gt;📌 &lt;a href=&quot;https://kindle-unlimited-search.nove-b.dev/&quot;&gt;今すぐ試す！&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;このツールが、あなたの読書ライフをより快適にする助けになれば幸いです！&lt;/p&gt;
&lt;h2&gt;星新一賞の最終候補にAIの小説が選ばれたらしい&lt;/h2&gt;
&lt;p&gt;上までの文章はすべてChat GPTに書いてもらった。&lt;/p&gt;
&lt;p&gt;下書きしてそれをSEOの観点で書き直してもらった。&lt;/p&gt;
&lt;p&gt;別に自分の文章が好きなわけじゃないけど、自分の文体じゃない。&lt;/p&gt;
&lt;p&gt;AIの発展はうれしいけど、小説から文章の個性が消えるのは少し寂しくもある。&lt;/p&gt;
&lt;p&gt;誰かに似た文章はかけるけど、オリジナルな文章を年齢とともに更新していけるのは人間だけな気がする。&lt;/p&gt;
&lt;p&gt;知らんけど。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://togetter.com/li/2517462&quot;&gt;「AIが書いたSF小説としては史上最高レベルかも」執筆のほぼ全てをAIに任せて星新一賞の最終候補に残った作品が話題に&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年2月】土日お出かけ月間のなか個人開発もけっこう楽しめた</title><link>https://blog.nove-b.dev/posts/2025-2</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-2</guid><content:encoded>&lt;h2&gt;2月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4ibVI4a&quot;&gt;鹿男あをによし&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4hFHFUb&quot;&gt;豆腐の角に頭ぶつけて死んでしまえ事件 (実業之日本社文庫)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2月も読めなった。&lt;/p&gt;
&lt;p&gt;というより今読んでいる朝井リョウの本が、なんとなく重たくって読書が進まない。&lt;/p&gt;
&lt;p&gt;そういえば冬になってから、ずっと&lt;a href=&quot;https://amzn.to/43nW7fP&quot;&gt;鬼平犯科帳&lt;/a&gt;が読みたいんだけど、過去に持っていたことを考えるとお金出して買いたくない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/kindle-dbs/hz/signup?tag=nove0822-22&quot;&gt;Kindle Unlimited&lt;/a&gt;の対象になってくれないかしら。&lt;/p&gt;
&lt;h2&gt;BOOX GoColor7が気になる&lt;/h2&gt;
&lt;p&gt;Kindleを購入してまるっと5年経つけど、&lt;a href=&quot;https://www.amazon.co.jp/kindle-dbs/hz/signup?tag=nove0822-22&quot;&gt;Kindle Unlimited&lt;/a&gt;でしか、ほぼほぼ本を読まなくなってきた。&lt;/p&gt;
&lt;p&gt;5年経ったのでさすがにKindleのレスポンスが遅くなってきた。&lt;/p&gt;
&lt;p&gt;そろそろ新しいのを買わなくちゃいけないんだけど、最近のKindleは27,980円するらしい。&lt;/p&gt;
&lt;p&gt;27,980円の読書しかできない端末ってどうなうんだろう。&lt;/p&gt;
&lt;p&gt;今使っているスマホも5000円で買ったというのに、それより高い読書しかできない端末ってあんまりしっくりこない。&lt;/p&gt;
&lt;p&gt;そんなか、&lt;a href=&quot;https://amzn.to/4hZ3fDL&quot;&gt;BOOX GoColor7&lt;/a&gt;というのを見つけた。&lt;/p&gt;
&lt;p&gt;Kindle Paperwhite と比較すると、2万円の差額でカラーに対応しているし、Android
OSが入っているらしい。&lt;/p&gt;
&lt;p&gt;3GBでスムーズに動くのかという疑問もあるけど、検討する価値はありそうということで、電気屋に行った時は探してみることにする。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;項目&lt;/th&gt;
&lt;th&gt;BOOX GoColor7&lt;/th&gt;
&lt;th&gt;Kindle Paperwhite&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;画面サイズ&lt;/td&gt;
&lt;td&gt;7インチ&lt;/td&gt;
&lt;td&gt;7インチ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;画面タイプ&lt;/td&gt;
&lt;td&gt;Kaleido 3 (カラーE Ink)&lt;/td&gt;
&lt;td&gt;モノクロE Ink (300ppi)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;フロントライト&lt;/td&gt;
&lt;td&gt;○ (調光・色温調整あり)&lt;/td&gt;
&lt;td&gt;○ (調光・色温調整あり)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;解像度&lt;/td&gt;
&lt;td&gt;1264×1680 (カラー: 150ppi, モノクロ: 300ppi)&lt;/td&gt;
&lt;td&gt;1236×1648 (300ppi)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OS&lt;/td&gt;
&lt;td&gt;Android 11&lt;/td&gt;
&lt;td&gt;Kindle専用OS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;アプリインストール&lt;/td&gt;
&lt;td&gt;○ (Google Play対応)&lt;/td&gt;
&lt;td&gt;× (Kindleストアのみ)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ストレージ容量&lt;/td&gt;
&lt;td&gt;32GB&lt;/td&gt;
&lt;td&gt;16GB / 32GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAM&lt;/td&gt;
&lt;td&gt;3GB&lt;/td&gt;
&lt;td&gt;非公開&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;防水性能&lt;/td&gt;
&lt;td&gt;×&lt;/td&gt;
&lt;td&gt;○ (IPX8)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;バッテリー持ち&lt;/td&gt;
&lt;td&gt;数週間 (使用状況による)&lt;/td&gt;
&lt;td&gt;数週間 (使用状況による)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;重量&lt;/td&gt;
&lt;td&gt;約195g&lt;/td&gt;
&lt;td&gt;約205g&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;接続端子&lt;/td&gt;
&lt;td&gt;USB-C&lt;/td&gt;
&lt;td&gt;USB-C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ワイヤレス通信&lt;/td&gt;
&lt;td&gt;Wi-Fi / Bluetooth&lt;/td&gt;
&lt;td&gt;Wi-Fi / Bluetooth (シグニチャーエディション)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;価格&lt;/td&gt;
&lt;td&gt;約50,000円前後&lt;/td&gt;
&lt;td&gt;約27,980円～32,980円&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;特徴&lt;/td&gt;
&lt;td&gt;カラー表示対応、Androidアプリ利用可&lt;/td&gt;
&lt;td&gt;Kindleストア最適化、防水性能あり&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;4月から保育園が始まる&lt;/h2&gt;
&lt;p&gt;ただ今、そんなものを探している場合じゃない。&lt;/p&gt;
&lt;p&gt;というのも4月から保育園が始まるので、今のうちにお出かけしておこうとなった。&lt;/p&gt;
&lt;p&gt;そういうわけで2月は&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;鎌倉&lt;/li&gt;
&lt;li&gt;吾妻山&lt;/li&gt;
&lt;li&gt;ソラトス&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;に行った。&lt;/p&gt;
&lt;p&gt;鎌倉は子どもだけでなく、親も楽しめるので良い。静かな喫茶店で大泣きしたのは焦ったけど、江ノ電を楽しそうに見ててよかった。&lt;/p&gt;
&lt;p&gt;吾妻山はなぜか歩いてくれたので、楽だった。長い滑り台で喜んでいたので良かった。&lt;/p&gt;
&lt;p&gt;最近、すごいしゃべるようになったし、鉄棒にぶら下がれるようになった。&lt;/p&gt;
&lt;p&gt;&amp;lt;p&amp;gt;&amp;lt;iframe style=&quot;max-width: 100%;“ allowfullscreen=&quot;allowfullscreen&quot; src=&quot;https://www.youtube.com/embed/videoseries?si=yr-WqzRnH4FOYc5P&amp;amp;list=PL911pe0HjN9gufWEDWCoQIsTGkyNSSkor&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;ゆる言語学ラジオで子どもの言語習得について話していたけど、本当にすごい。&lt;/p&gt;
&lt;p&gt;3月も土日は休まずお出かけしたい。&lt;/p&gt;
&lt;p&gt;とりあえず&lt;a href=&quot;https://playec.jp/&quot;&gt;PLAY! PARK ERIC CARLE&lt;/a&gt;にいく。&lt;/p&gt;
&lt;p&gt;ただ保育園の買い物ものいかないといけないので、引き続き土日は忙しそうだ。&lt;/p&gt;
&lt;h2&gt;2月の個人開発&lt;/h2&gt;
&lt;p&gt;そういうわけで個人開発は専ら平日の深夜に行っている。&lt;/p&gt;
&lt;h3&gt;Mastodonのインスタンスにボットを追加した&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/post/mastodon-solo-instance-local/&quot;&gt;Mastodonのソロインスタンスでローカルタイムラインを情報収集で活用する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/post/mastodon-bot-with-pm2/&quot;&gt;PM2を使ってMastodonのBotを作成した&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/post/add-new-user-to-mastodon-solo-instance-on-exserver-vps/&quot;&gt;エックスサーバーVPSのMastodonイメージを使用したソロインスタンスに新規ユーザーを追加した&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;p&amp;gt;
&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b_feed/114082465086205969/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;こんな感じでローカルタイムラインに興味ある&lt;code&gt;RSS&lt;/code&gt;フィードが流れるようになった。&lt;/p&gt;
&lt;h3&gt;ブログのテーマを変更した&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;/post/optimized-local-search-performance/&quot;&gt;Hugoのテーマ「Github Style Plus」のローカル検索をFuse.jsで最適化した。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ついでにプルリクも出しておいた。&lt;/p&gt;
&lt;p&gt;ただ受つけていないのか、スルーされている。&lt;/p&gt;
&lt;p&gt;いい修正だと思ったんだけど。&lt;/p&gt;
&lt;h3&gt;キンドルアンリミテッドの検索サービスを作った&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/post/node-google-cloud/&quot;&gt;Google CloudでNode.jsを起動する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/post/kindle-unlimited-search-service/index.md/&quot;&gt;Kindle Unlimitedの検索が使いにくいので、好きな作家の対象本を一覧表示するサービスを作った&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;なかなか有用なサイトだと思うので、使ってほしい。&lt;/p&gt;
&lt;p&gt;少しづつ検索上位に来るように施策してみるかと考えている。&lt;/p&gt;
&lt;p&gt;そう簡単にいかないだろうけれど。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kindle-unlimited-search.nove-b.dev/&quot;&gt;📚【無料で読める】好きな作家の本を検索！Kindle Unlimited対応作品一覧&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Windowsのキーボードで英字入力、日本語入力の切り替えをシンプルにする</title><link>https://blog.nove-b.dev/posts/windows-japanese-english-input-switch</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/windows-japanese-english-input-switch</guid><content:encoded>&lt;p&gt;最近、英語入力、日本語入力でよく間違える。&lt;/p&gt;
&lt;p&gt;なんでだろうと原因を考えてみたけど、現在どっちの入力モードかわからないことがいけない気がする。&lt;/p&gt;
&lt;p&gt;そこで明示的に切り替えられるようにした。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;「あ」（「A」の可能性もある）を右クリックでIMEオプションを開く&lt;/li&gt;
&lt;li&gt;設定&lt;/li&gt;
&lt;li&gt;キーとタッチレスのカスタマイズ&lt;/li&gt;
&lt;li&gt;キーの割り当てをオンに&lt;/li&gt;
&lt;li&gt;&lt;code&gt;無変換&lt;/code&gt;キー IME-on&lt;/li&gt;
&lt;li&gt;&lt;code&gt;変換キ&lt;/code&gt;ー IME-off&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;という風に設定すれば、&lt;/p&gt;
&lt;p&gt;&lt;code&gt;無変換&lt;/code&gt;キー押下で日本語入力に。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;変換&lt;/code&gt;キー押下で英語入力という風に明示的に変更することができるようになった。&lt;/p&gt;
&lt;p&gt;Macは標準でこの設定だった気がする、さすがMac。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React Router v7で作成したウェブアプリをPWA(インストールに対応のみ)にする</title><link>https://blog.nove-b.dev/posts/make-react-router-v7-app-pwa</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/make-react-router-v7-app-pwa</guid><content:encoded>&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/make-react-router-v7-app-pwa/#vite-plugin-pwa%E3%81%AF%E3%81%A8react-router-v7%E3%81%A7%E6%AD%A3%E5%B8%B8%E3%81%AB%E6%A9%9F%E8%83%BD%E3%81%97%E3%81%BE%E3%81%9B%E3%82%93&quot;&gt;⚠️&lt;strong&gt;追記&lt;/strong&gt;：vite-plugin-pwaはとReact Router v7で正常に機能しません&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;&lt;code&gt;React Router v7&lt;/code&gt;でウェブアプリを作成した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/post/kindle-unlimited-search-service/&quot;&gt;Kindle Unlimitedの検索が使いにくいので、好きな作家の対象本を一覧表示するサービスを作った&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これを少しずつ改良しているんだけど、サイトに訪問するのが面倒なのでPWAにすることにした。&lt;/p&gt;
&lt;h2&gt;環境&lt;/h2&gt;
&lt;p&gt;PWAにしたアプリの環境は下記の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;react-router&quot;: &quot;^7.1.5&quot;,
  &quot;react&quot;: &quot;^19.0.0&quot;,
  &quot;vite&quot;: &quot;^5.4.11&quot;,
}
&quot;volta&quot;: {
  &quot;node&quot;: &quot;23.8.0&quot;,
  &quot;npm&quot;: &quot;10.9.2&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;PWAにする&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://vite-pwa-org.netlify.app/guide/&quot;&gt;vite-plugin-pwa&lt;/a&gt;をインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install -D vite-plugin-pwa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;vite.config.ts&lt;/code&gt;の&lt;code&gt;plugins&lt;/code&gt;に&lt;code&gt;vite-plugin-pwa&lt;/code&gt;を追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
  plugins: [
    ...
    VitePWA({
      registerType: &quot;autoUpdate&quot;, // サービスワーカーを自動的に更新する設定
      manifest: {
        name: &quot;アプリ名&quot;,
        short_name: &quot;短縮名&quot;,
        description: &quot;アプリの説明&quot;,
        theme_color: &quot;#ffffff&quot;,
        background_color: &quot;#ffffff&quot;,
        display: &quot;standalone&quot;,
        orientation: &quot;portrait&quot;,
        start_url: &quot;/&quot;,
        icons: [
          {
            src: &quot;/icons/icon-192x192.png&quot;,
            sizes: &quot;192x192&quot;,
            type: &quot;image/png&quot;,
          },
          {
            src: &quot;/icons/icon-512x512.png&quot;,
            sizes: &quot;512x512&quot;,
            type: &quot;image/png&quot;,
          },
        ],
        screenshots: [
          {
            src: &quot;screenshots/screenshot1.png&quot;,
            sizes: &quot;640x480&quot;,
            type: &quot;image/png&quot;
          },
          {
            src: &quot;screenshots/screenshot2.png&quot;,
            sizes: &quot;640x480&quot;,
            type: &quot;image/png&quot;
          }
        ]
      },
    }),
  ],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記の記述でビルド時に&lt;code&gt;manifest.webmanifest&lt;/code&gt;が生成されるのでそれを&lt;code&gt;app/root.tsx&lt;/code&gt;で読み込む。&lt;/p&gt;
&lt;p&gt;で、必要となる下記を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public/icons/icon-192x192.png
public/icons/icon-512x512.png
public/screenshots/screenshot1.png
public/screenshots/screenshot2.png
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;テストする&lt;/h2&gt;
&lt;p&gt;PWAは開発環境でテストできないので、&lt;code&gt;npm run build&lt;/code&gt;でビルドしたデータを起動して確認する。で、無事にインストールできることを確認した。&lt;/p&gt;
&lt;p&gt;PWAのすべては享受できていないけど、インストールするのが目的なので達成した。&lt;/p&gt;
&lt;h2&gt;vite-plugin-pwaはとReact Router v7で正常に機能しません&lt;/h2&gt;
&lt;p&gt;今回&lt;code&gt;pwa&lt;/code&gt;化する過程で&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; { rel: &quot;manifest&quot;, href: &quot;/manifest.webmanifest&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を&lt;code&gt;root.tsx&lt;/code&gt;に追加している。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://vite-pwa-org.netlify.app/guide/&quot;&gt;vite-plugin-pwa&lt;/a&gt;が正常に機能していればそこも自動でやってくれる。&lt;/p&gt;
&lt;p&gt;オフラインのキャッシュも動いていないし、ただ&lt;code&gt;manifest.webmanifest&lt;/code&gt;を自動で作ってくれるという機能しか使えてない。&lt;/p&gt;
&lt;p&gt;実際に&lt;code&gt;issue&lt;/code&gt;もあった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/vite-pwa/vite-plugin-pwa/issues/809&quot;&gt;Feature Request: Vite PWA Support for React Router 7&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>VS Codeをコマンドから開くときに既存ウィンドウで開くようにする</title><link>https://blog.nove-b.dev/posts/vscode-command-open-existing-window</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/vscode-command-open-existing-window</guid><description>VS Codeをコマンドから開くときに既存ウィンドウで開くようにする</description><content:encoded>&lt;p&gt;&lt;code&gt;bash&lt;/code&gt;で特定のディレクトに行き、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;code .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドでVS Codeを開くことができる。&lt;/p&gt;
&lt;p&gt;いつもこの方法で開いていたのだが、毎回毎回新しいウィンドウで開くのが鬱陶しかったので、既存ウィンドウで開くコマンドを調べてみた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;code . -r
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記で既存ウィンドウで開けるらしい。&lt;/p&gt;
&lt;p&gt;ちなみに既存、新しいウィンドウで開くかは設定によるらしい。&lt;/p&gt;
&lt;p&gt;もし新しいウィンドウで開きたいときは、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;code . -n
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドを実行する。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>レスポンス429の時に成功するまでリクエストをし続ける</title><link>https://blog.nove-b.dev/posts/response-status-code-redefined</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/response-status-code-redefined</guid><content:encoded>&lt;h2&gt;運用こそ正義&lt;/h2&gt;
&lt;p&gt;ありがたいことに運用中のサービスを使ってくれる人が、本当にぼちぼちだが増えたきた......、気がする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kindle-unlimited-search.nove-b.dev/&quot;&gt;https://kindle-unlimited-search.nove-b.dev/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただまだいくつか問題点があり、今回はその１つ「ステータスコードがしっかり定義されていない」という問題を解決した。&lt;/p&gt;
&lt;p&gt;現状のサービスだと&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;該当する作家が見つからない&lt;/li&gt;
&lt;li&gt;クエリで送ったページが範囲外&lt;/li&gt;
&lt;li&gt;amazon側のリクエスト不可で応答できない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という起こりえるエラーをすべて&lt;code&gt;400&lt;/code&gt;のサーバーエラーでフロント側に返していた。&lt;/p&gt;
&lt;p&gt;これだと、フロント側でユーザーに対して異なるメッセージを提供することができず、全く親切じゃない。&lt;/p&gt;
&lt;p&gt;しかもフロントは&lt;code&gt;400&lt;/code&gt;が返ってくる前でリクエストをし続けるという、こちらも全く親切じゃない実装をしていた。&lt;/p&gt;
&lt;h2&gt;ステータスコードを定義した&lt;/h2&gt;
&lt;p&gt;そこで、該当する作家が見つからない時は&lt;code&gt;404&lt;/code&gt;を、ページが範囲害外の時は&lt;code&gt;416&lt;/code&gt;を、そしてリクエスト制限の時は&lt;code&gt;429&lt;/code&gt;を返すようにした。&lt;/p&gt;
&lt;p&gt;そしてフロントではその値で処理を分けることにした。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;404&lt;/code&gt;の時は「検索した作家の作品が見つかりませんでした。」というスナックバーを出し、&lt;code&gt;416&lt;/code&gt;の時はつまり、すべてのページを確認したということなので「作品（最大100件）の取得が完了しました。」というスナックバーを出し、&lt;code&gt;429&lt;/code&gt;の時は再度リクエスト制する（5回まで挑戦する）という仕様に書き換えた。&lt;/p&gt;
&lt;h2&gt;リクエストを再試行する&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;429&lt;/code&gt;のように再度リクエストするコードをプラグインなしで初めて書いてみたので備忘録してまとめておく。&lt;/p&gt;
&lt;p&gt;初めて知ったんだけど、指数バックオフという手法を取ることにした。&lt;/p&gt;
&lt;p&gt;指数バックオフとは&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;リトライ（再試行）する間隔を指数関数的に増加させる手法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことらしい。&lt;/p&gt;
&lt;p&gt;つまり初回のリトライに失敗したら1秒後に再試行、2回目失敗したら2秒後に再試行、3回目失敗したら4秒後...といった具合に増加していく。&lt;/p&gt;
&lt;p&gt;これに加えて今回は5回までリトライして接続できなかった時は処理を中断させることにした。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const fetchAPI = async () =&amp;gt; {
  setState(&quot;wait&quot;);
  let page = 1;
  let retryCount = 0;
  const maxRetryCount = 5; // 最大リトライ回数

  while (true) {
    // page が 10 を超えた場合はループを終了
    if (page &amp;gt; 10) {
      setState(&quot;end&quot;);
      console.log(&quot;成功&quot;);
      break;
    }

    try {
      const response = await fetch(`${endpoint}$`);

      if (response.ok) {
        console.log(&quot;データ取得に成功しました。&quot;);
        page++; // 次のページへ
        retryCount = 0; // リトライ回数をリセット
        await new Promise((resolve) =&amp;gt; setTimeout(resolve, 1000)); // 1秒待機
      } else if (response.status === 429 &amp;amp;&amp;amp; retryCount &amp;lt; maxRetryCount) {
        // 429 Too Many Requests が返された場合、リトライ
        const delay = Math.pow(2, retryCount) * 1000; // 指数バックオフ
        console.log(
          `リクエストが多すぎます。${delay / 1000}秒後にリトライします。`,
        );
        await new Promise((resolve) =&amp;gt; setTimeout(resolve, delay));
        retryCount++;
      } else {
        // その他のエラーの場合、エラーログを出力してループを終了
        console.error(
          `エラーが発生しました。ステータスコード: ${response.status}`,
        );
        setState(&quot;end&quot;);
        toast.error(&quot;失敗&quot;);
        break;
      }
    } catch (error) {
      console.error(&quot;失敗:&quot;, error);
      setState(&quot;end&quot;);
      break;
    }
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まず最大10ページまでページが10以下かどうかの判定をする。&lt;/p&gt;
&lt;p&gt;ページが10より大きい時はその時点で処理を終了する。&lt;/p&gt;
&lt;p&gt;10以下の場合は&lt;code&gt;api&lt;/code&gt;を叩き、成功したら、1秒待ちページに1を足してループ処理の先頭に戻る。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;429&lt;/code&gt;が返ってきた時、指数バックオフの値を定義し、定義した時間待ち、リトライカウントに1を足し、ループ処理の先頭に戻る。&lt;/p&gt;
&lt;p&gt;この時点でページに1を足さないので、また同じページの再リクエストができる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>GA4にイベントを送り、レポートで確認する</title><link>https://blog.nove-b.dev/posts/ga4-event-report</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/ga4-event-report</guid><content:encoded>&lt;h2&gt;みんなの好きな作家が気になる&lt;/h2&gt;
&lt;p&gt;ここ最近、ずっとアップデートを続けている&lt;a href=&quot;https://kindle-unlimited-search.nove-b.dev/&quot;&gt;Kindle Unlimited検索サイト&lt;/a&gt;のイベントを収集することにした。&lt;/p&gt;
&lt;p&gt;このサイトは好きな作家を登録したうえで使用するんだけど、そのイベント、つまりどの作家が登録されたかを取得できるようにした。&lt;/p&gt;
&lt;p&gt;理由としては将来的に作家ランキングとかを実装できればと考えたからと、個人的にみんながどんな作家を好んでいるかを知りたかったから。&lt;/p&gt;
&lt;h2&gt;イベントを送る&lt;/h2&gt;
&lt;p&gt;実装方法としては特別難しいことはない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function 作家登録処理(作家名: string) {
  ... 作家を登録する処理
  if (window.gtag) {
    window.gtag(&apos;event&apos;, &apos;registration_author&apos;, {
      event_value: 作家名,
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これだけで実装は完了。&lt;/p&gt;
&lt;p&gt;確認方法としてはリアルタイムで、&lt;code&gt;registration_author&lt;/code&gt;というイベントを確認し、そこの&lt;code&gt;event_value&lt;/code&gt;に値が取れていれば問題ない。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/realtime_event.png&quot; alt=&quot;registration_author&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/realtime_event_value.png&quot; alt=&quot;event_value&quot; /&gt;&lt;/p&gt;
&lt;p&gt;これだけだとレポートで一覧の確認ができないので、見れるようにカスタムディメンションに登録をする。&lt;/p&gt;
&lt;h2&gt;カスタムディメンションに登録&lt;/h2&gt;
&lt;p&gt;管理 =&amp;gt; カスタム定義 =&amp;gt; カスタムディメンションを作成を選択する。&lt;/p&gt;
&lt;p&gt;ディメンション名を任意で設定し、範囲をイベント、イベント パラメータを&lt;code&gt;event_value&lt;/code&gt;にする。&lt;/p&gt;
&lt;p&gt;で、数日たてばデータが反映され、レポートでイベントパラメーターの値一覧を見れるようになる。&lt;/p&gt;
&lt;h2&gt;値一覧を見る&lt;/h2&gt;
&lt;p&gt;ホーム &amp;gt; イベント で該当のイベントを選択する。&lt;/p&gt;
&lt;p&gt;そうすると登録したイベントのカスタムディメンション値一覧を取得することができる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/report.png&quot; alt=&quot;レポート&quot; /&gt;&lt;/p&gt;
&lt;p&gt;上記はとある日の登録された作家一覧。&lt;/p&gt;
&lt;p&gt;まだユーザーが少ない。ここが拡充していくことを祈っている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年3月】４月から変わる環境に備える</title><link>https://blog.nove-b.dev/posts/2025-3</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-3</guid><content:encoded>&lt;h2&gt;3月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4423fyw&quot;&gt;どうしても生きてる (幻冬舎文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4l7anzF&quot;&gt;バベル九朔 (角川文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4ldgG52&quot;&gt;汚れた手をそこで拭かない (文春文庫)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;朝井リョウは重かった。正直、デビュー当時は絶対認めないぞって思ったこともあったけど、とんでもない思い違いだった。逆立ちしても勝てない。&lt;/p&gt;
&lt;p&gt;万城目学は良くわからなかった。期待していた分、残念だった。&lt;/p&gt;
&lt;h2&gt;好きな小説家のKindleUnlimitedを簡単に検索できるサービスを作成した&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/post/kindle-unlimited-search-service/&quot;&gt;Kindle Unlimitedの検索が使いにくいので、好きな作家の対象本を一覧表示するサービスを作った&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kindle-unlimited-search.nove-b.dev/&quot;&gt;Kindle Unlimited 対応作品検索｜作家別無料読み放題リスト&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;もうずいぶん長いこと本はKindle Unlimited対象本だけを読んでいる。&lt;/p&gt;
&lt;p&gt;世間的に見ても活用しているほうだと思うし、相当感謝しているんだけど、検索のしにくさは辟易していた。&lt;/p&gt;
&lt;p&gt;そういうわけで自分のしたい検索ができるサービスを作成した。&lt;/p&gt;
&lt;p&gt;技術的には&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;React Router v7&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Tailwindcss&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Express&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cloud Platform&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;で特別難しいことはしていない。&lt;/p&gt;
&lt;p&gt;個人開発は無料で行うべきっていう思想から反しているので、どこまで続けられるかわからないけど、できる限り開発を続けていきたいと考えている。&lt;/p&gt;
&lt;h2&gt;ブログのテーマを戻した&lt;/h2&gt;
&lt;p&gt;2月にブログのテーマを変更したんだけど、すぐに戻した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/post/optimized-local-search-performance/&quot;&gt;Hugoのテーマ「Github Style Plus」のローカル検索をFuse.jsで最適化した。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ブログのテーマにこだわり始めるのは良くない兆候で、ブログの本質はコンテンツということを忘れちゃいけない。&lt;/p&gt;
&lt;p&gt;ただ気になるのは仕方ないので、ここいらで自作にテーマに取り組もうかと考えている。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Hugo&lt;/code&gt;にするか&lt;code&gt;Hexo&lt;/code&gt;にするかで悩むけど、たぶん&lt;code&gt;Hugo&lt;/code&gt;にする。&lt;/p&gt;
&lt;p&gt;急ぎはしないし時間もないので、ちょっとづつ作っていこうかと考えている。&lt;/p&gt;
&lt;h2&gt;3月はお出かけする&lt;/h2&gt;
&lt;p&gt;３月はお出かけするっていう目標を２月に掲げた。&lt;/p&gt;
&lt;p&gt;というのも４月から妻の職場復帰、子どもたちの保育園入園がある。&lt;/p&gt;
&lt;p&gt;そうすると今までのように平日休んで空いている公園で遊ぶこともできないし、土日は妻、子どもの体力回復に捧げられるかもしれない。&lt;/p&gt;
&lt;p&gt;そういうわけで色々行くことにした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PLAY! PARK ERIC CARLE&lt;/li&gt;
&lt;li&gt;河津桜&lt;/li&gt;
&lt;li&gt;ボーネルンド&lt;/li&gt;
&lt;li&gt;多摩動物公園&lt;/li&gt;
&lt;li&gt;やまと公園&lt;/li&gt;
&lt;li&gt;こどもの国&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;雨も降らなかったので土日全部足遊びに出かけたかもしれない。&lt;/p&gt;
&lt;p&gt;バス乗りたいとか電車乗りたいっていう要望にも応えられたし良かった。&lt;/p&gt;
&lt;p&gt;それにしてもPLAY! PARK ERIC CARLEは微妙だった。&lt;/p&gt;
&lt;p&gt;それに比べてやまと公園は常に小田急線が見える公園ということで子どもは大興奮だった。&lt;/p&gt;
&lt;p&gt;なんで男の子は電車が好きなのだろうか。&lt;/p&gt;
&lt;p&gt;自分の小さい頃は興味なかったらしいので、遺伝とかではなく、人類というもっと大きい遺伝子に組み込まれているのだろうか。&lt;/p&gt;
&lt;h2&gt;4月に向けて&lt;/h2&gt;
&lt;p&gt;４月から生活がガラッと変わるのは間違いない。&lt;/p&gt;
&lt;p&gt;7時30分には保育園に送る必要がある。&lt;/p&gt;
&lt;p&gt;だいたい起きて家を出るのに２時間かかるので、４月からは5時30分に起きて、大人の準備を終わらせ、６時には子どもたちを起こしたい。&lt;/p&gt;
&lt;p&gt;そのために睡眠時間を確保するために20時には子どもたちを寝かしつけたい。&lt;/p&gt;
&lt;p&gt;という４月からの生活に向け、３月末から実践を始めたけど、全くうまくいかない。&lt;/p&gt;
&lt;p&gt;まず20時までにすべての事柄を終わらすは無理だし、もっと遊びたいとぐずるし、朝は起きないしで全く思い通りにいかない。&lt;/p&gt;
&lt;p&gt;しかも夜泣きはするし、寝かしつけても泣いて起きて大声で呼ばれて、仕方なく添い寝してたら一緒に寝ちゃうしで、家事も終わらない。&lt;/p&gt;
&lt;p&gt;それに加えて保育園の準備が多すぎる。&lt;/p&gt;
&lt;p&gt;服にスタンプ押すのも面倒くさいし、買い物も沢山あるし、なるほど保育園を迎えるのも大変だと実感した。&lt;/p&gt;
&lt;p&gt;ただ、苦には感じない。&lt;/p&gt;
&lt;p&gt;少し大人になれたのかもしれない、31歳の年にやっと。&lt;/p&gt;
&lt;p&gt;保育園に行くのは少し寂しくもある。&lt;/p&gt;
&lt;p&gt;それにしてもどんどん大きくなる。驚くほどの成長スピードで瞬きしてたらもったいないくらい。&lt;/p&gt;
&lt;p&gt;{{&amp;lt; youtube _FXaF3wHsRw &amp;gt;}}&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>nextjs のproduction環境でだけconsoleを出力しないようにする</title><link>https://blog.nove-b.dev/posts/remove-console-next-production</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/remove-console-next-production</guid><content:encoded>&lt;h2&gt;結論&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/** @type {import(&apos;next&apos;).NextConfig} */
const nextConfig = {
  // Error: &quot;next start&quot; does not work with &quot;output: export&quot; configuration. Use &quot;npx serve@latest out&quot; instead.
  // output: &quot;export&quot;,
  reactStrictMode: false,
  compiler: {
    removeConsole: process.env.NODE_ENV === &quot;production&quot;,
  },
};

export default nextConfig;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コードで&lt;code&gt;nextjs&lt;/code&gt;の&lt;code&gt;production&lt;/code&gt;
ビルド時に&lt;code&gt;console&lt;/code&gt;が出力されなくなる。にした。&lt;/p&gt;
&lt;h2&gt;デバッグしないと進めない&lt;/h2&gt;
&lt;p&gt;コードを見て何が起きいるのかわかるくらいの玄人であれば問題ないんだけど、そんな技術力はなく、&lt;code&gt;console&lt;/code&gt;を出しまくり、どこで何がどうなっているのかを確認しないと進めない。&lt;/p&gt;
&lt;p&gt;そんな具合なのでコンソール画面には大量のログが溢れる。&lt;/p&gt;
&lt;p&gt;当然そんな状況じゃ、デプロイできないので、いちいち&lt;code&gt;console&lt;/code&gt;を消すのは面倒だし、そのまま開発環境では&lt;code&gt;console&lt;/code&gt;を使いたい。&lt;/p&gt;
&lt;p&gt;なので、デプロイ時だけ消したい。&lt;/p&gt;
&lt;h2&gt;本番環境でだけconsoleを消したい&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nextjs&lt;/code&gt;では設定でデプロイ時だけ&lt;code&gt;console&lt;/code&gt;を出力しない方法があるので実行した。&lt;/p&gt;
&lt;p&gt;てかたぶん、ほとんどのフレームワークにはあると思うんだけど。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;next.config.js&lt;/code&gt;で下記設定をする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module.exports = {
  compiler: {
    removeConsole: process.env.NODE_ENV === &quot;production&quot;,
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NODE_ENVを自身で定義する必要があると思ったけど、&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nextjs.org/docs/messages/non-standard-node-env&quot;&gt;公式&lt;/a&gt;を参照すると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The greater React ecosystem treats NODE_ENV as a convention, only permitting
three (3) values:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;production: When your application```` is built with next build development:
When your application is run with next dev test: When your application is
being tested (e.g. jest)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;のように事前に定義されているっぽい。&lt;/p&gt;
&lt;p&gt;これでどんどん&lt;code&gt;console&lt;/code&gt;を出力できる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>VSCodeで新規ファイルを常にマークダウンで開く</title><link>https://blog.nove-b.dev/posts/vscode-new-file-md</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/vscode-new-file-md</guid><content:encoded>&lt;p&gt;VSCodeで新規ファルを開く時、常にマークダウンで開きたいと常々思ってきた。&lt;/p&gt;
&lt;p&gt;setting.jsonで下記のように書けば常にマークダウンで開くようになる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;files.defaultLanguage&quot;: &quot;markdown&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>nove-b</author></item><item><title>Githubでリリースの設定方法とリリースの必要性について</title><link>https://blog.nove-b.dev/posts/github-release-setup-and-why-needed</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/github-release-setup-and-why-needed</guid><content:encoded>&lt;p&gt;２年前に１度だけGithubでリリース作成したことがあったけど、久しぶりすぎて忘れていたので改めてまとめることにした。&lt;/p&gt;
&lt;h2&gt;ブランチにタグをつける&lt;/h2&gt;
&lt;p&gt;リリースのベストプラクティスが良くわからなかったので調べてみたところ、小さいサイトでは&lt;code&gt;main&lt;/code&gt;ブランチにタグをつけて管理すればいいということだったので、今回はそうすることにした。&lt;/p&gt;
&lt;p&gt;そういうわけでまずはタグをつける。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main&lt;/code&gt;ブランチに移動し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git tag -a v0.0.0 -m &quot;Initial release&quot;
git push origin v0.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;タグをつけてタグをプッシュする。&lt;/p&gt;
&lt;h2&gt;Githubから設定する&lt;/h2&gt;
&lt;p&gt;後はGithubのリポジトリに行き、リリースぺージから作成したタグを選び、リリースするだけで完了。&lt;/p&gt;
&lt;h2&gt;リリースを作成する必要があるのか&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;main&lt;/code&gt;ブランチが常に最新で、タグ付けした時点でのコードを&lt;code&gt;Clone&lt;/code&gt;できないのであればリリース管理する必要あるのかと疑問に感じた。&lt;/p&gt;
&lt;p&gt;調べてみると、リリースは瞬間のスナップショットで再現性を求めるものらしい。&lt;/p&gt;
&lt;p&gt;さらにタグを指定してサブモジュールに追加することもできるっぽい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 1. クローンしてタグをチェックアウト
git clone https://github.com/user/other-repo.git
cd other-repo
git checkout tags/v1.0.0

# 2. 必要なコミットにいる状態で、上位リポジトリに追加
cd ..
git submodule add ./other-repo path/to/submodule

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;であればタグ付け、リリースは必要かもしれない。&lt;/p&gt;
&lt;p&gt;いずれ&lt;code&gt;Github Action&lt;/code&gt;でタグ付けしたらリリースが作れるようにしたい。&lt;/p&gt;
&lt;h2&gt;リリースしたのは&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nove-b/hugo-Passage/releases/tag/v0.0.0&quot;&gt;Hugo-Passage&lt;/a&gt;というHugoのテーマ。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年4月】春は軽やかに、でもずっしり重たくのしかかってきた</title><link>https://blog.nove-b.dev/posts/2025-4</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-4</guid><content:encoded>&lt;blockquote&gt;
&lt;p&gt;春が2階から落ちてきた。&lt;a href=&quot;%5B%E9%87%8D%E5%8A%9B%E3%83%94%E3%82%A8%E3%83%AD%5D(https://amzn.to/4cUHoeK)%E3%81%AE%E4%B8%80%E7%AF%80&quot;&gt;^1&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;落ちてきたので、受け止めようと手を伸ばしたら、あまりの重さに尻もちをついて立ち上がれなくなった。&lt;/p&gt;
&lt;p&gt;人生は伊坂幸太郎の小説のように美しく幕を開け、順当に収束へ向かうとは限らない。&lt;/p&gt;
&lt;p&gt;そう思い知ることになった４月だった。&lt;/p&gt;
&lt;p&gt;そんな怒涛のスタートを切った４月だけど意外と小説を読むことができた。&lt;/p&gt;
&lt;h2&gt;4月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;amzn.to/4ckqHJJ&quot;&gt;トリガール！ (角川文庫) &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;amzn.to/3FPyX88&quot;&gt;おうむの夢と操り人形 (Kindle Single)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;amzn.to/42xBHii&quot;&gt;山桃寺まえみち (PHP文芸文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;amzn.to/4iuemDU&quot;&gt;ホルモー六景 「鴨川ホルモー」シリーズ (角川文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;amzn.to/42LmNVM&quot;&gt;無限大ガール (Kindle Single)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3EVXTL0&quot;&gt;恋せぬふたり&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kindle
Singleが２冊なのでページ数的にはそこまで読めていないかもしれない。今月は大当たりはなかった印象だけど、外れもなかった。&lt;/p&gt;
&lt;p&gt;そういえば前月気になっていた&lt;a href=&quot;https://amzn.to/3Gztumm&quot;&gt;BOOX GoColor7&lt;/a&gt;なら電子図書館の本が読める？&lt;/p&gt;
&lt;p&gt;そろそろ買い換えたいんだけど、防水じゃないのが気になる。&lt;/p&gt;
&lt;h2&gt;今更ながら音が聞こえる&lt;/h2&gt;
&lt;p&gt;保育園入園で完全に生活の主軸が子どもに移った音がした。&lt;/p&gt;
&lt;p&gt;大人はどこかで人生を子どもに譲るタイミングが来ると思うんだけど、その１つのタイミングが今なのかもしれない。&lt;/p&gt;
&lt;p&gt;ただそうは思いつつ、春一番に吹かれても自分の人生にへばりついている自分がいる。&lt;/p&gt;
&lt;p&gt;ここら辺で何者にもなれない人たちは後続のためにすべてを捧げる生き方を選択する必要があるのかもしれないけど、そんなにすっぱり自分の人生を諦めることはできない。&lt;/p&gt;
&lt;p&gt;{{&amp;lt; youtube d6i4AtCxrDo&amp;gt;}}&lt;/p&gt;
&lt;p&gt;非常に悩ましい問題が目の前にある。&lt;/p&gt;
&lt;p&gt;育児エンジニアの記事が多いのもそういうことなんだろう。&lt;/p&gt;
&lt;h2&gt;現実にスケジュールなんて存在しない&lt;/h2&gt;
&lt;p&gt;今まではころころした子どもの相手さえしていればよかった。&lt;/p&gt;
&lt;p&gt;子どもたちに予定はないので、まあ遊んでいればよかった。&lt;/p&gt;
&lt;p&gt;ただ保育園が始まるとそうは行かない。朝6時に起こすので、20時には布団に行かせたい。&lt;/p&gt;
&lt;p&gt;しかしご飯は食べないし、まだ遊ぶって怒るし、歯磨きしないしで、なかなか思い通りにいかない。&lt;/p&gt;
&lt;p&gt;それでも何とか寝かしつけるともう自分の体力が0になっている。&lt;/p&gt;
&lt;p&gt;とは言え、一瞬一瞬がかけがえのない時間であるのも確かなんだけど。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/01.jpg&quot; alt=&quot;鯉のぼり&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;受け取ったバトンが想像より重かった&lt;/h2&gt;
&lt;p&gt;「パパ仕事行かないで」と泣いている子どもを見た時、本当に仕事を辞めようかと思った。&lt;/p&gt;
&lt;p&gt;慣らし保育から3週間経とうとしている。今は連れて行くとそのまま砂場に直行する。&lt;/p&gt;
&lt;p&gt;子供の成長はあまりにも早い。&lt;/p&gt;
&lt;p&gt;子どもが可愛いのは当然なんだけど、育てるのは本当に大変で、最近は育児卒業した人に対して尊敬の念を抱くようになった。よくぞ、この大海原を泳ぎ切った。どうやって泳ぎ切った？ 荒波だらけだったでしょう。 と問いただしたいくらいに。&lt;/p&gt;
&lt;p&gt;{{&amp;lt; youtube FJRfSwQEyfc&amp;gt;}}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;自分の仕事が一番辛いと思う奴にはならない&lt;a href=&quot;%5B%E3%82%A2%E3%82%A4%E3%83%8D%E3%82%AF%E3%83%A9%E3%82%A4%E3%83%8D%E3%83%8A%E3%83%8F%E3%83%88%E3%83%A0%E3%82%B8%E3%83%BC%E3%82%AF%5D(https://amzn.to/3GwZt6R)%E3%81%AE%E4%B8%80%E7%AF%80%E3%81%A0%E3%81%A3%E3%81%91%EF%BC%9F&quot;&gt;^2&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;って言ったのは斉藤和義が伊坂幸太郎か、一体どっちか先なのかわからない。&lt;/p&gt;
&lt;p&gt;これは本当にそうなんだけど、それでも大変な分類に属しているんじゃないかとふと思うときがある。&lt;/p&gt;
&lt;p&gt;でもきっとそんなことなく、現に妻の方がよっぽど大変そうで、自分なんて中途半端に仕事して、中途半端に家の手伝いしているくらいだと思う。どちらかに全振りできるほど、能力もないのが問題で、そう考えたらやっぱり。後続のためにすべてを捧げる生き方を選択をするべきなんだろうと思うけど、うーん、悩ましい。&lt;/p&gt;
&lt;p&gt;せめて仕事の方を早々に切り上げて、子どもが起きているうちに帰えれるようになればいいのかなと思っている。&lt;/p&gt;
&lt;p&gt;{{&amp;lt; youtube 0PIS8J8sbJg&amp;gt;}}&lt;/p&gt;
&lt;h2&gt;愛着を持てるかということ&lt;/h2&gt;
&lt;p&gt;そういう意味で仕事について考える。&lt;/p&gt;
&lt;p&gt;会社に、会社で作ったものに、真摯に向き合っている人は本当にすごいと思う。&lt;/p&gt;
&lt;p&gt;会社で評価されるより、個人的にはやっぱりGithubでStarがつく方が、個人開発したプラグインがブログで紹介される方がよっぽど嬉しい。&lt;/p&gt;
&lt;p&gt;会社に属する仕事でもなく、ジョブ型の仕事でもなく、プロダクトに属する仕事がしたい。&lt;/p&gt;
&lt;p&gt;って最近思っている。&lt;/p&gt;
&lt;p&gt;そのプロダクトに全振りしたい。&lt;/p&gt;
&lt;h2&gt;個人開発について&lt;/h2&gt;
&lt;p&gt;自身のプロダクトでは、2つリリースした。&lt;/p&gt;
&lt;p&gt;1つが&lt;a href=&quot;https://kindle-unlimited-search.nove-b.dev/&quot;&gt;Kindle Unlimited 対応作品検索｜作家別無料読み放題リスト&lt;/a&gt;で、作家を登録し、簡単にKindle
Unlimitedの作品を検索できるサイト。&lt;/p&gt;
&lt;p&gt;これは個人的に欲しかったので作成した。&lt;/p&gt;
&lt;p&gt;運営費が発生しているので、どこかでCloseする予定だけど、&lt;code&gt;Googole Cloud&lt;/code&gt;でインスタンスを立てて構築するっていう経験ができたので良かった。&lt;/p&gt;
&lt;p&gt;2つ目は&lt;a href=&quot;https://github.com/nove-b/hugo-Passage/releases/tag/v0.0.0&quot;&gt;hugo-Passage&lt;/a&gt;で&lt;code&gt;Hugo&lt;/code&gt;のテーマ。&lt;/p&gt;
&lt;p&gt;ブログの構築で悩みたくないので&lt;code&gt;Hugo&lt;/code&gt;にしたんだけど結局構築してしまった。&lt;/p&gt;
&lt;p&gt;まあ、自分の好きな形態にできたので良かった。&lt;/p&gt;
&lt;p&gt;リリースとか導入手順とか丁寧に書けたのはいい経験だった。&lt;/p&gt;
&lt;p&gt;オープンソースなのでプルリクとか出してもらえると大変うれしい。&lt;/p&gt;
&lt;p&gt;Starが欲しいので布教したいけど、どうやって布教すればいいのか全く分からない。&lt;/p&gt;
&lt;p&gt;ーーー&lt;/p&gt;
&lt;p&gt;またちょっと仕事が立て込んできたので、先にそっちを片付けて、次に作りたいものに着手する。&lt;/p&gt;
&lt;p&gt;次に作りたいものは決まっているので、引き続き励んでいくのだが、何のために励んでいるかわからない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>自分の環境でだけ、特定のフォルダをGitの管理化から除外する</title><link>https://blog.nove-b.dev/posts/local-git-ignore</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/local-git-ignore</guid><content:encoded>&lt;h2&gt;結論&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;.git/info/exclude
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でフォルダ、ファイルを指定することで&lt;code&gt;Git&lt;/code&gt; 管理から除外できる。&lt;/p&gt;
&lt;h2&gt;切り替え時のメモリ不足&lt;/h2&gt;
&lt;p&gt;個人の頭のスペックが著しく低いので、マルチタスクには向いていない。&lt;/p&gt;
&lt;p&gt;仕事でもその影響をひどく受ける。&lt;/p&gt;
&lt;p&gt;例えば1つの課題をやりつつ、もう1つの課題をこなさなくちゃいけない時。&lt;/p&gt;
&lt;p&gt;ブランチを変更後に、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;このブランチでは何をしていたのか&lt;/li&gt;
&lt;li&gt;どこまで進んでいるのか&lt;/li&gt;
&lt;li&gt;どのような方針で進めていたのか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;を思い出すことで時間を浪費する。とても効率が悪いし、燃費が悪い。&lt;/p&gt;
&lt;h2&gt;aiが言うに&lt;/h2&gt;
&lt;p&gt;どうすれば解決できるかChat GPTに相談してみたところ&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;めっちゃ共感します、その「タスク切り替えのもたつき」問題。これは実際に
**「タスクスイッチングコスト」**とか「コンテキストスイッチ」って呼ばれていて、脳の仕組み的にもちゃんと負荷がかかってるんですよね。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;て、すごいフランクに教えてくれた。&lt;/p&gt;
&lt;p&gt;そういえばなんか最近AIがフランクになってきている気がする。&lt;/p&gt;
&lt;p&gt;そろそろ人間の機嫌を取るフェーズに入ったのかもしれない。シンギュラリティは近く、そもそも仕事が奪われてタスクの切り替えで悩むこともなくなるかもしれないけど、まだ目の前に仕事はあるっぽいので、対策を聞き、改善を試みることにした。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;タスクを切り替える前に、今の状態・次やることを書き出すと、戻った時に再起動がめっちゃ早くなります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;どうやらこれがめっちゃ有効らしい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
【作業名】◯◯のバグ修正
【今やってたこと】
- APIのレスポンス確認中
- 400エラー出てるが原因不明

【次にやること】
- console.log 追加してリクエスト確認
- header と token を見直す

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じで書いておくと戻ってきたときに、すぐに作業に集中できるらしい。&lt;/p&gt;
&lt;h2&gt;切り替えメモをどこに書くか&lt;/h2&gt;
&lt;p&gt;早速実践してみることにしたけど、どこにメモするかで悩むことになった。&lt;/p&gt;
&lt;p&gt;Google
KeepとかNotionとかSlackでもいいんだけど、基本的にVsCodeにいるのでVsCodeで完結したい。&lt;/p&gt;
&lt;h2&gt;Git管理から外したい&lt;/h2&gt;
&lt;p&gt;ただ、VsCodeで作業しているディレクトリは大半Git管理されている。&lt;/p&gt;
&lt;p&gt;つまり自身のメモをそこに置くとGitの管理下になる。なんとか避けたいけど、プロジェクト全体のgitignoreに書くのも気に食わないし、他の人に影響を与える可能性がある。&lt;/p&gt;
&lt;p&gt;つまり自分の環境でだけGitの管理から外したい。&lt;/p&gt;
&lt;h2&gt;解決した&lt;/h2&gt;
&lt;p&gt;調べてみると、&lt;code&gt;.git&lt;/code&gt;の中の設定をいじればできるらしい。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.git/info/exclude
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で特定のフォルダを指定するとそのフォルダは自身の変更履歴に上がってこなくなる。&lt;/p&gt;
&lt;p&gt;当然、フォルダ名はプロジェクトで使わないようなフォルダ名にするのが無難なので、適当な&lt;code&gt;prefix&lt;/code&gt;でもつけて命名するようにする。&lt;/p&gt;
&lt;p&gt;これでタスク切り替えのもたつき問題は解決できると思ったけど、まだ絶賛もたついている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年5月】現状を妥協したい</title><link>https://blog.nove-b.dev/posts/2025-5</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-5</guid><content:encoded>&lt;p&gt;なんか色々書きたいこと考えたり、NoteBookLLMで作成してみたり、考えすぎて面倒になったので簡潔に書いていくことにした。&lt;/p&gt;
&lt;h2&gt;5月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3HEepQO&quot;&gt;ヒトコブラクダ層戦争（上） (幻冬舎文庫) &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3HEepQO&quot;&gt;ヒトコブラクダ層戦争（下） (幻冬舎文庫) &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4jyJrXC&quot;&gt;読楽 2025年1月号&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;檻の中のワルキューレ（伽村あきら）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4dTduZa&quot;&gt;小説推理2025年1月号&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;海よりも底に深く沈む（射線堂有紀）&lt;/li&gt;
&lt;li&gt;僕らが夕闇を埋めた場所（松樹凛）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ヒトコブラクダ層戦争は久々にページをめくる手が止まらない小説だった。&lt;/p&gt;
&lt;p&gt;月刊文芸誌を読むことにした。kindle
Unlimitedから当たり小説を選び取るのが難しい。文芸誌を読むことで選択というストレスなく多くの作家に触れられるようにしたい。&lt;/p&gt;
&lt;p&gt;ただ連載小説に手は出せないので短編とちょうど連載スタートした小説だけを読むことにする。&lt;/p&gt;
&lt;p&gt;大藪春彦文学賞の檻の中のワルキューレは面白かった。&lt;/p&gt;
&lt;p&gt;海よりも底に深く沈むは連載小説らしい引きがあり、次に期待が持てる。&lt;/p&gt;
&lt;p&gt;僕らが夕闇を埋めた場所は普通だった。&lt;/p&gt;
&lt;p&gt;五大文芸誌も読みたいけど、電子図書館にもなかった。そもそも電子化しているほうがマイノリティらしい。&lt;/p&gt;
&lt;p&gt;今月は漫画も結構読んだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ワールドトリガー&lt;/li&gt;
&lt;li&gt;忘却バッテリー&lt;/li&gt;
&lt;li&gt;スパイファミリー&lt;/li&gt;
&lt;li&gt;怪獣8号&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5月に行った場所&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;プラレール博&lt;/li&gt;
&lt;li&gt;湘南モノレール&lt;/li&gt;
&lt;li&gt;公園&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;電車に目がない双子の片方のために電車をよく見に行った。&lt;/p&gt;
&lt;p&gt;土日のどちらかは遠出し、どちらかは近場で少し休ませるようにしている。&lt;/p&gt;
&lt;p&gt;最近は感情も言葉も豊で見ていて本当に楽しい。&lt;/p&gt;
&lt;p&gt;一緒に公園で楽しめるようになってきた。&lt;/p&gt;
&lt;p&gt;保育園に行き始めたことで他人への遠慮がなくなってきた。&lt;/p&gt;
&lt;p&gt;他の子がいても気にせず突っ込むようになり、危なっかしい。&lt;/p&gt;
&lt;h2&gt;１つのAIに全振りしない&lt;/h2&gt;
&lt;p&gt;最近生成AIの進歩が凄まじい。&lt;/p&gt;
&lt;p&gt;Geminiの拡張機能でほぼほぼコードを書かずにいろいろなことが実現できる。&lt;/p&gt;
&lt;p&gt;すごい、楽しい、って思うけど、AIを使って何かできるのは天才たちだけで、凡人にできるのはAI側が用意しているAPIを叩くだけの仕事になっている気がする。&lt;/p&gt;
&lt;p&gt;個人的にはそういうわけで、AIに関しては深入りしない方がいい気がしている。&lt;/p&gt;
&lt;p&gt;もちろん最新のキャッチアップ、流行りに手を出すべきだけど、何かに全振りするのは時期尚早じゃないかと思う。&lt;/p&gt;
&lt;p&gt;AIは使うけど、その時々で最善の選択をする必要がありそう。&lt;/p&gt;
&lt;h2&gt;やりたいことと仕事&lt;/h2&gt;
&lt;p&gt;やりたいことが多すぎるけど、仕事のせいで手が回らない。&lt;/p&gt;
&lt;p&gt;仕事はつまらないけど、仕事じゃないと得られない知見もある。&lt;/p&gt;
&lt;p&gt;なんでこんな面倒な実装方法を取らなくちゃいけないんだ、個人開発ならそんなことしない。&lt;/p&gt;
&lt;p&gt;っていうことも要件的には実装する必要がある。&lt;/p&gt;
&lt;p&gt;それはそれで知見を得れるのでまあいいんだけど。&lt;/p&gt;
&lt;p&gt;でもやりたいことではない。&lt;/p&gt;
&lt;p&gt;そういうわけで、少しずつ仕事から足抜けしていく必要がある気がしている。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年6月】今年も半分終わったらしい</title><link>https://blog.nove-b.dev/posts/2025-6</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-6</guid><content:encoded>&lt;h2&gt;6月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/46nnZSt&quot;&gt;不時着する流星たち) &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;良書の基準は書きたいと思わせる本だ&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;となんかの本の後書きで誰かが書いていた。&lt;/p&gt;
&lt;p&gt;そういう意味で小川洋子の作品は個人的にすべて良書で個人的に外れたことがない。&lt;/p&gt;
&lt;p&gt;そしてこの本も例に漏れずだった。&lt;/p&gt;
&lt;p&gt;今月はまさかの1冊しか読めなかった。&lt;/p&gt;
&lt;p&gt;仕事が忙しいとかじゃなくて、お風呂をシャワーにしたのが最大の原因で、6月の猛暑で読書時間を失った。&lt;/p&gt;
&lt;p&gt;本を読めなくなるのは寂しいので能動的に時間を作っていきたい。&lt;/p&gt;
&lt;h2&gt;6月に行った場所&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ディズニーランド&lt;/li&gt;
&lt;li&gt;公園&lt;/li&gt;
&lt;li&gt;イケア&lt;/li&gt;
&lt;li&gt;水遊びを解禁した&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ディズニーランド&lt;/h3&gt;
&lt;p&gt;ここ最近、ディズニーランドに行っても同じ乗り物しか乗らない。&lt;/p&gt;
&lt;p&gt;2歳児が乗れる乗り物は限られていて、さらに知恵と想像力がついたせいで、色々なものに怯えるようになった。&lt;/p&gt;
&lt;p&gt;美女と野獣の野獣咆哮シーンでは泣き声を轟かせ、周りの人の注目を浴びていた。&lt;/p&gt;
&lt;p&gt;乗るものは同じだけど、今回は日帰りで、自分の親を伴って行くことにした。&lt;/p&gt;
&lt;p&gt;日帰りは意外と問題なく、別に泊まる必要ないんじゃという気付きを得た。&lt;/p&gt;
&lt;p&gt;自分の親がいるとなんとなく気づまりなのは30歳、男性、思春期真っただ中なのかもしれない。&lt;/p&gt;
&lt;p&gt;まあ、親も子どもも楽しそうにしていたので良かった。&lt;/p&gt;
&lt;h3&gt;公園&lt;/h3&gt;
&lt;p&gt;子どもにとっては天国なのかもしれないけど、暑すぎて本当に死と隣り合わせだと思う。&lt;/p&gt;
&lt;p&gt;自分が子どものころってこんなに暑かったかって思いだそうとするけど、暑かった気もするし、そうでもなかった気もする。&lt;/p&gt;
&lt;p&gt;多分当時は暑い寒いとかより、楽しいという本能で生きていたんだと思われる。&lt;/p&gt;
&lt;h3&gt;ウォーターテーブル解禁&lt;/h3&gt;
&lt;p&gt;もうどうしようもないくらいに暑いので、&lt;/p&gt;
&lt;p&gt;ウォーターテーブルを解禁した。&lt;/p&gt;
&lt;p&gt;これなら日陰で行えるし、ついでに庭に水もあげれるし、子どもも楽しいで、何とか乗り越えられそう。&lt;/p&gt;
&lt;p&gt;とは言え、ウォーターテーブルじゃ満足することなくなる気がするので、そろそろプールの目星をつける必要がある。&lt;/p&gt;
&lt;h3&gt;イケア&lt;/h3&gt;
&lt;p&gt;会社都合で完全在宅になった。&lt;/p&gt;
&lt;p&gt;しかし家で仕事する環境なんてないので、椅子と机を買うことが急務ということでイケアにいった。&lt;/p&gt;
&lt;p&gt;イケアのフードコートの朝ごはんは100円らしく、それを目がけていったら椅子取り合戦が繰り広げられており、当然敗北したので、ここでもまた椅子机難民になった。&lt;/p&gt;
&lt;p&gt;何とか席につく頃には子どもたちはお腹がすき愚図り、自分たちは疲れ果てで這う這うの体だった。&lt;/p&gt;
&lt;p&gt;もう行かないと誓ったけど、そういえばこの誓い前回もたてた気がすると思い出した。&lt;/p&gt;
&lt;p&gt;何とか在宅用の椅子と机を買い、事なきを得た。&lt;/p&gt;
&lt;h2&gt;会社都合の在宅&lt;/h2&gt;
&lt;p&gt;会社が7月1日から10月31日まで完全在宅に移行した。&lt;/p&gt;
&lt;p&gt;そもそも完全在宅なら別に都内の企業でも良かったようなという思いもあるけど、いったん蓋をする。&lt;/p&gt;
&lt;p&gt;個人的に在宅は苦手で、やっぱり家を出たい気持ちがある。&lt;/p&gt;
&lt;p&gt;個人的にお金を出してコアワーキングスペースまで行こうかと思ったけど実現してない。&lt;/p&gt;
&lt;p&gt;でも状況によってはそれもありかもしれないと思っている。&lt;/p&gt;
&lt;p&gt;てかやっぱり、そもそも完全在宅なら別に都内の企業でも良かったようなと思わざるえない。&lt;/p&gt;
&lt;h2&gt;スキルアップしたい&lt;/h2&gt;
&lt;p&gt;ただこっちが都内でよかったんじゃと言っても、誰も自分を受け入れてくれないとそもそも意味がない。&lt;/p&gt;
&lt;p&gt;よく考えたら自分の技術力に自信があるわけでもないし、裏付けする資格もない。&lt;/p&gt;
&lt;p&gt;ぜんぜん転職を考えているわけじゃないけど、セーフティーネットは必要だ、ということで競プロを始めようと思って１か月経った。&lt;/p&gt;
&lt;p&gt;コンテストが毎週土曜日21時とか寝かしつけで参加できない。&lt;/p&gt;
&lt;p&gt;競プロに参加せずにコーディングスキルをあげるためにはどうすればいいんだろうと考えつつ趣味に逃げてしまう。&lt;/p&gt;
&lt;h2&gt;コントリビューター&lt;/h2&gt;
&lt;p&gt;最近、趣味の個人開発で作りたいものが枯渇した。&lt;/p&gt;
&lt;p&gt;ただプログラミングはしたいということで、既に作成されているものに手を出すスタイルにした。&lt;/p&gt;
&lt;p&gt;個人開発で願わくば一攫千金とか思っていたけど、そもそも無理なので、純粋にプログラミングすることにした。&lt;/p&gt;
&lt;p&gt;そういうわけでコントリビュートして楽しむことにした。&lt;/p&gt;
&lt;p&gt;今月は１つしか出せなかったけど、週1くらいでは出していきたい。&lt;/p&gt;
&lt;p&gt;でもやっぱり個人開発は楽しいので作りたいものができ次第、再開する。&lt;/p&gt;
&lt;p&gt;なんか最近月まとめも適当になってきた。&lt;/p&gt;
&lt;p&gt;7月はしっかり書くようにする。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>OnPushとChangeDetectorRefでAngularのパフォーマンスを向上したい</title><link>https://blog.nove-b.dev/posts/angular-performance-onpush-change-detectorref</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/angular-performance-onpush-change-detectorref</guid><content:encoded>&lt;h2&gt;AngularのOnPush戦略&lt;/h2&gt;
&lt;p&gt;Angularのパフォーマンスを向上するために&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;changeDetection: ChangeDetectionStrategy.OnPush,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を導入した。&lt;/p&gt;
&lt;p&gt;これにより入力プロパティが変更された場合、またはコンポーネント自身やその子コンポーネントがイベントを発火した場合にのみ、変更検知するようになる。&lt;/p&gt;
&lt;p&gt;そもそもAngularのデフォルト変更検知は&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ブラウザイベント&lt;/li&gt;
&lt;li&gt;タイマーイベント&lt;/li&gt;
&lt;li&gt;HTTPリクエストの完了&lt;/li&gt;
&lt;li&gt;Promiseの解決/拒否&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;でブラウザイベントが発生するとすべてのコンポーネントが変更検知の対象になるらしい。&lt;/p&gt;
&lt;p&gt;つまり非常にコストが高い。&lt;/p&gt;
&lt;p&gt;そのため&lt;code&gt;OnPush&lt;/code&gt;戦略が重要になる。&lt;/p&gt;
&lt;p&gt;ちなみにベストプラクティスは&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;デフォルトではOnPushを適用せず、パフォーマンスが問題になったり、上記で挙げた「OnPushを検討すべきコンポーネント」の特性に合致したりする場合に限定して導入を検討する&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことだった。&lt;/p&gt;
&lt;p&gt;で、導入した場合、データが非同期で更新された場合や、参照が変更されないオブジェクトのプロパティが更新された場合など、Angularが自動的に変更を検知できないケースが発生する。&lt;/p&gt;
&lt;p&gt;そこで明示的に変更を検知するために&lt;code&gt;ChangeDetectorRef&lt;/code&gt;を使用する。&lt;/p&gt;
&lt;h2&gt;ChangeDetectorRefはコンポーネントの変更検知器への参照を提供する&lt;/h2&gt;
&lt;p&gt;開発者が変更検知のタイミングを細かく制御できるようにする&lt;code&gt;ChangeDetectorRef&lt;/code&gt;は4つのメソッドを持つ。&lt;/p&gt;
&lt;h3&gt;markForCheck&lt;/h3&gt;
&lt;p&gt;次回の変更検知サイクルでチェックする必要があることをマークするメソッド。
&lt;code&gt;markForCheck()&lt;/code&gt;を呼び出すだけではすぐに変更検知は実行されず、次の変更検知サイクル時に検知の対象となる。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「次のチェックで、忘れずにこのコンポーネントも見てね！」いつ使う？ コンポーネントの中のデータが非同期（例：setTimeoutやHTTPリクエストの結果など）で変わったけど、そのデータの「箱」（参照）自体は変わっていないとき。Angularは箱の中身が変わっただけでは、デフォルトで気付いてくれません。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;detectChanges&lt;/h3&gt;
&lt;p&gt;直ちに変更検知サイクルを強制的に実行する。頻繁な呼び出しはパフォーマンスに影響を与える可能性がある。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「今すぐ！このコンポーネントをチェックして見た目を更新して！」いつ使う？ コンポーネントの中のデータが非同期（例：setTimeoutやHTTPリクエストの結果など）で変わったけど、そのデータの「箱」（参照）自体は変わっていないとき。Angularは箱の中身が変わっただけでは、デフォルトで気付いてくれません。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;detach()&lt;/h3&gt;
&lt;p&gt;現在のコンポーネントを変更検知ツリーから切り離す。そのコンポーネントとその子孫コンポーネントは、明示的に&lt;code&gt;reattach()&lt;/code&gt;されるまで、以降の変更検知サイクルではチェックされなくなる。コンポーネントがめったに変更されない場合とかに使える。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「このコンポーネント、しばらくお休みさせて！」いつ使う？ Angularが通常検知しないような場所（例：ngZone.runOutsideAngular()の中）でデータが更新されたり、特定のタイミングでどうしても画面をすぐに更新したいとき。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;reattach()&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;detach()&lt;/code&gt;で切り離されたコンポーネントを変更検知ツリーに再アタッチする。再び通常の変更検知サイクルに含まれるようになる。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「お休み終わり！またチェックしてね！」いつ使う？ ほとんどデータが変わることがない、または特定の条件が満たされない限り、画面を更新する必要がないコンポーネントがある場合。大量のコンポーネントがある中で、一部を休ませて全体の負担を減らしたいときに役立ちます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;うーん、２年間くらい触ってて初めてしっかり理解を試みた。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>npxは永続的なインストールは行わないが、実行のために一時的なダウンロード（実質的なインストール）は行う</title><link>https://blog.nove-b.dev/posts/npx-temp-install</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/npx-temp-install</guid><content:encoded>&lt;p&gt;&lt;code&gt;npx&lt;/code&gt;はパッケージをインストールせずに実行できるという認識だったので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Need to install the following packages:
  xxxxxxxxxxxxxxxxxx
Ok to proceed? (y) y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という文言見て今さら不思議に思ったのでどういうものかと調べてみることにした。&lt;/p&gt;
&lt;h2&gt;厳密に言えば一時的にインストール（ダウンロード）される&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;パッケージをインストールせずに実行できる&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;というのは&lt;code&gt;npx&lt;/code&gt;でよくある説明でこれをそのまま受け取っていたけど、どうやら思っていたのとちょっと違った文脈だった。&lt;/p&gt;
&lt;h3&gt;node_modules ディレクトリに恒久的に追加されるわけではない&lt;/h3&gt;
&lt;p&gt;通常の&lt;code&gt;npm i&lt;/code&gt;のように&lt;code&gt;package.json&lt;/code&gt;に依存関係として追加されたり、グローバルに利用可能なコマンドとしてシステムに登録されたりするわけではないらしい。&lt;/p&gt;
&lt;h3&gt;実行後に自動的にクリーンアップされる、あるいはキャッシュされる&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;npx&lt;/code&gt;がダウンロードしたパッケージは、コマンドの実行が完了すると通常は自動的に削除されるか、次回以降の高速な実行のためにキャッシュされ、ディスク容量を占有し続けたり、手動でアンインストールする必要がない。&lt;/p&gt;
&lt;p&gt;つまり、&lt;code&gt;npx&lt;/code&gt;は永続的なインストールは行わないが、実行のために一時的なダウンロード（実質的なインストール）は行うとのことだった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Goでターミナルに表示するCLIを作成する</title><link>https://blog.nove-b.dev/posts/write-terminal-by-go</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/write-terminal-by-go</guid><content:encoded>&lt;p&gt;個人開発するものがないと&lt;a href=&quot;https://blog.nove-b.dev/posts/2025-6/&quot;&gt;【2025年6月】今年も半分終わったらしい&lt;/a&gt;で書いたけど、さっそく作りたいものができたので着手することにした。&lt;/p&gt;
&lt;p&gt;作りたいのは&lt;code&gt;CLI&lt;/code&gt;ツールで&lt;code&gt;npx xxxx&lt;/code&gt;というコマンドで自分のプロフィールが表示されるエンジニアの名刺みたいなもの。&lt;/p&gt;
&lt;p&gt;過去に流行ったらしいけど、知らなかった。&lt;/p&gt;
&lt;p&gt;この前聞いた&lt;code&gt;podcast&lt;/code&gt;でやっている人がいると聞き自分も作りたくなった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TypeScript&lt;/code&gt;で開発するのが楽そうだけど、せっかくなので&lt;code&gt;go&lt;/code&gt;で作ることにした。&lt;/p&gt;
&lt;h2&gt;GoでターミナルにHello World&lt;/h2&gt;
&lt;p&gt;過去に&lt;code&gt;go&lt;/code&gt;で&lt;code&gt;api&lt;/code&gt;とか作ったことあるけど、もう何も覚えていなかったのでほぼ最初からスタートした。&lt;/p&gt;
&lt;h2&gt;go mod initでモジュール管理をする&lt;/h2&gt;
&lt;p&gt;まずは&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go mod init github.com/xxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でモジュール管理を開始する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;node&lt;/code&gt;の&lt;code&gt;package.json&lt;/code&gt;のようなもの。&lt;code&gt;package.json&lt;/code&gt;にある&lt;code&gt;script&lt;/code&gt;のような機能を持っていない。&lt;/p&gt;
&lt;p&gt;ちなみに、&lt;code&gt;github.com/xxxxxxxxxx&lt;/code&gt;の部分は存在しないリポジトリでもいいらしく、&lt;code&gt;myproject&lt;/code&gt;のような名前でもいいらしい。&lt;/p&gt;
&lt;p&gt;ただ、最終的に公開する予定がある場合は、実際に公開するリポジトリのパスに合わせておくのがベストプラクティスとのことだった。&lt;/p&gt;
&lt;h2&gt;buildファイルの実行でターミナルに特定の文字列を表示する&lt;/h2&gt;
&lt;p&gt;次に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
	fmt.Println(&quot;Hello, World!&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という&lt;code&gt;main.go&lt;/code&gt;を作成する。&lt;/p&gt;
&lt;p&gt;`` bash o build -o hello-world main.go&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
最後に上記のようにビルドすると`hello-world`というファイルが同階層にアウトプットされる。

``` bash
./hello-world

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、ターミナルに&lt;code&gt;Hello World&lt;/code&gt;と表示される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年7月】浮世離れしたいけど、そんな勇気はない</title><link>https://blog.nove-b.dev/posts/2025-7</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-7</guid><content:encoded>&lt;h2&gt;7月に読んだ本&lt;/h2&gt;
&lt;p&gt;7月はまた本を1冊しか読めなかった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/44ZBIxU&quot;&gt;キッチン常夜灯 (角川文庫)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;「花束みたいな恋をした」で主人公の男がすぐに役立つビジネス・自己啓発書を読むばかりでカルチャーへの興味を失っていく姿が描かれていて、浮き世離れした姿に惹かれる自分は、そうはなりたくないいと思うんだけれど、徐々にそっち側に引っ張られているようで恐ろしい。&lt;/p&gt;
&lt;p&gt;実際、Audibleが無料とのことで契約して、何冊かビジネス書を聞いてみたりした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4mvXn6R&quot;&gt;スマホはどこまで脳を壊すか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3HjRudP&quot;&gt;なぜ働いていると本が読めなくなるのか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/40O9Z0L&quot;&gt;チーズはどこへ消えた？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4ldfqh8&quot;&gt;スタンフォード式最高の睡眠&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;まあ、Audibleは自分には合わず、何も頭に入ってこなかったという落ちになるんだけれど、ついに自分もビジネス書を読んでしまうのかと何とも言えない気持ちになった。&lt;/p&gt;
&lt;p&gt;そういうわけで浮き世離れした男代表の明智小五郎と出会うために、江戸川乱歩全集を再読することにした。&lt;/p&gt;
&lt;p&gt;夏に乱歩は妙に合う。&lt;/p&gt;
&lt;p&gt;色々と考え悩んでいた電子書籍専用端末だけれど、スマホで良くないかと思うようになってきた。&lt;/p&gt;
&lt;p&gt;スマホと電子書籍専用端末の2台持ちなんて意味わからないし、電子図書館も電波がなくちゃ読めないらしく、電子書籍専用端末で読むにはテザリングをする必要がある。&lt;/p&gt;
&lt;p&gt;それならスマホで良いという結論になった。&lt;/p&gt;
&lt;p&gt;ただいまだにスマホを寝る前にやると眠れなくなるという言い伝えを信じているので、少し試してみることにする。本当に寝つきが悪くなるようであれば、電子書籍専用端末の購入を検討する。&lt;/p&gt;
&lt;h2&gt;何かを選択する時にお金で悩みたくない&lt;/h2&gt;
&lt;p&gt;買えるなら買いたいんだけど、迷わず購入できるほどの金銭的余裕があるわけじゃない。&lt;/p&gt;
&lt;p&gt;子どもが毎日成長するので、子どもが小学生になった時の話まで出てくるようになった。&lt;/p&gt;
&lt;p&gt;学校帰りに家に誰がいてあげたい。&lt;/p&gt;
&lt;p&gt;そうするとどちらかの年収を倍にする必要がある。&lt;/p&gt;
&lt;p&gt;今の会社で、というより4年間同一企業に勤めて年収を倍にする方法なんて存在しない気がする。&lt;/p&gt;
&lt;p&gt;そうなると転職するしかないんだけど、別に転職するほど今の会社に不満があるわけじゃない。&lt;/p&gt;
&lt;p&gt;ただ最近いろいろ他の方から連絡が来たりするので、知らない企業の話し聞くくらいならと思い、気になっている企業に書類を送ったら、普通にお祈りされた。&lt;/p&gt;
&lt;p&gt;新卒以来、初めて書類落ちした。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;俺が弱い事を、とうの昔に知っている。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;images/hoshiumi.jpg&quot; alt=&quot;俺が弱い事を、とうの昔に知っている。&quot; /&gt;&lt;/p&gt;
&lt;p&gt;最近自分が弱くないと思い込んでいる節があったので、自分の現在地点を知るという意味ではとても良かったと思うようにする。&lt;/p&gt;
&lt;p&gt;地頭で敵わないのであれば努力するしかない。そして努力の方向を間違わないようにしたい。&lt;/p&gt;
&lt;h2&gt;努力というわけじゃないけどOSSに貢献することが性に合っている&lt;/h2&gt;
&lt;p&gt;努力というよりかは趣味としてOSSにコントリビュートするのが自分に合っている気がする。&lt;/p&gt;
&lt;p&gt;今までは個人開発1択だったんだけど、個人開発だと0から自分のコードを書くだけなので、コードリーティングとかをすることがない。別にそれでもいいんだけれど、別の人の書いたコードを読むのが意外と面白いことに気がついた。&lt;/p&gt;
&lt;p&gt;あと常に課題があるのも問題を解いているようで面白い。個人開発にしろ、OSSコントリビュートにしろ、それぞれできることが異なるのでいい塩梅でやっていきたい。&lt;/p&gt;
&lt;p&gt;今精力的に取り組んでいるのは&lt;code&gt;elk&lt;/code&gt;への&lt;a href=&quot;https://github.com/elk-zone/elk/issues?q=is%3Apr+author%3Anove-b&quot;&gt;コントリビュート&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;基本的に&lt;code&gt;issue&lt;/code&gt;に対してプルリクを送るんだけど、&lt;code&gt;Lint&lt;/code&gt;の警告が気になったのでプルリク投げたらすでに解決済みだった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fork&lt;/code&gt;した&lt;code&gt;main&lt;/code&gt;を最新化していなかったのが原因なので、常に&lt;code&gt;main&lt;/code&gt;を最新にすることを心掛けるようにする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git fetch upstream
git merge upstream/main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;競プロとかやりたいんだけど、今はまだそこまで手が回らない。&lt;/p&gt;
&lt;h2&gt;余裕がないことを家族、子どものせいにしない&lt;/h2&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;twitter-tweet&quot; data-media-max-width=&quot;560&quot;&amp;gt;&amp;lt;p lang=&quot;ja&quot; dir=&quot;ltr&quot;&amp;gt;だから親は人間的魅力に欠ける人が多いんだわ。毎日仕事して家帰って育児してると何もアイデアが浮かばねーわ。ただタスクに忙殺されてる。思考の余暇が無いしハングリー精神もない。故に新しいことを取り入れる余裕もない。結果無キャになる。子育ては確実に俺から男性的魅力を奪ってる。よくない。&amp;lt;/p&amp;gt;— トーマス＠ガジェマガ (@gadgetKaeru) &amp;lt;a href=&quot;https://twitter.com/gadgetKaeru/status/1948027352618815601?ref_src=twsrc%5Etfw&quot;&amp;gt;July 23, 2025&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt; &amp;lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;最近見たXの投稿で割と共感した。&lt;/p&gt;
&lt;p&gt;ただ余裕がないのは自分次第な気がするので、家族、子どものせいじゃない気がする。&lt;/p&gt;
&lt;p&gt;結婚したのにそれを感じさせないくらい楽しんでいる人だっているわけだし。&lt;/p&gt;
&lt;p&gt;それになんだって子どもはかわいい、たぶんいまが１番可愛い。&lt;/p&gt;
&lt;p&gt;この時間、時期に子どもより自分を優先するのはきっと後悔する、そうは思っても自分を諦めきれないのは4月にも書いたんだけれど。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2025-4/&quot;&gt;【2025年4月】春は軽やかに、でもずっしり重たくのしかかってきた&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;大宮鉄道博物館に行く&lt;/h3&gt;
&lt;p&gt;なんで子どもは電車が好きなのだろうか。&lt;/p&gt;
&lt;p&gt;全く共感できないけど、子どもが好きならばということで行ってみた。&lt;/p&gt;
&lt;p&gt;2時間かかったし、車中で子どもが吐くしで、大変だったけど、それなりに楽しんでくれたようだった。&lt;/p&gt;
&lt;p&gt;新幹線テラスは何分毎に新幹線が目の前を通り、普通に見ものだった。&lt;/p&gt;
&lt;p&gt;スジャータのカチカチアイスも食べれたし満足だった。&lt;/p&gt;
&lt;p&gt;もう少し大きくなったらまた行ってもいいかもしれない。&lt;/p&gt;
&lt;h3&gt;軽井沢に2泊3日の旅行にいく&lt;/h3&gt;
&lt;p&gt;色々あったけど、タイムラインとコメントだけ残しておく。&lt;/p&gt;
&lt;h4&gt;1日目&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;上里サービスエリア
&lt;ul&gt;
&lt;li&gt;子どもが吐くのが怖いので顔色を見つつ、すべてのSAをピックアップしていた。&lt;/li&gt;
&lt;li&gt;車で寝てくれたので、寝ている間に結構距離を稼げた。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;軽井沢ショッピングプラザ
&lt;ul&gt;
&lt;li&gt;フードコートでご飯を食べた&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;軽井沢コモングラウンズ
&lt;ul&gt;
&lt;li&gt;アイスを食べた&lt;/li&gt;
&lt;li&gt;蔦屋が運営しているらしい&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;BEB5軽井沢 by 星野リゾート
&lt;ul&gt;
&lt;li&gt;子連れに星野リゾートは間違いない&lt;/li&gt;
&lt;li&gt;寝るだけならちょうどいい&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2日目&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;01BAKERY
&lt;ul&gt;
&lt;li&gt;お昼ごはん買うために訪問したけど買わなかった。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Mel
&lt;ul&gt;
&lt;li&gt;お昼ごはん買うために訪問した。&lt;/li&gt;
&lt;li&gt;駐車場で待ち。&lt;/li&gt;
&lt;li&gt;妻と義母に任せた&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;おもちゃ王国
&lt;ul&gt;
&lt;li&gt;遊園地デビュー&lt;/li&gt;
&lt;li&gt;電車を運転するやつに3回乗った&lt;/li&gt;
&lt;li&gt;回転木馬をリタイヤ&lt;/li&gt;
&lt;li&gt;リベンジの時ずっと抱きついててかわいかった。&lt;/li&gt;
&lt;li&gt;ゴーカートデビューもした&lt;/li&gt;
&lt;li&gt;プラレール館に2時間くらいいた。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;つるや
&lt;ul&gt;
&lt;li&gt;ローカルのスーパーらしい&lt;/li&gt;
&lt;li&gt;寝ている子どもと駐車場で待っていた&lt;/li&gt;
&lt;li&gt;みんなが大量の買いもの袋を持って帰ってきた&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TsuruTonTan UDON NOODLE Brasserie 軽井沢
&lt;ul&gt;
&lt;li&gt;おしゃれなうどん屋さん&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/udon.jpg&quot; alt=&quot;うどん&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;3日目&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;とんぼの湯
&lt;ul&gt;
&lt;li&gt;温泉、良かった。&lt;/li&gt;
&lt;li&gt;夜も行けばよかったけど、子どもがいると...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;熊野皇大神社
&lt;ul&gt;
&lt;li&gt;長野と群馬の県境にある神社らしい&lt;/li&gt;
&lt;li&gt;御朱印発祥の地とのこと&lt;/li&gt;
&lt;li&gt;こどものトイレに付き合っていたら迷子になった&lt;/li&gt;
&lt;li&gt;みんなもう車に戻っていた&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;軽井沢発地市庭
&lt;ul&gt;
&lt;li&gt;時間余ったのでよった&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;帰宅
&lt;ul&gt;
&lt;li&gt;渋滞にはまり3時間50分かかった&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;しっかり疲れたけど、満足した。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年8月】夏休みと転職を諦め、いったん添い遂げる決意を固める</title><link>https://blog.nove-b.dev/posts/2025-8</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-8</guid><content:encoded>&lt;h2&gt;8月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3JHD202&quot;&gt;僕たちは我慢している&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/41tzGnF&quot;&gt;博士の長靴&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今月は2冊しか読めなった。&lt;/p&gt;
&lt;p&gt;大学生の時は20冊読んでいたので、その10分の1しか読めてない。&lt;/p&gt;
&lt;p&gt;多く読めばいいって言うものじゃないけれど、なんとなく悲しい気持ちにはなる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/41tzGnF&quot;&gt;博士の長靴&lt;/a&gt;は電子図書館で読んだ。&lt;/p&gt;
&lt;p&gt;毎日再ログインしなければいけないとか、通信が必要になるとか気になる点はいくつかあったけど、何より小説が30冊しかないので個人的には使い物にならないというのが、使ってみた感想。&lt;/p&gt;
&lt;p&gt;図書館にはもう少し頑張ってもらいたい。&lt;/p&gt;
&lt;h2&gt;キンドルアンリミテッドを退会した&lt;/h2&gt;
&lt;p&gt;キンドルアンリミテッドにしてから読み切れない本が増えた。&lt;/p&gt;
&lt;p&gt;たぶん無料なのでとりあえず読んでみようという考えで本を選ぶことが増えたからだと思う。&lt;/p&gt;
&lt;p&gt;本屋に行き楽しそうな本を見て読みたいなあ、でもキンドルアンリミテッドにないからなあ、ってなるのはあまりにも貧乏人過ぎるので、本くらいは買うようにする。&lt;/p&gt;
&lt;p&gt;9月からは好きな本を好きなだけ読むようにする。&lt;/p&gt;
&lt;h2&gt;8月3日はトイレ記念日&lt;/h2&gt;
&lt;p&gt;双子の片割れ（女）の方がトイレデビューした。&lt;/p&gt;
&lt;p&gt;女の子の方が成長が早いというがその通りですんなりトイレにいけるようになった。&lt;/p&gt;
&lt;p&gt;片割れ（男）のほうはまだまだかかりそうだけど、気長に待つことにする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.sukusuku.com/contents/321286&quot;&gt;おかあさんといっしょの2025年6月の月歌「ゆめみるゆっくりさん」&lt;/a&gt;を聞き、妻が片割れ（男）のことを歌っているみたいと言っていてその通りだと思った。&lt;/p&gt;
&lt;h2&gt;夏休みと昼休み&lt;/h2&gt;
&lt;p&gt;妻が学校の先生のため、夏休みがある。&lt;/p&gt;
&lt;p&gt;そのため子どもたちが家にいる。&lt;/p&gt;
&lt;p&gt;在宅の昼休みは水遊びに捧げたり、仕事以上の重労働だった。&lt;/p&gt;
&lt;p&gt;妻と2人でお昼食べ行ったり、家族で夜食べに行ったりできていいことも多かった。&lt;/p&gt;
&lt;p&gt;まあ、仕事はいつでもできるけど、子育てできる期間は短いので、いまをしっかり楽しむしかない。&lt;/p&gt;
&lt;p&gt;本当に子育ては一瞬で、この前まで新生児だったのに、いまはもう3歳になりかけている。&lt;/p&gt;
&lt;h2&gt;七五三の前撮り&lt;/h2&gt;
&lt;p&gt;3歳になるということはもう少しで七五三ということで前撮りに行った。&lt;/p&gt;
&lt;p&gt;男女双子なのでどうしようかと考えた結果、3歳と6歳にすることにした、たぶん。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/753.jpg&quot; alt=&quot;七五三&quot; /&gt;&lt;/p&gt;
&lt;p&gt;途中で着物を脱いで逃走したり、泣きわめいたりして、めちゃくちゃ大変だったけど、プロの写真を見たら可愛すぎてびっくりした。&lt;/p&gt;
&lt;p&gt;親バカじゃなくて本当に天使だったのでびっくりした。&lt;/p&gt;
&lt;h2&gt;マイメロにはまる&lt;/h2&gt;
&lt;p&gt;3歳になると恐ろしいことに色々な遊び場が有料になる。&lt;/p&gt;
&lt;p&gt;サンリオもその1つで2歳までは無料なので、なんとかして誕生日前までに行くぞ、と予定を捻じ込んだ。&lt;/p&gt;
&lt;p&gt;片割れ（男）のほうは、男の子らしく電車が好きだけど、片割れ（女）のほうは好きじゃない電車に付き合っている感が拭えなかった。&lt;/p&gt;
&lt;p&gt;ずっと可哀そうだと思っていたけどピンとくるものがないらしく、新幹線にはまろうと努力している感じさえした。&lt;/p&gt;
&lt;p&gt;しかし、サンリオに行き、帰ってきたときにはマイメロの大ファンになっていた。&lt;/p&gt;
&lt;p&gt;以来、マイメロちゃんを見つけるたびに興奮するようになった。&lt;/p&gt;
&lt;p&gt;当日は2つしかない乗り物を制覇し、キティちゃんとポムポムプリンと写真を撮った。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/sanrio.jpg&quot; alt=&quot;七五三&quot; /&gt;&lt;/p&gt;
&lt;p&gt;楽しかったらしく、また行きたいらしいけど、次からはお金がかかるので、ちょっと考える。&lt;/p&gt;
&lt;h2&gt;おかあさんといっしょスペシャルステージにいく&lt;/h2&gt;
&lt;p&gt;夏休みの最後のイベントで「おかあさんといっしょスペシャルステージ」行った。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/shinkansen.jpg&quot; alt=&quot;七五三&quot; /&gt;&lt;/p&gt;
&lt;p&gt;さいたまスーパーアリーナから新幹線が見えて、大興奮だった。&lt;/p&gt;
&lt;p&gt;去年も来たのに全く気がつかなかった。&lt;/p&gt;
&lt;p&gt;視点で相当見え方が変わると再認識した。&lt;/p&gt;
&lt;p&gt;ステージは年齢的なものか、今年のほうが楽しんでいるようだった。&lt;/p&gt;
&lt;p&gt;手を振ったり、一緒に踊ったり、成長が垣間見えた。&lt;/p&gt;
&lt;p&gt;途中で疲れて寝ちゃったけど、楽しんでいるようで良かった。&lt;/p&gt;
&lt;p&gt;次は11月のファミコンと3歳児のみが申し込める観覧に全力で応募する。&lt;/p&gt;
&lt;p&gt;来年もまだ卒業しないでくれると親としてはありがたい。&lt;/p&gt;
&lt;p&gt;来年もまだおかあさんといっしょが好きで、みんなで行けることを願っている。&lt;/p&gt;
&lt;h2&gt;国宝を見た&lt;/h2&gt;
&lt;p&gt;時間を作り、妻と国宝を見に行った。&lt;/p&gt;
&lt;p&gt;これがとんでもなく面白く、やっぱり多くの人が良いというものは間違いなくいいものであると再認識した。&lt;/p&gt;
&lt;p&gt;何がいいかは書けないので、書かない。&lt;/p&gt;
&lt;p&gt;スラムダンク以来の映画で久しぶりに1時間以上のコンテンツを見た気がする。&lt;/p&gt;
&lt;p&gt;ショートコンテンツに慣れすぎているので、3時間みれるか不安だったけど、あっという間だった。&lt;/p&gt;
&lt;p&gt;3時間をあっという間と感じさせる作品力に圧倒された。&lt;/p&gt;
&lt;h2&gt;転職活動の終結&lt;/h2&gt;
&lt;p&gt;7月に書類落ちしたことは書いたけど、8月にはずっと行きたかった、憧れていた企業に応募した。&lt;/p&gt;
&lt;p&gt;書類は通り、面接をした結果、1週間経っても返信がこないので多分落ちたのだと諦めることにする。&lt;/p&gt;
&lt;p&gt;面接では技術的な話もできたし、最近の話題を話すこともでき楽しかった。&lt;/p&gt;
&lt;p&gt;今の会社ではそういう話ができないので、やっぱり技術的に強い会社は知識豊富な人が多いなと感じた。&lt;/p&gt;
&lt;p&gt;とは言え、落ちたものは仕方ないのでいったん諦めて、今の会社と添い遂げる決意を持つように頑張ってみる。&lt;/p&gt;
&lt;p&gt;別に今の会社に不満があるわけじゃないので、これ以上就活を進める気もない。&lt;/p&gt;
&lt;p&gt;次のステージに行きたかったけど、行けなかったのは自分のブランド不足、技術力不足なので、もっと努力するしかない。&lt;/p&gt;
&lt;p&gt;自分のステージを改めて知ることができたので、ここからスタートする。&lt;/p&gt;
&lt;p&gt;いずれまた受けなおしたいと思っているし、受けると思う。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>React Router v7でConsoleを削除するメモ</title><link>https://blog.nove-b.dev/posts/delete-console-react-router-v7</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/delete-console-react-router-v7</guid><content:encoded>&lt;h2&gt;React Router v7で謎のConsoleが出続ける&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;React Router v7&lt;/code&gt;で開発していると下記コンソールが常に出ていた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Production Build&lt;/code&gt;すれば消えると思っていたので気にしなかったけど、そんなことなかったので初めて意識した。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;💿 Hey developer 👋. You can provide a way better UX than this when your app is loading JS modules and/or running `clientLoader` functions. Check out https://reactrouter.com/start/framework/route-module#hydratefallback for more information.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;訳すると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;こんにちは、デベロッパーの方へ。&lt;/p&gt;
&lt;p&gt;お使いのアプリがJSモジュールを読み込んだり、clientLoader関数を実行したりする際、これよりもずっと優れたUX（ユーザー体験）を提供できます。詳細については、https://reactrouter.com/start/framework/route-module#hydratefallback
をご覧ください。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;つまりもっといい開発できますよ、ということ。&lt;/p&gt;
&lt;p&gt;公式を見に行くと、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On initial page load, the route component renders only after the client loader
is finished. If exported, a HydrateFallback can render immediately in place of
the route component.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;HydrateFallback&lt;/code&gt;をエクスポートすると、初回レンダリング時、クライントローダーが完了するまで、&lt;code&gt;HydrateFallback&lt;/code&gt;でエクスポートしたコンポーネントを表示してくれるとのこと。&lt;/p&gt;
&lt;p&gt;追加して、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ずっと優れたUX（ユーザー体験）を提供でき&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;るようになった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>WindowsでDockerを用いPixelfedをビルドする</title><link>https://blog.nove-b.dev/posts/build-pixelfed</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/build-pixelfed</guid><content:encoded>&lt;h2&gt;Pixelfed is 何？&lt;/h2&gt;
&lt;p&gt;オープンソースのInstagramで、Mastodonとか同様に分散型のアーキテクチャを使用している。&lt;/p&gt;
&lt;p&gt;つまりFediverseの一部で、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Instagramの「より魅力的な（そして倫理的な）代替手段」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;と言われていたりいなかったり。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/875270529913186816/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;100%&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;h2&gt;Buildまでに結構手こずったのでやり方をメモしておく&lt;/h2&gt;
&lt;p&gt;結構というより、挫折しようかと思うほど手こずった。前提としてフロントエンドをメインとしているので&lt;code&gt;Docker&lt;/code&gt;の知識が乏しいというのが多分にある。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Docker&lt;/code&gt;に慣れている人であれば、こんなもの朝飯前かもしれない。&lt;/p&gt;
&lt;h3&gt;Documentはこちら&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.pixelfed.org/running-pixelfed/installation.html&quot;&gt;Pixelfed Docs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Envの作成&lt;/h3&gt;
&lt;p&gt;まず戸惑ったのが、&lt;code&gt;Env&lt;/code&gt;がたくさんあることで&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env.docker&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env.example&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env.testing&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;どれを使えばいいのかわからなかった。&lt;/p&gt;
&lt;p&gt;いろいろ調べた結果&lt;code&gt;env.docker&lt;/code&gt;を使うっぽいことが判明した。&lt;/p&gt;
&lt;p&gt;この時点でDocsに書いてあることと少し違うので、これが正しいのかわからない。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default Pixelfed comes with a .env.example file for production deployments,
and a .env.testing file for debug deployments. You&apos;ll need to rename or copy
one of these files to .env regardless of which environment you&apos;re working on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とはいえ、動いたのが&lt;code&gt;env.docker&lt;/code&gt;を使う方法なので、この方法で進めていく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cp env.docker .env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記コマンドで、&lt;code&gt;env.docker&lt;/code&gt;を&lt;code&gt;.env&lt;/code&gt;にコピーする。&lt;/p&gt;
&lt;p&gt;次に下記値を任意の値に変更する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;APP_NAME=&quot;PixelfedExample&quot;
APP_DOMAIN=&quot;pixelfed.example.com&quot;
ENFORCE_EMAIL_VERIFICATION=&quot;false&quot;
INSTANCE_CONTACT_EMAIL=&quot;メールアドレス&quot;
DB_PASSWORD=&quot;パスワード&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ちなみに&lt;code&gt;APP_DOMAIN&lt;/code&gt;を&lt;code&gt;localhost&lt;/code&gt;とかにしようとしたけれど、バリデーションがあるしく、特定の形式のドメイン名にしか設定ができなかった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;APP_DOMAIN&lt;/code&gt;の設定により、&lt;code&gt;pixelfed.example.com&lt;/code&gt;でサービスを開けるようになる。&lt;/p&gt;
&lt;p&gt;たぶんその設定は&lt;code&gt;docker\nginx\root\docker\templates\etc\nginx\conf.d\default.conf&lt;/code&gt;に記述されている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen 80 default_server;

    server_name {{ getenv &quot;APP_DOMAIN&quot; }};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これだけだと自身の指定したドメインとIPアドレスの紐づけが完了されていないので、&lt;code&gt;hosts&lt;/code&gt;ファイルを修正して紐づけを行っていく。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Windows\System32\drivers\etc\hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を開き、末尾に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;127.0.0.1 pixelfed.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と追記する。&lt;/p&gt;
&lt;h3&gt;Dockerを立ち上げる&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コマンドで&lt;code&gt;Docker&lt;/code&gt;を起動する。&lt;/p&gt;
&lt;p&gt;上手くいかないときは、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose logs --follow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でログを確認して修正していく。&lt;/p&gt;
&lt;p&gt;今回は認証キーがログに記載されていたいので、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose exec web php artisan passport:keys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で&lt;code&gt;Key&lt;/code&gt;を作成する。&lt;/p&gt;
&lt;p&gt;そして&lt;code&gt;Docker&lt;/code&gt;の問題がなくなるまで根気強く付き合っていく。&lt;/p&gt;
&lt;h3&gt;アカウントを作成する&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Docker&lt;/code&gt;の問題がすべて解決したら、アカウントを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose exec -u www-data web php artisan user:create
Creating a new user...

 Name:
 &amp;gt; name_id

 Username:
 &amp;gt; username

 Email:
 &amp;gt; email

 Password:
 &amp;gt;

 Confirm Password:
 &amp;gt;

 Make this user an admin? (yes/no) [no]:
 &amp;gt; yes

 Manually verify email address? (yes/no) [no]:
 &amp;gt; yes

 Are you sure you want to create this user? (yes/no) [no]:
 &amp;gt; yes

Created new user!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで一通り設定完了したので、&lt;code&gt;pixelfed.example.com&lt;/code&gt;にアクセスすると、トップページが表示させる。&lt;/p&gt;
&lt;h3&gt;証明書 (nginx.crt) と秘密鍵 (nginx.key) を作成 する&lt;/h3&gt;
&lt;p&gt;最後に&lt;code&gt;https&lt;/code&gt;で接続できるように、証明書を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p docker/nginx/ssl &amp;amp;&amp;amp; openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout docker/nginx/ssl/nginx.key -out docker/nginx/ssl/nginx.crt -subj &quot;//C=JP/ST=Tokyo/L=Tokyo/O=Dev/CN=pixelfed.example.com&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で、下記2ファイルが作成される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pixelfed\docker\nginx\ssl\nginx.crt
pixelfed\docker\nginx\ssl\nginx.key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事&lt;code&gt;Https&lt;/code&gt;接続ができるようになった。&lt;/p&gt;
&lt;h3&gt;ホットリロードが効かない&lt;/h3&gt;
&lt;p&gt;意気揚々とカスタマイズしようとして、ソース触っても画面が更新されない。&lt;/p&gt;
&lt;p&gt;なんなら、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose down
docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でも更新されず。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up --build -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で更新されることが確認できた。&lt;/p&gt;
&lt;p&gt;新たな問題なので解決に向けて調査していく（マウントの問題？）けど、ひとまずビルドできたのでOKとする。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/872321979626827906/embed?caption=false&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;100%&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;h2&gt;追記&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;docker compose up --build -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で&lt;code&gt;blade&lt;/code&gt;が更新される。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm run development
docker compose up --build -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で&lt;code&gt;vue&lt;/code&gt;が適用される。&lt;/p&gt;
&lt;p&gt;......、これが正しい運用方法なのかもしれない。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b/115271283215776951/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;100%&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年9月】やっと公園に行ける気温になった</title><link>https://blog.nove-b.dev/posts/2025-9</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-9</guid><content:encoded>&lt;h2&gt;9月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/47ZJPwm&quot;&gt;成瀬は天下を取りにいく（新潮文庫） 「成瀬」シリーズ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3KmX14J&quot;&gt;タイムマシンに乗れないぼくたち (文春文庫)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今月も2冊しか読めなった。&lt;/p&gt;
&lt;p&gt;Kindleデバイスが古くなった＆&lt;a href=&quot;https://blog.nove-b.dev/posts/2025-8/#%E3%82%AD%E3%83%B3%E3%83%89%E3%83%AB%E3%82%A2%E3%83%B3%E3%83%AA%E3%83%9F%E3%83%86%E3%83%83%E3%83%89%E3%82%92%E9%80%80%E4%BC%9A%E3%81%97%E3%81%9F&quot;&gt;キンドルアンリミテッドを退会した&lt;/a&gt;という理由で紙の本に切り替えた。&lt;/p&gt;
&lt;p&gt;久々の紙の本は思ったより軽くて、読みやすかった。&lt;/p&gt;
&lt;p&gt;読みやすさで言えばKindleなんて比じゃないレベルで読みやすい。&lt;/p&gt;
&lt;p&gt;ただ出先に何回か本を忘れ手持無沙汰になったので、Kindleは良かったと思うこともあった。&lt;/p&gt;
&lt;p&gt;つまり一長一短ってこと。&lt;/p&gt;
&lt;p&gt;今は紙の本にした。ただ明日はわからない。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/874297922089793661/embed?caption=false&amp;amp;likes=false&amp;amp;layout=compact&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;100%&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/877709545123760164/embed?caption=false&amp;amp;likes=false&amp;amp;layout=compact&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;100%&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;h3&gt;図書館は最強という再発見&lt;/h3&gt;
&lt;p&gt;9月読んだ本は適当に書店で買った。そうすると当然紙の本が家にある。&lt;/p&gt;
&lt;p&gt;本のデメリットは場所を取ることで、いままでの引っ越しでも何回もつらい思いをした。&lt;/p&gt;
&lt;p&gt;今は家に内田百閒の全集を残し本を置かないようにしている。&lt;/p&gt;
&lt;p&gt;そういうわけで、すぐに売りたいんだけど売る場所が家の近くにない。&lt;/p&gt;
&lt;p&gt;そこで図書館に頼ることにした。幸いなことに歩いて行ける場所に図書館がある。&lt;/p&gt;
&lt;p&gt;久々に、たぶん大学生依頼の予約をした。&lt;/p&gt;
&lt;p&gt;ただなかなか来ないので、１冊普通に買っちゃった。&lt;/p&gt;
&lt;h2&gt;9月13日はトイレ記念日(再)&lt;/h2&gt;
&lt;p&gt;双子の片割れ（男）の方がトイレデビューした。&lt;/p&gt;
&lt;p&gt;トイレデビューした日に外のトイレでもトイレデビューした。&lt;/p&gt;
&lt;p&gt;度胸がある。&lt;/p&gt;
&lt;p&gt;双子の片割れ（女）の方は家でのトイレは完璧だけど、外のトイレは怖がってギャン泣きする。&lt;/p&gt;
&lt;p&gt;お出かけすると、トイレにいる時間のほうが長いかもしれない。&lt;/p&gt;
&lt;p&gt;まだまだ先は長そうだけど、とりあえず２人ともデビューできた、お疲れさま。&lt;/p&gt;
&lt;h2&gt;おかあさんといっしょ&lt;/h2&gt;
&lt;p&gt;ファミリーコンサートに応募して落ちた。&lt;/p&gt;
&lt;p&gt;初応募で4列目が当たったのは奇跡だったのかもしれない。&lt;/p&gt;
&lt;p&gt;まあ、仕方がないので諦める。&lt;/p&gt;
&lt;p&gt;それとは別に3歳の1年間番組の観覧に応募ができる。&lt;/p&gt;
&lt;p&gt;毎月25日までに頑張って応募し続ける。&lt;/p&gt;
&lt;p&gt;とりあえず9月は応募した。&lt;/p&gt;
&lt;h2&gt;キックバイクにはまる&lt;/h2&gt;
&lt;p&gt;祖父母からもらったキックバイクに乗り始め、いい感じに興味を持ってくれたよう。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/877838065318735637/embed?caption=false&amp;amp;likes=false&amp;amp;layout=compact&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;100%&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;公園に行っては乗り回している。&lt;/p&gt;
&lt;p&gt;双子用ベビーカー、テント、キックバイク２つと大荷物で大変だけれど、公園に長い間いれるようになったので行く甲斐ができた。&lt;/p&gt;
&lt;p&gt;今までは他の子がたくさんいるともう帰ると言っていたけど、保育園のおかげが、成長か、まだ帰りたくないと言うようになった。&lt;/p&gt;
&lt;p&gt;せっかく行っているので、そっちのほうが嬉しい。&lt;/p&gt;
&lt;h2&gt;転職活動の終結と再開&lt;/h2&gt;
&lt;p&gt;ずっと憧れていた企業に落ちたことは8月に書いた。&lt;/p&gt;
&lt;p&gt;で、そういうわけならばと転職活動を辞めたんだけれど、実際にいろいろな企業の方と話すにつれ、楽しそうなプロダクトをたくさん見つけた。&lt;/p&gt;
&lt;p&gt;ただ転職試験となると、自分自身の実力不足が露呈するかもしれない。&lt;/p&gt;
&lt;p&gt;まあ、それも含めて自分の現在地を知るいい経験になりそうなので、面白そうなプロジェクトにはぶつかっていくことにした。&lt;/p&gt;
&lt;h3&gt;鍵っ子にしたくない&lt;/h3&gt;
&lt;p&gt;というのも今後のことを考える。&lt;/p&gt;
&lt;p&gt;鍵っ子が悪いわけじゃないけど、子どもが帰ってきたときに誰かが家にいてあげたい。&lt;/p&gt;
&lt;p&gt;そのためには一馬力に近い状態を目指す必要があり、年収を上げる必要がある。&lt;/p&gt;
&lt;p&gt;書いてて気が付いたけど、&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/2025-7/#%E4%BD%95%E3%81%8B%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%99%E3%82%8B%E6%99%82%E3%81%AB%E3%81%8A%E9%87%91%E3%81%A7%E6%82%A9%E3%81%BF%E3%81%9F%E3%81%8F%E3%81%AA%E3%81%84&quot;&gt;【2025年7月】浮世離れしたいけど、そんな勇気はない&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;過去に同じことを書いていた。&lt;/p&gt;
&lt;p&gt;まあ、そういうわけで少し恥ずかしい思いをするかもだけど当たって砕けていく。&lt;/p&gt;
&lt;h2&gt;Pixelfedと格闘する日々&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/build-pixelfed/&quot;&gt;WindowsでDockerを用いPixelfedをビルドする&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;分散型のインスタこと&lt;code&gt;Pixelfed&lt;/code&gt;を触っている。&lt;/p&gt;
&lt;p&gt;もともと&lt;code&gt;React Native&lt;/code&gt;のプロジェクトということで見つけたけど、WindowsのARMはAndroid
Studioをインストールできないとのことで諦め、Web版を触って楽しむことにした。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://social.nove-b.dev/@nove_b/115155416238228051/embed&quot; class=&quot;mastodon-embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;100%&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script src=&quot;https://social.nove-b.dev/embed.js&quot; async=&quot;async&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;何とかしてビルドまで持ってきたけど、全然全体像が見えずに困っている。&lt;/p&gt;
&lt;p&gt;別に無理してやる必要もないんだけど、ここまで来たらしっかり理解したいと思い、くらいついている。&lt;/p&gt;
&lt;p&gt;飽きるまで、挫折するまで頑張ってみる。&lt;/p&gt;
&lt;h3&gt;理解することの重要性&lt;/h3&gt;
&lt;p&gt;{{&amp;lt; youtube uAVQ9wjySUs &amp;gt;}}&lt;/p&gt;
&lt;p&gt;上記動画を見ていかに理解することが大切かを思い知った。&lt;/p&gt;
&lt;p&gt;結末を急ぎ、なあなあにするしてしまうことが多いので、意識的に行っていくようにする。&lt;/p&gt;
&lt;p&gt;木こりのジレンマと同じで、しっかり理解してから進むことが結局近道なんだと思われる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Pixelfed&lt;/code&gt;のビルドにしてもそうで、まずはソースコード理解をしたうえで、進めていきたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Hugoのテーマを変更したらnetlifyのビルドが失敗するようになった</title><link>https://blog.nove-b.dev/posts/netlify-build-hugo</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/netlify-build-hugo</guid><content:encoded>&lt;h2&gt;HugoのテーマをPaperModに戻した&lt;/h2&gt;
&lt;p&gt;Hugoのテーマをまた変更した。&lt;/p&gt;
&lt;p&gt;コントリビュートとリリースとブログを一元管理したいということで&lt;a href=&quot;http://localhost:1313/posts/2025-4/#%e5%80%8b%e4%ba%ba%e9%96%8b%e7%99%ba%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6&quot;&gt;自作のテーマを作成した&lt;/a&gt;けど、コントリビュートを自動で収集したくなったので、&lt;a href=&quot;https://github.com/atinux/my-pull-requests&quot;&gt;atinux/my-pull-requests&lt;/a&gt;を使用することにした。&lt;/p&gt;
&lt;p&gt;できたものは&lt;a href=&quot;https://contributions.nove-b.dev/&quot;&gt;これ&lt;/a&gt;、GithubのAPIから持ってくるのでこちらで運用する必要がない。&lt;/p&gt;
&lt;p&gt;そういうわけで、&lt;a href=&quot;https://github.com/nove-b/hugo-Passage&quot;&gt;hugo-Passage&lt;/a&gt;にあるコントリビュートカテゴリが必要なくなっため、ブログはブログだけを管理するように変更し、そのためにテーマを最初の&lt;a href=&quot;https://github.com/adityatelange/hugo-PaperMod&quot;&gt;hugo-PaperMod&lt;/a&gt;に戻した。&lt;/p&gt;
&lt;h2&gt;Hugoのビルドは脆い&lt;/h2&gt;
&lt;p&gt;で、戻して&lt;code&gt;netlify&lt;/code&gt;でビルドしたところ、失敗した。&lt;/p&gt;
&lt;p&gt;テーマを変えるとビルド失敗するのはよくあること？なので&lt;code&gt;netlify&lt;/code&gt;上で定義している&lt;code&gt;Hugo&lt;/code&gt;のバージョンを見直してみたりしたけど、一向にビルドが通らない。&lt;/p&gt;
&lt;h2&gt;原因はバージョンではなくビルドイメージ&lt;/h2&gt;
&lt;p&gt;他の原因かとエラーを探ると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hugo: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33&apos; not found (required by hugo)
hugo: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32&apos; not found (required by hugo)
hugo: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34&apos; not found (required by hugo)
hugo: /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.29&apos; not found (required by hugo)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;というログが残されていた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Netlify のビルド環境にインストールされている GLIBC（Linux の標準ライブラリ） のバージョンが、あなたが使っている Hugo のバイナリが要求するバージョンより古い のが原因です。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことらしい。&lt;/p&gt;
&lt;p&gt;確かにビルドイメージを&lt;code&gt;Ubuntu Focal 20.04&lt;/code&gt;から&lt;code&gt;Ubuntu Noble 24.04 (default)&lt;/code&gt;に変更したところビルドが成功した。&lt;/p&gt;
&lt;h2&gt;腑に落ちない&lt;/h2&gt;
&lt;p&gt;ただそうするといままで成功していた意味が分からない。&lt;/p&gt;
&lt;p&gt;腑に落ちないけれどChatGPTによると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Netlify はビルド高速化のために、以前使った Hugo の実行ファイルをキャッシュしておく仕組みがあります。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;つまり今までは最初に成功したときに&lt;code&gt;Hugo&lt;/code&gt;を使い続けていたのかもしれないとのこと。&lt;/p&gt;
&lt;p&gt;それがいつのものかわからないし、どのバージョンかもわからない。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1:59:22 AM: Failed to fetch cache, continuing with build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ただ確かにログを見ると以前の &lt;code&gt;Hugo&lt;/code&gt;
バイナリキャッシュが使えなかったと書かれていた。&lt;/p&gt;
&lt;p&gt;なので、解決策としてはビルドイメージを&lt;code&gt;Ubuntu Noble 24.04 (default)&lt;/code&gt;を変更するという着地になった。&lt;/p&gt;
&lt;p&gt;ちょっと釈然としないので、もしわかりやすく説明できる人がいたら教えてください。&lt;/p&gt;
&lt;p&gt;次テーマを変えようって思い立った時は、&lt;code&gt;Hugo&lt;/code&gt;を辞めると思う。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>とりあえずデプロイしたらキャッシュに惑わされたのでNuxtのユニバーサルレンダリングについて調べてみた</title><link>https://blog.nove-b.dev/posts/netlify-build-my-pull-requests</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/netlify-build-my-pull-requests</guid><content:encoded>&lt;h2&gt;SSGでデプロイされていると勘違いしていた&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://contributions.nove-b.dev/&quot;&gt;https://contributions.nove-b.dev/&lt;/a&gt;を&lt;code&gt;Netlify&lt;/code&gt;にデプロイしている。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Clone&lt;/code&gt;元は&lt;a href=&quot;https://github.com/atinux/my-pull-requests&quot;&gt;https://github.com/atinux/my-pull-requests&lt;/a&gt;で、&lt;code&gt;env&lt;/code&gt;を変更するだけで自分ようになるので、ソースコードを読まずに&lt;code&gt;nuxi build&lt;/code&gt;でデプロイした。&lt;/p&gt;
&lt;p&gt;最近は静的ジェネレータをメインに触っていたせいか、&lt;code&gt;SSG&lt;/code&gt;でデプロイされると思い込んでいたので、プルリクを出すたびにデプロイしなくちゃいけなく、デプロイの定期実行をどうしようと思い悩んでいた。&lt;/p&gt;
&lt;p&gt;先日プルリクを出したあとに見に行くと、最新のプルリクが反映されており、勝手にデプロイが走ったのかと混乱した。&lt;/p&gt;
&lt;p&gt;デプロイ履歴を見に行くとデプロイ履歴は更新されていない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SSG&lt;/code&gt;じゃないんじゃと思い返して、試しにプルリクを出し、観察しに行くとプルリクが更新されておらず、さらに混乱する。&lt;/p&gt;
&lt;p&gt;しばらく経ち再訪すると更新されていて大混乱したので、しっかりコードを見に行くことにした。&lt;/p&gt;
&lt;h2&gt;コードリーディングしていく&lt;/h2&gt;
&lt;h2&gt;CSR or SSR api fetch&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fetch&lt;/code&gt;している部分を見に行くと、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { data: contributions } =
  (await useFetch) &amp;lt; Contributions &amp;gt; &quot;/api/contributions&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特に特別なことをしていない。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;a href=&quot;https://nuxt.com/docs/4.x/api/composables/use-fetch&quot;&gt;&lt;code&gt;useFetch&lt;/code&gt;&lt;/a&gt;とは、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;このコンポーザブルは、との便利なラッパーを提供します。URL とフェッチ オプションに基づいてキーを自動的に生成し、サーバールートに基づいてリクエスト URL の型ヒントを提供し、API レスポンス タイプを推測します。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことだった。&lt;/p&gt;
&lt;p&gt;調べてみると特定のレスポンスにおけるKeyだけを取得できる&lt;code&gt;pick&lt;/code&gt;という機能とか&lt;code&gt;ssr&lt;/code&gt;と&lt;code&gt;csr&lt;/code&gt;を切り替える&lt;code&gt;server&lt;/code&gt;とかあって便利そうだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nuxt.com/docs/4.x/api/composables/use-fetch#parameters&quot;&gt;パラメーター一覧&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ちなみに全体で&lt;code&gt;ssr&lt;/code&gt;と&lt;code&gt;csr&lt;/code&gt;を切り替える方法は、&lt;code&gt;nuxt.config.ts&lt;/code&gt;で&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default defineNuxtConfig({
  ssr: false,
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のように設定すると実現できるようだった。&lt;/p&gt;
&lt;p&gt;つまり特別なことはしてないので、&lt;code&gt;Nuxt&lt;/code&gt;のデフォルトのレンダリングをしていると思われる。&lt;/p&gt;
&lt;h2&gt;Nuxtのレンダリングモード&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Nuxt&lt;/code&gt;の&lt;a href=&quot;https://nuxt.com/docs/4.x/guide/concepts/rendering&quot;&gt;ドキュメント&lt;/a&gt;を見に行くとデフォルトはユニバーサルレンダリングというレンダリング方法らしい。&lt;/p&gt;
&lt;p&gt;ユニバーサルレンダリングについて調べてみると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;また、ページが事前に生成されている場合は、キャッシュから完全にレンダリングされたHTMLページを返すこともあります。クライアントサイドレンダリングとは異なり、ユーザーはアプリケーションの初期コンテンツ全体を即座に取得できます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;そうすると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;SSG&lt;/code&gt;じゃないんじゃと思い返して、試しにプルリクを出し、観察しに行くとプルリクが更新されておらず、さらに混乱する。しばらく経ち再訪すると更新されていて大混乱したうえで、しっかりコードを見に行くことにした。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ここで即座に反映されなかったことが腹落ちした。&lt;/p&gt;
&lt;p&gt;それでこのキャッシュに関しては&lt;code&gt;isr&lt;/code&gt;のことを言っているっぽい。&lt;/p&gt;
&lt;p&gt;調べてみると&lt;code&gt;nuxt.config.ts&lt;/code&gt;に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  $production: {
    routeRules: {
      &apos;/&apos;: { isr: 60 * 5 },
      &apos;/api/contributions&apos;: { isr: 60 * 5 },
      &apos;/feed.xml&apos;: { isr: 60 * 5 },
    },
  },
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;という記述があった。&lt;/p&gt;
&lt;p&gt;一度生成されると5分間 (60秒 * 5) キャッシュされて&lt;code&gt;ssr&lt;/code&gt;で生成された静的ページが表示されるようになる。&lt;/p&gt;
&lt;p&gt;という仕組みになっていた。&lt;/p&gt;
&lt;p&gt;便利なリポジトリは活用しつつ、勉強の一助にもしたいと思った今日この頃でした。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年10月】イベントが盛りだくさんだった</title><link>https://blog.nove-b.dev/posts/2025-10</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-10</guid><content:encoded>&lt;h2&gt;10月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/43NCHjw&quot;&gt;嫌いなら呼ぶなよ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4nBwgYe&quot;&gt;愛なき世界(上)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3X80VBq&quot;&gt;愛なき世界(下)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4omkQIZ&quot;&gt;アーセナルにおいでよ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;図書館本を本格的に読み始めた。&lt;/p&gt;
&lt;p&gt;文庫本だけじゃないので持ち運びがつらいときもあるけど、無料で人気作が読める図書館って便利すぎる。&lt;/p&gt;
&lt;p&gt;この世の中でえもっとも有益な公共サービスかもしれない。&lt;/p&gt;
&lt;p&gt;10月は4冊読んだ。&lt;/p&gt;
&lt;p&gt;中でも綿矢りさが圧倒的だった。&lt;/p&gt;
&lt;p&gt;最年少芥川賞受賞時からずっと天才のまま。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center;&quot;&amp;gt;
&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/879965011037884041/embed?caption=true&amp;amp;likes=false&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400px&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center;&quot;&amp;gt;
&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/882987192796770789/embed?caption=true&amp;amp;likes=false&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400px&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center;&quot;&amp;gt;
&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/884993158063585473/embed?caption=true&amp;amp;likes=false&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400px&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h2&gt;盛りだくさんの10月&lt;/h2&gt;
&lt;h3&gt;ハロウィンツリーを出した&lt;/h3&gt;
&lt;p&gt;過去に買ったクリスマスツリーだけど、あまりにも使う頻度が少なすぎたので、ハロウィンツリーなるものにして活用することにした。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center;&quot;&amp;gt;
&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/880379863710645972/embed?caption=false&amp;amp;likes=false&amp;amp;layout=compact&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;ハロウィンに全くなじみないし、どういうイベントかも知らないけど可愛いので良しとする。&lt;/p&gt;
&lt;h3&gt;幸せを掴みに行く&lt;/h3&gt;
&lt;p&gt;見ると幸せになれるというドクターイエロー。&lt;/p&gt;
&lt;p&gt;引退したということが話題になって久しいが、どうやら引退したのは特定の機体の話であり、一部のドクターイエローはまだ現役らしい。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JR東海のドクターイエロー（T4編成）は、老朽化のため2025年1月に検測走行を終了し、引退しました。JR西日本のドクターイエロー（T5編成）も2027年頃に引退予定です。今後は、営業車両に搭載される検測機能によって後継される予定です&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;しかもしっかり調べてみるとどうやら走る日時の予測が出ており、それなりに正しそうだった。&lt;/p&gt;
&lt;p&gt;それじゃ、会いに行こうということで小田原駅に見に行った。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center;&quot;&amp;gt;
&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/880077931271281707/embed?caption=false&amp;amp;likes=false&amp;amp;layout=compact&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;わざわざ見に行くなんていう物好きいないと思ったら子どもずれの家族がわんさかいて、みんな子どものために頑張っているなって思うと少し幸せになれた。&lt;/p&gt;
&lt;p&gt;今度は駅ではなく、走っているドクターイエローを見に行く計画を立てている。&lt;/p&gt;
&lt;p&gt;引退までに、子どもがはまっている間にもう何回かは見にいきたい。&lt;/p&gt;
&lt;h3&gt;七五三のお祝い&lt;/h3&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center;&quot;&amp;gt;
&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/887556198281477654/embed?caption=false&amp;amp;likes=false&amp;amp;layout=compact&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;3歳なので七五三のお祝いをした。&lt;/p&gt;
&lt;p&gt;あいにくの雨だったけど、子どもたちの期限がよかったので良しとする。&lt;/p&gt;
&lt;p&gt;男女双子の七五三は何歳の時にやるのか、世の中の男女双子の親に聞いてみたい。&lt;/p&gt;
&lt;p&gt;前日に椅子から落ちて時間外の緊急外来に駆け込んだら、ただの怪我ですって言われたのはいい思い出。&lt;/p&gt;
&lt;h3&gt;アンパンマンミュージアムにも行った&lt;/h3&gt;
&lt;p&gt;イベント多すぎて記憶が薄れているけど、アンパンマンミュージアムにも行った。&lt;/p&gt;
&lt;p&gt;アンパンマンとバイキングに抱きついて楽しそうにしていた。&lt;/p&gt;
&lt;p&gt;ハロウィン仕様だったので来年はクリスマスに行きたい。&lt;/p&gt;
&lt;h2&gt;転職のこと&lt;/h2&gt;
&lt;p&gt;いったん転職活動はストップすることにした。&lt;/p&gt;
&lt;p&gt;転職活動することで、ある程度自分の現在地が分かった気がする。&lt;/p&gt;
&lt;p&gt;自信喪失することもあったけど、思っている金額以上のオファーをもらえることもあった。&lt;/p&gt;
&lt;p&gt;個人的な話でいうとスキルアップが転職の目的なので、転職することで本当にスキルアップできるかということが重要で、逆に言えば転職しなくてもスキルアップができるのであればそれでもいいと思っている。&lt;/p&gt;
&lt;p&gt;いまいちよくわかなくなってきたので、もう少し整理することにする。&lt;/p&gt;
&lt;h2&gt;OSS活動&lt;/h2&gt;
&lt;p&gt;スキルアップの話につながるけど、個人開発でオレオレコードを書くより、他人のコードを読んで勉強したいということで積極的にOSSに貢献していこうと思い立った。&lt;/p&gt;
&lt;p&gt;今月の貢献は、&lt;/p&gt;
&lt;p&gt;https://github.com/atinux/my-pull-requests/pull/20&lt;/p&gt;
&lt;p&gt;https://github.com/vscode-reborn-ai/vscode-reborn-ai/pull/176&lt;/p&gt;
&lt;p&gt;https://github.com/dargmuesli/nuxt-cookie-control/pull/300&lt;/p&gt;
&lt;p&gt;https://github.com/react-chatbotify/react-chatbotify/pull/362&lt;/p&gt;
&lt;p&gt;上記4点で、週1件は貢献したいと思っているので、まあそれなりの成績に落ち着いた。&lt;/p&gt;
&lt;p&gt;これは引き続き続けていきたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>ローカルのvite-plugin-pwaを、手元のReact Router v7プロジェクトで直接利用する方法</title><link>https://blog.nove-b.dev/posts/dev-react-router-v7-vite-pwa-plugin</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/dev-react-router-v7-vite-pwa-plugin</guid><content:encoded>&lt;p&gt;&lt;code&gt;React Router v7&lt;/code&gt;で&lt;code&gt;vite-plugin-pwa&lt;/code&gt;で使えないという情報をもらった。&lt;/p&gt;
&lt;p&gt;確認したところ確かに使えないことが確認できたので、&lt;a href=&quot;https://blog.nove-b.dev/posts/make-react-router-v7-app-pwa/&quot;&gt;React Router v7で作成したウェブアプリをPWA(インストールに対応のみ)にする&lt;/a&gt;に急いで「(インストールに対応のみ)」という文言を追加した。&lt;/p&gt;
&lt;p&gt;どうやらインストールのみ対応であれば問題はなさそうだった。&lt;/p&gt;
&lt;p&gt;せっかくなのでなぜうまく使いないのか確かめてみようと思い立った。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;npm&lt;/code&gt;でインストールしても色々試せないので、ローカルに置いた&lt;code&gt;vite-plugin-pwa&lt;/code&gt;で試してみることにした。&lt;/p&gt;
&lt;p&gt;該当する&lt;code&gt;issue&lt;/code&gt;は、こちら。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vite-pwa/vite-plugin-pwa/issues/809&quot;&gt;Feature Request: Vite PWA Support for React Router 7 #809&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;pnpmの ワークスペース(workspace) 機能を使うのが最も簡単&lt;/h2&gt;
&lt;p&gt;って&lt;code&gt;gemini&lt;/code&gt;が言っていたので、それを手掛かりにする。&lt;/p&gt;
&lt;p&gt;そもそも&lt;code&gt;pnpm&lt;/code&gt;のワークスペースとは、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;pnpmのワークスペースは、複数のパッケージ（プロジェクト）を単一のリポジトリで管理するための機能です。これは、一般的に「モノレポ（Monorepo）」と呼ばれる開発スタイルを実現するのに役立ちます&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;で、これも&lt;code&gt;gemini&lt;/code&gt;が言っていた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vite-pwa-plugin&lt;/code&gt;は複数のフレームワークに対応しているのが特徴で、そのすべてのプロジェクト&lt;code&gt;pnpm&lt;/code&gt;のワークスペースを用い1つのリポジトリで管理しているとのことらしい。&lt;/p&gt;
&lt;p&gt;モノレポってフロントとバックエンドを１つのリポジトリで管理するためのものって決めつけていたので、こういう使い方もできるのかと驚いた。&lt;/p&gt;
&lt;p&gt;本題に戻し&lt;code&gt;pnpm-workspace.yaml&lt;/code&gt;というファイルを見に行くと、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;packages:
  - docs/
  - examples/*
onlyBuiltDependencies:
  - sharp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と書かれている。&lt;/p&gt;
&lt;p&gt;で、&lt;code&gt;examples&lt;/code&gt;を見に行くと、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;examples\vue-router
examples\react-router
examples\solid-router
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;とか対応しているプロジェクトがあるのでここに各プロジェクトを作成すればいいっぽい。&lt;/p&gt;
&lt;h2&gt;プロジェクトを作成してみる&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npx create-react-router@latest react-router-v7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↓新しく&lt;code&gt;git&lt;/code&gt;を初期化するか聞かれるけど、すでに&lt;code&gt;git&lt;/code&gt;管理されたプロジェクトの中にいるので&lt;code&gt;No&lt;/code&gt;を選択する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Initialize a new git repository?
         No
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↓&lt;code&gt;npm&lt;/code&gt;を使うか聞かれるけど&lt;code&gt;vite-plugin-pwa&lt;/code&gt;は&lt;code&gt;pnpm&lt;/code&gt;を使用しているので&lt;code&gt;No&lt;/code&gt;を選択する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Install dependencies with npm?
         No
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでインストールが完了した。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;examples&lt;/code&gt;以下にプロジェクトが作成されていることを確認できる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;examples\react-router-v7
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;vite-plugin-pwaをインストールし、自分自身を見るように修正する&lt;/h2&gt;
&lt;p&gt;ここでいう自分自身は&lt;code&gt;clone&lt;/code&gt;した&lt;code&gt;vite-plugin-pwa&lt;/code&gt;のこと。&lt;/p&gt;
&lt;p&gt;まずは作成したプロジェクトに&lt;code&gt;vite-plugin-pwa&lt;/code&gt;をインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm add vite-plugin-pwa -D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;インストールすると最新の&lt;code&gt;vite-plugin-pwa&lt;/code&gt;がインストールされるので、自分自身を見るようにする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &quot;devDependencies&quot;: {
    &quot;vite-plugin-pwa&quot;: &quot;^1.1.0&quot;,
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;↓ 修正&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &quot;devDependencies&quot;: {
    &quot;vite-plugin-pwa&quot;: &quot;workspace:*&quot;,
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;vite-plugin-pwa&lt;/code&gt;のルートディレクトリに戻り&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で依存関係を修正する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vite-plugin-pwa&quot;: &quot;workspace:*&quot;,&lt;/code&gt; と指定することで、&lt;code&gt;examples/react-router-v7&lt;/code&gt;
プロジェクトは、&lt;code&gt;npm&lt;/code&gt;で公開されているバージョンの
&lt;code&gt;vite-plugin-pwa&lt;/code&gt;をインストールする代わりに、ローカルのルートディレクトリにある&lt;code&gt;vite-plugin-pwa&lt;/code&gt;のソースコードを直接参照するようになる。&lt;/p&gt;
&lt;h2&gt;ルートディレクトリにある&lt;code&gt;vite-plugin-pwa&lt;/code&gt;のソースコードが参照されているか確認する&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;import { VitePWA } from &quot;../../src&quot;;

export default defineConfig({
  plugins: [
    tailwindcss(),
    reactRouter(),
    tsconfigPaths(),
    VitePWA({
      registerType: &quot;autoUpdate&quot;,
    }),
  ],
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずは&lt;code&gt;vite-plugin-pwa&lt;/code&gt;を呼び出し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm --filter react-router-v7 dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;で&lt;code&gt;react-router-v7&lt;/code&gt;のアプリを起動する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src\index.ts&lt;/code&gt;下記のように修正し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export function VitePWA(userOptions: Partial&amp;lt;VitePWAOptions&amp;gt; = {}): Plugin[] {
  // eslint-disable-next-line no-console
  console.log(&apos;LOCAL vite-plugin-pwa 読み込まれていますか?!&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;まずはプラグインのビルドを実行し、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Exampleアプリを起動する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; pnpm --filter react-router-v7 dev

&amp;gt; react-router-v7@ dev C:\Users\username\dev\vite-plugin-pwa\examples\react-router-v7
&amp;gt; react-router dev

LOCAL vite-plugin-pwa 読み込まれていますか?!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;追記したログが出ていることが確認できたので目的は達成できた。&lt;/p&gt;
&lt;h2&gt;サーバーが起動しない&lt;/h2&gt;
&lt;p&gt;コンソールが出ているところまでは確認できたけど、開発サーバーが立ち上がらない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;React Router v7&lt;/code&gt;で使えないことは聞いているけど、&lt;code&gt;VitePWA()&lt;/code&gt;を追加しただけでは落ちないはず。&lt;/p&gt;
&lt;p&gt;つまり別の問題が起きているっぽい。&lt;/p&gt;
&lt;p&gt;&lt;s&gt;エラーを&lt;code&gt;gemini&lt;/code&gt;に読んでもらうと&lt;code&gt;react-router-dom&lt;/code&gt;と&lt;code&gt;react-router&lt;/code&gt;のバージョンの不整合が原因だったらしい。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;s&gt;&lt;code&gt;&quot;react-router&quot;: &quot;^7.9.2&quot;&lt;/code&gt;では&lt;code&gt; &quot;react-router-dom&quot;: &quot;^7.9.2&quot;&lt;/code&gt;を使用する必要があるけれど、指定がなかったので&lt;code&gt;pnpm&lt;/code&gt;がワークスペース内の別の場所で使われている古いバージョンが参照されていた。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;s&gt;なので、明示的に&lt;code&gt;&quot;react-router-dom&quot;: &quot;^7.9.2&quot;&lt;/code&gt;を追加し解決できた。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;s&gt;&lt;code&gt;svelte-kit&lt;/code&gt;のエラーが出ているけど、今回は問題ないので、ひとまずこれでスタートラインに立てた。&lt;/s&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;code&gt;vite.config.ts&lt;/code&gt;の&lt;code&gt;tsconfigPaths()&lt;/code&gt;の引数がなかったことが原因だった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt; tsconfigPaths({ projects: [&apos;./tsconfig.json&apos;] }&lt;/code&gt;で解決した。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;あとはいろいろ触ってどこまで使えて、どこで使えなくなるかを試していきたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年11月】たぶん今が一番かわいい</title><link>https://blog.nove-b.dev/posts/2025-11</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-11</guid><content:encoded>&lt;h2&gt;11月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3Kqfwph&quot;&gt;シャーロック・ホームズの凱旋&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3MjdIiw&quot;&gt;世界一流エンジニアの思考法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4oADCLM&quot;&gt;ミシンと金魚&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4pJ2MJk&quot;&gt;三千円の使いかた&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4pVQ0Hz&quot;&gt;君のクイズ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3XVUjXv&quot;&gt;勿忘草の咲く町で&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3Kz1VvG&quot;&gt;メイド・イン京都&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/890478300978952414/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/893051880929763783/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/893649113249667675/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/894613951102247430/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/895165791161477120/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/896413537736084040/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/897267435478739660/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;今月は７冊と結構読めた。&lt;/p&gt;
&lt;p&gt;寒くなって湯船に浸かるようになり、読書時間が増えたことが読書量につながった。&lt;/p&gt;
&lt;p&gt;これだけ読んで無料って図書館が優秀すぎる。&lt;/p&gt;
&lt;p&gt;予約と返却期間を考えるのは面倒くさいけれど、(700 * 7)円、得しているのはでかい。&lt;/p&gt;
&lt;p&gt;あとキンドルアンリミッド縛りを辞めたのも読書量が増えた要因かもしれない。&lt;/p&gt;
&lt;h2&gt;不要なものをハードオフに売った&lt;/h2&gt;
&lt;p&gt;青春の思い出ギター、もうずいぶん触ってないし、誇り被っていたので思い切って売ることにした。&lt;/p&gt;
&lt;p&gt;ついでに他の不用品もいくつか売りに出した。&lt;/p&gt;
&lt;p&gt;結果、8万円になった。&lt;/p&gt;
&lt;p&gt;できる限り物を持たないようにしたいので、内田百閒の全集も売ろうとしたけどそれは止められた。&lt;/p&gt;
&lt;p&gt;別に読んだしいらないんだけど、もう少し置いておけば値上がりするかもしれないので、もう少し大切にしまっておく。&lt;/p&gt;
&lt;p&gt;とりあえず、グッドバイ、青春。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;青春の管理下にあるぼくだった 明日を平気で殺しまくった&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;木下龍也の短歌を残しておく。&lt;/p&gt;
&lt;p&gt;あと青春といえば、最近のradの新曲が刺さった。&lt;/p&gt;
&lt;p&gt;久しぶりにradに戻ってきた。&lt;/p&gt;
&lt;p&gt;{{&amp;lt;youtube Utzc3Uum9-g&amp;gt;}}&lt;/p&gt;
&lt;h2&gt;秩父に旅行にいく&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ムーミンバレーパーク
&lt;ul&gt;
&lt;li&gt;唐揚げすごい勢いで食べてた&lt;/li&gt;
&lt;li&gt;にょろにょろアイスすごい勢いで食べてた&lt;/li&gt;
&lt;li&gt;15時に出る予定が18時までいてしまった&lt;/li&gt;
&lt;li&gt;謎の怪物がいた&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;秩父
&lt;ul&gt;
&lt;li&gt;ホテルのサイトに書いてある住所が間違いで迷子になる&lt;/li&gt;
&lt;li&gt;貸し切りの家のような感じで奇麗でよかった&lt;/li&gt;
&lt;li&gt;夜ごはん「ちんばた」に行くと大行列で1時間近く待った&lt;/li&gt;
&lt;li&gt;寝かしつけとともに寝落ちした&lt;/li&gt;
&lt;li&gt;朝起きて露天風呂だけ満喫した&lt;/li&gt;
&lt;li&gt;秩父神社に行く&lt;/li&gt;
&lt;li&gt;長瀞に行く&lt;/li&gt;
&lt;li&gt;SLパレオエクスプレスに乗る&lt;/li&gt;
&lt;li&gt;子どもがいなければ経験しなかった経験ができて世界が広がった&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;やっぱり旅行は楽しいので、また行きたい。&lt;/p&gt;
&lt;p&gt;ただ子連れの旅行は準備も大変だし、当日も大変で、歩かないので、次の日腕が筋肉痛になったり、時間のミスが許されなかったりと結構気を遣う。&lt;/p&gt;
&lt;p&gt;まあそれでも次はどこ行こうって考えている。&lt;/p&gt;
&lt;p&gt;とりあえずディズニー行かないと。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/898204918042611179/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;h2&gt;その他&lt;/h2&gt;
&lt;p&gt;クリスマスツリーをだした。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe title=&quot;Pixelfed Post Embed&quot; src=&quot;https://pixelfed.social/p/nove_b/890187021068685802/embed?caption=true&amp;amp;likes=true&amp;amp;layout=full&quot; class=&quot;pixelfed__embed&quot; style=&quot;max-width: 100%; border: 0&quot; width=&quot;400&quot; allowfullscreen=&quot;allowfullscreen&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;script async defer src=&quot;https://pixelfed.social/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;京王レールランドにも行った。&lt;/p&gt;
&lt;p&gt;多摩動物公園とかハグハグとか併設しているので、退屈しない。&lt;/p&gt;
&lt;p&gt;京王レールランドだけで言うとコスパもいい。&lt;/p&gt;
&lt;p&gt;双子の男の子趣味が明確なのでそっちに寄せた場所に行っちゃうけど、他の男女双子はどうしているのだろうか。&lt;/p&gt;
&lt;p&gt;最近の考えることの１つ。&lt;/p&gt;
&lt;h2&gt;多分今が１番かわいい&lt;/h2&gt;
&lt;p&gt;最近は遊べるようになって本当にかわいい。&lt;/p&gt;
&lt;p&gt;寝る前に帰りたいと思うし、そもそも仕事なんてしてる場合じゃないと思う。&lt;/p&gt;
&lt;p&gt;朝も保育園に送らずにそのまま一緒にいたいと思う。&lt;/p&gt;
&lt;p&gt;ただ一緒にいると仕事なんて比じゃないレベルで疲れるんだけど...。&lt;/p&gt;
&lt;p&gt;最近はパズルとかくれんぼを家でしている。&lt;/p&gt;
&lt;p&gt;鬼役してると抱っこしてと言って鬼の服の中に隠れようとするの、最高に馬鹿でかわいい。&lt;/p&gt;
&lt;p&gt;パズルに関しては、3歳で80ピースを１人でやってるので、たぶん天才だと思う。&lt;/p&gt;
&lt;p&gt;片方は32ピース苦戦しているけど。&lt;/p&gt;
&lt;h2&gt;マストドンをアップデートした&lt;/h2&gt;
&lt;p&gt;もともとサービスが提供しているイメージを使用していたので、結構手こずった。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;バックアップ&lt;/li&gt;
&lt;li&gt;削除&lt;/li&gt;
&lt;li&gt;Gitから最新のマストドンをクローン&lt;/li&gt;
&lt;li&gt;バックアップから必要になるデータを移管&lt;/li&gt;
&lt;li&gt;必要なサービスを諸々アップデート&lt;/li&gt;
&lt;li&gt;無事に4.14から5.0にできた&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;mastodon-embed&quot; data-embed-url=&quot;https://social.nove-b.dev/@nove_b/115503697290682618/embed&quot; style=&quot;background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;&quot;&amp;gt; &amp;lt;a href=&quot;https://social.nove-b.dev/@nove_b/115503697290682618&quot; target=&quot;_blank&quot; style=&quot;align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, &apos;Segoe UI&apos;, Oxygen, Ubuntu, Cantarell, &apos;Fira Sans&apos;, &apos;Droid Sans&apos;, &apos;Helvetica Neue&apos;, Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;&quot;&amp;gt; &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;32&quot; height=&quot;32&quot; viewBox=&quot;0 0 79 75&quot;&amp;gt;&amp;lt;path d=&quot;M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z&quot; fill=&quot;currentColor&quot;/&amp;gt;&amp;lt;/svg&amp;gt; &amp;lt;div style=&quot;color: #787588; margin-top: 16px;&quot;&amp;gt;Post by @nove_b@social.nove-b.dev&amp;lt;/div&amp;gt; &amp;lt;div style=&quot;font-weight: 500;&quot;&amp;gt;View on Mastodon&amp;lt;/div&amp;gt; &amp;lt;/a&amp;gt; &amp;lt;/blockquote&amp;gt; &amp;lt;script data-allowed-prefixes=&quot;https://social.nove-b.dev/&quot; async src=&quot;https://social.nove-b.dev/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;他サーバーのアカウント画像とかが取れないバグがまだ残っているので、どこかで時間を取って直したい。&lt;/p&gt;
&lt;p&gt;たぶん、&lt;code&gt;/etc/nginx/sites-available/mastodon&lt;/code&gt;をがっつり書き得たことが悪さしている。&lt;/p&gt;
&lt;p&gt;引用機能を使えるようになったとのことでアップデートしたけど、メインで使っている&lt;code&gt;Elk&lt;/code&gt;がまだ対応してないのでそもそも使えなった。&lt;/p&gt;
&lt;p&gt;貢献してもいいんだけど、ここら辺はコアメンバーがやるのか？よく運用方法がわからない。&lt;/p&gt;
&lt;h2&gt;FitBitの睡眠レポートを作成した&lt;/h2&gt;
&lt;p&gt;毎日、睡眠のログ取っているんだけど、いまいち活用方法ないのでAIにレポート化してもらい毎朝投げてもらうことにした。&lt;/p&gt;
&lt;p&gt;数字で見るよりわかりやすくなったけどアドバイスが、カフェインを控えましょうの一辺倒で何の意味もない。&lt;/p&gt;
&lt;p&gt;プロントが悪いんだろうけど、調整するモチベーションまではない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nove-b/fitbit-sleep-report&quot;&gt;fitbit-sleep-report&lt;/a&gt;、プルリクお待ちしております。&lt;/p&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;mastodon-embed&quot; data-embed-url=&quot;https://social.nove-b.dev/@nove_b/115545653662035156/embed&quot; style=&quot;background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;&quot;&amp;gt; &amp;lt;a href=&quot;https://social.nove-b.dev/@nove_b/115545653662035156&quot; target=&quot;_blank&quot; style=&quot;align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, &apos;Segoe UI&apos;, Oxygen, Ubuntu, Cantarell, &apos;Fira Sans&apos;, &apos;Droid Sans&apos;, &apos;Helvetica Neue&apos;, Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;&quot;&amp;gt; &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;32&quot; height=&quot;32&quot; viewBox=&quot;0 0 79 75&quot;&amp;gt;&amp;lt;path d=&quot;M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z&quot; fill=&quot;currentColor&quot;/&amp;gt;&amp;lt;/svg&amp;gt; &amp;lt;div style=&quot;color: #787588; margin-top: 16px;&quot;&amp;gt;Post by @nove_b@social.nove-b.dev&amp;lt;/div&amp;gt; &amp;lt;div style=&quot;font-weight: 500;&quot;&amp;gt;View on Mastodon&amp;lt;/div&amp;gt; &amp;lt;/a&amp;gt; &amp;lt;/blockquote&amp;gt; &amp;lt;script data-allowed-prefixes=&quot;https://social.nove-b.dev/&quot; async src=&quot;https://social.nove-b.dev/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;h2&gt;vite-pwa-plugin 読んでる&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;React Router v7&lt;/code&gt;を最近よく使うんだけど、&lt;code&gt;vite-pwa-plugin&lt;/code&gt;と競合するっぽく、なんでそんなことになるのかコード読んでみているけど、なにもわからない。&lt;/p&gt;
&lt;p&gt;ただ書き方のお作法とか学ぶことは多い。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/make-react-router-v7-app-pwa/&quot;&gt;React Router v7で作成したウェブアプリをPWA(インストールに対応のみ)にする&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/dev-react-router-v7-vite-pwa-plugin/&quot;&gt;ローカルのvite-plugin-pwaを、手元のReact Router v7プロジェクトで直接利用する方法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;リリースに名前が載るのがうれしい&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/elk-zone/elk/releases/tag/v0.17.0&quot;&gt;Releases v0.17.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Elkのリリースに名前が載った。&lt;/p&gt;
&lt;p&gt;だからどうといったことはないんだけど、なんとなくうれしい。&lt;/p&gt;
&lt;p&gt;何かあれば引き続き貢献していきたい。&lt;/p&gt;
&lt;h2&gt;フリーランスって魅力的なのかしら&lt;/h2&gt;
&lt;p&gt;最近、仕事中に周りを見てるといろいろ考える。&lt;/p&gt;
&lt;p&gt;そもそも最近転職の話があった時に結構考えたんだけど、前提として仕事をしたくないという思いが心の奥底にある。&lt;/p&gt;
&lt;p&gt;役職がついて周りが帰属意識高い人で囲まれるようになったので、より意識の違いを感じる。&lt;/p&gt;
&lt;p&gt;そういえば自己評価する機会があったけど、どの項目にもチェックできなかった。&lt;/p&gt;
&lt;p&gt;絶対評価らしいけど、周りに自分より会社に真摯に向き合っている人見ると、なんとなく気後れする。&lt;/p&gt;
&lt;p&gt;この根底にあるものはどう払しょくすればいいのか。&lt;/p&gt;
&lt;p&gt;案件にのめりこむのは好きだし、ずっと面白い案件に関わりたい。&lt;/p&gt;
&lt;p&gt;ただ会社関係のことに関わりたくない。&lt;/p&gt;
&lt;p&gt;その点、フリーランスって意外と魅力的なのか？ 意外と親和性あるのか？&lt;/p&gt;
&lt;p&gt;ただ税金関係とかは当然したくない。&lt;/p&gt;
&lt;p&gt;まったく生きにくい世の中だ。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;生前は無名であった鶏がからあげクンとして蘇る&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;こんな短歌作れるくらいの才能が欲しかった。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>vite pwa pluginでreact router v7がpwaにできない理由を調べてみた</title><link>https://blog.nove-b.dev/posts/vite-pwa-plugin-bug-report</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/vite-pwa-plugin-bug-report</guid><content:encoded>&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/make-react-router-v7-app-pwa/&quot;&gt;React Router v7で作成したウェブアプリをPWA(インストールに対応のみ)にする&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.nove-b.dev/posts/dev-react-router-v7-vite-pwa-plugin/&quot;&gt;ローカルのvite-plugin-pwaを、手元のReact Router v7プロジェクトで直接利用する方法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;過去に&lt;code&gt;react router v7&lt;/code&gt;が&lt;code&gt;vite-pwa-plugin&lt;/code&gt;で&lt;code&gt;pwa&lt;/code&gt;化できないと言うことを言ってきた。&lt;/p&gt;
&lt;p&gt;実際のIssueは&lt;a href=&quot;https://github.com/vite-pwa/vite-plugin-pwa/issues/809&quot;&gt;Feature Request: Vite PWA Support for React Router 7 #809&lt;/a&gt;←こちら。&lt;/p&gt;
&lt;h2&gt;問題の現象&lt;/h2&gt;
&lt;p&gt;まず起きている事象としては、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;manifest&lt;/code&gt;の作成はできているけど、&lt;/li&gt;
&lt;li&gt;&lt;code&gt;index.html&lt;/code&gt;にスクリプトの挿入がされない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;pwa&lt;/code&gt;の機能が使えないとかそう言う次元ではなく、そもそも&lt;code&gt;vite-pwa-plugin&lt;/code&gt;をそのまま使おうとすると&lt;code&gt;pwa&lt;/code&gt;にすらならない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;manifest&lt;/code&gt;は生成されているので&lt;code&gt;root.tsx&lt;/code&gt;に&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; { rel: &quot;manifest&quot;, href: &quot;/manifest.webmanifest&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を追加すれば&lt;code&gt;pwa&lt;/code&gt;化はできるが、&lt;code&gt;vite-pwa-plugin&lt;/code&gt;の使い方ではない。&lt;/p&gt;
&lt;p&gt;実際にコードを動かしてデバックする方法は&lt;a href=&quot;https://blog.nove-b.dev/posts/dev-react-router-v7-vite-pwa-plugin/&quot;&gt;こちら&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;原因の調査&lt;/h2&gt;
&lt;p&gt;まずはなんで&lt;code&gt;index.html&lt;/code&gt;で&lt;code&gt;manifest&lt;/code&gt;が読み込まれないかを実際にコードを読んで理解を試みた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export function VitePWA(userOptions: Partial&amp;lt;VitePWAOptions&amp;gt; = {}): Plugin[] {
  const ctx = createContext(userOptions);
  const api = createAPI(ctx);
  return [
    MainPlugin(ctx, api),
    InfoPlugin(ctx, api),
    BuildPlugin(ctx),
    DevPlugin(ctx),
    AssetsPlugin(ctx),
  ];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これが&lt;code&gt;vite-pw-plugin&lt;/code&gt;を構成する関数群。&lt;/p&gt;
&lt;p&gt;で、コードを読んでいくと開発環境の場合は、&lt;code&gt;DevPlugin(ctx),&lt;/code&gt;で&lt;code&gt;script&lt;/code&gt;を挿入記述らしきものを見つけた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;transformIndexHtml&lt;/code&gt;内で&lt;code&gt;transformIndexHtmlHandler&lt;/code&gt;が呼び出される&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transformIndexHtmlHandler&lt;/code&gt;内の&lt;code&gt;html = injectServiceWorker(html, options, true)&lt;/code&gt;が実行される。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;head&lt;/code&gt;に&lt;code&gt;manifest&lt;/code&gt;が登録される仕組み&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;つまりこれが発火していない。&lt;/p&gt;
&lt;h2&gt;関連するIssue&lt;/h2&gt;
&lt;p&gt;で、いろいろ調べてみると&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/remix-run/react-router/issues/12736&quot;&gt;Vite plugin transformIndexHtml does not work #12736 &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;こんな&lt;code&gt;issue&lt;/code&gt;を見つけた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The transformIndexHtml is never called. This means a whole set of vite plugins
will not work without any error message.&lt;/p&gt;
&lt;p&gt;I understand there&apos;s a good reason why this vite plugin method cannot work
with RR, but it should at least throw an error or warning to let the user know
the plugin they installed will not work at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これに対し、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is related to #12352, since our plugin is overriding that subsequent
plugin and doesn&apos;t allow for options to be able to inject your own plugin
functionality into it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;のように返信されている。&lt;/p&gt;
&lt;p&gt;翻訳すると、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;私たちのプラグインが、後続のプラグインを上書きしているため、オプションを利用して独自のプラグイン機能を注入することを許可していません。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のようになる。&lt;/p&gt;
&lt;h2&gt;結論&lt;/h2&gt;
&lt;p&gt;つまりどうしようもない気がする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vite-pwa-plugin&lt;/code&gt;の修正を待つのではなく、&lt;code&gt;react-router&lt;/code&gt;側の話なのかもしれない。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>Angularのライブラリを作成し、GitHub Packagesで共通化、複数のAngularプロジェクトで使用する</title><link>https://blog.nove-b.dev/posts/angular-library-github-package</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/angular-library-github-package</guid><content:encoded>&lt;h2&gt;はじめに&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Angular&lt;/code&gt;で複数のプロジェクトを作成している。基本的なデザインシステムがあるのでそれを各プロジェクトで使用したいのだが、プロジェクトごとで二元管理をしたくないので、&lt;code&gt;submodule&lt;/code&gt;を使用していたんだけど、運用が面倒なので&lt;code&gt;GitHub Packages&lt;/code&gt;に移行することにした。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Angular&lt;/code&gt;でライブラリを作成し&lt;code&gt;GitHub Package&lt;/code&gt;で公開するメモを書いておく。&lt;/p&gt;
&lt;h2&gt;Angularライブラリとは&lt;/h2&gt;
&lt;p&gt;まずそもそそも&lt;code&gt;Angular&lt;/code&gt;の&lt;code&gt;Library&lt;/code&gt;とは、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Angularライブラリは、コンポーネント、サービス、ディレクティブなどの再利用可能なコードをまとめたパッケージです。これらは単独で実行することはできず、Angularアプリケーションにインポートして使用されます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;h2&gt;GitHub Packagesとは&lt;/h2&gt;
&lt;p&gt;そして&lt;code&gt;GitHub Packages&lt;/code&gt;とは&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GitHub
Packagesは、コンテナやその他の依存関係を含むソフトウェアパッケージをホストおよび管理するためのプラットフォームです。ソースコード管理とパッケージ管理を同じGitHub上で一元化できる点が大きな特徴です。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;h3&gt;GitHub Packagesの利用シーン&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;GitHub Packages&lt;/code&gt;の利用シーンとしては、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;組織内でのみ共有したい非公開のライブラリやコンポーネントを、npmやDocker
Hubのような外部サービスではなく、GitHub内で安全にホストしたい場合。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ちなみに&lt;code&gt;npm&lt;/code&gt;パッケージも非公開で公開できるらしい。&lt;/p&gt;
&lt;p&gt;ただ有料らしいので、制限付きとはいえ無料で非公開設定ができるという点では、&lt;code&gt;GitHub Packages&lt;/code&gt;の方が有用そうだった。&lt;/p&gt;
&lt;h3&gt;GitHub Packagesの制限&lt;/h3&gt;
&lt;p&gt;制限は&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ストレージ容量:500 MB&lt;/li&gt;
&lt;li&gt;データ転送量:1 GB/月 (月間)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とのこと。&lt;/p&gt;
&lt;p&gt;利用枠的にUIコンポーネントを共有する分にはなんの問題もない気がする。&lt;/p&gt;
&lt;h2&gt;Angularライブラリの作成&lt;/h2&gt;
&lt;p&gt;まずは&lt;code&gt;Angular&lt;/code&gt;のUIライブラリーを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user@nameMacBook-Air filename % ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | &apos;_ \ / _` | | | | |/ _` | &apos;__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 19.2.19
Node: 22.7.0
Package Manager: npm 10.8.2
OS: darwin arm64

Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1902.19 (cli-only)
@angular-devkit/core         19.2.19 (cli-only)
@angular-devkit/schematics   19.2.19 (cli-only)
@schematics/angular          19.2.19 (cli-only)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;バージョンとか前提はこんな感じだった。&lt;/p&gt;
&lt;h3&gt;プロジェクトの作成&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ng new angular-ui-component --no-create-application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このコマンドでアプリケーション自体を作成せずに&lt;code&gt;Angular&lt;/code&gt;の箱を作成する。&lt;/p&gt;
&lt;h3&gt;ライブラリの生成&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ng generate library ui-library --prefix=ui
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次にライブラリを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--prefix=ui
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を書くことで&lt;code&gt;ui-button&lt;/code&gt;のように接頭辞をつけることができる。&lt;/p&gt;
&lt;p&gt;このコマンドを実行することで、&lt;code&gt;projects/ui-library&lt;/code&gt;フォルダができる。&lt;/p&gt;
&lt;p&gt;この&lt;code&gt;src/lib&lt;/code&gt;以下にコンポーネントを作成していく。&lt;/p&gt;
&lt;h3&gt;コンポーネントの作成&lt;/h3&gt;
&lt;p&gt;例えば&lt;code&gt;Button&lt;/code&gt;コンポーネントを作成するのであれば、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ng g component button
CREATE projects/ui-library/src/button/button.component.css (0 bytes)
CREATE projects/ui-library/src/button/button.component.html (21 bytes)
CREATE projects/ui-library/src/button/button.component.spec.ts (592 bytes)
CREATE projects/ui-library/src/button/button.component.ts (213 bytes)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;でコンポーネントを作成する。&lt;/p&gt;
&lt;h3&gt;public-api.tsへの登録&lt;/h3&gt;
&lt;p&gt;作成できたら外部に公開する要素の定義をするために、&lt;code&gt;public-api.ts&lt;/code&gt;に登録する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export * from &quot;./lib/button/button.component&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;GitHub Packagesへの公開準備&lt;/h2&gt;
&lt;p&gt;これでライブラリの準備はできたので次に&lt;code&gt;GitHub Packages&lt;/code&gt;を使用する準備をする。&lt;/p&gt;
&lt;h3&gt;package.jsonの修正&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;projects/ui-library/package.json&lt;/code&gt;を修正する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;@nove-b/angular-ui-component&quot;,
  &quot;version&quot;: &quot;0.0.1&quot;,
  &quot;publishConfig&quot;: {
    &quot;registry&quot;: &quot;https://npm.pkg.github.com/&quot;
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;パッケージ名に&lt;code&gt;Github&lt;/code&gt;のアカウント名を入れるようにする。&lt;/p&gt;
&lt;h3&gt;Personal Access Tokenの発行&lt;/h3&gt;
&lt;p&gt;次に&lt;code&gt;Personal Access Token (Classic)&lt;/code&gt;を発行する。&lt;/p&gt;
&lt;p&gt;この時に、スコープ選択で &lt;code&gt;write:packages&lt;/code&gt; (パッケージのアップロード用) と
&lt;code&gt;read:packages&lt;/code&gt; (ダウンロード用) にチェックを入れて生成する。&lt;/p&gt;
&lt;h3&gt;.npmrcの設定&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Token&lt;/code&gt;の発行ができたら公開をするために、&lt;code&gt;.npmrc&lt;/code&gt;をルートに作成する。&lt;/p&gt;
&lt;p&gt;秘匿情報を入れるのに&lt;code&gt;.ignore&lt;/code&gt;する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm login --scope=@nove-b/angular-ui-component --registry=https://npm.pkg.github.com
# Username: nove-b
# Password: ghp_xxxxxxxxxx(Personal Access Token (Classic))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;ライブラリのビルドと公開&lt;/h2&gt;
&lt;p&gt;これで公開の準備が整ったので、ライブラリをビルドする。&lt;/p&gt;
&lt;h3&gt;ライブラリのビルド&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;angular-ui-component % ng build ui-library
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで&lt;code&gt;build&lt;/code&gt;ファイルができるので、公開する。&lt;/p&gt;
&lt;h3&gt;ライブラリの公開&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;cd dist/ui-library
npm publish
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;なぜかうまくいかなかったのでコマンドから試みる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user@NamenoMacBook-Air ui-library % npm login --scope=@nove-b --registry=https://npm.pkg.github.com
npm notice Log in on https://npm.pkg.github.com/
Username: nove-b
Password: Personal Access Token (Classic)

Logged in to scope @nove-b on https://npm.pkg.github.com/.
user@NamenoMacBook-Air ui-library %
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでログインできたので公開する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm publish

...

npm notice Publishing to https://npm.pkg.github.com/ with tag latest and default access
+ @nove-b/angular-ui-component@0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;無事に公開できた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/users/nove-b/packages/npm/package/angular-ui-component&quot;&gt;angular-ui-component&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;ライブラリの使用&lt;/h2&gt;
&lt;p&gt;次にこれを使用してみる。&lt;/p&gt;
&lt;p&gt;まずはまた&lt;code&gt;Angular&lt;/code&gt;のアプリケーションを作成するけど、そこら辺は割愛する。&lt;/p&gt;
&lt;p&gt;で、立ち上げた。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/ngnew.png&quot; alt=&quot;ng new&quot; /&gt;&lt;/p&gt;
&lt;p&gt;これにさっきのライブラリを呼び出すようにする。&lt;/p&gt;
&lt;h3&gt;使用するアプリケーションでの.npmrcの設定&lt;/h3&gt;
&lt;p&gt;まずはルートに&lt;code&gt;.npmrc &lt;/code&gt;を作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@nove-b:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=ghp_xxxxxxxxxx(Personal Access Token (Classic))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ライブラリのインストール&lt;/h3&gt;
&lt;p&gt;次にインストールする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install @nove-b/angular-ui-component@0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;コンポーネントのインポートと使用&lt;/h3&gt;
&lt;p&gt;インストールが完了したら使用するコンポーネントファイルにインポートする。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { ButtonComponent } from &apos;@nove-b/angular-ui-component&apos;;

@Component({
  selector: &apos;app-root&apos;,
  imports: [RouterOutlet, ButtonComponent],
  templateUrl: &apos;./app.component.html&apos;,
  styleUrl: &apos;./app.component.scss&apos;
})
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div style=&quot;margin-top: 20px; margin-bottom: 20px;&quot;&amp;gt;
  &amp;lt;ui-button [label]=&quot;&apos;UI コンポーネントボタン&apos;&quot;&amp;gt;&amp;lt;/ui-button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これ画面で確認できた。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/ngnew-ui.png&quot; alt=&quot;ng new&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;まとめ・考察&lt;/h2&gt;
&lt;p&gt;組織の場合はTokenとかどういう運用になるんだろう。今は個人でやっているので、個人のTokenを使っているけれど、みたいな疑問もあるけれど、社内システムのUIコンポーネントとかを作成しておき、&lt;code&gt;css&lt;/code&gt;を上書きできるようにしておけばすごい汎用性高そうだ。&lt;/p&gt;
&lt;p&gt;まあ、社内システムに&lt;code&gt;Angular&lt;/code&gt;を使うかというと微妙なところなので、せめて&lt;code&gt;vue&lt;/code&gt;、&lt;code&gt;react&lt;/code&gt;で&lt;code&gt;Angular&lt;/code&gt;ライブラリのような仕組みがあればいいかもしれない。&lt;/p&gt;
&lt;p&gt;あるいは&lt;code&gt;vanilla js&lt;/code&gt;にするかというところか。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;せめて&lt;code&gt;vue&lt;/code&gt;、&lt;code&gt;react&lt;/code&gt;で&lt;code&gt;Angular&lt;/code&gt;ライブラリのような仕組みがあればいいかもしれない。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;組み込みではないっぽい。組み合わせできるっぽいので今度挑戦してみたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>2025年を振り返ってみる</title><link>https://blog.nove-b.dev/posts/2025-all</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-all</guid><content:encoded>&lt;p&gt;また年が変わった。&amp;lt;br /&amp;gt; 毎年変わらず、恒例の1年振り返りをすることにする。&lt;/p&gt;
&lt;h2&gt;家のこと&lt;/h2&gt;
&lt;h3&gt;保育園のルーティン&lt;/h3&gt;
&lt;p&gt;家庭では、保育園の通園が始まり、時間のサイクルがまた変わった。&amp;lt;br /&amp;gt;
5時半に起き、自分の準備をし、子どもを起こし、準備をさせて保育園に連れていく。&amp;lt;br /&amp;gt;
泣いている姿に後ろ髪引かれつつ保育園を後にし、残っている家事を終えたら会社に向かう。&lt;/p&gt;
&lt;p&gt;っていうルーティンができた。&lt;/p&gt;
&lt;p&gt;結構辛かったけど、流石に慣れてきた。&lt;/p&gt;
&lt;p&gt;たぶん子どもたちも慣れてきたおかげで少しづつ楽になってきた。&lt;/p&gt;
&lt;p&gt;いつかこちらを見ずに保育園に走っていくことを考えると、いま離れる時に泣いてくれるのも貴重なのかもしれない。&lt;/p&gt;
&lt;p&gt;自分に時間が、余裕がなくなると、その貴重な時間を無駄にしちゃうので、&amp;lt;br /&amp;gt;
子どもがいるときは無駄にしないで向き合いたいなあって思っている。&lt;/p&gt;
&lt;h3&gt;お出かけ&lt;/h3&gt;
&lt;p&gt;子どもたちの好きが増えて色々なところに行くことが楽しくなってきた。&lt;/p&gt;
&lt;p&gt;印象に残っているものは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ディズニーランドと星野リゾート
&lt;ul&gt;
&lt;li&gt;&amp;lt;blockquote class=&quot;mastodon-embed&quot; data-embed-url=&quot;https://social.nove-b.dev/@nove_b/113860713877036686/embed&quot; style=&quot;background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;&quot;&amp;gt; &amp;lt;a href=&quot;https://social.nove-b.dev/@nove_b/113860713877036686&quot; target=&quot;_blank&quot; style=&quot;align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, &apos;Segoe UI&apos;, Oxygen, Ubuntu, Cantarell, &apos;Fira Sans&apos;, &apos;Droid Sans&apos;, &apos;Helvetica Neue&apos;, Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;&quot;&amp;gt; &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;32&quot; height=&quot;32&quot; viewBox=&quot;0 0 79 75&quot;&amp;gt;&amp;lt;path d=&quot;M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z&quot; fill=&quot;currentColor&quot;/&amp;gt;&amp;lt;/svg&amp;gt; &amp;lt;div style=&quot;color: #787588; margin-top: 16px;&quot;&amp;gt;Post by @nove_b@social.nove-b.dev&amp;lt;/div&amp;gt; &amp;lt;div style=&quot;font-weight: 500;&quot;&amp;gt;View on Mastodon&amp;lt;/div&amp;gt; &amp;lt;/a&amp;gt; &amp;lt;/blockquote&amp;gt; &amp;lt;script data-allowed-prefixes=&quot;https://social.nove-b.dev/&quot; async src=&quot;https://social.nove-b.dev/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;プラレール博&lt;/li&gt;
&lt;li&gt;ディズニーランドに日帰り&lt;/li&gt;
&lt;li&gt;大宮鉄道博物館
&lt;ul&gt;
&lt;li&gt;&amp;lt;blockquote class=&quot;mastodon-embed&quot; data-embed-url=&quot;https://social.nove-b.dev/@nove_b/114922563075319673/embed&quot; style=&quot;background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;&quot;&amp;gt; &amp;lt;a href=&quot;https://social.nove-b.dev/@nove_b/114922563075319673&quot; target=&quot;_blank&quot; style=&quot;align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, &apos;Segoe UI&apos;, Oxygen, Ubuntu, Cantarell, &apos;Fira Sans&apos;, &apos;Droid Sans&apos;, &apos;Helvetica Neue&apos;, Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;&quot;&amp;gt; &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;32&quot; height=&quot;32&quot; viewBox=&quot;0 0 79 75&quot;&amp;gt;&amp;lt;path d=&quot;M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z&quot; fill=&quot;currentColor&quot;/&amp;gt;&amp;lt;/svg&amp;gt; &amp;lt;div style=&quot;color: #787588; margin-top: 16px;&quot;&amp;gt;Post by @nove_b@social.nove-b.dev&amp;lt;/div&amp;gt; &amp;lt;div style=&quot;font-weight: 500;&quot;&amp;gt;View on Mastodon&amp;lt;/div&amp;gt; &amp;lt;/a&amp;gt; &amp;lt;/blockquote&amp;gt; &amp;lt;script data-allowed-prefixes=&quot;https://social.nove-b.dev/&quot; async src=&quot;https://social.nove-b.dev/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;軽井沢に2泊3日
&lt;ul&gt;
&lt;li&gt;&amp;lt;blockquote class=&quot;mastodon-embed&quot; data-embed-url=&quot;https://social.nove-b.dev/@nove_b/114953815061236363/embed&quot; style=&quot;background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;&quot;&amp;gt; &amp;lt;a href=&quot;https://social.nove-b.dev/@nove_b/114953815061236363&quot; target=&quot;_blank&quot; style=&quot;align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, &apos;Segoe UI&apos;, Oxygen, Ubuntu, Cantarell, &apos;Fira Sans&apos;, &apos;Droid Sans&apos;, &apos;Helvetica Neue&apos;, Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;&quot;&amp;gt; &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;32&quot; height=&quot;32&quot; viewBox=&quot;0 0 79 75&quot;&amp;gt;&amp;lt;path d=&quot;M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z&quot; fill=&quot;currentColor&quot;/&amp;gt;&amp;lt;/svg&amp;gt; &amp;lt;div style=&quot;color: #787588; margin-top: 16px;&quot;&amp;gt;Post by @nove_b@social.nove-b.dev&amp;lt;/div&amp;gt; &amp;lt;div style=&quot;font-weight: 500;&quot;&amp;gt;View on Mastodon&amp;lt;/div&amp;gt; &amp;lt;/a&amp;gt; &amp;lt;/blockquote&amp;gt; &amp;lt;script data-allowed-prefixes=&quot;https://social.nove-b.dev/&quot; async src=&quot;https://social.nove-b.dev/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;サンリオピューロランド&lt;/li&gt;
&lt;li&gt;おかあさんといっしょ スペシャルステージ&lt;/li&gt;
&lt;li&gt;七五三
&lt;ul&gt;
&lt;li&gt;&amp;lt;blockquote class=&quot;mastodon-embed&quot; data-embed-url=&quot;https://social.nove-b.dev/@nove_b/115037347955081967/embed&quot; style=&quot;background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;&quot;&amp;gt; &amp;lt;a href=&quot;https://social.nove-b.dev/@nove_b/115037347955081967&quot; target=&quot;_blank&quot; style=&quot;align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, &apos;Segoe UI&apos;, Oxygen, Ubuntu, Cantarell, &apos;Fira Sans&apos;, &apos;Droid Sans&apos;, &apos;Helvetica Neue&apos;, Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;&quot;&amp;gt; &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;32&quot; height=&quot;32&quot; viewBox=&quot;0 0 79 75&quot;&amp;gt;&amp;lt;path d=&quot;M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z&quot; fill=&quot;currentColor&quot;/&amp;gt;&amp;lt;/svg&amp;gt; &amp;lt;div style=&quot;color: #787588; margin-top: 16px;&quot;&amp;gt;Post by @nove_b@social.nove-b.dev&amp;lt;/div&amp;gt; &amp;lt;div style=&quot;font-weight: 500;&quot;&amp;gt;View on Mastodon&amp;lt;/div&amp;gt; &amp;lt;/a&amp;gt; &amp;lt;/blockquote&amp;gt; &amp;lt;script data-allowed-prefixes=&quot;https://social.nove-b.dev/&quot; async src=&quot;https://social.nove-b.dev/embed.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;アンパンマンミュージック&lt;/li&gt;
&lt;li&gt;秩父に1泊2日
&lt;ul&gt;
&lt;li&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:2atly2y5kfyjcj5zap6pv4wd/app.bsky.feed.post/3m6chgh2tgw2k&quot; data-bluesky-cid=&quot;bafyreifpwgegvy4zzyov24v5qw6jiyhnujitxnnbsv2e4zbmsgx72urnzm&quot; data-bluesky-embed-color-mode=&quot;dark&quot;&amp;gt;&amp;lt;p lang=&quot;&quot;&amp;gt;子どもが生まれて旅行の世界も広がった。&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3m6chgh2tgw2k?ref_src=embed&quot;&amp;gt;[image or embed]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;— nove-b (&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd?ref_src=embed&quot;&amp;gt;@nove-b.dev&amp;lt;/a&amp;gt;) &amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3m6chgh2tgw2k?ref_src=embed&quot;&amp;gt;2025年11月23日 22:51&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;七五三&lt;/h3&gt;
&lt;p&gt;そうだった、七五三をやった。&lt;/p&gt;
&lt;p&gt;男女双子なのでいつやるかという話があったが、とりあえず３歳はやることにした。&lt;/p&gt;
&lt;p&gt;前撮りは散々で被布を脱ぎ捨て脱走しカメラマンを困らせたが、そこは流石のプロのカメラマンで上手に撮ってくれた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;保育園入園で完全に生活の主軸が子どもに移った音がした。大人はどこかで人生を子どもに譲るタイミングが来ると思うんだけど、その１つのタイミングが今なのかもしれない。ただそうは思いつつ、春一番に吹かれても自分の人生にへばりついている自分がいる。&lt;a href=&quot;%5B%E3%80%902025%E5%B9%B44%E6%9C%88%E3%80%91%E6%98%A5%E3%81%AF%E8%BB%BD%E3%82%84%E3%81%8B%E3%81%AB%E3%80%81%E3%81%A7%E3%82%82%E3%81%9A%E3%81%A3%E3%81%97%E3%82%8A%E9%87%8D%E3%81%9F%E3%81%8F%E3%81%AE%E3%81%97%E3%81%8B%E3%81%8B%E3%81%A3%E3%81%A6%E3%81%8D%E3%81%9F%5D(https://blog.nove-b.dev/posts/2025-4/)&quot;&gt;^1&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;子ども中心の生活&lt;/h3&gt;
&lt;p&gt;って今年は悩むこともあったけど、いまはもう子ども中心でいいやって思うようになった。&lt;/p&gt;
&lt;p&gt;無条件に子どもは優遇されるべきだし、中心にいるべきだって、自分を諦めるほどに可愛くて仕方ない。&lt;/p&gt;
&lt;p&gt;今年もこれから一緒に平和で健康で可愛くいてほしいと祈る。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;愛は祈りだ。僕は祈る。僕の好きな人たちに皆そろって幸せになってほしい。それぞれの願いを叶えてほしい。温かい場所で、あるいは涼しい場所で、とにかく心地よい場所で、それぞれの好きな人たちに囲まれて楽しく暮らしてほしい。最大の幸福が空から皆に降り注ぐといい。&lt;a href=&quot;%5B%E5%A5%BD%E3%81%8D%E5%A5%BD%E3%81%8D%E5%A4%A7%E5%A5%BD%E3%81%8D%E8%B6%85%E6%84%9B%E3%81%97%E3%81%A6%E3%82%8B%E3%80%82%5D(https://amzn.to/49wzSqs)%E3%81%AE%E6%9B%B8%E3%81%8D%E5%87%BA%E3%81%97&quot;&gt;^2&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;仕事のこと&lt;/h2&gt;
&lt;p&gt;子どもたちの健やかな成長を願うには、仕事を切り離すことができない。&lt;/p&gt;
&lt;h3&gt;転職活動のきっかけ&lt;/h3&gt;
&lt;p&gt;妻とよく話すのは小学校に入った時、子どもが家に帰ってた時に誰かが家にいてあげたい。&lt;/p&gt;
&lt;p&gt;そのためにはどちらかが仕事を辞める、あるいは量を減らす必要がある。&lt;/p&gt;
&lt;p&gt;で、たとえば１馬力で生きていくとなると結構稼がなくてはいけないのに対し、今はその水準に達していない。&lt;/p&gt;
&lt;p&gt;そのことを考え、今年はぬるっと転職活動をしてみた。&lt;/p&gt;
&lt;h3&gt;転職活動の結果&lt;/h3&gt;
&lt;p&gt;結果、2/4で落ち着いた。&lt;/p&gt;
&lt;p&gt;２社のうち、１社（A社）はこちらの提示した無謀な給料をそのままオファーしてくれ、もう１社（B社）はそこから50万ダウンでオファーをくれた。&lt;/p&gt;
&lt;p&gt;思ったより上手くいって自信がついた一方で働き方を考えるきっかけになった。&lt;/p&gt;
&lt;h3&gt;働き方の考え方&lt;/h3&gt;
&lt;p&gt;どちらもリモート可能だったが、週2日は出社が推奨され、どちらかと言えば出社してほしい匂いを感じた。&lt;/p&gt;
&lt;p&gt;個人的には出社することはやぶさかではないというより、そっちの方がパフォーマンスが上がると思っていたので、気にしていなかったけど、内定を保留し考えている時、たまたま電車で都内に出たがあまりにも辛かった。&lt;/p&gt;
&lt;p&gt;電車も辛いし、歩けば人に当たる人の多さも辛い。&lt;/p&gt;
&lt;p&gt;遊びに行ったけど帰る時にはぐったりして、これは働くどころの話じゃないというふうに思い直した。&lt;/p&gt;
&lt;p&gt;そう考えると、フルリモートがよく、ただわがままだけど、家では集中できないので自分で指定した場所で仕事ができる環境がベストという風に落ち着いた。&lt;/p&gt;
&lt;p&gt;そしてこれは譲れない条件かもしれない。&lt;/p&gt;
&lt;p&gt;今年もゆるりと転職活動は続けるけど、そこをブレないように進めていこうと思った。&lt;/p&gt;
&lt;p&gt;そういうわけでまだまだ現在の職場でお世話になる。&lt;/p&gt;
&lt;h3&gt;現在の職場と今後の展望&lt;/h3&gt;
&lt;p&gt;ただプロフェッショナルになるには、環境も整えないといけない。&lt;/p&gt;
&lt;p&gt;今の職場でプロフェッショナルになれるかというとそれは違う。&lt;/p&gt;
&lt;p&gt;人が少なく、いろんな仕事に触れる環境ではあるけど、レベルの高い仕事にチャレンジできるわけでもなければ、もちろん尊敬できる人はいるけど、かといってものすごく強いエンジニアがいるわけでない。&lt;/p&gt;
&lt;p&gt;なので一流に触れられるかと言えば、全く触れられない。&lt;/p&gt;
&lt;p&gt;今年はそこを改善していこうと思っている。&lt;/p&gt;
&lt;p&gt;具体的には去年始めた&lt;code&gt;oss&lt;/code&gt;活動に引き続き取り組み、自身のブランディングをしっかりと固めていきたい。&lt;/p&gt;
&lt;p&gt;時間ないのは事実だけど、言い訳にせず上手くやっていきたい。&lt;/p&gt;
&lt;p&gt;時間とか、若さとか、体力を使わずに、上手く余裕を持って一流に近づきたい。&lt;/p&gt;
&lt;h2&gt;まとめ&lt;/h2&gt;
&lt;p&gt;2025〜2026に向けまとめると、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;子どもとの時間をしっかり取りたい&lt;/li&gt;
&lt;li&gt;フルリモートの仕事という軸を持ちゆるく転職活動する&lt;/li&gt;
&lt;li&gt;引き続き&lt;code&gt;oss&lt;/code&gt;に力を入れていく&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年12月】12月は一瞬で過ぎ去る</title><link>https://blog.nove-b.dev/posts/2025-12</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2025-12</guid><content:encoded>&lt;h2&gt;12月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4stUnvA&quot;&gt;まるで渡り鳥のように　藤井太洋SF短編集 (創元日本ＳＦ叢書) &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4jivrTx&quot;&gt;松岡まどか、起業します　ＡＩスタートアップ戦記&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4qphQMr&quot;&gt;現代生活独習ノート (講談社文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4qsjzki&quot;&gt;七つの怖い扉 (新潮文庫)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4pdJxXw&quot;&gt;あまからカルテット (文春文庫 ゆ 9-2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3MQU39S&quot;&gt;団地のふたり (双葉文庫 ふ 22-05) &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/48VfZcp&quot;&gt;I love letter　アイラブレター (文春文庫)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;7冊だった。なんか社会人になり、起承転結がはっきりしていない本を読めなくなった気がする。空想の中でくらい、奇想天外な展開を求めているのかもしれない。&lt;/p&gt;
&lt;p&gt;いい距離間の友達が主人公の本が多かった。&lt;/p&gt;
&lt;p&gt;現実でも年末ということで食事に誘われることが多く、なんか色々考えた。友達は大切にした方がいいって考えながら断った。&lt;/p&gt;
&lt;h2&gt;ウィルス性じゃない胃腸炎&lt;/h2&gt;
&lt;p&gt;双子の片方がウィルス性じゃない胃腸炎になった。ウィルス性じゃない胃腸炎ってストレスとか疲れからくるらしく、1年の疲れが出たのかもしれない。保育園に頑張って通って偉かった。&lt;/p&gt;
&lt;p&gt;しかし登園時いつになったら泣かなくなるんだろう。&lt;/p&gt;
&lt;p&gt;泣く癖に帰りは帰りたがらないらしい。&lt;/p&gt;
&lt;h2&gt;ドクターイエロー&lt;/h2&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:2atly2y5kfyjcj5zap6pv4wd/app.bsky.feed.post/3m7elwsmtok2k&quot; data-bluesky-cid=&quot;bafyreiah3ec5ccnnygirn47ela6teygsev5pm6yyhpx6ctaczeh2o2ar3y&quot; data-bluesky-embed-color-mode=&quot;dark&quot;&amp;gt;&amp;lt;p lang=&quot;&quot;&amp;gt;ドクターイエロー見に行ってきた。
石拾ってるほうが楽しそうだった。&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3m7elwsmtok2k?ref_src=embed&quot;&amp;gt;[image or embed]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;— nove-b (&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd?ref_src=embed&quot;&amp;gt;@nove-b.dev&amp;lt;/a&amp;gt;) &amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3m7elwsmtok2k?ref_src=embed&quot;&amp;gt;2025年12月7日 12:42&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;2回目のドクターイエローを見に行った。前回は小田原駅に入ってくるのを見たので、次は走っているのを見せたいと思い、近くで見られる場所を探して見に行った。たぶん、子どもたちはドクターイエローがそろそろ見納めで見れることが珍しいということを知らない。それでも機会は与えたいと思うあたり、自分でもしっかり親をやっていると思う。&lt;/p&gt;
&lt;h2&gt;年末は&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;公園&lt;/li&gt;
&lt;li&gt;鎌倉&lt;/li&gt;
&lt;li&gt;公園&lt;/li&gt;
&lt;li&gt;公園&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;で、終わる。&lt;/p&gt;
&lt;p&gt;公園に行かない時間は、追い込みの大掃除、そして夜は妻と桃鉄に興じる。&lt;/p&gt;
&lt;p&gt;仕事がないと本当に平和な日々を送れる。&lt;/p&gt;
&lt;h2&gt;旅行に行きたい&lt;/h2&gt;
&lt;p&gt;1月にはディズニーに行く予定を立ててる。&lt;/p&gt;
&lt;p&gt;で、その次は大井川鉄道を見に行こうかって話している。&lt;/p&gt;
&lt;p&gt;子どもの興味が変わるたびに旅行先がどんどん出てきて、わりと充実している。&lt;/p&gt;
&lt;h2&gt;Macにした&lt;/h2&gt;
&lt;p&gt;armのサーフェスでandroid
studioが使えないという事実を知り、Macを買うかって思っていたところ、会社のMacに空きがでたので所有権を得ることができた。Macのキーボード打ちにくいけど、わりかし満足している。環境構築が楽になったので、それだけで満足。&lt;/p&gt;
&lt;p&gt;操作性というかOSレベルでWindowsとそれほど変わった気はしない。&lt;/p&gt;
&lt;p&gt;ちなみにサーフェスのほうがかっこいいと思っている。&lt;/p&gt;
&lt;h2&gt;vite-pwa-pluginのコードを読んでいた&lt;/h2&gt;
&lt;p&gt;一部実装でうまくいかない箇所があったので、コードを読んで原因を追究していた。解決はできなさそうだったけど、原因の理解はできた。AIによって0～１が楽になり、個人開発に魅力がなくなってきて、複雑で大規模なコードのバグを修正する方がやりがいを感じるようになってきた。&lt;/p&gt;
&lt;p&gt;12月はこれくらい、いつも早く終わる。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2025年01月】PixelfedへのPRと、Astroで作るレビューサイトと遊園地</title><link>https://blog.nove-b.dev/posts/2026-1</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2026-1</guid><content:encoded>&lt;h2&gt;1月に読んだ本&lt;/h2&gt;
&lt;p&gt;読んだ本は埋め込んでいる&lt;a href=&quot;https://books.nove-b.dev/&quot;&gt;https://books.nove-b.dev/&lt;/a&gt;にまとめている。&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe
src=&quot;https://books.nove-b.dev/date/202601/&quot;
width=&quot;100%&quot;
height=&quot;400&quot;
style=&quot;border: none; margin-top: 20px; margin-bottom: 20px;&quot;
title=&quot;&quot;&amp;gt;
&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;今月は上田岳弘に出会えたことが大きかった。&lt;/p&gt;
&lt;p&gt;こんなに面白い作家を知らなかったとは。&lt;/p&gt;
&lt;h2&gt;今年の目標は破れたり&lt;/h2&gt;
&lt;h2&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:2atly2y5kfyjcj5zap6pv4wd/app.bsky.feed.post/3mbdoajt2rc22&quot; data-bluesky-cid=&quot;bafyreibrhw5jzdmrcxllqaieiakr32qeudsaqfzicsan47rek6gnukaqme&quot; data-bluesky-embed-color-mode=&quot;system&quot;&amp;gt;&amp;lt;p lang=&quot;ja&quot;&amp;gt;✨️2026年の目標&lt;/h2&gt;
&lt;p&gt;・毎日、日報を書く・毎週、ossに触れる・毎月、3記事書く・シール帳をやり遂げる&amp;lt;/p&amp;gt;—
nove-b
(&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd?ref_src=embed&quot;&amp;gt;@nove-b.dev&amp;lt;/a&amp;gt;)
&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3mbdoajt2rc22?ref_src=embed&quot;&amp;gt;2026年1月1日 14:41&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;年の初めに自らに課した目標だけど早々に達成できないことが判明した。&lt;/p&gt;
&lt;p&gt;毎日日記を書くとかとんでもないし、&lt;code&gt;OSS&lt;/code&gt;に触れることはできるけど、自分のClosedなプロジェクトにも触れたいと言うことで諦めた。&lt;/p&gt;
&lt;p&gt;記事も個人開発をしている間はそっちを優先しちゃって疎かになるしで、色々とできない理由を挙げることはできる。&lt;/p&gt;
&lt;p&gt;唯一シール帳は、はなんとかなるかもしれない。&lt;/p&gt;
&lt;p&gt;とはいえ、なんとかなったところで何もないのだけれど。&lt;/p&gt;
&lt;h2&gt;初詣&lt;/h2&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:2atly2y5kfyjcj5zap6pv4wd/app.bsky.feed.post/3mbivclespo2u&quot; data-bluesky-cid=&quot;bafyreifojnhuxhigrf3odifpaouomuolbkijhmivmpq37qpoeh4xoqxjuu&quot; data-bluesky-embed-color-mode=&quot;system&quot;&amp;gt;&amp;lt;p lang=&quot;&quot;&amp;gt;初詣、ルーメソ🍜&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3mbivclespo2u?ref_src=embed&quot;&amp;gt;[image or embed]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;— nove-b (&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd?ref_src=embed&quot;&amp;gt;@nove-b.dev&amp;lt;/a&amp;gt;) &amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3mbivclespo2u?ref_src=embed&quot;&amp;gt;2026年1月3日 16:31&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;今年も大山に行った。&lt;/p&gt;
&lt;p&gt;一昨年、去年と抱っこだったので、恐る恐る行ったのだが、今年は片方が全部歩いてれた。&lt;/p&gt;
&lt;p&gt;階段階段と楽しそうに歩いていたのでよかった。&lt;/p&gt;
&lt;p&gt;来年は両方歩いてほしい。&lt;/p&gt;
&lt;p&gt;些細なことで成長を実感する。&lt;/p&gt;
&lt;h2&gt;子供たちと初めてのディズニーシー&lt;/h2&gt;
&lt;p&gt;子どもができディズニーランドには3回行ったけど、シーには初めて行った。&lt;/p&gt;
&lt;p&gt;シーは少し年齢が高めの乗り物が多いと言うことで敬遠していたが、行ってみるとそんなことなかった。&lt;/p&gt;
&lt;p&gt;事前にトイストーリーとラプンツェルを見せてから行ったからか、結構楽しんでくれたようだった。&lt;/p&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:2atly2y5kfyjcj5zap6pv4wd/app.bsky.feed.post/3mcmzanenf22p&quot; data-bluesky-cid=&quot;bafyreieg6gokodpsjo4zurxvxjal5ohyhlvwpbt35ahksp73xvtob574w4&quot; data-bluesky-embed-color-mode=&quot;system&quot;&amp;gt;&amp;lt;p lang=&quot;ja&quot;&amp;gt;夢の国から帰って現実やってた。&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3mcmzanenf22p?ref_src=embed&quot;&amp;gt;[image or embed]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;— nove-b (&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd?ref_src=embed&quot;&amp;gt;@nove-b.dev&amp;lt;/a&amp;gt;) &amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3mcmzanenf22p?ref_src=embed&quot;&amp;gt;2026年1月18日 1:18&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;アナ雪に乗れなかったのことが唯一の後悔。&lt;/p&gt;
&lt;p&gt;6時に家出たんだけど、もっと早く家を出なくちゃいけないのかもしれない。&lt;/p&gt;
&lt;h2&gt;よみうりランドにいった&lt;/h2&gt;
&lt;p&gt;イルミネーションを見にいくかと言うことでアフターパスでよみうりランドに行った。&lt;/p&gt;
&lt;p&gt;子どもたちの上着を忘れるといったハプニングも多くあったけど、楽しそうに乗り物に乗っていてよかった。&lt;/p&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:2atly2y5kfyjcj5zap6pv4wd/app.bsky.feed.post/3mdr44bx72k2q&quot; data-bluesky-cid=&quot;bafyreigmmiislk26kmgo4ys4zn6kudkisdkbojzptd35admjkmdhrwicaq&quot; data-bluesky-embed-color-mode=&quot;system&quot;&amp;gt;&amp;lt;p lang=&quot;ja&quot;&amp;gt;ポケモンあった。&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3mdr44bx72k2q?ref_src=embed&quot;&amp;gt;[image or embed]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;— nove-b (&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd?ref_src=embed&quot;&amp;gt;@nove-b.dev&amp;lt;/a&amp;gt;) &amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3mdr44bx72k2q?ref_src=embed&quot;&amp;gt;2026年2月1日 9:45&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;３歳児が楽しそうに乗っていたやつ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;https://www.yomiuriland.com/attraction/spindrive/&lt;/li&gt;
&lt;li&gt;https://www.yomiuriland.com/attraction/gurugurudrive/&lt;/li&gt;
&lt;li&gt;https://www.yomiuriland.com/attraction/merry/&lt;/li&gt;
&lt;li&gt;https://www.yomiuriland.com/attraction/seachicken-go/&lt;/li&gt;
&lt;li&gt;https://www.yomiuriland.com/attraction/sweetscup/&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;また行きたいと行っていたので次は暖かい日に。&lt;/p&gt;
&lt;h2&gt;家に帰り子どもが寝ていると寂しい&lt;/h2&gt;
&lt;p&gt;それ以外にも土日は毎日公園に行った。&lt;/p&gt;
&lt;p&gt;家の近くのふわふわドームデビューを果たし、とても楽しそうだった。&lt;/p&gt;
&lt;p&gt;仕事が遅なり、家に帰ると子どもが寝ていて悲しくなる。&lt;/p&gt;
&lt;p&gt;逆に間に合うとうるさいけど、楽しい。&lt;/p&gt;
&lt;p&gt;いい感じに自分の中で子どもが中心になっている。&lt;/p&gt;
&lt;h2&gt;Pixelfedにプルリクを出した&lt;/h2&gt;
&lt;p&gt;最近よく使っていたPixelfedにプルリクを出した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/pixelfed/pixelfed/pull/6398&quot;&gt;feat(embed): add color theme support&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ダークモードで埋め込みをしたかったので、選択できるようにしたんだけマージされない。&lt;/p&gt;
&lt;p&gt;なんかプルリクたまっているようだった。&lt;/p&gt;
&lt;p&gt;作者は&lt;code&gt;vue&lt;/code&gt; +
&lt;code&gt;Laravel&lt;/code&gt;から&lt;code&gt;nuxt&lt;/code&gt;へのリニューアルを考えているようだし、その影響かもしれない。&lt;/p&gt;
&lt;p&gt;個人的に早く埋め込み改善してほしいのでレビューしてほしいのだけど、&lt;code&gt;OSS&lt;/code&gt;のメンテナーは多忙だし気長に待つしかない。&lt;/p&gt;
&lt;h2&gt;Astroで読んだ本を管理するサイトを作成した&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://books.nove-b.dev/&quot;&gt;https://books.nove-b.dev/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;いままで読書メータとかreadsを使ってきたけど、サービス終了した時のことを考えると自分でデータを持っていたと言う思いを持ち自作した。&lt;/p&gt;
&lt;p&gt;これはもっとブラッシュアップしたらリリース記事を書きたいし、テンプレートを公開したい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item><item><title>【2026年2月】個人開発したらプチバズりした</title><link>https://blog.nove-b.dev/posts/2026-2</link><guid isPermaLink="true">https://blog.nove-b.dev/posts/2026-2</guid><description>2026年2月に考えたこととか</description><content:encoded>&lt;h2&gt;2月に読んだ本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4k8ZIol&quot;&gt;命の砦&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/3ZMVPfb&quot;&gt;上流階級&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4a8J5FN&quot;&gt;貸本屋おせん&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/46L0z8X&quot;&gt;空飛ぶタイヤ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4kT0KVW&quot;&gt;ミーツ・ザ・ワールド&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4rxorFF&quot;&gt;ペッパーズ・ゴースト&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amzn.to/4s7YhsT&quot;&gt;今夜も満月クリニックで&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;読まず嫌いだった池井戸潤を読み、あまりの面白さに完徹するかと思った。&lt;/p&gt;
&lt;p&gt;食わず嫌い、読まず嫌いは良くない。&lt;/p&gt;
&lt;p&gt;その勢いで&lt;a href=&quot;https://amzn.to/3NaSbcn&quot;&gt;ハヤブサ消防団&lt;/a&gt;を借りたので、それを読むのも楽しみにしている。&lt;/p&gt;
&lt;h3&gt;本の感想を静的にホストすることを辞めた&lt;/h3&gt;
&lt;p&gt;先月&lt;code&gt;Astro&lt;/code&gt;で自作した「読んだ本を管理するサイト」の更新があまりにも面倒だったのでやめた。&lt;/p&gt;
&lt;p&gt;元々、自分のコンテンツなのでGitHubで静的に管理しようという思いで作ったんだけど、本の感想を書くために&lt;code&gt;vscode&lt;/code&gt;を開き、&lt;code&gt;build&lt;/code&gt;するという工程があまりにも面倒くさすぎたので、前のシンプルなまとめ方に戻すことにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://books.nove-b.dev/&quot;&gt;https://books.nove-b.dev/&lt;/a&gt;、グッドバイ👋。&lt;/p&gt;
&lt;p&gt;使いたい人がいれば&lt;code&gt;Public&lt;/code&gt;にしようかと考えている。&lt;/p&gt;
&lt;h2&gt;雪が降る&lt;/h2&gt;
&lt;p&gt;冬季オリンピックが開催され、首都圏で珍しく雪が積もった。&lt;/p&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:2atly2y5kfyjcj5zap6pv4wd/app.bsky.feed.post/3medilik43k2h&quot; data-bluesky-cid=&quot;bafyreiecq2cyiqu4cf6cekr45vzjadxj7jep3mqm3a5wioxbqwzmxmwx6a&quot; data-bluesky-embed-color-mode=&quot;system&quot;&amp;gt;&amp;lt;p lang=&quot;ja&quot;&amp;gt;⛄️&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3medilik43k2h?ref_src=embed&quot;&amp;gt;[image or embed]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;— nove-b (&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd?ref_src=embed&quot;&amp;gt;@nove-b.dev&amp;lt;/a&amp;gt;) &amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3medilik43k2h?ref_src=embed&quot;&amp;gt;2026年2月8日 17:16&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;子どもたちにとっては初めての雪で、長靴も手袋も持っていなかったので、非常に寒そうに遊んでいた。&lt;/p&gt;
&lt;p&gt;「寒い、寒い」言いつつ楽しそうで微笑ましかった。&lt;/p&gt;
&lt;p&gt;そこいらで雪だるま作りが行われており、次の日たくさんの雪だるまがこっちを見ていた。&lt;/p&gt;
&lt;h2&gt;冬季オリンピックと風邪&lt;/h2&gt;
&lt;p&gt;4年前の北京五輪、小林陵侑が大ジャンプをした時、寒気に襲われていた。&lt;/p&gt;
&lt;p&gt;まさかと思い検査したところ、当時猛威を震っていたコロナに罹っていることがわかった。&lt;/p&gt;
&lt;p&gt;それから4年経ち、パリ五輪で世界が盛り上がる中、また寒気に襲われていた。&lt;/p&gt;
&lt;p&gt;熱を測ると39.2分あり、検査の結果インフルエンザが確定した。&lt;/p&gt;
&lt;p&gt;子どもに、妻にうつさないように完全隔離されたけど、妻にうつしてしまい、家庭活動がストップした。&lt;/p&gt;
&lt;p&gt;子どもがいると風邪の代償がでかすぎる。&lt;/p&gt;
&lt;p&gt;その後、大人2人は治ったけど、子どもたちの調子が上がらない。&lt;/p&gt;
&lt;p&gt;微熱が続くけど、一通りの検査だと全て陰性で花粉かしらという結論に至った。&lt;/p&gt;
&lt;p&gt;心配だけど様子を見るしかない。&lt;/p&gt;
&lt;h2&gt;遊びの予定が悉くキャンセルに&lt;/h2&gt;
&lt;p&gt;そんなわけで遊びに行く予定がことごとくキャンセルになった。&lt;/p&gt;
&lt;p&gt;たまに遊びに行くと自分の花粉も辛く、何もかもやる気が出ない。&lt;/p&gt;
&lt;p&gt;外には出れないけど、体力お化けを相手しないといけない、さてどうすればいいのか。&lt;/p&gt;
&lt;h2&gt;おかあさんといっしょ&lt;/h2&gt;
&lt;p&gt;あと子ども関係でいうと「おかあさんといっしょ」のあずきお姉さんが引退するらしい。&lt;/p&gt;
&lt;p&gt;子どもの成長と一緒に見てきたあずきお姉さん、最後のファミコンはなんとか当選するといいのだけど。&lt;/p&gt;
&lt;h2&gt;Zedエディタに移行しvscodeに戻る&lt;/h2&gt;
&lt;p&gt;2月も1月に続き個人開発をした。&lt;/p&gt;
&lt;p&gt;会社では&lt;code&gt;cursor&lt;/code&gt;を使っており、個人でも使っていたんだけど、アカウントの変更があまりにも面倒くさかったので、話題のZedエディタに移行してみた。&lt;/p&gt;
&lt;p&gt;で、従量課金なく使える&lt;code&gt;Github copilot&lt;/code&gt;に登録し、Zedエディタと接続して使っていたんだけど、&lt;code&gt;vscode&lt;/code&gt;で良くない？と思い、結局&lt;code&gt;vscode&lt;/code&gt;に戻ってきた。&lt;/p&gt;
&lt;h2&gt;AT protocolで本の感想を書くサイトを作った&lt;/h2&gt;
&lt;p&gt;で、&lt;code&gt;Github copilot&lt;/code&gt;をふんだんに使い個人開発をした。&lt;/p&gt;
&lt;p&gt;結果、少しバズった。&lt;/p&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:2atly2y5kfyjcj5zap6pv4wd/app.bsky.feed.post/3mfwh4nozxc2e&quot; data-bluesky-cid=&quot;bafyreidmkdadagvzf4w6kn64r6hipv5wuyyv5nwzfstg2k22jadk7w7dtm&quot; data-bluesky-embed-color-mode=&quot;system&quot;&amp;gt;&amp;lt;p lang=&quot;ja&quot;&amp;gt;BlueSkyのアカウントでログインでき、
読んだ本の感想を積み上げるサイト作ってみた。&lt;/p&gt;
&lt;p&gt;library-sky.com
library-sky.com/user/nove-b....&amp;lt;/p&amp;gt;— nove-b (&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd?ref_src=embed&quot;&amp;gt;@nove-b.dev&amp;lt;/a&amp;gt;) &amp;lt;a href=&quot;https://bsky.app/profile/did:plc:2atly2y5kfyjcj5zap6pv4wd/post/3mfwh4nozxc2e?ref_src=embed&quot;&amp;gt;2026年2月28日 23:35&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;大バズりではないけど、個人的にこんなにバズったので初めてで少し怖くなった。&lt;/p&gt;
&lt;p&gt;作ったものは、読書感想投稿サイトで、blueskyのフィードを用い、他ユーザーの投稿を見ることができ、自身の投稿はサイトにまとめられるというもの。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AT protocol&lt;/code&gt;を活用しようという思いで作ったのだけど、&lt;code&gt;AT protocol&lt;/code&gt;の理解が浅いので本当に正しい使い方ができているのかが怪しい。&lt;/p&gt;
&lt;p&gt;ただ、blueskyのカントリーマネージャーもコメントしてくれたのでたぶん間違っていない、と信じたい。&lt;/p&gt;
&lt;p&gt;&amp;lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at://did:plc:ry4imxuyyuy24rwptucka2a3/app.bsky.feed.post/3mfxjxs7u2k2o&quot; data-bluesky-cid=&quot;bafyreid5kdojh33cvnrsbz2ntrejox6yhooogpwutiyadsrdkw3n6zmwii&quot; data-bluesky-embed-color-mode=&quot;system&quot;&amp;gt;&amp;lt;p lang=&quot;ja&quot;&amp;gt;フィードで感想がまとまっているの、いいですね。  bsky.app/profile/did:...&lt;/p&gt;
&lt;p&gt;ATプロトコルベースの、エンタメ全般のレビューを書ける（+読める）Popfeed Social @popfeed.social というアプリも入れて試してみてますが、アプリを開いて感想を目にするのはレビューを書くときだけになりがち。&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:ry4imxuyyuy24rwptucka2a3/post/3mfxjxs7u2k2o?ref_src=embed&quot;&amp;gt;[image or embed]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;— Naoko Takano / 高野直子 (&amp;lt;a href=&quot;https://bsky.app/profile/did:plc:ry4imxuyyuy24rwptucka2a3?ref_src=embed&quot;&amp;gt;@naoko.cc&amp;lt;/a&amp;gt;) &amp;lt;a href=&quot;https://bsky.app/profile/did:plc:ry4imxuyyuy24rwptucka2a3/post/3mfxjxs7u2k2o?ref_src=embed&quot;&amp;gt;2026年3月1日 9:59&amp;lt;/a&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;script async src=&quot;https://embed.bsky.app/static/embed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;ソースをオープンにしているので、気になる箇所はプルリク等をお待ちしています。&lt;/p&gt;
&lt;p&gt;https://github.com/nove-b/library-sky&lt;/p&gt;
&lt;p&gt;結構使ってくれる人がいるので、しっかり運用していきたい。&lt;/p&gt;
&lt;p&gt;そしてATプロトコルをしっかり調べて記事にでもまとめたい。&lt;/p&gt;
</content:encoded><author>nove-b</author></item></channel></rss>