ちょっと一息

ちょっと一息

主に自分の学んだこと、使えそうなことをまとめてます

GatsbyJSに入門

ブログ更新がとても久しぶりです

梅雨が明けて8月となってしまいました。みなさんいかがお過ごしでしょうか?

それにしても暑いですね...
毎日36℃ぐらいあるのでとてもだるいです^^;

前回は1ヶ月2回ほど記事を書こうと思っていたのですが、バタバタと作業をしていて、更新できていませんでした。
少し落ち着いたのと、記事に残したい事柄が増えてきたので、毎週1記事は更新できるようにしていきたいなと思っています!

今回のテーマ

さて、今回はReactを使った静的サイトジェネレーターGastsbyJSに入門してみたいと思います!

GatsbyJSって?

GatsbyJSで検索していただけると詳しい説明が色々出てくるので詳細は割愛しますが、大雑把にまとめると、

  • ビルド時にHTMLを生成する
  • 早いページを作れる

って感じのようです。

詳しくは公式(GatsbyJS)を確認してみてください。

どうして?

  1. 今回こちらに入門してみようと思ったのは、自分のポートフォリオサイトをGatsbyJSで作ってみたくなったこと
  2. webサイトを作成してみて欲しいと知人に相談されたこと

の2点です。

Reactを少し触っているので、webサイトもReactで作ってみたかったので、GatsbyJSに入門してみることにしました!

何する?

GatsbyJSを入門するにあたり、まずは公式サイトのチュートリアルをやってみました。
チュートリアルで学んだことを順番にまとめていこうと思います。
今回はチュートリアル1.Get to know Gatsby building blocksを行ったのでまとめてみました。

Hello World

Nodejsとyarnはインストールしてあったので、

gatsby new hello-world https://github.com/gatsbyjs/gatsby-starter-hello-world

を実行してhello world スターターを利用して雛形を作成しました。
hello-worldディレクトリが作成され、いくつかディレクトリとファイルが作成されました。

f:id:yasumuo:20190811195736p:plain
hello-world

src/pages/index.js を書き換えてみると、

// src/pages/index.js
import React from 'react'

export default () => (
  <div style={{ color: `purple`}}>
    <h1>Hello Gatsby!</h1>
    <p>What a world.</p>
    <img src="https://source.unsplash.com/random/400x200" alt="" />
  </div>
)

f:id:yasumuo:20190811201635p:plain
index.jsを編集
いい感じにページを修正できました。ホットリロードなので、ソースコードを変更するとすぐに確認できていいですね!

ページの追加

