20190209のNode.jsに関する記事は7件です。

nodeでcliツールを作る

ターミナルで

my-cli --env=production

みたいな感じで起動できる対話型のcliツールを作るやり方です。

対話型cli

enquirerというnpmを使えば対話型のcliツールは簡単に作れます。

標準入力からもらう引数

標準入力から引数をもらうにはyargsというnpmを使えば簡単にできます。

独自コマンド

node index.jsみたいに起動させるのではなく、my-cliのような独自コマンドでプログラムを動かすにはpackage.jsonのbinを使います。
package.jsonに以下のように書いて

  "bin": {
    "my-cli": "./index.js"
  }

index.jsの先頭に

#!/usr/bin/env node

を書いて、

npm install -g

を実行します。

これでターミナルでmy-cliと実行することで./index.jsが動くようになります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Lineで匿名チャットルームを作ってみた

開発のきっかけ

お腹が痛い時にどことない孤独を感じるのでどうにかしたい

その時の気持ちを共有できる匿名チャットルームがあれば良いのでは?

作るか

概要

匿名で会話が出来るLineBotを作っていきます。
なぜLineBotかと言うと、Lineの仕様上匿名のグループチャットは作れない為です。

使用技術

Node.js
Heroku

公式リファレンス
https://developers.line.biz/ja/reference/messaging-api/#common-properties

事前準備

すでにLineBotでメッセージの送受信ができている前提で話を進めさせていただきます。

こちらの記事を参考にしてとりあえず動くと状態まで開発を進めておいてください。

https://qiita.com/nkjm/items/38808bbc97d6927837cd

コードの編集

今回主に編集するファイルはindex.jsです。
紹介した記事の通りに作成すると、このようになっているかと思います。

index.js
// -----------------------------------------------------------------------------
// モジュールのインポート
const server = require("express")();
const line = require("@line/bot-sdk"); // Messaging APIのSDKをインポート

// -----------------------------------------------------------------------------
// パラメータ設定
const line_config = {
    channelAccessToken: process.env.LINE_ACCESS_TOKEN, // 環境変数からアクセストークンをセットしています
    channelSecret: process.env.LINE_CHANNEL_SECRET // 環境変数からChannel Secretをセットしています
};

// -----------------------------------------------------------------------------
// Webサーバー設定
server.listen(process.env.PORT || 3000);


// -----------------------------------------------------------------------------
// ルーター設定
server.post('/webhook', line.middleware(line_config), (req, res, next) => {
    res.sendStatus(200);
    console.log(req.body);
});

const bot = new line.Client(line_config);

// -----------------------------------------------------------------------------
// ルーター設定
server.post('/webhook', line.middleware(line_config), (req, res, next) => {
    // 先行してLINE側にステータスコード200でレスポンスする。
    res.sendStatus(200);

    // すべてのイベント処理のプロミスを格納する配列。
    let events_processed = [];

    // イベントオブジェクトを順次処理。
    req.body.events.forEach((event) => {
        // この処理の対象をイベントタイプがメッセージで、かつ、テキストタイプだった場合に限定。
        if (event.type == "message" && event.message.type == "text"){
            // ユーザーからのテキストメッセージが「こんにちは」だった場合のみ反応。
            if (event.message.text == "こんにちは"){
                // replyMessage()で返信し、そのプロミスをevents_processedに追加。
                events_processed.push(bot.replyMessage(event.replyToken, {
                    type: "text",
                    text: "これはこれは"
                }));
            }
        }
    });

    // すべてのイベント処理が終了したら何個のイベントが処理されたか出力。
    Promise.all(events_processed).then(
        (response) => {
            console.log(`${response.length} event(s) processed.`);
        }
    );
});

このコードに

・ユーザーidの追加機能
・ユーザーidの削除機能
・登録しているユーザー全員へメッセージを転送する機能

これらの機能を追加する為このように変更します。

