moyashidaisuke's diary

フリーランスのエンジニアのダイスケです。プログラム関連とかギター関連とか旅行関連とか色々。

個人ブログをはてなブログから Gatsby + Netify に移行した

モチベーション

  • 技術系、旅行系と記事の幅が広いので、もう少しカスタマイズしたい
  • wordpressは宗教的理由で使わない
  • せっかくだしナウい系の技術を触るようにしたい
  • はてなブログちょっと遅いよね
  • まあまあ時間かけてるので、そろそろ少しはマネタイズできるように独自ドメインにしたりしたい(ガチではやらないです。ついで程度)

採用技術

というわけで、チュートリアルで良さげだったのでGatsbyjsにします。 moyashidaisuke.hatenablog.com

vue.jsの方が馴染んでるんだけど、なんだかんだReactの方がメジャーなのである程度やっておきたいなーと。

サーバはNetlifyにします。Firebaseでも全然良いのですが、Netlifyの方が前から興味あったので、というだけの理由です。なんか合わなかったらFirebaseに移行します。

techblog.kayac.com

あと、Contentfulとの組み合わせも流行ってるようですが、記事をGit管理したいのと、今回はカスタマイズ性を求めてるので使わない方針で。

www.contentful.com

方針

  • 立ち上げ優先で
    • やり始めるときりないので、さっさと運用初めて、カスタマイズは後でやる
    • デザインも最小限で
  • はてなブログに書いた記事は移行する
  • ドメインはとる

はてなブログのエクスポート

blog.cheezenaan.net

motemen.hatenablog.com

macなのでbrewで

 brew install Songmu/tap/blogsync

適当なディレクトリを作って設定ファイル書く

blogsync.yaml

moyashidaisuke.hatenablog.com:
  username: moyashidaisuke
  password: 秘密
default:
  local_root: 適当なディレクトリ

実行

blogsync pull moyashidaisuke.hatenablog.com

できました。

ファイルはマークダウン形式なのでこのまま使えそう。

f:id:moyashidaisuke:20190430182340p:plain

あっさり完了。

テンプレから初期セットアップ

環境セットアップ

チュートリアルで作ったdockerを流用。 さっくりいくと思いきや、後述の「雛形(template作成)」のところでエラーがでまくって試行錯誤した結果がこちら。

docker-compose.yml

version: '3'
services:
  node:
    build: node
    tty: true
    volumes:
    - ./node:/node:cached # cachedつけると早い
    ports:
    - "8000:8000"

Dockerfile

# ベースイメージを指定
FROM node:10-alpine

# node.js の環境変数を定義する
# 本番環境では production
ENV NODE_ENV=development

RUN apk add git curl python make g++ autoconf automake libtool nasm

# http://sharp.pixelplumbing.com/en/stable/install/
RUN apk add vips-dev fftw-dev build-base --update-cache \
    --repository https://alpine.global.ssl.fastly.net/alpine/edge/testing/ \
    --repository https://alpine.global.ssl.fastly.net/alpine/edge/main



RUN npm install -g gatsby-cli


# ディレクトリを移動する
#WORKDIR /blog


# ポート8000番を開放する
EXPOSE 8000

雛形(template作成)

これにしました。

www.gatsbyjs.org

github.com

gatsby new  blog https://github.com/greglobinski/gatsby-starter-hero-blog.git

yarn か npm か聞かれるので、npmにする(yarnだと動かなかった) ついでのnodeのバージョンも12だと動かなかった。

最後にgitのcommitまでしようとしてくれてエラーになるが、gitのコミットはhost側でやるので無視してOK

fatal: unable to auto-detect email address (got 'root@0ebab49be50e.(none)')



  Error: Command failed: git commit -m "Initial commit from gatsby: (https://github.com/greg  lobinski/gatsby-starter-hero-blog.git)"
  *** Please tell me who you are.
  Run
    git config --global user.email "you@example.com"
    git config --global user.name "Your Name"
  to set your account's default identity.
  Omit --global to set the identity only in this repository.
  fatal: unable to auto-detect email address (got 'root@0ebab49be50e.(none)')