Using page components(https://www.gatsbyjs.org/tutorial/part-one/#-using-page-components)によると、
src/pages/ にjsファイルを作成するとページが作成できるようなので、チュートリアルに従ってaboutページを作成しました。

// src/pages/about.js

import React from "react"
export default () => (
  <div style={{ color: `teal` }}>
    <h1>About Gatsby</h1>
    <p>It's pretty cool</p>
  </div>

http://localhost/8000/about にアクセスすると、

f:id:yasumuo:20190811204227p:plain
aboutページ

aboutページを表示することができました!

コンポーネントの再利用

コンポーネントを細かく作って再利用できるようにすると処理がまとまって綺麗に作れるので、共通部分のヘッダーをコンポーネント化します。
こちらはGatsbyに限ったことではないですが、src/component/ ディレクトリを作成してコンポーネントファイルを作成していきます。

// src/components/header.js

import React from "react"
export default props => <h1>{props.headerText}</h1>

これを使って、index.jsとabout.jsを書き換えます。

// src/pages/index.js

import React from 'react'
import Header from '../components/header'

export default () => (
  <div style={{ color: `purple`}}>
    <Header headerText='Hello Gatsby!' />
    <p>What a world.</p>
    <img src="https://source.unsplash.com/random/400x200" alt="" />
  </div>
)


// src/pages/about.js

import React from "react"
import Header from '../components/header'

export default () => (
  <div style={{ color: `teal` }}>
    <Header headerText='About Gatsby' />
    <p>It's pretty cool</p>
  </div>

この辺りはサイドバーとかレイアウトとかで共通なものをコンポーネント化するのが良さそうですね。

ページリンク

ページ間を遷移するためにリンクを設置します。
Gatsbyにはサイトページ内を遷移するためのLinkコンポーネントを利用します。

// src/pages/index.js

import React from "react"
import Header from '../components/header'
import { Link } from 'gatsby'

export default () => (
  <div style={{ color: `teal` }}>
    <Link to='/contact/' />Contact</Link>
    <Header headerText='About Gatsby' />
    <p>It's pretty cool</p>
  </div>

// src/pages/contact.js

import React from "react"
import { Link } from "gatsby"
import Header from "../components/header"
export default () => (
  <div style={{ color: `teal` }}>
    <Link to="/">Home</Link>
    <Header headerText="Contact" />
    <p>Send us a message!</p>
  </div>
)

とすることで、

f:id:yasumuo:20190812001053p:plain

Contactページへのリンクを作成できます。
Contactをクリックすると、

f:id:yasumuo:20190812001210p:plain
ページリンク

ぬるっとContactページに遷移することができました!(^^)

ビルド

Gatsbyで作ったプロジェクトのルートで

gatsby build

と実行することでビルドできます。

f:id:yasumuo:20190812013242p:plain
ビルド

ビルドが簡単に完了しました^^

デプロイ

今回のチュートリアルで簡単に作成したページをデプロイしてみます。

surgeというものを使うと静的ページをサクッとホスティングできるみたいです!(初めて知りました^^;)

yarn global add surge

でsurgeをインストールします。

surge

コマンドを実行すると、email, パスワード, プロジェクトなどを聞かれるので適当
に入力するだけで、デプロイまでやってくれるようです。(お手軽!)

surge /public

を実行してビルドしたファイルをデプロイします。
デプロイが完了したので、URLにアクセスしてみると、、、

f:id:yasumuo:20190812014940p:plain
デプロイ結果

デプロイできました!
デプロイしたディレクトリを指定するだけでお手軽にできました。

まとめ

Gatsbyに初めて触れてみましたが、ReactベースなのでReactを少し知っているとすんなり使えそうですね!

次のチュートリアルではスタイルの付け方を説明されているようです。(styled-componentでスタイリングできたらいいなぁ〜)

データの取得と表示まで理解できるとかなりゴリゴリ使っていけそうなので、引き続きチュートリアルをやってまとめていきたいと思います!

Google App Scriptを使ってみた~ その2 ~

久しぶりの投稿です

あっという間に新年度になってしまいました。皆さん新年度は何か新しい目標などあるのでしょうか?私はとりあえず、1ヶ月に2記事はブログを更新したいなと思っています(笑)
今月1週目の土曜日は京都はとても天気がよかったので、お花見に行ってきました!去年は道路を移動中に見るだけだったので、今年は少しゆっくり見れて気持ちよかったですよ!
サムネイルはその時撮った桜の写真です(^^)
さて、では本題に入ります。

今回やること

前回の記事はやりたいことが途中で終わってしまっていたのですが、とりあえずslackとGASを連携して、slackで書いた文字をそのままおうむ返しすることができました。
今回は少し修正して、slackからグーグルカレンダーに予定を登録できるようにしてみたいと思います。

やりたかった理由

この機能を作ってみたかった理由ですが、2種類のカレンダーに1回で予定を入れたかったのです。自分用のカレンダーと共有用のカレンダーを使っていて、共有用のカレンダーは複数人の予定が見れて便利なのですが、逆に自分の予定が見辛くなるのでこれまでは自分用と共有用で2回カレンダーに入力していました。
これが案外面倒なので、1回入力したら両方に登録できたら便利だなと思ったのが1番のきっかけです。
他の理由としては、slackを使うことが多いのでslackから登録したかったこと、カレンダーアプリだと連続4日だけの予定とかを登録するのに使い辛かったからです。

作り方

前回までで、slackから文字を送信できているので、CalendarAppを使って登録していきます。
流れとしては、slackに予定を送信 → GASで受け取った文字を処理 → カレンダーに登録 → slackに返事 となるように作ってみます。

作ったもの

カレンダーIDの取得

最初に登録したいカレンダーのIDを取得します。
カレンダーのIDはカレンダーを表示して、以下の写真の場所から確認できます。

f:id:yasumuo:20190415010420p:plain
カレンダーIDの場所(1)

  1. 画像の歯車をクリック
  2. 「設定」をクリック
  3. 「マイカレンダーの設定」から知りたいカレンダー名を選択して「カレンダーの設定」をクリック

f:id:yasumuo:20190415010458p:plain
カレンダーIDの場所(2)

  • 下にスクロールして「カレンダーの統合」の欄にカレンダーのIDがあります

CalendarAppを使ってイベントを登録する

CalendarAppというものを使うことで、簡単にイベントを登録することができます。

  1. 予定を登録したいカレンダーIDを取得したら、getCalendarByIdメソッドを使ってカレンダーを取得します。
  2. createEventメソッドを使うことで予定を登録します。

やることはこの二つだけです!

var myCalendar = CalendarApp.getCalendarById('カレンダーID');
var title = 'CalendarAppテスト';
var startTime = new Date('2019/5/10 09:00:00');
var endTime = new Date('2019/5/10 10:00:00');
var option = {
    description: 'テストテスト',
    location: '京都駅'
}
  
myCalendar.createEvent(title, startTime, endTime, option);

例えば、上記のように書くと5/10 9:00 ~ 10:00で予定を登録できます。
関数にしてGASで実行してみたあとカレンダーを見てみると、

f:id:yasumuo:20190415025618p:plain
登録の例

このように予定が登録できていました!

slackから複数の予定を登録できるようにする

登録はさっきの例でできるようになったので、あとは複数の予定をslackから登録できるようにすればひとまず完成です。

自分で使えるだけで良いので、タイトルや時間はカンマ区切り、イベントは改行で区切ることにしました。
こちらは詳細を割愛しますが、slackから受け取った予定をsplit関数で改行コードとカンマで分けてループでカレンダーに登録しているだけです。

function doPost(e) {
  if(e.parameter.user_name != "slackbot") {
    // カレンダーの取得
    var myCalendar = getMyCalendar();
    
    // 文字からイベント情報の配列を取得
    var EventArray = createEventTextArray(e.parameter.text);
    
    // イベントをカレンダーに登録
    registerEvent(myCalendar, EventArray);
    
    // 返事をslack上に返す
    postSlackMessage(e.parameter.token, e.parameter.channel_name, '登録しときますた! デュフフww');
  }
}

// カレンダーの取得
function getMyCalendar() {
  var myCalendar = CalendarApp.getCalendarById(PropertiesService.getScriptProperties().getProperty('MY_CALENDAR_ID'));
  return myCalendar;
}

// カレンダーに登録
function registerEvent(calendar, eventTextArray) {
  for(var i=0; i < eventTextArray.length; i++) {
    var event = createEventObject(eventTextArray[i]);
    calendar.createEvent(event.title, event.startTime, event.endTime, event.option);
  }
}

// 受け取ったテキストからイベントの配列を作成
function createEventTextArray(postedEventsText) {
  var eventsArray = postedEventsText.split(/\n/);
  return eventsArray;
}

// 受け取った文字列からイベントを作成するオブジェクトを返す
function createEventObject(eventText) {
  var eventDetailArray = eventText.split(',');
  var option = {}
  if(eventDetailArray[3]) {
    option.description = eventDetailArray[3]
  }
  if(eventDetailArray[4]) {
    option.location = eventDetailArray[4]
  }
  return {
    title: eventDetailArray[0],
    startTime: new Date(eventDetailArray[1]),
    endTime: new Date(eventDetailArray[2]),
    option: option
  }
}

function postSlackMessage(web_token, channel, text) {
  var WEB_TOKEN = PropertiesService.getScriptProperties().getProperty('WEB_HOOK_TOKEN');
  if (WEB_TOKEN != web_token) {
    throw new Error('error');
  }
  var token = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN');
  var slackApp = SlackApp.create(token);
  
  var options = {
    channel: "#"+ channel,
    message: text
  };
   
  slackApp.postMessage(options.channel, options.message);
}

これで準備ができたので、保存してwebアプリケーションとして導入します。

前回作ったslackに返事をしてくれるボットの画像を変更して、返答メッセージも変更して準備ができました!

動作確認

slackに予定を書いて、動作するか試してみます。

f:id:yasumuo:20190415031847p:plain
複数登録

上記のようにタイトルと時間を複数書いて、送信すると...



f:id:yasumuo:20190415032004p:plain
結果1

このようにアプリが返事してくれました!
いい感じにフラウさんが予定を登録してくれたみたいです。このキャラクターはゲームのキャラクターで凄いプログラマーです。(デュフフ フラウとかで検索するとヒットすると思います。)
好きなキャラなのでこんな感じにしてみました(笑)

で、肝心のカレンダーの方を確認してみると...

f:id:yasumuo:20190415032817p:plain
結果2

しっかりカレンダーに登録できました!

まとめ

CalendarAppを使うとカレンダーIDが取得できるととても簡単に予定を登録することができました!
1週間の予定や、繰り返しなどのメソッドもあるようなので、用途に合わせて使えそうです。

この後の拡張としては、

  • 共有カレンダーのIDを取得してカレンダーを取得する
  • 予定を登録する際に共有カレンダーにも登録する

を上記で作ったコードに加えれば、僕の一番やりたかったことができそうなので、時間がある時に作ってみようと思います!

slack, google カレンダー, GASで似たようなことをしてみたい人に少しでも参考になれば幸いです。

次回はまだ決まってないのですが、ReactとFirebaseを使った認証とかをまとめていきたいなと思っています。

Google App Scriptを使ってみた~ その1 ~

あけましておめでとうございます

あっという間に2019年の2月になりました。先月はドタバタしていて全く発信できませんでした...
今月からまたコツコツ色々まとめてみます。さて、前回は簡単にJavaScriptのクラスをまとめました。今回はFirebaseとの連携とかをまとめてみようと思ったのですが、色々あってGASを触ってみたのでまとめてみました。

Google App Script

Google App Script (GAS)はその名の通りGoogleが提供しているJavaScriptをベースとした実行環境です。
Googleのサーバー上に実行環境があり、色々と便利そうです。今回使ってみようと思ったGASの利点は以下になります。

  • Googleの関連サービスと連携することができる
  • 外部サービスと連携することができる
  • 自分でサーバーを用意する必要がない


Googleの関連サービスと連携できる

GoogleドライブやGメールとか、Googleが提供しているサービスと簡単に連携することができるようです。
今回はGoogleカレンダー連携したかったのでGASを使ってカレンダーに予定を追加できるようにしてみました。

外部サービスと連携できる

Twiiter, LINE, チャットワークといったwebサービスが提供しているAPIを使って連携できるようです。
今回はSlackと繋げてみました。

自分でサーバーを用意する必要がない

レンタルサーバーを借りたり、自分でサーバーの環境構築をする必要がなく、すぐに使用できます。準備が必要ないっていうのが楽でとてもいいですね!

やってみたこと

今回やりたかったことは、Slackに日付と時刻、内容を書くとGoogleカレンダーに予定を登録できる仕組みです。

slackからの投稿を受け取る → GASを使ってGoogleカレンダーに予定を投稿

これをただやりたかっただけなのですが、色々と連携方法とかをまとめてみました。やることは、

細かく分けると上記の4つです。

SlackとGASの連携

まずSlackからの投稿を受け取りたかったのでGASと連携します。

  1. Slack のAppから発信webフックを設定します。
    f:id:yasumuo:20190212030939p:plain
    SlackのApp
    f:id:yasumuo:20190212031832p:plain
    発信webフック
    f:id:yasumuo:20190212031909p:plain
    設定

    インストールできたらインテグレーションの設定をします。チャンネルと引き金となる言葉をひとまず設定して、トークンはどこかに記録しておきます。
    この設定をすることで、引き金となる言葉と一緒にメッセージをslackに投稿することでGASにそのメッセージを渡す準備ができました。(URLは後から設定します)

  2. GASにSlackAppライブラリを追加する

    今回はまず、
    Slackから投稿→投稿したメッセージをGASからSlackへ返す
    を実現してみます。

    そこでGASからSlackに簡単にpostできるようにするために以下に紹介されているライブラリをGASに導入します。
    Slack BotをGASでいい感じで書くためのライブラリを作った - Qiita
    f:id:yasumuo:20190212041152p:plain
    ライブラリを追加

    f:id:yasumuo:20190212044007p:plain
    Tokenの作成

    以下の記事を参考にトークンを作成してチャンネルに試しに送信してみてメッセージが投稿されれば準備OK.
    Slack API 推奨Tokenについて - Qiita
    取得した発信webフックとslack APIトークンをGASのプロジェクトのプロパティとして保存しておきました。

    ここまでで、まずGASからメッセージを送信できるか試してみました。以下のように書いて、関数を実行したところうまくslackにメッセージが送信できました!
function postSlackMessage() {
  var token = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN');
  var slackApp = SlackApp.create(token);
  
  var options = {
    channel: "#schedule",
    message: "Hello from Gas"
  };
  
  slackApp.postMessage(options.channel, options.message);
}

f:id:yasumuo:20190212050557p:plain
メッセージ送信

3. Slackから投稿したメッセージをGASで受け取ってそのまま返す

 次にGASのdoPost関数と発信webフックを使ってslackに投稿したメッセージをGASで扱ってみます。

function doPost(e) {
  if(e.parameter.user_name != "slackbot") {
    postSlackMessage(e.parameter.token, e.parameter.channel_name, e.parameter.text);
  }
}


function postSlackMessage(web_token, channel, text) {
  var WEB_TOKEN = PropertiesService.getScriptProperties().getProperty('WEB_HOOK_TOKEN');
  if (WEB_TOKEN != web_token) {
    throw new Error('error');
  }
  var token = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN');
  var slackApp = SlackApp.create(token);
  
  var options = {
    channel: "#"+ channel,
    message: text
  };
  
  slackApp.postMessage(options.channel, options.message);
}

このようにdoPost関数を作成して、GASを「webアプリケーションとして公開」します。
最後にGASを公開した時にURLが取得できるので、こちらを発信webフックのインテグレーションの設定 URL に貼り付けて保存すると完了です。

f:id:yasumuo:20190212055713p:plain
動作確認

最後に何か文字を書いてそのまま返ってくればとりあえず完成です!

まとめ

今回、簡単にGASをさわってみました。slackから受け取ったメッセージはdoPost関数を使うだけで簡単に扱えました。slackから送信するための準備、GASから返すためのtokenを準備するのに少し時間がかかってしまいましたが、サーバーを自分で用意しなくていいのはとても便利ですね!
次回はその2としてGoogleカレンダーと連携、slackから予定を投稿する方法をまとめてみます。

JavaScriptのオブジェクト(プロトタイプ) ~ その2 ~

前回の続き

あっという間に今年も残すところあと1日ですね。
少し間が空きましたが、前回の続きでJavascriptオブジェクト指向についてです。
前回クラスの定義コンストラクについてまとめました。今回はプロトタイプを使ったメソッドの宣言や継承をまとめてみました。

メソッドの宣言

メソッドを後付けする

Personオブジェクトにメソッドを後付けしてみる。

var Person = function(name, age) {
 this.name = name;
 this.age = age;
};

var taro = new Person('太郎', 20);

taro.greet = function() {
 return "名前: " + this.name + ", 年齢: " + this.age;
}

console.log(taro.greet());    // 名前: 太郎, 年齢: 20

このようにして、メソッドを後から追加することができる。
ここで、もう一つPersonオブジェクトのインスタンスを作成すると、

var hanako = new Person('花子', 25);
console.log(hanako.greet());    // Uncaught TypeError

となり最後がエラーになりなる。
メソッドを後付けすると、インスタンス固有のメソッドとなってしまうみたい。
同じクラスから生成してもそれぞれのインスタンスが持つものが違ってしまう。

prototypeを使う

後付けすると、インスタンスが持つプロパティやメソッドが異なることがわかった。
インスタンスで共通のものを定義する場合はコンストラクタで前回定義したけど、これは無駄にメモリを消費するらしい。
メモリ消費を抑えるためにprototypeというプロパティを使ってメンバを追加する。

var Person = function(name, age) {
 this.name = name;
 this.age = age;
};

// getName, getAgeを追加

Person.prototype = {
 getName : function() { return this.name; },
 getAge : function() { return this.age; }
};

var suzuki = new Person('鈴木', 30);

console.log(suzuki.getName());    // 鈴木

こうすることで、メモリ消費を抑えたメンバの追加ができるみたい。

メンバが呼び出された時の動作は、

  1. インスタンスにメンバがあるかどうか確認
  2. インスタンスにメンバがない場合は、元となるPersonオブジェクトを暗黙的に参照してメンバを取得

といった感じになる。
インスタンスメソッドを定義するときはprototypeプロパティを使えば良さそう。

静的メンバを定義するときは、

Person.Tribe = 'ヒト族';

静的メンバはオブジェクト(クラス)で共通のものだから、このようにオブジェクトに直接追加でいい。

継承

次に、元のオブジェクトを引き継いで新しいクラスを作成する場合

プロトタイプチェーン

プロトタイプの連なりのこと。
プロトタイプにインスタンスを設定すると暗黙的に参照できるようになり、継承ができるようになる。
例えば、Personオブジェクトを継承したKansaizinオブジェクトを作ってみると

var Person = function() {}

Person.prototype = {
 hello : function() { return 'おはよう'; }
};

var Kansaizin = function() {};
Kansaizin.prototype = new Person();

Kansaizin.prototype.say = function() { return 'なんでやねん!'; }

// おっちゃん
var ottyan = new Kansaizin();

console.log(ottyan.hello());    // おはよう
console.log(ottyan.say());    // なんでやねん!

こんな感じに、Personオブジェクトのhelloメソッドを呼び出すことができてる。
helloを呼び出した時の動作は、

  1. Kansaizinオブジェクトのottyanインスタンスのメンバを探して
  2. helloメンバがないのでKansaizinオブジェクトのプロトタイプPersonのインスタンスのメンバを探して呼び出す。

メンバをプロトタイプを次々辿って呼び出すのでプロトタイプチェーンと呼ばれているみたい。

継承したメソッドのオーバーライド

継承した親オブジェクトのメソッドを子オブジェクトで変更したい場合は、

Kansaizin.prototype.hello = function() { return 'おはようさん!'; }

console.log(ottyan.hello());    // おはようさん!

prototype.helloとして書き換えればオーバーライドができる。

まとめ

今回は、prototypeプロパティを使ったメソッドの宣言、継承をまとめました。暗黙的な参照っていうのが分かりにくいけどメモリ消費を抑えれるのはいいね!
より詳細は、またまとめようと思うけど、ES6ではclass構文が使えるので、先にこっちでの書き方とかをまとめてみよう!
次は、最近firebaseとかGoに触れたのでまたまとめてみます。

みなさん今年も1年お疲れ様でした。良いお年をお迎えください!

JavaScriptのオブジェクト(プロトタイプ)

初投稿!

一発目の題材にふさわしい気もしませんが、以前学んだJavaScriptのオブジェクトについて忘れているのでまとめてみました。(とりあえず基本だけ)

続きを読む