index.js
var fs = require('fs');

const server = require("express")();
const line = require("@line/bot-sdk");

const line_config = {
    channelAccessToken: process.env.LINE_ACCESS_TOKEN,
    channelSecret: process.env.LINE_CHANNEL_SECRET
};

server.listen(process.env.PORT || 3000);

const bot = new line.Client(line_config);

// サーバー設定

server.post('/webhook', line.middleware(line_config), (req, res, next) => {

    res.sendStatus(200);

    var user_ids = require('./user_ids.json');

    function unlink(path) {
      fs.unlink(path, function (err) {
        if (err) {
            throw err;
        }
      });
    }

    function writeFile(path, data) {
      fs.writeFile(path, data, function (err) {
        if (err) {
            throw err;
        }
      });
    }

    req.body.events.forEach((event) => {

        if (event.type == 'follow'){
            function getUniqueStr(myStrong){
                var strong = 1000;
                if (myStrong) strong = myStrong;
                    return new Date().getTime().toString(16)  + Math.floor(strong*Math.random()).toString(16)
            }

            let uuid         = getUniqueStr();
            let line_user_id = event.source.userId;

            user_ids[uuid] = line_user_id;

            unlink('./user_ids.json');
            writeFile('./user_ids.json', JSON.stringify(user_ids));

            console.log('------updated follow function------');
            console.log(user_ids);
            console.log('------updated follow function------');
        }

        if (event.type == 'unfollow'){
            for(key in user_ids){
                if(user_ids[key] == event.source.userId){
                    delete user_ids[key]
                    writeFile('./user_ids.json', JSON.stringify(user_ids));

                    console.log('------updated unfollow function------');
                    console.log(user_ids);
                    console.log('------updated unfollow function------');
                }
            }
        }

        if (event.type == "message" && event.message.type == "text"){
            let message = {
                type: 'text',
                text: event.message.text
            };

            for(key in user_ids){
                if(user_ids[key] != event.source.userId){
                    bot.pushMessage(user_ids[key], message);
                }
            }
        }

    });
});

これプラス
ユーザーデータを保存しておくファイルである、user_ids.jsonをindex.htmlと同じ階層に追加しておいてください

user_ids.json
{}

編集が完了したら

$ ./deploy.sh

このコマンドでデプロイしてみましょう。
デプロイが完了したら、一度Botをブロックしてから友達追加してみましょう。
正しく編集出来ていたらメッセージの送受信が出来るようになっていると思います。
(一人では確認できないので、友達を招待してください)

ただし、お頭が少々残念な方々を招待しすぎると2chのようなカオスな空間が出来てしまうので注意が必要です。
bot.png

※ルームにそぐわない方は後でBotから排除させて頂きました☆

コードの説明

追加した処理ごとに説明をしていきます。

ユーザーの追加機能

index.js
        if (event.type == 'follow'){
            function getUniqueStr(myStrong){
                var strong = 1000;
                if (myStrong) strong = myStrong;
                    return new Date().getTime().toString(16)  + Math.floor(strong*Math.random()).toString(16)
            }

            let uuid         = getUniqueStr();
            let line_user_id = event.source.userId;

            user_ids[uuid] = line_user_id;

            unlink('./user_ids.json');
            writeFile('./user_ids.json', JSON.stringify(user_ids));

            console.log('------updated follow function------');
            console.log(user_ids);
            console.log('------updated follow function------');
        }

イベントのタイプがfollow(友達追加)だった場合
ランダムに作成した番号とユーザーのLineIdをセットにしたHashを、パースしたuser_idsに追加し、その値を元にuser_ids.jsonを更新しています。

ユーザーの削除機能

index.js
        if (event.type == 'unfollow'){
            for(key in user_ids){
                if(user_ids[key] == event.source.userId){
                    delete user_ids[key]
                    writeFile('./user_ids.json', JSON.stringify(user_ids));

                    console.log('------updated unfollow function------');
                    console.log(user_ids);
                    console.log('------updated unfollow function------');
                }
            }
        }

