開発日誌

開発した時に躓いたこととかの記録

個人サイトをポコポコ作るには

  • 最近個人サイトをポコポコ生やしてるので書く。
    • 更新間に合ってないが作った主な個人サイトは https://manasas.dev に適宜まとめている)。

前提

  • ギャラリー・ブログ・jsのみで作れる簡易なツールのサイトを作る想定
  • アプリケーション的なサイトも近い技術で作れるとは思う

使うもの

Github

  • 基本はmainブランチ1本構成
  • 大きめのもの作る時はブランチ切ることもある

ホスティングサービス

  • 基本Vercelを使ってるが、FirebaseやCloudflareも利用している

Firebase

  • ポートフォリオで利用
    • 制作時、Firestoreに激ハマりしていた名残
  • Github Actionsを組んで利用
  • ホスティングのみに利用するにはtoo muchな感じがあるので新規ではあまり採用していない

Vercel

Cloudflare

  • mana's toolsで利用
    • Calckeyの鯖立てした時に『Coudflareはhostingもできる』を知ったのがキッカケ
  • これもGithubリポジトリつなぐだけ。普通にホスティングする分にはVercelと大きな違いはないかも。

ホスティングサービス、どれを選ぶ?

やり方

  1. 何らかのフロントエンドフレームワークを使ってサイトを作る
    • Next.js, Astro, Svleteらへんが今の推し
  2. Githubに上げる
  3. ホスティングサービスでポチポチでリポジトリつないでホスティング
  4. サブドメインを作成。ホスティングサービスでポチポチで独自ドメインに変更。ドメイン変更が反映されるまでちょっとまつ。
  5. 完成🎉

おわり

  • ねっ、簡単でしょ?
  • 野良のHTML + CSS直打ち民を増やしたい気持ちがある。
  • サーバー借りるのは勇気がいるし、このへんのホスティングサービスならタダから小さくはじめられるよ!と、思ったのだが、Githubとフロントエンドフレームワークはそれなりに大きな壁になってしまうだろうか……
    • コンポーネント使わなければAstro/Svelteは個人サイト作るのに手軽だと思うのでちょいちょい言語化していきたい

Astroでいにしえの個人サイトを作った

  • いにしえの個人サイトをつくった。

    • ここでいう『いにしえの個人サイト』とは『1ページ1ページ真心込めてHTML+CSSを凝り凝りしてるサイト』のことをさす。
  • サイトはコレ↓

やりたかったこと

  • いにしえの個人サイトをpushで自動デプロイで作りたい
  • できれば非ITの人でもできる構成にしたい

やったこと

仕様技術

選定理由

Astro
  • HTML+CSSができてできるだけシンプルなものをチョイス
  • いつかjsやりたくなった時は局所でReactが召喚できるのも高ポイント
Vercel
  • いつもの
Bing Image Creator
  • 日本語で画像生成依頼ができて、1回の依頼で4枚作ってくれて、かつ応答速度もそこそこ良い

思ったこと

  • やった後、非ITの人向けの記事を書こうとして『Githubの導入を非ITの人向けに説明するのめっちゃムズい』ということに気づいた
    • 世の中にある記事も非ITに伝わるかって思うとだいぶ悩む
    • HTML+CSSを書きたい時点である程度のハードルは越えてくれそうだが、悩む
    • でも非ITの人向けのCSSデコみたいな話も書いていきたいので、この点はまた今度、でもいいから書いていこうかなと思う。
      • 日誌に書くのかの点については悩んでるがカテわけで日誌に書くでいいかなと思ってる
  • Bing Image Creator、良い
    • ローカルで動作させるStableDiffusionとWaifuDiffusionくらいしか触ったことなかったが、どちらも1/2枚ずつが限界だったので、4枚ずつでこの速度なら満足。
  • Astro、良い。
    • Astroが良いというよりは、単純なマークアップであればcss, htmlが1ファイルにまとまってる方が管理が楽で好き
  • いにしえの個人サイトたーのしーーー

    • ガラケー時代の個人サイト民なので『ガラケーでも見れるレイアウト』をしたくなる
    • 背景を『上少しグラデ重ねることで切替の違和感を減らす』ようにしているが、こういうスタイル書くの楽しい
    • 若干画像が重い気配があるのではやめに調整したい
  • おわり。

    • 長年小説を人目に晒さなかったのでちょっと恥ずかしい気持ちがあるが、サイトのレイアウトに関しては個人的に神ってんなと思ってるのでレイアウトを見てください!!!
    • コンテンツ更新も続けていけるようにがんばりたい