起動

 gatsby develop -H 0.0.0.0

queries/secondSegmentation fault というエラーが出てしまうのだが何回かリトライすると動く。

ブラウザで localhost:8000 を叩いて画面が出ればOK。長かった、、、

f:id:moyashidaisuke:20190501200208p:plain

とりあえず公開

www.gatsbyjs.org

「Try this starter」 Netlifyのリンクがあるのでそちらから。

指示に従って進める

GitHub認証して、

f:id:moyashidaisuke:20190502124918p:plain

リポジトリ名いれてSave & デプロイ f:id:moyashidaisuke:20190502125041p:plain

デプロイ完了した事になってるが、実際にはまだ見られない。 ビルドコマンドやpathの設定がされてないので。 f:id:moyashidaisuke:20190502125019p:plain

というわけで設定してく

Gatsby用の設定の仕方がhelpに書いてあるので指示に従う

www.netlify.com

よく見たらあたしく作られたリポジトリにリンクされてしまっていたので(謎)、リポジトリの設定変更もした

f:id:moyashidaisuke:20190502130532p:plain

デプロイするとエラー発生

11:07:26 AM: error Plugin gatsby-plugin-algolia returned an error
11:07:26 AM: 
11:07:26 AM:   AlgoliaSearchError: Please provide an application ID. Usage: algoliasearch(app  licationID, apiKey, opts)

github.com

テンプレートのREADMEをよく読むと、ALGOLIAという外部サービスを使う前提になっているようなので、登録する。

Algoliaについてはこちら。

blog.leko.jp

READMEにブログへのリンクがある。

dev.greglobinski.com

なんかだいぶ画面が違ったけど、雰囲気で選ぶ(すいませんキャプチャ取り忘れ、、、)

必要なのはこの4つのパラメータ

ALGOLIA_APP_ID=... 
ALGOLIA_SEARCH_ONLY_API_KEY=...
ALGOLIA_ADMIN_API_KEY=...
ALGOLIA_INDEX_NAME=...

上の3つは「API Keys」メニューにある。「ALGOLIA_INDEX_NAME」は自分でIndex作成する時に指定したやつ。

.envをコミットしろ的な説明もあるんだけど、それは乱暴なのでNetlifyのenv機能を使って設定する。

f:id:moyashidaisuke:20190502132409p:plain

成功!

