<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Re:heat</title>
        <link>https://reheat.vercel.app</link>
        <description>torobi's blog.</description>
        <lastBuildDate>Fri, 09 Oct 2026 15:55:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>ja</language>
        <copyright>All rights reserved 2026, torobi</copyright>
        <item>
            <title><![CDATA[UIToolKitでLabelが表示できない時に確認すべきこと]]></title>
            <link>https://reheat.vercel.app/articles/c67ut9gw7e</link>
            <guid isPermaLink="false">https://reheat.vercel.app/articles/c67ut9gw7e</guid>
            <pubDate>Wed, 22 Oct 2025 13:41:06 GMT</pubDate>
            <description><![CDATA[UIToolkitでなぜかLabelが表示できない...テキストは入っているはずなのに、高さ、幅が0になってしまう。
原因を探るためにあれこれ迷走しましたが、原因は驚くほど単純でした。
結論：TSSを定義している場合、UnityDefaultRuntimeThemeを継承していないと-unity-font-definitionのデフォルト値がなくなってしまう。明示的に設定しない場合はLabelのテキストが表示されない。]]></description>
            <content:encoded><![CDATA[<p>些細なことで時間を溶かしたので、同じ轍を踏む人が減るように書き残しておきます。</p><h1 id="hdbf98b940f">前提条件</h1><ul><li>Labelにテキストは設定している</li><li>フォントは指定していない</li></ul><h1 id="ha09d336012">症状</h1><ul><li>UIToolkitでLabelを配置してもテキストが表示されない</li><li>Labelの高さ・幅が0になってしまう</li><li>UI Builderではちゃんと表示される</li></ul><h1 id="hcb9dacb773">結論</h1><p>TSSを定義・設定していたが、<code>UnityDefaultRuntimeTheme</code> を継承していなかったため。</p><p><code>UnityDefaultRuntimeTheme</code>にはLabel型に対してデフォルトの <code>-unity-font-definition</code> が設定されているので特に何もせずとも表示されますが、独自にTSSを作成するだけだとデフォルトの設定がなくなるためにラベルが表示されなくなるようです。</p><p>独自のTSSを作成する場合は、<code>-unity-font-definition</code>を設定するか、Inherited Themes に（RuntimeでUIToolkitを使う場合は） <code>UnityDefaultRuntimeTheme</code> を設定しましょう！</p><figure><img src="https://images.microcms-assets.io/assets/41d23176f50a4c49a8fb42dbe06ad2b5/ee8c449dfaaa45dab68ce9b0c5063160/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202025-10-21%2023.58.36.png" alt="" width="916" height="776"></figure>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift用のLinterを自作している話]]></title>
            <link>https://reheat.vercel.app/articles/ct3svip58n</link>
            <guid isPermaLink="false">https://reheat.vercel.app/articles/ct3svip58n</guid>
            <pubDate>Thu, 19 Dec 2024 15:21:10 GMT</pubDate>
            <description><![CDATA[SwiftLintに拡張しやすさを求めてLinterを自作した話。
]]></description>
            <content:encoded><![CDATA[<p>この記事は<a href="https://adventar.org/calendars/10267" target="_blank" rel="noopener noreferrer nofollow">琉球大学(知能情報)アドベントカレンダー Advent Calendar 2024</a>の記事です。</p><h1 id="hcaa90397d4">作ったもの</h1><p>OSSとしてGitHubで公開してます。</p><div class="iframely-embed"><div class="iframely-responsive" style="height: 140px; padding-bottom: 0;"><a href="https://github.com/torobi/SwallowLint" data-iframely-url="//cdn.iframe.ly/api/iframe?card=small&amp;url=https%3A%2F%2Fgithub.com%2Ftorobi%2FSwallowLint&amp;key=c271a3ec77ff4aa44d5948170dd74161"></a></div></div><script async src="//cdn.iframe.ly/embed.js" charset="utf-8"></script><h1 id="hd92040d0df">きっかけ</h1><p>SwiftのLinterは、<a href="https://github.com/realm/SwiftLint" target="_blank" rel="noopener noreferrer nofollow">SwiftLint</a>ほぼ一択なのが現状です。SwiftLintに独自のルールを追加したい場合、<a href="https://github.com/realm/SwiftLint?tab=readme-ov-file#1-swift-custom-rules" target="_blank" rel="noopener noreferrer nofollow">Swift Custom Rules</a>と<a href="https://github.com/realm/SwiftLint?tab=readme-ov-file#2-regex-custom-rules" target="_blank" rel="noopener noreferrer nofollow">Regex Custom Rules</a>の2種類の方法があります。</p><h3 id="h52ce1ab371">Swift Custom Rules</h3><p>Swift Syntaxを用いてルールを作れます。Swiftで表現できるため複雑なルールを実現できますが、Bazelでビルドする必要があります。</p><h3 id="hea6cd9ba2b">Regex Custom Rules</h3><p>正規表現を用いてルールを作れます。 <code>.swiftlint.yml</code> に書き加えるだけで手軽にルールを追加できますが、任意の正規表現にマッチした箇所に警告を出す、という仕組みなので複雑なルールを実現するのは難しいです。</p><p>ある程度複雑なルールを実現するにはSwift Custom Rules一択ですが、Bazelでビルドする必要がある都合上、環境構築がやや面倒です。個人用や社内独自のコーディングルール用にカスタマイズすることを考えると、ルールはサクッと追加できるのが望ましいため、いっそのこと拡張しやすいようなLinter自体を自作することにしました。</p><h1 id="h6dcdf917f2">Linterを作る</h1><p>Linterと呼べるようなものを作るには、ざっくり以下のような機能が必要です。</p><ul><li>CLIの引数として外部から値を設定できる</li><li>ソースコードの構文解析</li><li>エディタ上で任意の行に警告を表示する</li></ul><p>これらを実現するためにはどうすれば良いかをざっくり解説します。</p><h2 id="h463f83b356">CLIの引数として外部から値を設定</h2><p><a href="https://github.com/apple/swift-argument-parser" target="_blank" rel="noopener noreferrer nofollow">ArgumentParser</a>を用いることで簡単に引数を受け取るCLIを作ることができます。</p><p>ArgumentParserはプロパティラッパーを使って機能を実現しています。引数にしたいプロパティに対して<code>@Argument</code>, <code>@Flag</code>, <code>@Option</code>といったプロパティラッパーを付与することでコマンドとしてビルドした際に引数として受け取れる値になります。</p><pre><code class="language-swift">import ArgumentParser

@main
struct FooCommand: ParsableCommand {
    @Flag(help: &quot;Include a counter with each repetition.&quot;)
    var includeCounter = false

    @Option(name: .shortAndLong, help: &quot;The number of times to repeat &apos;phrase&apos;.&quot;)
    var count: Int? = nil

    @Argument(help: &quot;The phrase to repeat.&quot;)
    var phrase: String
}</code></pre><h2 id="hf7ac4fcab6">ソースコードの構文解析</h2><p>Linterとして動作するためには、コマンド実行時にLint対象のソースファイルを構文解析する必要があります。</p><p>これは<a href="https://github.com/swiftlang/swift-syntax" target="_blank" rel="noopener noreferrer nofollow">SwiftSyntax</a>を用いることで簡単に実現できます。本記事ではかなり簡単に解説するので、SwiftSyntaxについての詳しい解説を聞きたい人は以下の資料・動画などを見ると良いかなと思います。</p><p><a href="https://fortee.jp/iosdc-japan-2023/proposal/da53c5df-a243-46b1-a3e2-c35dd9fdda11">https://fortee.jp/iosdc-japan-2023/proposal/da53c5df-a243-46b1-a3e2-c35dd9fdda11</a></p><p></p><p>SwiftSyntaxで何ができるかを簡単にまとめると、以下の2つです。</p><ol><li>ソースコードのオブジェクト化</li><li>ASTの探索</li></ol><h3 id="hc05cadd5c3">ソースコードのオブジェクト化</h3><p>ソースコードはAST（抽象構文木）というものに変換できます。Swift Syntaxは、ソースコードを元にして、ASTを表現したオブジェクトを生成できます。HTMLを元にDOMを生成するのと同じです。どのような構造のオブジェクトが生成されるのかは<a href="https://swift-ast-explorer.com/" target="_blank" rel="noopener noreferrer nofollow">Swift AST Explorer</a>を使うと分かりやすいと思います。</p><h3 id="hc77e1efa15">ASTの探索</h3><p><code>SyntaxVisitor</code>の <code>visit()</code> を用いることで、ASTの各ノードを順番に探索することができます。引数の <code>node</code> の型で任意の種類のノードのみ探索できます。</p><pre><code class="language-swift">final class MySyntaxVisitor: SyntaxVisitor {
    override func visit(_ node: 探索対象のノード型) -&gt; SyntaxVisitorContinueKind {
        // 引数のnode型のノードに到達した場合にしたい処理を書く

        // 子ノードの探索をする場合
        return .visitChildren

        // 子ノードの探索をしない場合
        // return .skipChildren
    }
}

// 探索開始
MySyntaxVisitor(viewMode: .all).walk(探索対象のSourceFileSyntax)</code></pre><p><code>SyntaxVisitor</code> の代わりにSyntaxRewriterを使うことで、探索しているASTの書き換えを行うことができます。</p><pre><code class="language-swift">final class MySyntaxRewriter: SyntaxRewriter {
    override func visit(_ node: 書き換え対象のノード型) -&gt; 書き換え対象のノード型 {
        // ~nodeを加工する~

        return super.visit(加工後のnode)
    }
}

// 書き換え
let rewrittenAST = MySyntaxRewriter().visit(packageSwift)</code></pre><h2 id="hfb5b72d973">エディタ上で任意の行に警告を表示する</h2><p>Linterというツールの性質上、エディタ上にルールに違反している箇所を表示できると便利です。Xcode上で特定の行に警告を表示するのは意外と簡単で、以下のフォーマットでprintするようにするだけです。</p><pre><code class="language-swift">// 警告
print(&quot;{/path/to/your/file}:{line}:{column}: warning: foo warning message&quot;)

// エラー
print(&quot;{/path/to/your/file}:{line}:{column}: error: foo warning message&quot;)</code></pre><p><code>ファイルパス:行:文字: warning: 出力したいメッセージ</code> で警告を出せる感じですね。 <code>warning</code>を <code>error</code> に変えると赤いエラー表示として出力されます。</p><h1 id="ha214098e44">まとめ</h1><p>かなりざっくりとした説明になってしまいましたが、Linterの基盤となる機能の解説でした。今後、余裕ができればconfigファイルの読み込みや、ルールの抽象化、 <code>disable:next</code> などによる部分的な無効化・有効化などについても解説できればと思います。</p><p>それでは、よきSwiftライフを。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[highlight.jsでdiffと言語を同時にシンタックスハイライトする]]></title>
            <link>https://reheat.vercel.app/articles/qlfd-2jnm</link>
            <guid isPermaLink="false">https://reheat.vercel.app/articles/qlfd-2jnm</guid>
            <pubDate>Wed, 21 Feb 2024 04:27:52 GMT</pubDate>
            <description><![CDATA[highlight.jsを使ってdiffとプログラミング言語のシンタックスハイライトを同時にかけられるように実装しました。]]></description>
            <content:encoded><![CDATA[<h1 id="h8d027c8ed3">はじめに</h1><p>本ブログはhighlight.jsでコードブロックにハイライトをつけていますが、highlight.jsにはdiffとプログラミング言語の両方のシンタックスハイライトを重ねがけすることができません。この重ねがけの機能は<a href="https://zenn.dev/zenn/articles/markdown-guide#diff-%E3%81%AE%E3%82%B7%E3%83%B3%E3%82%BF%E3%83%83%E3%82%AF%E3%82%B9%E3%83%8F%E3%82%A4%E3%83%A9%E3%82%A4%E3%83%88">Zenn</a>や<a href="https://qiita.com/Qiita/items/e84f5aad7757afce82ba#diff%E3%81%A8%E5%90%84%E8%A8%80%E8%AA%9E%E3%81%AE%E3%82%B7%E3%83%B3%E3%82%BF%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%90%8C%E6%99%82%E3%81%AB%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">Qiita</a>には実装されていますが、highlight.jsにはデフォルトでその機能がついていないようだったので自力で実装してみました。</p><h2 id="h3de35099b3">参考</h2><p>highlight.jsを使った実装の仕組みにおいてhighlightjs-code-diffを参考にさせていただきました。最初からこのライブラリ使えばいいんじゃない？と思いましたが実際使ってみると使っているテーマ的に差分がある部分の文字色が変わるだけだったため、<code>+/-</code>の記号だけdiffのハイライトになり、ほとんど言語のハイライトと同じになってしまったので独自実装する形にしました。</p><h1 id="hd264ef2862">diffのハイライト</h1><p>前提としてdiffのハイライトって何？という人用に軽く説明しときますと、Gitの差分のアレです。</p><p>変更前の行に<code>-</code>をつけて、変更後の行に<code>+</code>をつけます。</p><pre><code class="language-diff">- git difff
+ git diff</code></pre><h1 id="heef2fda56b">highlight.jsを拡張する</h1><p>highlight.jsの<code>HLJSApi</code>オブジェクトのラッパーを作る形でdiffと言語のハイライトができるように拡張します。
仕様としては変更前の行は<code>+</code>, 変更後の行は<code>-</code>, 変更のない行は空白が付いているものとし、この3種類を<code>diffMarker</code>と呼ぶこととします。また、重ねがけをする際には言語名を<code>diff-言語名</code>とします。例えばdiff+typescriptなコードブロックをシンタックスハイライトする場合は<code>diff-typescript</code>を言語名として<code>HLJSApi</code>オブジェクトに渡します。</p><p>処理の流れは大まかには2つのステップからなります。</p><ol><li><code>diffMarker</code>を削除したコード文字列に対して任意のプログラミング言語のハイライトを行う</li><li>ハイライト済みのHTML文字列の各行を<code>&lt;span&gt;</code>で囲い、classには<code>diffMarker</code>に応じたものを付ける</li></ol><p>diffの要素を除外して言語のハイライトを行い、後付けでdiffのハイライトをする感じですね。テーマによらず行ごとハイライトするために、diffのハイライトを行うcssは自分で用意します。</p><h2 id="h21034affcd"><code>diffMarker</code>を削除したコード文字列に対して任意のプログラミング言語のハイライトを行う</h2><p>コードブロックで表示される文字列（コード文字列）が変数<code>code</code>に入っているとします。</p><pre><code class="language-typescript">const code = `
-const add = (a, b) =&gt; a - b
+const add = (a, b) =&gt; a + b
 console.log(add(1, 2))
`</code></pre><p><code>code</code>から<code>diffMarker</code>を取り除き、highlight.jsの<code>hljs.highlight()</code>を用いてシンタックスハイライトします。typescriptとしてハイライトして、それ以外の設定は変数<code>options</code>に入っているものとします。</p><pre><code class="language-typescript">// const options = ハイライト時の設定

// diffMarkerを取り除く
const diffLines = code.split(&apos;\n&apos;);
const codeWithoutDiffMarkers = diffLines.map((line) =&gt; line.slice(1)).join(&apos;\n&apos;); 

// シンタックスハイライト
const result = hljs.highlight(codeWithoutDiffMarkers, { ...options, language });</code></pre><p><code>result.value</code>にはハイライトされるよう処理が施されたHTML文字列が入っています。</p><pre><code class="language-html">&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt; = (&lt;span class=&quot;hljs-params&quot;&gt;a, b&lt;/span&gt;) =&amp;gt; a - b
&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt; = (&lt;span class=&quot;hljs-params&quot;&gt;a, b&lt;/span&gt;) =&amp;gt; a + b
&lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))</code></pre><h2 id="hc3a2da628b">ハイライト済みのHTML文字列の各行を<code>&lt;span&gt;</code>で囲い、classには<code>diffMarker</code>に応じたものを付ける</h2><p><code>result.value</code>をdiffのハイライトがされるように以下の加工をします。</p><ul><li>取り除いた<code>diffMarker</code>を元に戻す</li><li><code>diffMarker</code>が<code>+</code>の行を<code>addition-line-highlight</code>classの<code>&lt;span&gt;</code>で囲む<ul><li><code>-</code>の場合は<code>deletion-line-highlight</code></li></ul></li><li><code>diffMarker</code>自体を<code>addition-marker</code>classの<code>&lt;span&gt;</code>で囲む<ul><li><code>-</code>の場合は<code>deletion-marker</code></li></ul></li></ul><pre><code class="language-typescript">const highlightedLines = result.value.split(&apos;\n&apos;);
const highlightedLinesWithDiffMarkers = highlightedLines.map((line, i) =&gt; {
  const diffMarker = diffLines[i].slice(0, 1);

  switch (diffMarker) {
    case &apos;+&apos;:
      return `&lt;span class=&quot;addition-line-highlight&quot;&gt;&lt;span class=&quot;addition-marker&quot;&gt;${diffMarker}&lt;/span&gt;${line}&lt;/span&gt;`;
    case &apos;-&apos;:
      return `&lt;span class=&quot;deletion-line-highlight&quot;&gt;&lt;span class=&quot;deletion-marker&quot;&gt;${diffMarker}&lt;/span&gt;${line}&lt;/span&gt;`;
    default:
      return `${diffMarker}${line}`;
  }
});</code></pre><p>これでdiff用のハイライトが付くようになります。</p><h2 id="h8b8e7529f7"><code>HLJSApi</code>オブジェクトのラッパーとして実装する</h2><p><code>HLJSApi</code>を拡張する形で実装します。ついでにちょっとしたバリデーションや、言語が<code>diff-</code>から始まらない時は通常通りにハイライトするようにしたりします。</p><div data-filename="highlightDiffPlus.ts"><pre><code class="language-typescript">import { HighlightResult, HighlightOptions, HLJSApi } from &apos;highlight.js&apos;;
import &apos;./highlight-diff.css&apos;;

