個人ブログをはてなブログから Gatsby + Netify に移行した
- モチベーション
- 採用技術
- 方針
- はてなブログのエクスポート
- テンプレから初期セットアップ
- とりあえず公開
- ドメイン設定する
- 諸々改修
- 過去記事いれる
- はてなブログからのforward設定
- まとめ
- 参考
モチベーション
- 技術系、旅行系と記事の幅が広いので、もう少しカスタマイズしたい
- wordpressは宗教的理由で使わない
- せっかくだしナウい系の技術を触るようにしたい
- はてなブログちょっと遅いよね
- まあまあ時間かけてるので、そろそろ少しはマネタイズできるように独自ドメインにしたりしたい(ガチではやらないです。ついで程度)
採用技術
というわけで、チュートリアルで良さげだったのでGatsbyjsにします。 moyashidaisuke.hatenablog.com
vue.jsの方が馴染んでるんだけど、なんだかんだReactの方がメジャーなのである程度やっておきたいなーと。
サーバはNetlifyにします。Firebaseでも全然良いのですが、Netlifyの方が前から興味あったので、というだけの理由です。なんか合わなかったらFirebaseに移行します。
あと、Contentfulとの組み合わせも流行ってるようですが、記事をGit管理したいのと、今回はカスタマイズ性を求めてるので使わない方針で。
方針
- 立ち上げ優先で
- やり始めるときりないので、さっさと運用初めて、カスタマイズは後でやる
- デザインも最小限で
- はてなブログに書いた記事は移行する
- ドメインはとる
はてなブログのエクスポート
macなのでbrewで
brew install Songmu/tap/blogsync
適当なディレクトリを作って設定ファイル書く
blogsync.yaml
moyashidaisuke.hatenablog.com: username: moyashidaisuke password: 秘密 default: local_root: 適当なディレクトリ
実行
blogsync pull moyashidaisuke.hatenablog.com
できました。
ファイルはマークダウン形式なのでこのまま使えそう。
あっさり完了。
テンプレから初期セットアップ
環境セットアップ
チュートリアルで作った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作成)
これにしました。
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。長かった、、、
とりあえず公開
「Try this starter」 Netlifyのリンクがあるのでそちらから。
指示に従って進める
GitHub認証して、
リポジトリ名いれてSave & デプロイ
デプロイ完了した事になってるが、実際にはまだ見られない。 ビルドコマンドやpathの設定がされてないので。
というわけで設定してく
Gatsby用の設定の仕方がhelpに書いてあるので指示に従う
よく見たらあたしく作られたリポジトリにリンクされてしまっていたので(謎)、リポジトリの設定変更もした
デプロイするとエラー発生
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)
テンプレートのREADMEをよく読むと、ALGOLIAという外部サービスを使う前提になっているようなので、登録する。
Algoliaについてはこちら。
READMEにブログへのリンクがある。
なんかだいぶ画面が違ったけど、雰囲気で選ぶ(すいませんキャプチャ取り忘れ、、、)
必要なのはこの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機能を使って設定する。
成功!
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が発行したドメインでアクセスすると動いてる!
ドメイン設定する
ドメイン買う
まずはドメインを決めて買います。
お名前.com -> なぜか最後の申し込みでエラー(海外にいたから?
むーむー -> ユーザー登録でSMSが必要で登録できず(海外でデータ専用のSIMを使ってたので不可
さくら -> できた
というわけで、moyashidaisuke.com を買いました。
netlifyに設定する
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の設定まで自動でされました。
諸々改修
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
とりあえずこれで表示されます。カテゴリーとか動いてないけど後で。
年/月/日/{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
そんな大きな記事じゃないんだけど、、、、そんな検索にニーズがあるとは思えないので機能を削ることに。
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もほとんど無いし)
まとめ
けっこう細かい調整が必要で思ったより時間かかりました、、、 というわけで、この記事を最後に次からは新しいブログの方だけ更新していく予定!
新しいブログはこちら。
残タスク
- カテゴリ
- google analyticsとかseach console設定
- はてな独自タグで書いてるやつの移行
- 画像周り
- リンク周り
- Amazonへのリンク
- アイコン設定
- トップの画像変更
- その他全体的にデザイン調整