イベントのタイプがunfollow(ブロック)だった場合
ブロックしてきたユーザーのLineIdをuser_ids.jsonから削除しています。

登録しているユーザー全員へメッセージを転送する機能

index.js
        if (event.type == "message" && event.message.type == "text"){
            let message = {
                type: 'text',
                text: event.message.text
            };

            for(key in user_ids){
                if(user_ids[key] != event.source.userId){
                    bot.pushMessage(user_ids[key], message);
                }
            }
        }

イベントのタイプがmessageでしかもそのtypeがtextだった場合(メッセージを送信した場合)
user_ids.jsonに保存していた、メッセージを送信したユーザー以外のLineIdに向かいメッセージを送信しています。

動作確認方法

「どんな仕組みで動いてんの?」
「なぜか動かない」
そんな方は
Herokuのログをリアルタイムで見ながら、Lineを操作する事がおすすめです。
下記コマンドで吐き出されたログを絶えず見ることができます。

heroku logs --tail

データ管理

このままだと、gitを更新するたびにuser_ids.jsonが初期化されてしまうので、user_ids.jsonをgitの対象外にしておきましょう

git rm --cached user_ids.json

最後に

もし興味があったら、お腹が痛い人たちBotにぜひ参加してみませんか?
QRコードはこれです。
qr.png

何か面白い匿名チャットを思いついたらぜひ作ってみてください!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavascriptでJSON

はじめに

 JavascriptでJSONを扱う機会が多いのでまとめてみます。mapとかreduceとかそろそろ使いこなせるようになりたいです。

前提

 扱うJSONは下のような感じにしました。気分です。最近iPod卒業して以下の3つを品定め中だからです。ランキングは一部抜粋、今Apple Musicに傾きつつあるので、他のやつのランキングはスキップで。まあだいたい同じですし。

var sample = {
    Music_Services:[
        {
            Service: "Apple Music",
            Company: "Apple",
            Top_Song_Ranking:{
                observation_date: "2019-02-09",
                ranking:[
                    {
                        artist: "あいみょん",
                        song: "マリーゴールド",
                        rank: 1
                    },
                    {
                        artist: "ONE OK ROCK",
                        song: "Stand Out Fit In",
                        rank: 2
                    },
                    {
                        artist: "あいみょん",
                        song: "今夜このまま",
                        rank: 3
                    },
                    {
                        artist: "エド・シーラン",
                        song: "Shape of You",
                        rank: 7
                    },
                    {
                        artist: "あいみょん",
                        song: "愛を伝えたいだとか",
                        rank: 9
                    }
                ]
            }
        },
        {
            Service: "Google Play Music",
            Company: "Google",
            Top_Song_Ranking: null
        },
        {
            Service: "Spotify",
            Company: "Spotify AB",
            Top_Song_Ranking: null
        }
    ]
}

* データ構造は適当に作ったものでApple MusicのAPI定義とかに合わせたりしてません。

参照

レコード参照

「音楽サービスのどんなデータ入ってるのかザーッと見たい」

sample["Music_Services"].forEach((item) => {
    console.log(item)
})

{ Service: 'Apple Music',
  Company: 'Apple',
  Top_Song_Ranking: 
   { observation_date: '2019-02-09',
     ranking: [ [Object], [Object], [Object], [Object], [Object] ] } }
{ Service: 'Google Play Music',
  Company: 'Google',
  Top_Song_Ranking: null }
{ Service: 'Spotify',
  Company: 'Spotify AB',
  Top_Song_Ranking: null }

[Object]の中身表示したかったらconsole.log(JSON.stringify(item)) にすれば見れますね。

プロパティ参照

「一覧だと見づらいからどんな属性があるかだけ見たい」