export function hljsDiffPlus(hljs: HLJSApi): HLJSApi {
  function isValidDiffCode(codeLines: string[]): boolean {
    const isValidDiffCode = codeLines
      .filter((line) =&gt; line.length &gt;= 1)
      .every((line) =&gt; {
        const headChar = line[0];
        return headChar == &apos; &apos; || headChar == &apos;+&apos; || headChar == &apos;-&apos;;
      });

    return isValidDiffCode;
  }

  function highlight(code: string, options: HighlightOptions): HighlightResult {
    const diffLangPrefix = &apos;diff-&apos;;

    if (!options.language.startsWith(diffLangPrefix)) {
      return hljs.highlight(code, options);
    }

    const language = options.language.slice(diffLangPrefix.length);
    const diffLines = code.split(&apos;\n&apos;);

    if (!isValidDiffCode(diffLines)) {
      console.warn(&apos;改行以外の文字を含む行は空白/+/-のいずれかで始まる必要があります。&apos;);
    }

    const codeWithoutDiffMarkers = diffLines.map((line) =&gt; line.slice(1)).join(&apos;\n&apos;);

    const result = hljs.highlight(codeWithoutDiffMarkers, { ...options, language });
    const highlightedLines = result.value.split(&apos;\n&apos;);

    if (highlightedLines.length !== diffLines.length) {
      console.warn(
        `正常にhighlightできませんでした。diffのみのhighlightを行います。input_lang: ${options.language}`,
      );
      return hljs.highlight(code, { ...options, language: &apos;diff&apos; });
    }

    const highlightedLinesWithDiffMarkers = highlightedLines.map((line, i) =&gt; {
      const diffMarker = diffLines[i].slice(0, 1);

      switch (diffMarker) {
        case &apos;+&apos;:
          return `&lt;span class=&quot;addition-line-highlight&quot;&gt;&lt;span class=&quot;addition-marker&quot;&gt;${diffMarker}&lt;/span&gt;${line}&lt;/span&gt;`;
        case &apos;-&apos;:
          return `&lt;span class=&quot;deletion-line-highlight&quot;&gt;&lt;span class=&quot;deletion-marker&quot;&gt;${diffMarker}&lt;/span&gt;${line}&lt;/span&gt;`;
        default:
          return `${diffMarker}${line}`;
      }
    });

    result.code = code;
    result.value = highlightedLinesWithDiffMarkers.join(&apos;\n&apos;);
    result.language = options.language;

    return result;
  }

  return {
    ...hljs,
    highlight(
      codeOrLanguageName: string,
      optionsOrCode: string | HighlightOptions,
      ignoreIllegals?: boolean,
    ): HighlightResult {
      return typeof optionsOrCode === &apos;string&apos;
        ? highlight(optionsOrCode, { language: codeOrLanguageName, ignoreIllegals })
        : highlight(codeOrLanguageName, optionsOrCode);
    },
  };
}</code></pre></div><h2 id="h193520c69e">diff用のCSSを作成する</h2><p>diff部分が行ごとハイライトされるようなCSSを作成します。色はテーマやコードブロックの背景色に合わせて適宜調整します。このCSSは<code>highlightDiffPlus.ts</code>で読み込んでいます。</p><div data-filename="highlight-diff.css"><pre><code class="language-css">.addition-line-highlight {
  background-color: #2c4334;
  display: inline-block;
}
.addition-marker {
  color: #afa;
}

