もう何度も同じ事を繰り返すのでMEMO
MacOSX に入っている sed コマンドは Linux のとは少し違うので brew install
brew install gnu-sed --default-names
でこんな感じで実行
find ./src -name '*.html' | xargs sed -i 's/xxx/yyy/g'
Gatsby は Node.js 製の Static Site Generator です。JSON ファイルのようなデータ構造からも静的ファイルを生成する事ができます。 今回は WebAPI から fetch する方法を紹介します。
前々回、前回と違い外部API から resouce を取得して Gatsby の node を生成する plugin は v1.5.3
時点でまだ存在しません。その為自身でこれらの処理を記述する必要があります。
プロジェクトを作成します。
gatsby new practice-gatsby-http && cd $_ yarn add node-fetch touch gatsby-node.js
今回使用する WebAPI ですが、面倒なので http://jsonplaceholder.typicode.com/posts をそのまま使用します。
gatsby-node.js に sourceNodes 関数を追加します。sourceNodes に関しての詳しい説明は以下のページをご覧ください。
https://www.gatsbyjs.org/docs/node-apis/#sourceNodes
nodes 生成時に必要なデータをファイルから読み込む為に gatsby-node.js
に以下の処理を追記します。
yarn add node-fetch
gatsby-node.js
を修正します。
const crypto = require('crypto'); const _ = require(`lodash`); exports.sourceNodes = async ({ boundActionCreators }) => { const { createNode } = boundActionCreators const posts = await fetch("http://jsonplaceholder.typicode.com/posts?_limit=20").then(res => res.json()) // Process data into nodes. posts.forEach((post) => { createNode({ post, id: post.id + "", children: [], parent: "posts", internal: { type: "posts", content: JSON.stringify(post), contentDigest: crypto .createHash(`md5`) .update(JSON.stringify(post)) .digest(`hex`), } }) }) return }
GraphiQL で allPosts と posts クエリーをそれぞれ発行する
query { allPosts { edges { node { id post { id title body } } } } }
query { posts(id: {eq: "1"}) { post { id title body } } }
というわけで3回に渡って Gatsby の主幹となる nodes を生成する処理について紹介しました。実際に Page を生成するにはも少しステップが必要なのですがまた気が向いた時に tutorial でも作りたいと思います。
React.js の component を使って Blog などを生成できる Gatsby という Node.js 製の Statice site generator を紹介しました。 Markdown だけでなく JSON ファイルのようなデータ構造からも静的ファイルを生成する事ができるので今回はそのやり方を紹介します。
ちなみに、v1.3 を試していたらすでに v1.5 になっていました。タイトルどうしよう。
プロジェクトを作成する
gatsby new practice-gatsby-json && cd $_
nodes 生成時に必要なデータをファイルから読み込む為のプラグインを追加する。
yarn add gatsby-source-filesystem
gatsby-config.js
を修正し、プラグインを設定します。
module.exports = { siteMetadata: { title: `Gatsby Default Starter`, }, - plugins: [`gatsby-plugin-react-helmet`], + plugins: [ + `gatsby-plugin-react-helmet`, + { + resolve: `gatsby-source-filesystem`, + options: { + path: `${__dirname}/src/pages`, + name: 'pages', + }, + } + ], }
nodes 生成時に JSON 形式から変換させるプラグインを追加する
yarn add gatsby-transformer-json
gatsby-config.js
を修正し、プラグインを設定します。
path: `${__dirname}/src/pages`, name: 'pages', }, - } + }, + `gatsby-transformer-json`, ], }
jsonplaceholder
のデータをお借りします。以下のような json ファイルを src/pages/posts.json
として保存します。
[ { "id": "1", "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" }, { "id": "2", "title": "qui est esse", "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" } ]
yarn develop
http://localhost:8000/___graphql を開いて以下のクエリを実行します。
{ allPostsJson { edges { node { id title body } } } }
query { postsJson(id: {eq: "1"}) { id title body } }
というわけで JSON ファイルから nodes を生成する方法を紹介しました。gatsby@1.0.0 以降から nodes を生成するのに markdown 以外の方法が増えたので gatsby の可能性に私はとても期待しています。
次回は http で外部API を fetch して、そこから nodes を生成する方法を紹介します。
React.js と Vue.js のどちらが優れているかはどちらでも良いと思っています。なんですが React.js のエコシステム
のほうが一歩先を歩んでいると思っています*1。私が React.js のエコシステム
を推す理由に一つになっているツールがめでたくメジャーバージョンをリリースしたのでご紹介したいと思います。
Markdown を記述して Static な page を書き出すツールです。いわゆる Static Generator。今回のバージョンから Markdown 以外にも色々なところからデータを集積して Graphql で取り出すインターフェースが採用されました 。
私が Gatsby を好む理由ですが、React.js で書いた Compnent をそのまま利用できるところです。react-storybook 上に state less な compnents を集めている人はその財産をそのまま利用できます。
このあたりの記事を参考にすると良いのではないでしょうか。
GraphQL の概念とかその辺の記述を読んでいると時間かかると思いますが、最低限自分が必要な場面での使い方を覚える分にはそんなに時間かからないと思います。
Gatsby は GraphiQL
というツールを使って問い合わせできるので少しだけ紹介します。
やってみます。
npm install -g gatsby gatsby new personal-blog && cd $_ npm run develop
次のような画面が出てきたら成功です。
DONE Compiled successfully in 182ms 15:27:47 I Your site is running at http://localhost:8000 I Your graphql debugger is running at http://localhost:8000/___graphql
http://localhost:8000/___graphql を開いてみましょう。これが graphiql
の画面です。試しに以下のような Query を書いてみましょう。
query { allSitePage(limit:1000) { edges { node { id } } } }
そうすると以下のような画面になると思います。
詳しくは下記のドキュメントをご覧下さい。Gatsby は元となるデータをMarkdown であったり、JSON ファイルなどから集積しますが、その単位が以下の Node
と呼ばれるものです。
https://www.gatsbyjs.org/docs/node-interface/
Graphql で問い合わせするのはこの node です。Gatsby をカスタマイズしたい場合は、node を作成する
ことと Graphql で node を取得
する方法を覚えれば OK です。
とりあえず一通り以下の Blog の通りに作業してみましょう。
手順通りに終わったら以下の Graphql を書いて見ましょう。以下が Markdown で記述された Node 一覧
です
query { allMarkdownRemark(filter: {}) { edges { node { id } } } }
以下のようなレスポンスが返ってくると思います。以下の例では Markdown のファイルを2個作成しています。
{ "data": { "allMarkdownRemark": { "edges": [ { "node": { "id": "/Users/okamuuu/personal-blog.bak/src/pages/08-12-2017-getting-next/index.md absPath of file >>> MarkdownRemark" } }, { "node": { "id": "/Users/okamuuu/personal-blog.bak/src/pages/07-12-2017-getting-started/index.md absPath of file >>> MarkdownRemark" } } ] } } }
次に Node 詳細
を問い合わせします。
query { markdownRemark(frontmatter: {path: {eq: "/hello-world"}}) { html frontmatter { date(formatString: "MMMM DD, YYYY") path title } } }
以下の結果が表示されると思います。
{ "data": { "markdownRemark": { "html": "<p>Oooooh-weeee, my first blog post!</p>", "frontmatter": { "date": "July 12, 2017", "path": "/hello-world", "title": "My First Gatsby Post" } } } }
というわけでなんとなく Gatsby が集積した情報を問い合わせる方法が分かるんじゃないかと思います。
下記に詳しい説明があるのでこの単語に聞き覚えがない方は一度ご一読下さい。
Gatsby で Markdown を使って Static Site を作る方法を学びました。 次回は JSON file から Static な Site を生成する方法を紹介します。
*1:React.js と Vue.js との優劣は議論する気はないのですがこれらのエコシスムの一長一短に関しての議論は歓迎します
夏らしい事をしたいが、7月8月の週末は今回(7月22日の時点)を逃すと今年は最大でも6回しかない。チャンスは少ない。ならば俺たちは今すぐ行かねばならない。
あんまり覚えてないんですが確かこんな感じの話をしたんだと思います。
という訳で南伊豆の海岸(東側と南側)を探索しました。
時間はあんまり正確じゃないですがこんな感じだったと思います。
初日
時間 | 内容 |
---|---|
7月22日(土) 12:30 | 行くぞと決まる |
7月22日(土) 13:00 | 品川へJR山手線で移動開始 |
7月22日(土) 13:30 | 熱海へ伊豆特急で移動開始 |
7月22日(土) 15:00 | 弓ヶ浜(下田)へレンタカーで移動開始 |
7月22日(土) 19:00 | 弓ヶ浜のもき丸で晩御飯 |
7月22日(土) 22:00 | 就寝 |
二日目
時間 | 内容 |
---|---|
7月23日(日) 8:00 | 起床 |
7月23日(日) 8:30 | 弓ヶ浜の青木さざえ店で朝ごはん |
7月23日(日) 10:00 | チェックアウト |
7月23日(日) 10:30 | 逢ヶ浜でシュノーケリングを楽しむ(素潜り) |
7月23日(日) 11:30 | ヒリゾ浜へレンタカーで移動開始 |
7月23日(日) 13:30 | ヒリゾ浜でシュノーケリングを楽しむ(素潜り) |
7月23日(日) 14:30 | 熱海に向かってレンタカーで移動開始(下田街道を北上) |
7月23日(日) 18:00 | 熱海到着レンタカー返却 |
7月23日(日) 18:30 | 解散 |
7月23日(日) 19:00 | 熱海 -> 品川へ新幹線で移動開始 |
7月23日(日) 19:50 | 品川へ到着 |
特急踊り子号(伊豆急下田行) で。JR山手線内で移動中にスマホで席を確保します。えきねっとを使いましょう。品川駅で特急券を受け取ります。
品川駅で乗車券を受け取りつつレンタカーを手配します。最初、レンタカーは熱海のレンタリースのHPを見るも全て貸し出し中になっていました。電話したら何故か借りられたので今回はギリギリセーフ。 車借りられないと今回の旅は何もできないんで結構つらいのでちょっと危なかった。どの駅に降りるかは車を借りてから決めるようにすると良いでしょう。
さて、無事に新幹線に乗りました。さて現時点で我々のステータスは下記の通り。
現時点、ほぼ無策です。そんなわけで新幹線の移動時間を使ってスマホを使って情報収集を行います。この時間で計画、実行できた事
という事でレンタカーを借りて移動開始、車内で楽天トラベルを使って宿泊所施設を予約し移動開始。大体90km ぐらいでしょうか。思った以上に伊豆半島は大きかった。次回ここに遊びに来る場合は下田まで列車で移動した方が良いという学びを得ました。
さていい感じの砂浜ですが、何をもっていい感じなのか決めないと評価できないので、とりあえずこの記事においては「沖縄の砂浜のように白い砂」だといい感じだと思ってください。
熱海サンビーチや伊東オレンジビーチも悪くはなかったのですが白い砂浜は伊豆先端である南伊豆まで行かねば発見できませんでした。
西側に関しては今回未調査です。
というわけで弓ヶ浜に到着しました。大体19時ぐらいだったかな?晩御飯を食べたいので宿泊所の人にどこがいいのか聞いたところ「バーベキューガーデン海の家 もき丸」が良さそうでした。「青木さざえ店」も良さげでしたが残念ながら夕方で閉店しているのでどちらにしろ「バーベキューガーデン海の家 もき丸」しか選択肢は無かったんですが。
食べた物と飲んだものは以下の通り。写真はシッタカとトコブシです。
この店は店主が漁師でもあるらしいので海産物はとても美味しかったです。なぜかピザも美味しいっていう。夕暮れ時のビーチを眺めながら飲むビールは最高すよねえ。
ただ蚊とアリが少し多かったので虫除けが欲しかったですね。あとウェットティッシュ。淑女と一緒に行かれる予定がある方は必ずご持参ください。
おやすみなさい
というわけで翌朝8:00ぐらいから活動開始。昨日行けなかった青木さざえ店で朝ごはん。
今回は宿泊所の駐車場を利用したので我々は特に料金は発生していないのですが、弓ヶ浜の駐車場事情について報告します。
まず1回1500円必要です。かつ、駐車場スペースが限られています。砂浜近くの駐車場は8時から9時の時点で満車になっていました。
路地を少しはいるとおじいちゃんとおばあちゃんがいて一回1000円の駐車場を案内していました。このお二人は朝ごはんを食べに行くときはいらっしゃいましたが朝ごはんから戻るといなくなっていました。そして1000円の駐車場が満車になっていました。
どうやら一回1000円の駐車場のほうも8時から9時には満車になるようです。 弓が浜へ遊びに行く予定がある皆さまは駐車場がどのあたりにあるのか事前にチェックしたほうが良さそうです。
今回我々はシュノーケリングするスポットを探すほうが優先度が高かったので砂浜ではなく岩場へ行きました。
結構綺麗で海藻もたくさん生えていたので穴場スポットを見つけたのかもしれません。
ちなみに他にもシュノーケリングしている人がいましたがほとんどの人がラッシュガードをつけていました。カインズホームスーパーで買った980円のゴーグルと海パンだけで来ていたのは我々だけでした。この日は曇りだったのものすごく寒かったです。
さてヒリゾ浜へ移動したのですがそもそも橋渡しポイントへの駐車場が満杯です。11:30 ごろに到着しのたですが、スタッフから「12:30ぐらいになれば午前中に来たお客様帰るので入れ替わりで駐車場が空くんじゃないかなあ」という説明を受けたのでそのあたりで昼ごはんを食べる事にしました。
北へ 6km ほど移動して蕎麦屋さんを発見。暖かい鴨南蛮を食べました。まあまあ美味しかったです。同伴したおじさんは蕎麦好きでどうして冷たい蕎麦じゃないんだ!?という顔をしましたが逢ヶ浜で体温を結構失った私にとってはなかなかのご馳走でした。
無事車を止めて渡し船を利用します。渡し船は1日券1500円です。ヒリゾ浜(岩場)へは船で移動する必要があり、1日に何度も往復しています。実質は1往復しかしない人がほとんどだと思います。
そして渡し船に。ダイビングスーツに身をまとった本格的な人たちがいる中、980円のゴーグルと海パンでやってきたおじさん2人が乗り込みます。
そして案の定海水が冷たい。しかし入らないと何しに来たのか分からない。というわけで頑張って水中へ。逢ヶ浜とは比べ物にならないほどの魚に遭遇。快晴だったらすごく幻想的な風景なんだろうなと思いました。
私はこの日、私は生まれて初めて Go Pro を買いたいと思いました。そして海を堪能して再び渡し船で戻ります。で戻って気づいたのですがウェットスーツとかレンタルしていました...
さて無事に任務完了したので熱海へ向かって出発します。途中で河津七滝ループ橋を体験。昔の人は天城越えするのどんだけ大変だったんだろうと思いました。
で下田街道を通るのでしたら道の駅、浄蓮の滝はおすすめです。鮎の塩焼き美味しそうでしたがそこまでお腹空いてなかったので見送りしました。
ちなみにわさびのアイスクリームはちょっと微妙かな...ここはわさび作っててわさび田がありました。水綺麗。
そういえば伊豆ではテングサがたくさん取れるらしく、テングサでつくられたところてんは名物のようです。ところてんはおいしかったので機会があればぜひ食べてみてください。
そして帰宅途中になんだか美味しそうな自家製ソーセージを作っているお店を発見。もう1人のおじさんが「最近ソーセージにはまっててこれを見逃す事ができない」とおっしゃったので立ち寄りました。保冷する必要があるので私は購入しませんでしたので美味しかったか不明ですが後日ヒアリングして追記しておきます。
無事熱海に着いたのですが一方通行の道が多くて熱海をぐるぐる。ガソリンスタンドまでなかなかたどり着けないっていう。
でガソリンを満タンにしたのですが今回の旅は 300km 近く走ったのですが 12.04L しか消費していませんでした。
車種はなんだっけな...
私は車を所有していないのでどれぐらいすごいのか分かってませんがなんかすごいらしいです。
そして何故か人多すぎの熱海。知らない間に熱海が今盛り上がっているのか!?と思ったら熱海海上花火大会でした。
花火を見ながら酒を飲むなかなかの好機でしたがこれ以上体力を消耗すると明日の仕事に影響するだろうという事で見送りました。というわけで解散。
というわけで品川に到着しました。ちなみに熱海から品川駅までの新幹線のチケットを購入すると 熱海->東京山手線内
みたいな料金になるので品川駅からJR山手線の駅でしたら切符を買わなくても大丈夫です。
旅慣れてる人は知っているんでしょうけど東京とか、大阪とかそういうルールがあるのできになる方はぜひ調べて見てください。
というわけで今回の旅で学んだ事
Angular なアプリを開発していたのですが CirlceCI 上でいきなりテストが通らなくなった
あと TypeError: Cannot create property '__creationTrace__' on string '__zone_symbol__optimizedZoneEventTask'
とか言われます。
調査した過程で、下記の issue にたどり着いた
とりあえず zone.js を v0.8.13
から v0.8.12
にダウングレードしました。おしまい。
もう何度も同じメッセージを目撃し、時間を無駄にしているのでメモ
src/app/app.module.ts
に FormsModule を追加する
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -10,7 +11,8 @@ import { AppComponent } from './app.component'; ], imports: [ BrowserModule, - AppRoutingModule + AppRoutingModule, + FormsModule ], providers: [], bootstrap: [AppComponent]