var firstService = sample["Music_Services"][0]
Object.keys(firstService).forEach((data) => {
  console.log(data);
})

Service
Company
Top_Song_Ranking

「もっと深い属性が見たい」

Object.keys(firstService["Top_Song_Ranking"]).forEach((data) => {
  console.log(data);
})
console.log("====")

var firstSong = firstService["Top_Song_Ranking"]["ranking"][0]
Object.keys(firstSong).forEach((data) => {
  console.log(data);
})

observation_date
ranking
====
artist
song
rank

 基本的に1つ目のレコードだけサンプル的にとってきて中を覗く感じです。レコードによってプロパティに過不足ある場合とかは対象外で。

検索

単一検索

「Apple Musicの情報だけ欲しい」

const AppleMusic = sample["Music_Services"].find((item, index) => {
    return (item.Service === "Apple Music")
})
/*こっちでもおなじ
const AppleMusic = sample["Music_Services"].find((item, index) => {
    if(item.Service === "Apple Music") return true
})
*/

console.log(AppleMusic)

{ Service: 'Apple Music',
  Company: 'Apple',
  Top_Song_Ranking: 
   { observation_date: '2019-02-09',
     ranking: [ [Object], [Object], [Object], [Object], [Object] ] } }

ここからはApple Musicしか眼中に入れません。
なので、変数 "AppleMusic"を使いまわします。

複数検索

「あいみょんの曲ってどんぐらいランキング入ってるんだろ」

const Aimyon_Songs = AppleMusic["Top_Song_Ranking"]["ranking"].filter((item, index) => {
    return (item.artist === "あいみょん")
})

console.log(Aimyon_Songs)

[ { artist: 'あいみょん', song: 'マリーゴールド', rank: 1 },
  { artist: 'あいみょん', song: '今夜このまま', rank: 3 },
  { artist: 'あいみょん', song: '愛を伝えたいだとか', rank: 9 } ]

*本当は他にももっと入ってますよ

「英語タイトルの曲どんくらいランキング入ってるんだろ」

const English_Titles = AppleMusic["Top_Song_Ranking"]["ranking"].filter((item, index) => {
    return (item.song.match(/[a-zA-Z]/))
})

console.log(English_Titles)

[ { artist: 'ONE OK ROCK', song: 'Stand Out Fit In', rank: 2 },
  { artist: 'エド・シーラン', song: 'Shape of You', rank: 7 } ]

*おまけ

filterは複数検索の時ですね。findも兼ねますが、なんとなく使い分けたいなと。

制限

「曲名だけ一覧でバーっと見たい」

const song_names = AppleMusic["Top_Song_Ranking"]["ranking"].map(x => x["song"])
console.log(song_names)

[ 'マリーゴールド',
  'Stand Out Fit In',
  '今夜このまま',
  'Shape of You',
  '愛を伝えたいだとか' ]

 mapって主にこういうときに使うイメージですね。他にもあるかな。

集約

「結局ランキングにどういうアーティストが何曲ずつくらい入ってるんだろ」

const summary = AppleMusic["Top_Song_Ranking"]["ranking"].reduce((accum, current)=> {
    //同じアーティスト名がaccumの中にあるか検索
    const element = accum.find((item) => {return item.artist === current.artist});
    //あったらカウントだけする
    if(element){ element.count ++}
    //なかったらaccumに追加してあげる
    else{
        accum.push({
            artist: current.artist,
            count: 1
        });
    }
    return accum
}, []);

console.log(summary)

[ { artist: 'あいみょん', count: 3 },
  { artist: 'ONE OK ROCK', count: 1 },
  { artist: 'エド・シーラン', count: 1 } ]

 reduceは集約するときに使う感じですね。forEachで足していくほうがわかりやすいんですけどreduceが使えたらかっこいいなと。まだまだ慣れません。

おわりに

 reduceはやはり小難しい。あいみょんすごい。もう少し追記していきたいと思っているところです。


  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