Svelteの書き方の特徴をざっくり語る

コンポーネントのファイルの構成

  • HTML、CSSJavaScriptを1ファイルにまとめるタイプ
    • このタイプ、CSSを書く場所に悩まなくて良いので好き
<script lang="ts">
   export let value: number = 0;
   export let text: string;
   export let min: number = 0;
   export let max: number = 255;
   export let step: number = 1;
</script>

<div class="root">
    <div class="label">{text}</div>
    <div class="slider"><input type="range" bind:value {min} {max} {step} /></div>
    <div class="num"><input type="number" bind:value {min} {max} {step} /></div>
</div>

<style lang="scss">
    .root {
        display: flex;
        .label {
            width: 5rem;
        }
        .num {
            width: 7rem;
        }
        .slider {
            width: 10rem;
        }
        div {
            margin: 0.25rem 0;
        }
        input {
            border-radius: 8px;
        }
    }
</style>

コンポーネントの引数定義

  • 下記のexportしているものがSvelteのコンポーネントの引数。
    • 初期値ないものがrequired。
export let value: number = 0;
export let text: string;
export let min: number = 0;
export let max: number = 255;
export let step: number = 1;
  • これ以上なくシンプル。Svelteのwrite less codeの思想を表現している点のひとつだと思う。
  • typeとして定義してる方がまとまってて好みという印象があるが、慣れかも。

jsの変数をCSSに渡したい時

  • JavaScript -> HTMLのstyleでCSS variableを定義 -> CSS という形になる
  • JavaScriptの変数を利用したい部分が少なければstyleにスタイル書くのもアリかもしれない
<script lang="ts">
   import type { ImgOptions } from './type';

   export let imgSrc: string;
   export let text: ImgOptions;
   export let mask: ImgOptions;
</script>

<div
    class="root"
    style="
  --text-blend-mode: {text.blendMode}; 
  --text-top: {text.top}px; --text-left: {text.left}px; 
  --text-red: {text.red}; --text-green: {text.green}; --text-blue: {text.blue}; --text-alpha: {text.alpha}; 
  --text-z-index: {text.layer};
  --mask-blend-mode: {mask.blendMode}; 
  --mask-top: {mask.top}px; --mask-left: {mask.left}px; 
  --mask-red: {mask.red}; --mask-green: {mask.green}; --mask-blue: {mask.blue}; --mask-alpha: {mask.alpha};
  --mask-z-index: {mask.layer};"
>
    <div class="imgWrapper">
        <p class="text">Welcome</p>
        <img src={`https://source.unsplash.com/${imgSrc ? imgSrc : 'Ak81Vc-kCf4'}`} alt="画像" />
    </div>
</div>

<style lang="scss">
    .root {
        display: flex;
        justify-content: center;
        margin: 48px;
        margin-bottom: 500px;
        .imgWrapper {
            position: relative;
            margin: 24px;
            img {
                width: 500px;
            }
            .text {
                display: block;
                position: absolute;
                font-size: 88px;
                font-weight: 700;
                top: var(--text-top);
                left: var(--text-left);
                margin: 0;
                z-index: var(--text-z-index);
                line-height: 1;
                color: rgba(var(--text-red), var(--text-green), var(--text-blue), var(--text-alpha));
                mix-blend-mode: var(--text-blend-mode);
            }

            &::before {
                position: absolute;
                display: block;
                width: calc(100% + 48px);
                height: calc(100% + 48px);
                content: '';
                top: var(--mask-top);
                left: var(--mask-left);
                background: rgba(var(--mask-red), var(--mask-green), var(--mask-blue), var(--mask-alpha));
                z-index: var(--mask-z-index);
                mix-blend-mode: var(--mask-blend-mode);
            }
        }
    }
</style>
  • Reactはcss in jsを使えばいい。CSS modules使ってる時はちょっと大変そう。
  • Astroは未調査だけどぱっと調べた感じだとSvelteと同じようなことをすることになりそう
    • Astro(.astro)はあまり動的なコンテンツ向けではない感があるので、jsを多用する場合はAstroのアイランドアーキテクチャを利用してReactとかVue.jsを利用した方がいいかも
  • Vue.jsはv-bindでjsの変数をCSS内にバインドすることができるらしい