11:23:29 AM: Build ready to start
11:23:35 AM: build-image version: d5d16c91ca3e1e5a990086daa8a1d5bd8564d12a
11:23:35 AM: build-image tag: v3.2.2
11:23:35 AM: buildbot version: 93c10be3dc42bccef2b5600a7e10ec1d4a1c7051
11:23:36 AM: Fetching cached dependencies
11:23:36 AM: Failed to fetch cache, continuing with build
11:23:36 AM: Starting to prepare the repo for build
11:23:36 AM: No cached dependencies found. Cloning fresh repo
11:23:36 AM: git clone https://github.com/daisuke-fukuda/gatsbyjs-blog
11:23:37 AM: Preparing Git Reference refs/heads/master
11:23:38 AM: Starting build script
11:23:38 AM: Installing dependencies
11:23:40 AM: v10.15.3 is already installed.
11:23:41 AM: Now using node v10.15.3 (npm v6.4.1)
11:23:41 AM: Attempting ruby version 2.6.2, read from environment
11:23:42 AM: Using ruby version 2.6.2
11:23:43 AM: Using PHP version 5.6
11:23:43 AM: Started restoring cached node modules
11:23:43 AM: Finished restoring cached node modules
11:23:43 AM: Installing NPM modules using NPM version 6.4.1
11:24:36 AM: > deasync@0.1.14 install /opt/build/repo/node/blog/node_modules/deasync
11:24:36 AM: > node ./build.js
11:24:37 AM: `linux-x64-node-10` exists; testing
11:24:37 AM: Binary is fine; exiting
11:24:37 AM: > sharp@0.21.3 install /opt/build/repo/node/blog/node_modules/sharp
11:24:37 AM: > (node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)
11:24:38 AM: info
11:24:38 AM: sharp Downloading https://github.com/lovell/sharp-libvips/releases/download/v8.7.0/libvips-8.7.0-linux-x64.tar.gz
11:24:41 AM: > gatsby-telemetry@1.0.9 postinstall /opt/build/repo/node/blog/node_modules/gatsby-telemetry
11:24:41 AM: > node src/postinstall.js
11:24:41 AM: > cwebp-bin@5.0.0 postinstall /opt/build/repo/node/blog/node_modules/cwebp-bin
11:24:41 AM: > node lib/install.js
11:24:41 AM:   ✔ cwebp pre-build test passed successfully
11:24:41 AM: > mozjpeg@6.0.1 postinstall /opt/build/repo/node/blog/node_modules/mozjpeg
11:24:41 AM: > node lib/install.js
11:24:42 AM:   ✔ mozjpeg pre-build test passed successfully
11:24:42 AM: > pngquant-bin@5.0.2 postinstall /opt/build/repo/node/blog/node_modules/pngquant-bin
11:24:42 AM: > node lib/install.js
11:24:43 AM:   ✔ pngquant pre-build test passed successfully
11:24:47 AM: npm
11:24:47 AM: WARN gatsby-starter-hero-blog@2.0.0 No repository field.
11:24:47 AM: npm
11:24:47 AM: WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.9 (node_modules/fsevents):
11:24:47 AM: npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.9: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
11:24:47 AM: added 2612 packages from 1405 contributors and audited 43643 packages in 63.028s
11:24:47 AM: found 2 vulnerabilities (1 low, 1 moderate)
11:24:47 AM:   run `npm audit fix` to fix them, or `npm audit` for details
11:24:47 AM: NPM modules installed
11:24:47 AM: Started restoring cached go cache
11:24:47 AM: Finished restoring cached go cache
11:24:47 AM: unset GOOS;
11:24:47 AM: unset GOARCH;
11:24:47 AM: export GOROOT='/opt/buildhome/.gimme/versions/go1.12.linux.amd64';
11:24:47 AM: export PATH="/opt/buildhome/.gimme/versions/go1.12.linux.amd64/bin:${PATH}";
11:24:47 AM: go version >&2;
11:24:47 AM: export GIMME_ENV='/opt/buildhome/.gimme/env/go1.12.linux.amd64.env';
11:24:47 AM: go version go1.12 linux/amd64
11:24:47 AM: Installing missing commands
11:24:47 AM: Verify run directory
11:24:47 AM: Executing user command: gatsby build
11:24:50 AM: success open and validate gatsby-configs — 0.029 s
11:24:52 AM: success load plugins — 1.305 s
11:24:52 AM: success onPreInit — 0.012 s
11:24:52 AM: success delete html and css files from previous builds — 0.010 s
11:24:52 AM: success initialize cache — 0.026 s
11:24:52 AM: success copy gatsby files — 0.025 s
11:24:52 AM: success onPreBootstrap — 0.008 s
11:24:52 AM: success source and transform nodes — 0.299 s
11:24:52 AM: success building schema — 0.394 s
11:24:52 AM: Using environment config: 'production'
11:24:53 AM: success createPages — 0.107 s
11:24:53 AM: success createPagesStatefully — 0.104 s
11:24:53 AM: success onPreExtractQueries — 0.004 s
11:24:53 AM: success update schema — 0.083 s
11:24:53 AM: success extract queries from components — 0.231 s
11:24:53 AM: success run static queries — 0.113 s — 1/1 8.96 queries/second
11:24:54 AM: warning code block or inline code language not specified in markdown. applying generic code block
11:25:02 AM: success run page queries — 8.551 s — 27/27 3.16 queries/second
11:25:02 AM: success write out page data — 0.004 s
11:25:02 AM: success write out redirect data — 0.001 s
11:25:46 AM: success Build manifest and related icons — 0.000 s
11:25:46 AM: success onPostBootstrap — 0.003 s
11:25:46 AM: info bootstrap finished - 58.174 s
11:26:26 AM: success Building production JavaScript and CSS bundles — 40.282 s
11:26:35 AM: success Building static HTML for pages — 8.901 s — 27/27 24.92 pages/second
11:26:46 AM: success index to Algolia — 10.743 s
11:26:46 AM: Generated public/sw.js, which will precache 10 files, totaling 443815 bytes.
11:26:46 AM: info Done building in 118.347 sec
11:26:46 AM: Build script success
11:26:46 AM: Starting cache prep script
11:26:46 AM: Caching artifacts
11:26:46 AM: Started saving node modules
11:26:46 AM: Finished saving node modules
11:26:46 AM: Started saving pip cache
11:26:46 AM: Finished saving pip cache
11:26:46 AM: Started saving emacs cask dependencies
11:26:46 AM: Finished saving emacs cask dependencies
11:26:46 AM: Started saving maven dependencies
11:26:46 AM: Finished saving maven dependencies
11:26:46 AM: Started saving boot dependencies
11:26:47 AM: Finished saving boot dependencies
11:26:47 AM: Started saving go dependencies
11:26:47 AM: Finished saving go dependencies
11:26:48 AM: Cache script success
11:26:48 AM: Starting to deploy site from 'node/blog/public'
11:26:48 AM: Creating deploy tree 
11:26:49 AM: 82 new files to upload
11:26:49 AM: 0 new functions to upload
11:26:53 AM: Starting post processing
11:26:57 AM: Post processing done
11:26:57 AM: Site is live
11:27:26 AM: Finished processing build request in 3m50.593483821s
11:27:26 AM: Shutting down logging, 0 messages pending