image-minによる画像圧縮

1~11のコマンドを実行すると画像の圧縮がすぐに行えるようになります

自分で導入する際にgulpやimageminを調べたりして
大変だったのでコピペだけで使えるようにまとめました。

ターミナルでコマンドを実行してください。

1 - nodebrewをインストール

brew install nodebrew

2 - yarnをインストール

brew install yarn

3 - npm init (npmを使うための設定)

npm init

4 - srcファイルを作成

mkdir src

5 - distファイルを作成

mkdir dist

6 - gulpfile.jsを作成

touch gulpfile.js

7 - gulpをインストール

npm install gulp

8 - imageminをインストール

imagemin

npm i gulp-imagemin

9 - imagemin-mozjpegをインストール

imagemin-mozjpeg

npm i imagemin-mozjpeg

10 - imagemin-pngquantをインストール

imagemin-pngquant

npm i imagemin-pngquant

ここまで実行するとこのようなディレクトリ構造になっています。

スクリーンショット 2019-02-09 17.35.34.png

├ dist                                     ・圧縮した画像が置かれる (ディストリビューションの略)
├ gulpfile.js                       ・gulpの設定を行う          
├ node_modules                     ・nodeの設定が補完される
├ package-lock.json           ・nodeのバージョンを表記する
├ package.json                     ・nodeの設定を記述する
└ src                                       ・圧縮前の画像を保管する                                              

11 - gulpfile.jsに下記をコピぺする

gulpfile.js
const gulp = require('gulp');
const distDir = 'dist';
const srcDir = 'src';
const imagemin = require('gulp-imagemin');
const pngquant = require('imagemin-pngquant');
const mozjpeg = require('imagemin-mozjpeg');

gulp.task('img', () => {
  return gulp.src(srcDir + '/*.{png,jpg,gif}')
    .pipe(imagemin([
      pngquant('65-80'),// 配列を渡すと文字列を渡すようにエラーが出たので画質のみを設定
      mozjpeg({
        quality: 85,
        progressive: true
      }),
      imagemin.svgo(),
      imagemin.optipng(),
      imagemin.gifsicle()
    ]))
    .pipe(gulp.dest(distDir));
});

実行

gulp img

png画像を圧縮

圧縮前 (37KB)

test.png

Using gulpfile ~/test_gulp/gulpfile.js
Starting 'img'...
gulp-imagemin: Minified 1 image (saved 25 kB - 67%)
Finished 'img' after 527 ms

圧縮後 (12KB)

test.png

jpg画像を圧縮

スマホで撮った写真を圧縮してみる。

圧縮前 (1.9MB)

test.jpg

Using gulpfile ~/test_gulp/gulpfile.js
Starting 'img'...
gulp-imagemin: Minified 1 image (saved 25 kB - 67%)
Finished 'img' after 571 ms

圧縮後 (1.2MB)

test.jpg

まとめ

画像容量を6割近く削減することができました。
デザイナーではない素人目ですが画像の劣化などあまり気になりませんでした。

・基本的に gulpfile.js を変更すれば設定を変更可能です。
・細かい圧縮の設定などを変更したい場合はリンクの公式のオプションを参考にしてみてください。

ここまでお読みいただきありがとうございました。

雑談:iPhoneXの画質すごい

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コピペですぐに使えるimage-minによる画像圧縮

1~11のコマンドを実行すると画像の圧縮がすぐに行えるようになります

自分で導入する際にgulpやimageminを調べたりして
大変だったのでコピペだけで使えるようにまとめました。

ターミナルでコマンドを実行してください。

1 - nodebrewをインストール

brew install nodebrew

2 - yarnをインストール

brew install yarn

3 - npm init (npmを使うための設定)

npm init

4 - srcファイルを作成

mkdir src

5 - distファイルを作成

mkdir dist

6 - gulpfile.jsを作成

touch gulpfile.js

7 - gulpをインストール