.deletion-line-highlight {
  background-color: #553335;
  display: inline-block;
}
.deletion-marker {
  color: #faa;
}</code></pre></div><h2 id="ha09b7e9309">既存の<code>HLJSApi</code>オブジェクトと置き換えて使う</h2><p>通常のhighlight.jsは以下のようにして使います。</p><pre><code class="language-typescript">import hljs from &apos;highlight.js&apos;;

hljs.highlight(コード文字列, { language: &apos;言語名&apos;);</code></pre><p>自作した<code>hljsDiffPlus()</code>を使って置き換えます。</p><pre><code class="language-typescript">import plainHljs from &apos;highlight.js&apos;;
import { hljsDiffPlus } from &apos;./highlightDiffPlus&apos;;

const hljs = hljsDiffPlus(plainHljs);
hljs.highlight(コード文字列, { language: &apos;言語名&apos;);</code></pre><p>これでdiffと言語の両方のシンタックスハイライトが効くようになりました！<br>実際に使ってみるとこんな感じです。</p><pre><code class="language-diff-typescript">-import hljs from &apos;highlight.js&apos;;
+import plainHljs from &apos;highlight.js&apos;;
+import { hljsDiffPlus } from &apos;./highlightDiffPlus&apos;;

+const hljs = hljsDiffPlus(plainHljs);
 hljs.highlight(コード文字列, { language: &apos;言語名&apos;);</code></pre>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[MicroCMS+Next.jsでブログを自作する]]></title>
            <link>https://reheat.vercel.app/articles/214tw09cm36</link>
            <guid isPermaLink="false">https://reheat.vercel.app/articles/214tw09cm36</guid>
            <pubDate>Wed, 21 Feb 2024 03:22:09 GMT</pubDate>
            <description><![CDATA[MicroCMSのテンプレートを使うと簡単にブログが作れそうだったのでやってみた]]></description>
            <content:encoded><![CDATA[<p>記念すべき第1回目の記事はこのブログ自体についてです。</p><p>そろそろ何某かの記事を書いて公開したい！自分だけのブログが欲しい！でもデザインは自由に変更したい！でもブログを書くときの快適性は欲しい！という要望を叶えるために色々調べていたところ、ヘッドレスCMSに辿り着きました。</p><p><a href="https://templates.microcms.io/" target="_blank" rel="noopener noreferrer nofollow">MicroCMSのテンプレート</a>を使うとかなり簡単に実装できそうだったので作ってみました。</p><h1 id="h6d644f57d6">ヘッドレスCMSとは</h1><p>MicroCMSの記事がわかりやすかったので置いておきます。<br></p><div class="iframely-embed"><div class="iframely-responsive" style="height: 140px; padding-bottom: 0;"><a href="https://blog.microcms.io/what-is-headlesscms/" data-iframely-url="//cdn.iframe.ly/api/iframe?card=small&amp;url=https%3A%2F%2Fblog.microcms.io%2Fwhat-is-headlesscms%2F&amp;key=c271a3ec77ff4aa44d5948170dd74161"></a></div></div><script async src="//cdn.iframe.ly/embed.js" charset="utf-8"></script><p>ものすごく簡単に言うと、ブログで言えば</p><ol><li>ブログの記事を作成する機能</li><li>作成した記事を保存する機能</li><li>保存している記事をページ上に表示する機能</li></ol><p>という機能がありますが、1と2をヘッドレスCMSに任せ、3は自力で作る、みたいな感じです。このブログで言うと1,2をMicroCMS, 3をNext.jsによって実現しています。</p><h1 id="hc8a0b04c87">MicroCMSとは</h1><p>MicroCMSは日本製のヘッドレスCMSで、ちょっとしたブログで使う分には無料で使えます。</p><h2 id="he3a4b9655f">MicroCMSテンプレート</h2><p>MicroCMSにはテンプレートが用意されており、それを用いることでヘッドレスCMSが担当しない「3. 保存している記事をページ上に表示する機能」の実装が簡単になります。</p><div class="iframely-embed"><div class="iframely-responsive" style="height: 140px; padding-bottom: 0;"><a href="https://templates.microcms.io/" data-iframely-url="//cdn.iframe.ly/api/iframe?card=small&amp;url=https%3A%2F%2Ftemplates.microcms.io%2F&amp;key=c271a3ec77ff4aa44d5948170dd74161"></a></div></div><script async src="//cdn.iframe.ly/embed.js" charset="utf-8"></script><p>テンプレートをgithubからcloneしてくるだけでほとんど実装が完了します。後の手順はリポジトリのREADMEを読んで進めればOK。</p><p>本ブログは<a href="https://templates.microcms.io/templates/detail/a530e59f-d66d-4b85-9ef5-4cf4288adb09" target="_blank" rel="noopener noreferrer nofollow">シンプルなブログ</a>テンプレートを使っていますが、シンプルとは言うものの検索機能だったりタグ機能は持っているのでかなり工数の削減ができます。</p><h1 id="hb7ffee06ae">テンプレートをカスタマイズする</h1><p>テンプレートのままだとサンプルの画像がロゴに使われていたりするので、独自のロゴで置き換えたりトップページのタイトルを変更したりします。</p><h2 id="hf0ab71b325">画像の置き換え</h2><p>単純に画像を置き換えたものは以下です。</p><ul><li><code>public/logo.svg</code></li><li><code>public/no-image.png</code></li><li><code>public/ogp.png</code></li></ul><h2 id="h912126340e">Faviconの置き換え</h2><p>faviconにsvgが使えるっぽいです。元々あった<code>app/favicon.ico</code>を削除して代わりに<code>app/icon.svg</code>を配置します。このままだと<code>favicon.ico</code>がないよ！と怒られるので<code>metadata</code>にiconのパスを書き加えます。</p><div data-filename="app/layout.tsx"><pre><code class="language-typescript">export const metadata = {
  // ※最初から書かれていたものは省略

  icons: { // 追加
    icon: &apos;icon.svg&apos;,
  },
};</code></pre></div><h2 id="h13281ea771">メタデータの変更</h2><p>サイトのtitleやdescriptionを変更します。</p><div data-filename="app/layout.tsx"><pre><code class="language-diff-tsx"> export const metadata = {
   metadataBase: new URL(process.env.BASE_URL || &apos;http://localhost:3000&apos;),
-  title: &apos;Simple Blog&apos;,
-  description: &apos;A simple blog presented by microCMS&apos;,
+  title: &apos;Re:heat&apos;,
+  description: &quot;torobi&apos;s blog.&quot;,
   openGraph: {
-    title: &apos;Simple Blog&apos;,
-    description: &apos;A simple blog presented by microCMS&apos;,
+    title: &apos;Re:heat&apos;,
+    description: &quot;torobi&apos;s blog.&quot;,
     images: &apos;/ogp.png&apos;,
   },
   alternates: {
     canonical: &apos;/&apos;,
   },
   icons: {
     icon: &apos;icon.svg&apos;,
   },
 };</code></pre></div><h2 id="h7c773ce7ea">ヘッダーの画像のaltを変更</h2><div data-filename="components/Header/index.tsx"><pre><code class="language-diff-tsx"> export default function Header() {
   return (
     &lt;header className={styles.header}&gt;
       &lt;Link href=&quot;/&quot;&gt;
         &lt;Image
           src=&quot;/logo.svg&quot;
-          alt=&quot;SIMPLE&quot;
+          alt=&quot;Reheat&quot;
           className={styles.logo}
           width={348}
           height={133}
           priority
         /&gt;
       &lt;/Link&gt;
     &lt;/header&gt;
   );
 }</code></pre></div><h2 id="hb949cb4704">フッターの変更</h2><p>名前を変更し、さらに名前をクリックするとポートフォリオサイトに飛ぶように変更します。ついでに© 制作年 著作名になるように順番を変更します。</p><div data-filename="components/Footer/index.tsx"><pre><code class="language-diff-tsx"> import styles from &apos;./index.module.css&apos;;

 export default function Footer() {
   return (
     &lt;footer className={styles.footer}&gt;
-      &lt;p className={styles.cr}&gt;© SIMPLE. All Rights Reserved 2023&lt;/p&gt;
+      &lt;p className={styles.cr}&gt;
+        © 202４{&apos; &apos;}
+        &lt;a href=&quot;https://140degrees.com/About/profile&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;
+          torobi
+        &lt;/a&gt;
+        . All Rights Reserved.
+      &lt;/p&gt;
     &lt;/footer&gt;
   );
 }</code></pre></div><h1 id="ha214098e44">まとめ</h1><p>MicroCMS + Next.jsで自作ブログを構築してみました。MicroCMSの記事作成画面は使いやすく、編集中でもWYSIWYG的に表示されるのがいいですね！（正確にはFrontend側の表示がそのまま見れるわけではないのでWYSIWYGではないですが）表だったりリンクの埋め込みプレビューなどは編集画面上でも綺麗に表示されるので見やすいです。表もMarkdown記法だとしんどいですが、MicroCMSだと編集画面でも表として描画されて操作できるのでかなり楽です。この辺りの操作感はNotionと近いかと思います。</p><p>公開に際し最低限の変更はここで行いましたが、空き時間にデザイン変更や機能追加なんかもゆっくりやっていきます。</p>]]></content:encoded>
        </item>
    </channel>
</rss>