個人開発のWEBサービスをどこにホスティングするか(本番環境はどこのサーバを借りてデプロイするか)
WSL2でNode.jsの環境構築・npmのインストール
「nvm」と「n」の2種類のインストール方法がある。
GitHubのスター数で勝り、Microsoft公式で推奨されている「nvm」の手順を記載する。
前提:WSL2を使用可能なこと takaittakait.hatenablog.com
# インストールするパッケージ一覧を更新 sudo apt update sudo apt install -y curl # nvmをインストール curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bas # nodejsとnpmをインストール nvm install --lts npm --version # yarnをインストール curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list sudo apt install -y yarn
WSL2にGoをインストールする。またはバージョンアップする。
WSL2環境で、Goをインストールして、プロジェクトを作り、実行するところまで行います。
既にインストール済みでバージョンアップしたい場合にも、同じ方法が使えます。
公式のインストール手順はこちら
既存のGoを削除
既にインストール済みならこちらから実施してください。
sudo rm -rf /usr/local/go
既存のGoファイルが別のパスにある場合は、そのパスを指定する必要があります。
どのパスにあるか分からない場合は、下のコマンドで探しましょう。
which go
Goインストーラーをダウンロード
sudo wget https://go.dev/dl/go1.18.linux-amd64.tar.gz
1.18
の部分でGoのバージョンを指定します。
最新のバージョンをダウンロードしたい場合は、公式の「Download Go for Linux」のリンクアドレスをコピーしましょう。
Goインストーラーを解凍して実行
sudo tar -C /usr/local -xzf go1.18.linux-amd64.tar.gz
こちらも、ダウンロードしたインストーラーのバージョンを指定するようにしましょう。
Goインストーラーを削除
コマンドじゃなくてもOKです。
sudo rm go1.18.linux-amd64.tar.gz
Goを環境変数に追加
ホームディレクトリ配下の.profile
のPATHに追加します。
PATH=$PATH:/usr/local/go/bin export PATH
以下のコマンドを打ち反映させます。
source ~/.profile
Goがインストールできたか確認
go version
WSL2でDockerを利用する + redisをDockerで起動する方法
Dockerをインストール
sudo apt update sudo apt upgrade sudo apt install docker.io
Dockerを起動
sudo dockerd
redisを起動
sudo docker run --name redis -d -p 6379:6379 redis-server --appendonly yes
redisを操作する
docker exec -it redis bash
execでコンテナのbashに入ったら、このコマンドを入力します。
redis-cli
以降はredisの操作です。データ型によって使えるコマンドは異なります。
keys * get key1 hgetall key1
redis操作を終了します。
exit
コンテナ内での操作を終了します。
exit
Dockerを終了
Ctrl + C
Go言語入門 - 変数
Go言語入門のうち、変数についてまとめています。
Goの公式仕様はこちらに載っています。 https://go.dev/ref/spec
変数とは
変数は、ある型1つと、それに合った値1つを保持するものです。
例えばstring型の変数は、文字列である"a"を保持できます。逆に、数字の1などを保持することはできません。
宣言
基本的には、関数内で変数の宣言を行います。
main.go例
package main import "fmt" func main() { s := "a" fmt.Println(s) }
宣言の方法はいくつかあるので、次はそれを挙げていきます。
変数名 := 値
最も使うパターンです。
上のmain.go例で使っているのもこれです。
宣言と代入を行っていて、最もシンプルに書けます。
型名が省略されていますが、型は値から自動で推測されます。
- 値が
""
で囲まれている(=値が文字列) → string型 - 値が数字 → int型
- 値が
true
またはfalse
→ bool型
右辺が値ではなく、変数名 := 関数名(引数)
というパターンもあります。この場合は、関数の宣言で値の型が決まっています。
var 変数名 型名
例
var s string
このパターンのように初期値の無い宣言を行うと、値には型のゼロ値が入ります。
型によってゼロ値は異なり、string型は""(=空文字)、int型は0です。
var 変数名 型名 = 値
var s string = "a"
var 変数名 = 値
var s = "a"
複数の変数を宣言
s, t := "a", "b" var s, t string var s, t string = "a", "b" var s,t = "a", "b" var ( s string t = "a" )
Next.jsでコードブロックにシンタックスハイライトで色を付ける
編集対象ファイルの全コード
シンタックスハイライトを付ける上で変更するのは、root/pages/blog/[id].tsxファイルのみです。最初に、このファイルの例を貼っています。
import { client } from "../../libs/client"; import type { Article } from '../../types/article'; import styles from '../../styles/Home.module.css' import Head from 'next/head' import cheerio from 'cheerio'; import hljs from 'highlight.js'; import 'highlight.js/styles/night-owl.css'; import {endpoint} from '../index' type props = { article: Article, highlightedBody:string, tableOfContents:content[] }; type content = { text: string; id: string; name: string; } export default function BlogId({article, highlightedBody, tableOfContents}:props) { return ( <div className={styles.container}> <Head> <title>{article.title}</title> <meta name="description" content={article.description} /> <link rel="icon" href="/favicon.ico" /> </Head> <main className={styles.postmain}> <h1 className={styles.title}>{article.title}</h1> <div className={styles.toc}> <h4>目次</h4> <ul id="lists"> {tableOfContents.map(content => { if (content.name == "h2"){ return <li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li> }else if (content.name=="h3"){ return <ul><li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li></ul> }else if (content.name=="h4"){ return <ul><ul><li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li></ul></ul> } })} </ul> </div> <div className={styles.post} dangerouslySetInnerHTML={{__html: highlightedBody}}/> </main> </div> ); } // パス指定 export const getStaticPaths = async () => { const data = await client.get({ endpoint: endpoint }); const articles: Article[] = data.contents; const paths = articles.map((content) => `/`+endpoint+`/${content.id}`); return { paths, fallback: false }; }; // データをテンプレートに受け渡す export const getStaticProps = async (context: any) => { const id = context.params.id; const res:Article = await client.get({ endpoint: endpoint, contentId: id }); // autoでシンタックスハイライトを付ける const $ = cheerio.load(res.body) $('pre code').each((_, elm) => { const result = hljs.highlightAuto($(elm).text()) $(elm).html(result.value) $(elm).addClass('hljs') }) const headings = $('h2, h3, h4').toArray() const toc:content[] = headings.map((data) => { return { //@ts-ignore text: String(data.children[0].data), id: data.attribs.id, name: data.name, } }) return { props: { article:res, highlightedBody:$.html(), tableOfContents:toc }, } };
各処理の紹介
ハイライト付HTMLの作成
getStaticProps内で、ハイライトされたHTMLを作成します。
const $ = cheerio.load(res.body) $('pre code').each((_, elm) => { const result = hljs.highlightAuto($(elm).text()) $(elm).html(result.value) $(elm).addClass('hljs') }) return { props: { article:res, highlightedBody:$.html(), tableOfContents:toc }, }
今回は言語を指定せず、オートで言語を判断させています。
$.html()がHTML要素になるので、これを引数として渡せばOKです。
ハイライト付HTMLの表示
export default function XXX の中に記載します。
export default function BlogId({article, highlightedBody, tableOfContents}:props) { return ( <div className={styles.container}> // 省略 <div className={styles.post} dangerouslySetInnerHTML={{__html: highlightedBody}}/>
まず、引数でハイライト付HTML(例のhighlightedBody)を受け取ります。
これを表示するのに変更が必要な箇所は、例の最後の行のように、ハイライト済みのHTML要素を指定するところだけです。
Next.js×TypeScript×microCMSで目次を作成する
Next.js×TypeScript×microCMSで目次を作成する方法をご紹介します。
例 : https://tkblog.netlify.app/blog/asbz5h_mr1h
目次を追加したい場合は、ブログの個別記事に当たるtsxファイルに記述します。
この記事の例では、/pages/blog/[id].tsxのコードを貼っています。
インストール
コマンドでcheerioをインストールします。
yarn add cheerio
これでインポートが可能になります。
import cheerio from 'cheerio';
getStaticProps
const headings = $('h2, h3, h4').toArray() const toc:content[] = headings.map((data) => { return { //@ts-ignore text: String(data.children[0].data), id: data.attribs.id, name: data.name, } })
$('h2, h3, h4').toArray()
のように、$()
内に目次として抽出したい要素をカンマ区切りで指定します。
各要素をどのように表示するかはdefault
関数で制御します。
text
には表示されるテキストが入ります。h2
などのタグに挟まれるテキストのことです。
id
には自動生成のidが入ります。
name
にはh2
やh3
などが入ります。
HTML
<ul id="lists"> {tableOfContents.map(content => { if (content.name == "h2"){ return <li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li> }else if (content.name=="h3"){ return <ul><li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li></ul> }else if (content.name=="h4"){ return <ul><ul><li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li></ul></ul> } })} </ul>
簡略化すると、{tableOfContents.map(content => {return HTML要素}
です。
例の様に配列.map
とするとループ処理になり、content
に各要素が入ります。
(content, index)
と書けばindexも利用できます。
h2,h3,h4で目次を入れ子にしたかったので、ulタグの中にulタグを入れています。
初心者がNext.js×TypeScript×microCMSでブログ作成
JavaScriptもNext.jsもTypeScriptもmicroCMSも初心者の私が、これらを組み合わせてブログを作成してみました。
ブログのリンク : https://tkblog.netlify.app/
ベースはmicroCMS公式ページ(https://blog.microcms.io/microcms-next-jamstack-blog/)に載っています。
しかし公式の例はTypeScriptではないので、いくつか変更を加えました。
他に追加した機能もあり記事内のコード例に含まれているのですが、それらについては別記事で紹介しようと思っています。
Next.jsのインストールまでは別記事で書いています。
takaittakait.hatenablog.com
目次
個別記事オブジェクトの型を定義
記事オブジェクトの型を定義するために、新たにファイルを作成しました。
root/types/article.ts
export type Article = { id: string createdAt: string updatedAt: string publishedAt: string revisedAt: string description: string title: string body: string eye_catch: { url: string } tag: string }
各フィールドの名前と型は、microCMSのAPIと合わせる必要があります。
記事一覧ページの中身を変更
root/papes/index.tsx
import Head from 'next/head' import Image from 'next/image' import Link from 'next/link' import React from 'react' import { client } from '../libs/client' import type { Article } from '../types/article' import styles from '../styles/Home.module.css' type props = { articles: Article[] }; export default function Home({ articles }: props) { return ( <div className={styles.container}> <Head> <title>記事一覧</title> <meta name="description" content="Next.jsでブログ作成" /> <link rel="icon" href="/favicon.ico" /> </Head> <main className={styles.indexmain}> <h1 className={styles.title}>記事一覧</h1> <div className={styles.grid}> {articles.map(article => ( <div key={article.id} className={styles.card}> <Link href={`/blog/${article.id}`}><a className=""> <Image className={styles.thumbnail} src={article.eye_catch.url || ''} width={600} height={400} alt={article.eye_catch.url}></Image> <p>{article.title}</p> </a></Link> </div> ))} </div> </main> </div> ); } export const getStaticProps = async () => { const data = await client.get({ endpoint: 'blog' }) return { props: { articles: data.contents, }, } }
ファイル名はindex.tsx
で固定です。これからこのファイル内の各処理について解説していきます。
型をインポート
import type { Article } from '../types/article'
先程作成したArticle型をインポートしています。
他のimport行は全て既存のもののインポートなので、書くだけで使えるはずです。
getStaticProps関数
export const getStaticProps = async () => { const data = await client.get({ endpoint: 'blog' }) return { props: { articles: data.contents, }, } }
順番が前後してしまいますが、getStaticProps
からご紹介します。
この関数を利用すると、ビルド時にデータを取得し、静的なHTMLを出力できます。リクエストが来る度にいちいちページ生成を行わないので、レスポンスが高速です。
endpoint
にはmicroCMSのAPIのエンドポイントを入れましょう。これでビルド時にmicroCMSのAPIにリクエストして、記事一覧を取得するようになります。
props
はリクエストして受けとったデータそのものです。フィールドのarticles
に、データに含まれる記事配列を入れています。このフィールド名articles
は後の手順で名前を合わせないといけないので注意が必要です。
Home関数
type props = { articles: Article[] }; export default function Home({ articles }: props) { return ( <div>sample</div> ); }
ここで新たな型を定義しています。props
型のフィールドarticles
は、getStaticProps
内で指定したフィールド名と合わせなければいけません。
Home
関数のexport
は恐らくJavaで言うpublicです。
Home{}の{}内で引数の設定をしています。
この例ではprops
オブジェクトを引数で受け取り、そのフィールドarticles
を引数内で利用する、という設定です。
関数だと、sampleFunc (name :string):string
というような書き方がより一般的なのかなと思います。
(引数名:引数の型):戻り値の型
という形式です。
default
が付いた関数はJSX.Element
型(≒HTML要素?)を返します。なのでreturn();
内に記事一覧ページのHTML要素を記述します。
個別記事ページを作成
root/pages/blog/[id].tsx
import { client } from "../../libs/client"; import styles from '../../styles/Home.module.css' import Head from 'next/head' import type { Article } from '../../types/article'; type props = { article: Article, }; export default function BlogId({article}:props) { return ( <div className={styles.container}> <Head> <title>{article.title}</title> <meta name="description" content={article.description} /> <link rel="icon" href="/favicon.ico" /> </Head> <main className={styles.postmain}> <h1 className={styles.title}>{article.title}</h1> <div className={styles.post} dangerouslySetInnerHTML={{__html: article.body}}/> </main> </div> ); } // パス指定 export const getStaticPaths = async () => { const data = await client.get({ endpoint: "blog" }); const articles: Article[] = data.contents; const paths = articles.map((content) => `/blog/${content.id}`); return { paths, fallback: false }; }; // データをテンプレートに受け渡す export const getStaticProps = async (context: any) => { const id = context.params.id; const res:Article = await client.get({ endpoint: "blog", contentId: id }); return { props: { article:res }, } };
また順番が前後しますが、getStaticPaths
→getStaticProps
→BlogId
の順で見ていきます。
getStaticPaths
// パス指定 export const getStaticPaths = async () => { const data = await client.get({ endpoint: "blog" }); const articles: Article[] = data.contents; const paths = articles.map((content) => `/blog/${content.id}`); return { paths, fallback: false }; };
名前通り、固定記事パスを指定しています。blog
はmicroCMSのAPIのエンドポイント、content.id
が各記事の識別子です。
getStaticProps
// データをテンプレートに受け渡す export const getStaticProps = async (context: any) => { const id = context.params.id; const res:Article = await client.get({ endpoint: "blog", contentId: id }); return { props: { article:res }, } };
BlogId(defaultの関数)
export default function BlogId({article}:props) { return ( <div className={styles.container}> <Head> <title>{article.title}</title> <meta name="description" content={article.description} /> <link rel="icon" href="/favicon.ico" /> </Head> <main className={styles.postmain}> <h1 className={styles.title}>{article.title}</h1> <div className={styles.post} dangerouslySetInnerHTML={{__html: article.body}}/> </main> </div> ); }
index.tsxのdefault
関数とほぼ同じ構造です。
<div className={styles.post} dangerouslySetInnerHTML={{__html: article.body}}/>
で、個別記事のHTML要素をテンプレート内に入れています。
WSL2でNext.jsの環境構築とアプリケーション作成
wsl2環境で、0からNext.jsの環境構築とアプリケーションの作成まで行う方法をご紹介します。コマンドはそのままコピー&ペーストして使えるようになっているはずです。
npmとyarnをインストール
Next.jsアプリケーションを作成
TypeScriptを用いたい場合は、コマンドのオプションに--ts
を追加 します。
npx create-next-app app-name
Windows10でWSL2(Ubuntu)をインストールし、Linux開発環境を構築する方法
Windows10でLinux開発環境を構築する方法を紹介します。
コマンドは全てコピペできるように書いています。
目次
WSL2をインストールする
コマンドプロンプトを管理者権限で開く
検索バーにcmd
を入力すれば、コマンドプロンプトが表示されます。
それから管理者として実行
をクリックします。
WSL2をインストールするコマンドを入力する
wsl --install
PCを再起動する
私の場合は、上記コマンドを実行し再起動した後、アプリ一覧にUbuntuが追加されました。
Ubuntuを起動する
上の手順が完了していれば、アプリ一覧にUbuntuが追加されるので、そちらを開きます。
Ubuntuの初回起動時は、ユーザー名とパスワードを設定しなければいけません。
次回以降にこのセットが必要なので、忘れないようにメモしましょう。
Visual Studio Codeの設定をする
Visual Studio Codeをインストールする。
コードエディタとしてVisual Studio Code(以下 VSCode)をインストールします。
インストールは下記の公式リンクから行ってください。
Visual Studio Code – コード エディター | Microsoft Azure
VSCodeからWSL2環境に接続する
VSCodeの拡張機能「Remote-WSL」をインストールしてください。
左下緑色の枠内をクリックし、「Open folder in WSL」を選択します。
これで、VSCodeを用いてWSL2環境で開発できるようになります。
以降はVSのCodeターミナルにコマンドを入力することになります。
もしそこでコマンドが権限で弾かれた場合は、頭にsudo
を付けて実行してください。
ここで必要なパスワードが、Ubuntu初回起動時に設定したパスワードです。