npm install gulp

8 - imageminをインストール

imagemin

npm i gulp-imagemin

9 - imagemin-mozjpegをインストール

imagemin-mozjpeg

npm i imagemin-mozjpeg

10 - imagemin-pngquantをインストール

imagemin-pngquant

npm i imagemin-pngquant

ここまで実行するとこのようなディレクトリ構造になっています。

スクリーンショット 2019-02-09 17.35.34.png

├ dist                                     ・圧縮した画像が置かれる (ディストリビューションの略)
├ gulpfile.js                       ・gulpの設定を行う          
├ node_modules                     ・nodeの設定が補完される
├ package-lock.json           ・nodeのバージョンを表記する
├ package.json                     ・nodeの設定を記述する
└ src                                       ・圧縮前の画像を保管する                                              

11 - gulpfile.jsに下記をコピぺする

gulpfile.js
const gulp = require('gulp');
const distDir = 'dist';
const srcDir = 'src';
const imagemin = require('gulp-imagemin');
const pngquant = require('imagemin-pngquant');
const mozjpeg = require('imagemin-mozjpeg');

gulp.task('img', () => {
  return gulp.src(srcDir + '/*.{png,jpg,gif}')
    .pipe(imagemin([
      pngquant('65-80'),// 配列を渡すと文字列を渡すようにエラーが出たので画質のみを設定
      mozjpeg({
        quality: 85,
        progressive: true
      }),
      imagemin.svgo(),
      imagemin.optipng(),
      imagemin.gifsicle()
    ]))
    .pipe(gulp.dest(distDir));
});

実行

gulp img

png画像を圧縮

圧縮前 (37KB)

test.png

Using gulpfile ~/test_gulp/gulpfile.js
Starting 'img'...
gulp-imagemin: Minified 1 image (saved 25 kB - 67%)
Finished 'img' after 527 ms

圧縮後 (12KB)

test.png

jpg画像を圧縮

スマホで撮った写真を圧縮してみる。

圧縮前 (1.9MB)

test.jpg

Using gulpfile ~/test_gulp/gulpfile.js
Starting 'img'...
gulp-imagemin: Minified 1 image (saved 25 kB - 67%)
Finished 'img' after 571 ms

圧縮後 (1.2MB)

test.jpg

まとめ

画像容量を6割近く削減することができました。
デザイナーではない素人目ですが画像の劣化などあまり気になりませんでした。

・基本的に gulpfile.js を変更すれば設定を変更可能です。
・細かい圧縮の設定などを変更したい場合はリンクの公式のオプションを参考にしてみてください。

ここまでお読みいただきありがとうございました。

雑談:iPhoneXの画質すごい

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【コピペですぐに使える】画像圧縮機能

1~11のコマンドを実行すると画像の圧縮がすぐに行えるようになります

自分で導入する際にgulpやimageminを調べたりして
大変だったのでコピペだけで使えるようにまとめました。

ターミナルでコマンドを実行してください。

1 - nodebrewをインストール

brew install nodebrew

2 - yarnをインストール

brew install yarn

3 - npm init (npmを使うための設定)

npm init

4 - srcファイルを作成

mkdir src

5 - distファイルを作成

mkdir dist

6 - gulpfile.jsを作成

touch gulpfile.js

7 - gulpをインストール

npm install gulp

8 - imageminをインストール

imagemin

npm i gulp-imagemin

9 - imagemin-mozjpegをインストール

imagemin-mozjpeg

npm i imagemin-mozjpeg

10 - imagemin-pngquantをインストール

imagemin-pngquant

npm i imagemin-pngquant

ここまで実行するとこのようなディレクトリ構造になっています。

スクリーンショット 2019-02-09 17.35.34.png