headの書き換え方

  • <svelte:head>という独自タグを使う
  • 地味にフレームワークごとに書き方が違って面白い点だと思う
<script lang="ts">
   export let title: string;
</script>

<svelte:head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <link rel="icon" type="image/svg+xml" href="/mylogo.ico" />
    <meta name="description" content="=まなさすが作ったツール集" />
    <meta property="og:site_name" content="manasandbox" />
    <meta property="og:title" content={title} />
    <meta property="og:url" content="https://tools.manasas.dev" />
    <meta property="og:description" content="まなさすが作ったツール集" />
    <meta property="og:image" content="https://tools.manasas.dev/aza166.png" />
    <title>{title}</title>
</svelte:head>

<body>
    <header>
        <h1><a href="/">Mana's tools</a></h1>
    </header>
    <main>
        <slot />
    </main>
    <footer><a href="https://manasas.dev/" rel="me">© 2022 Manami SASAKI</a></footer>
</body>
  • app.html%sveltekit.head%に反映されるのだろうな、と思う
    • app.htmlが存在するフレームワークもなんか珍しい気がする。Next.jsやastroはこういう類はないのでなんか懐かしい印象がある。
<!DOCTYPE html>
<html lang="ja">
    <head>
       <meta charset="utf-8" />
       <link rel="icon" href="%sveltekit.assets%/mylogo.ico" />
       <meta name="viewport" content="width=device-width" />
       %sveltekit.head%
   </head>
    <body data-sveltekit-preload-data="hover">
        <div style="display: contents">%sveltekit.body%</div>
    </body>
</html>

学習用コンテンツ

  • Svelteは公式から下記のような書き換えて実行して学べるサンプルがたくさん用意されていて学びやすい
  • REPLという『コード片を実行できる仕組み』らしい。プログラミング入門にはかなりよさそう。
  • Svelteの公式、ちょっと重くて中々遷移できない時があるのは私だけだろうか。

おわりに

  • lessさは確かなのでプロトタイプにはかなり良さそう
  • 先の通りjsからCSSに渡すのはやや面倒なので、jsとcssが密接な場合は別フレームワークを検討した方が良さそう
  • 本番プロダクトに使うかは自分はまだちょっと保留。

Next.js(app directory)でMarkdownを読み込む

やりたいこと

  • Next.jsのapp directoryモードで.mdファイルを読み込んでページの途中に表示するやつをやりたい

やり方

  • 公式にもやり方は書いてある
  • ただし上記の方法はapp directoryでは使えないのでapp dirへの移行方法を参考に改変
  • おおざっぱにいうとgetStaticPropsは不要になって、React Component自体をasyncにしてgetStaticPropsに詰めてたものはReact Component内でawaitで呼んでよくなった
  • 他は既存に同じ

  • インストール

npm install remark remark-html gray-matter
  • 実装
import styles from './page.module.scss'
import { remark } from 'remark'
import html from 'remark-html'
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'

const getMdData = async () => {
  const fullPath = path.join('./src/app/', 'content.md')
  const fileContents = fs.readFileSync(fullPath, 'utf8')

  const matterResult = matter(fileContents)

  const processedContent = await remark()
    .use(html)
    .process(matterResult.content)
  const contentHtml = processedContent.toString()

  return {
    fullPath,
    contentHtml,
    ...matterResult.data,
  }
}

const Home = async () => {
  const contentData = await getMdData()
  return (
    <main>
        <div dangerouslySetInnerHTML={{ __html: contentData.contentHtml }} />
    </main>
  )
}

export default Home

つぶやき

  • 今までの感覚からするとそこでasync/awaitしていいんすか!?って感じがあるが、確かにこの方がシンプルでいいかも
  • 脳死でやるとReact Componentのロジック部がすぐ肥大化しそうなのでガッツリ作るプロダクトではGETは別ファイルに記載とかにした方が良さそう
  • app directory、思ったより大きな変更っぽいのでもうちょっとちゃんとキャッチアップしようと思った
    • 名前の響き的に大きな変更だと思ってなかった、名前で判断してはいかんね