Netlifyが発行したドメインでアクセスすると動いてる!

f:id:moyashidaisuke:20190502132931p:plain

ドメイン設定する

ドメイン買う

まずはドメインを決めて買います。

お名前.com -> なぜか最後の申し込みでエラー(海外にいたから?

むーむー -> ユーザー登録でSMSが必要で登録できず(海外でデータ専用のSIMを使ってたので不可

さくら -> できた

というわけで、moyashidaisuke.com を買いました。

netlifyに設定する

www.ravness.com

Unless your DNS provider supports CNAME flattening, ANAME or ALIAS records for root domains, we strongly recommend setting the www subdomain as your primary domain. Our “To WWW or Not WWW” article has more details on why we recommend that configuration.

確かにwww付きをメインにすることを推奨してますね。

さくらの場合、whois情報の方から変更する事になるので注意が必要です。(1hくらいハマった、、、

きっかり24hくらいで、httpsの設定まで自動でされました。

諸々改修

dev.greglobinski.com

meta情報

/content/meta/config.js

module.exports = {
  siteTitle: "moyashidaisuke's diary", // <title>
  shortSiteTitle: "moyashidaisuke's diary", // <title> ending for posts and pages
  siteDescription: "平日はエンジニア、土日はミュージシャン(自称)のダイスケです。プログラム関連とかギター関連とかなんでも。\n",
  siteUrl: "https://www.moyashidaisuke.com",
  // pathPrefix: "",
  siteImage: "preview.jpg",
  siteLanguage: "ja",

  /* author */
  authorName: "moyashidaisuke",
  authorTwitterAccount: "moyashidaisuke",

  /* info */
  headerTitle: "moyashidaisuke's diary",
  headerSubTitle: "moyashidaisuke's diary",

  /* manifest.json */
  manifestName: "moyashidaisuke's diary",
  manifestShortName: "moyashidaisuke", // max 12 characters
  manifestStartUrl: "/index.html",
  manifestBackgroundColor: "white",
  manifestThemeColor: "#666",
  manifestDisplay: "standalone",

  // gravatar
  // Use your Gravatar image. If empty then will use src/images/jpg/avatar.jpg
  // Replace your email adress with md5-code.
  // Example https://www.gravatar.com/avatar/g.strainovic@gmail.com ->
  // gravatarImgMd5: "https://www.gravatar.com/avatar/1db853e4df386e8f699e4b35505dd8c6",
  gravatarImgMd5: "https://www.gravatar.com/avatar/3b0446884fc47b25b4bc2c8b06f97a24",

  // social
  authorSocialLinks: [
    { name: "github", url: "https://github.com/guitaristdaisuke" },
    { name: "twitter", url: "https://twitter.com/moyashidaisuke" },
    { name: "facebook", url: "http://facebook.com/moyashidaisuke" }
  ]
};

いらないページ削除

content/pages にある不要ページを削除(勝手にヘッダーからも削除されます)

 deleted:    node/blog/content/pages/2--starters/gatsby-starter-personal-blog.png
    deleted:    node/blog/content/pages/2--starters/gatsby-starter-simple-landing.png
    deleted:    node/blog/content/pages/2--starters/index.md
    deleted:    node/blog/content/pages/3--front-end-dev/index.md
    deleted:    node/blog/content/pages/4--privacy/index.md
    deleted:    node/blog/content/pages/5--terms/index.md
    deleted:    node/blog/content/posts/draft-post/index.md
    deleted:    node/blog/content/posts/draft-post/photo-1490474418585-ba9bad8fd0ea.jpg

デモのテキストを修正

英語で色々書いてあるので適当に削除

 node/blog/content/pages/1--about/index.md | 24 +++---------------------
 node/blog/content/parts/footnote.md       |  7 +------
 node/blog/src/components/Hero/Hero.js     |  3 ++-

過去記事いれる

フォルダ名、ファイル名の形式をあわせる必要があります。

2017-10-01--two-things-are-infinite/index.md

※日付の後がページのURLになるようです。

はてなのURL https://moyashidaisuke.hatenablog.com/entry/2019/04/30/172151

新URL https://www.moyashidaisuke.com/172151

こんな感じにしようと思います。

blogsyncで取得したファイルは、

年/月/日/{id}.md 年月日/{id}.md

が混在しています。多分、はてなブログの前にはてなダイアリーで書いてたものがあるからだと思います。

年月日/{id}.md (はてなダイアリー形式)

数も多くないいので手動で対応します。 ファイル名とフォルダ名はちまちまやります。

ヘッダーにcover(サムネ)が無いとエラーになるので、dummyを設定します。ついでにauthorも設定

cover: dummy.jpg
author: moyashidaisuke

Title -> titleに置換します

title: HerokuでPlay!を動かす その1

とりあえずこれで表示されます。カテゴリーとか動いてないけど後で。

f:id:moyashidaisuke:20190502170723p:plain

年/月/日/{id}.md(はてなブログ形式)

適当スクリプト作ってフォルダ名とファイル名をformat

<?php


$serch_dir = dirname(__FILE__) .'/moyashidaisuke.hatenablog.com/entry';

$files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($serch_dir,
        FilesystemIterator::CURRENT_AS_FILEINFO |
        FilesystemIterator::KEY_AS_PATHNAME |
        FilesystemIterator::SKIP_DOTS
    ),
    RecursiveIteratorIterator::SELF_FIRST
);

foreach($files as $path => $info) {
//    echo 'file path : '. $path              .PHP_EOL;
//    echo 'file size : '. $info->getSize()   .PHP_EOL;

    if ($info->isFile()) {
      $relativePath = str_replace($serch_dir. '/', '', $path);

      $dirs = explode('/', $relativePath);

      if (sizeof($dirs) != 4) {
        echo 'なんか形式が違う'. $path;
        continue;
      }

      if (pathinfo($path, PATHINFO_EXTENSION) != 'md') {
          echo 'なんか形式が違う'. $path;
          continue;
      }

      $newDir = $serch_dir.'/../'. $dirs[0].'-'.$dirs[1].'-'.$dirs[2].'--'.str_replace('.md', '', $dirs[3]);
      echo $newDir;


      mkdir($newDir, 0766, true);
      copy($path, $newDir.'/index.md');


      // dummy画像配置
      copy('./dummy.jpg', $newDir.'/dummy.jpg');

    }
    echo PHP_EOL;
}

あとは一緒。

なぜか TypeError: Cannot read property 'slug' of null というエラーが発生したが、gatsbyjsを再起動したらちゃんと読み込まれました。

あと、はてなブログで下書きのものもエクスポートされてるので、公開しちゃわないように注意( Draft: true となっています)。draft-post の下に移動しておきましょう。

色々表示は崩れますが、一応表示はされるようになりました。

※後で気がついたけど、{id} はidじゃなくて、時分秒なんですね、、、yyyymmddhhmiss形式にしておいた方がよかった、、、

Algoliaきる

過去記事をデプロイしようとしたところ、以下のエラーが発生。

 11:51:33 AM:   AlgoliaSearchError: Record at the position 152 objectID=/181521/0 is too big s  ize=11401 bytes. Contact us if you need an extended quota

www.algolia.com

そんな大きな記事じゃないんだけど、、、、そんな検索にニーズがあるとは思えないので機能を削ることに。

gatsby-config.jsの gatsby-plugin-algoliaのブロックを削って、pages/search.jsを削除すればOK

はてなブログからのforward設定

【SEO的にもOK】はてなブログでリダイレクト設定をする方法【JSリダイレクト】 | ナオユネット

↑はwordpressへの設定方法になっていますが、jsでごりっとやるのであれば今回も使えるはず、、、

というわけでjs書いていきます。

https://moyashidaisuke.hatenablog.com/entry/2019/04/29/225844

https://www.moyashidaisuke.com/225844

https://moyashidaisuke.hatenablog.com/entry/20120903/1346672014

https://www.moyashidaisuke.com/1346672014

になれば良いので、pathの最後のブロックだけ活かせばOK

<script>
   var newDomain = "https://www.moyashidaisuke.com"; // 新URL
  var replacedStr;
  var path = location.pathname;

  if(path.startsWith('\/entry')){ //記事ページの時

    // pathを/区切りで分解
    var ary = path.split('/');

    // 最後のブロックをidとして使う
    replacedStr = '/' + ary[ary.length - 1];

  } else {
      replacedStr = '';
  }

  var url = newDomain + replacedStr;

  // check
  console.log(url);


  var link = document.getElementsByTagName("link")[0];
      link.href = url;

  setTimeout("redirect()", 0); // 0秒後にジャンプ
  function redirect(){
      location.href = url;
  }
    
    
</script>

ブラウザで動作確認できればOK。 カテゴリはそもそも移行してないので無視。(pvもほとんど無いし)

まとめ

けっこう細かい調整が必要で思ったより時間かかりました、、、 というわけで、この記事を最後に次からは新しいブログの方だけ更新していく予定!

新しいブログはこちら。

www.moyashidaisuke.com

残タスク

  • カテゴリ
  • google analyticsとかseach console設定
  • はてな独自タグで書いてるやつの移行
    • 画像周り
    • リンク周り
    • Amazonへのリンク
  • アイコン設定
  • トップの画像変更
  • その他全体的にデザイン調整

参考

blog.cheezenaan.net

blog.mono0x.net