├ dist                                     ・圧縮した画像が置かれる (ディストリビューションの略)
├ gulpfile.js                       ・gulpの設定を行う          
├ node_modules                     ・nodeの設定が補完される
├ package-lock.json           ・nodeのバージョンを表記する
├ package.json                     ・nodeの設定を記述する
└ src                                       ・圧縮前の画像を保管する                                              

11 - gulpfile.jsに下記をコピぺする

gulpfile.js
const gulp = require('gulp');
const distDir = 'dist';
const srcDir = 'src';
const imagemin = require('gulp-imagemin');
const pngquant = require('imagemin-pngquant');
const mozjpeg = require('imagemin-mozjpeg');

gulp.task('img', () => {
  return gulp.src(srcDir + '/*.{png,jpg,gif}')
    .pipe(imagemin([
      pngquant('65-80'),// 配列を渡すと文字列を渡すようにエラーが出たので画質のみを設定
      mozjpeg({
        quality: 85,
        progressive: true
      }),
      imagemin.svgo(),
      imagemin.optipng(),
      imagemin.gifsicle()
    ]))
    .pipe(gulp.dest(distDir));
});

実行

gulp img

png画像を圧縮

圧縮前 (37KB)

test.png

Using gulpfile ~/test_gulp/gulpfile.js
Starting 'img'...
gulp-imagemin: Minified 1 image (saved 25 kB - 67%)
Finished 'img' after 527 ms

圧縮後 (12KB)

test.png

jpg画像を圧縮

スマホで撮った写真を圧縮してみる。

圧縮前 (1.9MB)

test.jpg

Using gulpfile ~/test_gulp/gulpfile.js
Starting 'img'...
gulp-imagemin: Minified 1 image (saved 25 kB - 67%)
Finished 'img' after 571 ms

圧縮後 (1.2MB)

test.jpg

まとめ

画像容量を6割近く削減することができました。
デザイナーではない素人目ですが画像の劣化などあまり気になりませんでした。

・基本的に gulpfile.js を変更すれば設定を変更可能です。
・細かい圧縮の設定などを変更したい場合はリンクの公式のオプションを参考にしてみてください。

ここまでお読みいただきありがとうございました。

雑談:iPhoneXの画質すごい

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub Link Card Creatorがカッコいいのでnpm scriptsに組み込む

はじめに

みんなにOSSを見てもらいたい人の為に、GitHubリポジトリのOGP的画像を自動生成してくれるサービスを作った
こちらの記事で紹介されているGitHub Link Card Creatorが素晴らしくカッコいいので、node.jsのnpm scriptsに組み込む方法を模索してみました。

対象とするユーザー

  • Go?なにそれ?
  • 普段はnode.jsを使っている。
  • ターミナルを触ったことがある。
  • 自作のGitHubリポジトリにリンクカードをつけたい。
  • macユーザーである。

この記事の環境

この記事は以下の環境を想定しています。各ソフトのバージョンが異なると、記事の内容は適用できない場合があります。ご注意ください。

  • macOS 10.14.3
  • node 8.11.4
  • go 1.11.5 darwin/amd64
  • Homebrew 2.0.0

この記事で解消したい問題

GitHub Link Card CreatorにはオフィシャルのWebアプリケーションがあります。
GitHub Link Card Creator

こちらのWebアプリケーションを利用すれば、画像の生成からリンクコードの出力までが一気にできます。
しかし、出力された画像URLがQiitaでは直接利用できないという問題があります。(参考 :issue#4)

現状では、生成された画像をQiitaの記事内にアップロードし、生成されたリンクURLを書き換えることで対応が可能です。
しかしQiitaに画像をアップロードしてしまうと、カード情報の更新のたびに再アップロードが必要になります。

この問題を解消するため

  • GitHub Link Card Creatorをローカル環境で動かす。
  • npm scriptsのタスクに組み込む。
  • 生成された画像をGitHub Pagesにプッシュする。
  • Qiitaの記事から画像を読み込む。

という組み込み作業を行ってみます。

Goとは

Go公式ページ

GoはGoogleが主導して開発しているプログラム言語およびその環境です。
正式な名称はGoですが、golangと呼ばれることもあります。
開発環境はオープンソースで、パッケージをインストールすればマルチプラットフォームで動作します。

設定

macOS環境で、Homebrewを経由してGoパッケージをインストールします。

Homebrewのインストール

Homebrew
HomebrewはmacOS用のパッケージマネージャーです。Homebrewからさまざまなパッケージをインストールできます。
すでにHomebrewを導入している人は、この項目をスキップしてください。

このスクリプトをターミナルに入力すると、Homebrewがインストールされます。

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

インストールが成功したか確認するためにバージョンを表示してみます。

brew -v
Homebrew 2.0.0

バージョン番号が表示されたら無事インストール成功です。

Go環境の構築

インストール

先ほどインストールしたHomebrewを利用して、Goのパッケージをインストールします。

brew install go

パッケージのサイズが100MB以上ありますので、少し処理に時間がかかります。ゆっくりお待ちください。

go version
go version go1.11.5 darwin/amd64

こちらもバージョン情報が表示できればインストール成功です。

GitHub Link Card Creatorのインストール

GitHub Link Card Creatorパッケージは、以下のコマンドでインストールできます。

go get github.com/po3rin/github_link_creator/cmd/repoimg

ホームディレクトリ直下のgoフォルダーの中にファイルが保存されていれば、インストールは成功です。

パスの設定

GitHub Link Card Creatorはターミナルからコマンドrepoimgで呼び出すことができます。
このコマンドが通るように、ターミナルにパスを通す必要があります。

このパスはホームディレクトリ直下の.bash_profileというファイルに保存されています。
このファイルに以下の2行のパスを追加します。

export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

ターミナルから.bash_profileを編集する方法はこちらの記事をご参照ください。
MacでPATHを通す

また、Finderとお好きなテキストエディターを使って編集することもできます。

Finderから「移動」→「フォルダへ移動…」を選択し

~/.bash_profileへ移動します。
ここで表示されたファイルをお好きなテキストエディターで編集してください。

ターミナルの再起動

.bash_profileの変更はそのままでは反映されません。再読み込みのコマンドを実行するか、ターミナルを再起動する必要があります。

再読み込みのコマンドは以下の通りです

source ~/.bash_profile

.bashrcや.bash_profileなどの変更設定をすぐに反映させたい

WebStormやVS Codeなどのターミナルを内包しているソフトも、再起動をする必要があります。

以下のようなエラーが出る場合は、.bash_profileの反映ができていません。ソフトやmacの再起動を試してみてください。

bash: repoimg: command not found

ここまでの作業でGitHub Link Card Creatorがターミナルから呼び出せるようになりました。

repoimg -n <GitHubのユーザー名>/<リポジトリ名>

で画像が生成されれば成功です。

GitHub Pagesの設定

次に、GitHub Pagesの公開設定を行います。


まずは作成済みのリポジトリのWebページにアクセスし、Settingsを開きます。


次に、GitHub Pagesの設定項目に移動し、Sourceをmaster Branch /docs folderに変更します。

これでリポジトリの./docs以下がhttps://<ユーザー名>.github.io/<リポジトリ名>/でアクセスできます。

npm scriptsに統合

最後に、npm scriptsにrepoimgコマンドを組み込みます。

package.json
  "scripts": {
    "doc:card": "repoimg -n <GitHubのユーザー名>/<リポジトリ名> -o ./docs/card.png"
  }

このスクリプトで./docs/card.pngが生成されます。
このファイルをプッシュすると以下のURLでアクセスができます。

https://<ユーザー名>.github.io/<リポジトリ名>/card.png

このURLをGitHub Link Card Creatorで生成される埋め込みコードに組み込むと

無事Qiitaの記事からGitHub Pagesの画像ファイルが読み込めました!

以上、ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む