20200122のNode.jsに関する記事は12件です。

Slackに匿名で画像を投稿できるようにした

はじめに

Slackで匿名チャンネルを作りました。
直接聞きにくい相談やちょっとした雑談で使えるので便利です。

「画像も投稿できたらコミュニケーションの幅が広がるのでは?」と思ったのがきっかけで、
画像も匿名で投稿できるようにしました。

処理の流れとしては、
1. BotにDMで画像を送信する
2. Botが画像を受け取ったら、ローカルに保存する
3. 指定したチャンネルに保存した画像をBotが代わりに投稿する
4. ローカルに保存した画像を削除する
5. 終わり
となってます。

JavaScript初心者なので至らない点もあると思いますが、ご了承ください。

準備

この記事を参考に、

  • ワークスペース内で使うSlack Botの作成
  • API Tokenの取得
  • Botkitのインストール

を行ってください。

説明のために、今回作成したBotの名前は"anonymous_bot"とします。

BotとChannelのIDを取得

先ほど取得したAPI Tokenを使って、Botと匿名で投稿したいチャンネルのIDを取得してください。

  • BotのIDを取得
    https://slack.com/api/users.list?token=さっき取得したAPI_Token
  • ChannelのIDを取得
    https://slack.com/api/channels.list?token=さっき取得したAPI_Token

取得できるIDは、大文字のアルファベットと数字の組み合わせになっているはずです。
例:ABC0ED123

プログラムの作成

以下のプログラムをコピペしてください。

slack_bot.js
const Botkit = require('/path/to/Botkit.js');
const os = require('os');
const fs = require('fs');
const download = require('download');
const https = require('https');
const del = require('delete');

const slackBot_id = 'BotのID';
const channel_id = '投稿したいChannelのID';
const token = '取得したAPI Token';

var controller = Botkit.slackbot({
    debug: false,
});

var bot = controller.spawn({
    token: token
}).startRTM();

controller.on('file_shared', function(bot, message){

    if(message.user_id != slackBot_id){ //Bot自身の投稿には反応しない
        const messageObj = {
            token: token,
            file: message.file_id
        };

        bot.api.files.info(messageObj, function(err, res){
            if(err){
                console.log(err)
            }

            else{
                console.log('[file_shared] on');
                var now = new Date();
                var file_name = now.getFullYear()+':'+(now.getMonth()+1)+':'+now.getDate()+':'+now.getHours()+':'+now.getMinutes()+':'+now.getSeconds()+'.jpg';
                var file_dir = '/path/to/image_dir/';
                var file_path = file_dir + file_name; //ローカルに保存する際のディレクトリとファイル名
                var file_url = res.file.url_private_download;//送信された画像のURL

                var options = {
                    'method': 'GET',
                    'hostname': 'files.slack.com',
                    'path': file_url,
                    'rejectUnauthorized': 'false',
                    'headers': {
                    'Authorization': 'Bearer ' + token
                    }
                };

                var file = fs.createWriteStream(file_path);
                var responseSent = false;

                //URL先の画像をローカルに保存
                https.get(options, response => {
                    response.pipe(file);
                    file.on('finish', () => {
                        file.close(() => {
                            if(responseSent) return;
                            responseSent = false;
                        });//file.close
                    });//file.on
                });//https.get
                console.log('file download');

                //時間差で画像の送信→画像の削除を行う
                setTimeout(() => {
                    const messageObj = {
                            file: fs.createReadStream(file_path),
                            filename: file_name,
                            title: file_name,
                            channels: channel_id
                    };
                    bot.api.files.upload(messageObj, function(err, res){
                        if(err){
                            console.log(err);
                        }

                        else{
                            console.log('file upload');
                        }
                    });//bot.api.files

                    setTimeout(() => {
                        del([file_path], function(err, res){
                            if(err){
                                console.log(err);
                            }

                            else{
                                console.log('file delete');
                            }
                        });//del
                    }, 1000);//setTimeout
                },1000);//setTimeout

            }//else
        });//bot.api.files
    }//if

    console.log("finish");
});//controller.on

実行方法

# Botの起動
$ forever start slack_bot.js 

# Botの停止
$ forever stop slack_bot.js

BotにDMで画像を送ると、
Screenshot from 2020-01-22 23-18-54.png

Botが指定したチャンネルに代わりに投稿してくれます。
Screenshot from 2020-01-22 23-17-00.png


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

Glitchが全く動作しない時または誤作動でコード変えても反応しないときの対処法

対処方法

  1. Consoleを開く コマンドライン
  $ killall node

を実行する。
2. しばらくたってそれ以上動かなかったら、
package.json の一部の空白一文字消す。
3. しばらくたつと動く。

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

pre-commitとtextlintを使ってHTMLに潜むゼロ幅スペース文字や記号の表記ゆれを倒す

概要

括弧や数字の全角半角が表記揺れしていたり、href内にゼロ幅スペースが紛れ込んでいてリンク切れが起こってしまったりすることをtextlintを使って防ごうという記事です。

サクッとページ単位で確認できればいい方はこちら

textlintとは?

文章の校正をしてくれるリンターツールです。漢字よりひらがなのほうがいい場合や、「てにをは」がおかしいような文章を指摘してくれます。

導入手順

1. プロジェクトの作成

※ この工程はpackage.jsonを生成するものです。すでにある方はスキップしてください。

npm init

2. パッケージのインストール

npm install --save-dev textlint textlint-rule-prh # textlint関係
npm install --save-dev husky lint-staged # pre-commit関係

3. pre-commitが動作するように設定する

package.jsonに次の項目を追記してください。

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.html": "textlint"
  }
}

4. textlintの設定ファイルを作成

./node_modules/.bin/textlint --init

作成された.textlintrcファイルの中身を次のように上書きしてください。
これでtextlintがHTMLファイルを読むようになり、オリジナルの辞書を利用するようになります。

※今回は使いませんがHTMLを読むためのプラグイン「textlint-plugin-html」については後述します。

{
  "filters": {},
  "rules": {
    "prh": {
      "rulePaths": ["./prh.yml"]
    }
  },
  "plugins": {
    "@textlint/text": {
        "extensions": [".html"]
    }
  }
}

5. 辞書ファイルを作成

package.jsonと同じ階層にprh.ymlというファイルを作成します。
中身を次のように設定してみてください。

version: 1
rules:
  - expected: VS Code
    patterns: VSCode
    prh: 正しい表記はVS Code

  - expected: ""
    patterns: "/[\\u034f\\u200b\\u200c\\u200d\\u200e\\u200f\\u2028\\u2029\\u202a\\u202b\\u202c\\u202d\\u202e\\u2061\\u2062\\u2063\\ufeff]/"
    prh: ゼロ幅スペースを検出しました

項目を増やしたいときは次の塊を追加することで対応できます。patternsには正規表現も利用できますし、リストで複数項目設定することもできます。

  - expected: 正しい表記
    patterns: 検出する表記
    prh: エラーメッセージ(説明文)

参考:prh/prh.yml at master · prh/prh

6. 試してみる

プロジェクト内に適当なHTMLファイルを作成します。たとえば、test.htmlなど。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<p>私はVSCodeが好きです</p>
<p>ここに→"​"←ゼロ幅スペース文字がいます</p>
</body>
</html>

このHTMLファイルがpackage.jsonと同じ階層にあるとき、次のようなコマンドでリンターに検査させられます。

./node_modules/.bin/textlint test.html

するとおそらく次のようなログがでるはずです。

D:\dummy\dummy\test.html
  10:6  ✓ error  VSCode => VS Code
正しい表記はVS Code           prh
  11:9  ✓ error  ​ =>
ゼロ幅スペースを検出しました  prh

✖ 2 problems (2 errors, 0 warnings)
✓ 2 fixable problems.
Try to run: $ textlint --fix [file]

出ない場合は、node_modulesフォルダを削除し、npm iコマンドを実行してみてください。

7. コミットしてみる

うまくpre-commitが動作していれば次のようなエラーが出てコミットが中断されるはずです。
こちらもうまく出ない場合は、node_modulesフォルダを削除し、npm iコマンドを実行してみてください。

Sourcetree

image.png

TortoiseGit

image.png

いろいろ試してみよう

検出には正規表現も使えるので、他にも様々な表記ゆれや誤実装を回収できそうです。

  - expected: 
    patterns: (
    prh: 全角括弧を利用してください

  - expected: 
    patterns: )
    prh: 全角括弧を利用してください

などなど…。Webサイトの運用で表記ゆれやゼロ幅スペースにお困りの場合は試してみてください。

タグを無視するtextlint-plugin-html

HTMLのタグを無視させたい場合はtextlint-plugin-htmlを一緒にインストールしてください。

npm i -D textlint-plugin-html

.textlintrcの設定は次のようになります。

{
  "filters": {},
  "rules": {
    "prh": {
      "rulePaths": ["./prh.yml"]
    }
  },
  "plugins": [
    "html"
  ]
}

なお、どうやら&copy;などは「©」として解釈されるようなので、不要な実態参照を検出するルールはできない模様。たぶん。おそらく。

検出されない場合がある(追記)

コードの順番など、特定のケースでうまく検出されない場合がある模様。調査中。
https://github.com/textlint-rule/textlint-rule-prh/issues/74

参考文献

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

[JavaScript][Node.js]メモ:アロー関数の即時関数(関数を定義してその場で実行する)

アロー関数と即時関数を組み合わせる書き方。

const a = (() => {
    // 何らかの処理
    return 'Hello!'
})()

余談だが、即時関数の正式名は、「IIFE (即時実行関数式)」っぽい。
「即時関数」でググっても公式のドキュメントにはなかなかたどり着けない。

参考リンク

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

QualityForward APIを使ってテストスイートを作成する際の注意点

QualityForwardはクラウドベースのテスト管理サービスです。APIを公開しており、テスト管理に関するデータのCRUD操作ができるようになっています。テストケースであったり、それらをまとめたテストスイートなどを作成できます。

今回、APIを使うためのSDKを開発していてハマったポイントについて、メモしておきます。

テストスイートが表示されない

テストスイートは次のAPI操作で作成できます。

POST /api/v2/test_suites.json

そして、作成はできるのですが、なぜか一覧には出ません。Node.js SDKで書くと、次のようなコードです。

const count = testSuites.length;
const testSuite: TestSuite = client.TestSuite();
testSuite.name = 'APIから作成したテストスイート';
testSuite.project_id = 748;
testSuite.label_category1 = '機能カテゴリ';
testSuite.use_category1 = true;
testSuite.label_content1 = '環境';
testSuite.use_content1 = true;
testSuite.coverage_panel_column = null;
await testSuite.save();

Web上での操作を真似る

そこでWeb上の管理画面での操作を見てみたところ、テストスイートを作成すると同時にテストスイートバージョンが作成されていることが分かりました。テストスイートバージョンはテストスイートをバージョン管理し、同じテストケースを繰り返しテストするための仕組みです。

つまりテストスイートを作成しただけでは十分ではなく、同時にテストスイートバージョンも作成する必要がありました。コードとしては、下記を追加します。

// テストスイートバージョンの作成
const tsv = testSuite.version();
tsv.name = 'バージョン1';
// テストスイートにセット
testSuite.setVersion(tsv);
// そしてテストスイートを保存
await testSuite.save();

こうしてあげることで、テストスイート一覧にAPIから作成したテストスイートが表示されるようになりました。

Screenshot_ 2020-01-22 16.09.08.png

まとめ

APIドキュメントには、まだアンドキュメントな部分が多く、手探りが必要な部分が多々あります。SDKは現在、Node.js / Python / Ruby / Google Apps Script版を開発しています。SDKから利用することで、なるべくアンドキュメントなところをエラーで返すようにしていきますので、ぜひご利用ください。

QualityForward

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

DynamoDBでPromiseが使えた(Lambda Node.js)

はじめに

Lambda(Node.js)でDynamoDBに接続し、値を取得したいときに、
非同期であるために、自分でPromiseで返す関数を作成していた。

コード

/**
 * データの挿入を行う。
 * @param ddb
 * @param params
 * @returns {Promise<any>}
 */
exports.addItem = function (ddb, params) {
    return new Promise(function (resolve) {
        ddb.putItem(params, function (err, data) {
            if (err) {
                console.log("PUT失敗", err, err.stack);
            } else {
                console.log("PUT成功");
                resolve(data);
            }
        });
    });
};

await this.addItem(ddb, putParams);

改善後

なんと最後にpromise()を呼ぶことで、Promise型のものを返却してくれるようで、わざわざ自分でラップする必要がなかった。

await ddb.getItem(findParams, function (err, data) {
            if (err) {
                console.log("GET失敗");
            } else {
                console.log("GET成功");
            }
        }).promise();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cannot find module 'express' | dockerでNode.js

Node.jsで必要なファイルやディレクトリなどは割愛

早速、エラーが出たときの設定は以下の通り

Dockerfile

appディレクトリを作成、その中にDockerfileを保存します。

Dockerfile
# nodeの最新バージョンを指定
FROM node:10

#docker内でのディレクトリを作成
RUN mkdir /code
WORKDIR /code

# node.js公式サイトのdocker化ドキュメント通り
# copy先にcodeディレクトリを指定
COPY package*.json /code/

RUN npm install
RUN npm install express --save
RUN useradd -md /bin/bash local
ADD . /code/

CMD [ "npm", "start" ]

docker-compose.yml

docker-compose.yml
version: '3'

services:
  prog-app:
    build:
      context: ./app/
    image: sample-app-node
    command: bash -c "npm run start"
    volumes:
      - ./app/:/code
    container_name: sampapp
    ports:
      - "8001:5000"
    environment:
      TZ: 'Asia/Tokyo'

package.json

package.json
{
  "name": "sample-app",
  "version": "1.0.0",
  "description": "sample app description",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node app.js"
  },
  "repository": {
    "type": "git",
    "url": ""
  },
  "license": "MIT",
  "dependencies": {
    "express": "^4.17.1",
    "ejs": "^3.0.1"
  },
  "engines": {
    "node": "10.x"
  }
}

app.js

app.js
const express = require('express');
const index = require('./routes/index');
const port = process.env.PORT || 5000;

const app = express();

app.use('/static', express.static('public'));

app.set('view engine', 'ejs');

app.use('/', index);

app.listen(port, () => console.log(`app listening on port ${port}!`));

module.exports = app;

error

internal/modules/cjs/loader.js:638
    throw err;
    ^

Error: Cannot find module 'express'

expressがなぜか使えない。
以下のサイトに解決策がありました。
https://castaneai.hatenablog.com/entry/2019/01/29/151257

docker-compose.yml
version: '3'

services:
  prog-app:
    build:
      context: ./app/
    image: sample-app-node
    command: bash -c "npm run start"
    volumes:
      - ./app/:/code
      - /code/node_modules # 追加
    container_name: sampapp
    ports:
      - "8001:5000"
    environment:
      TZ: 'Asia/Tokyo'

dockerコンテナ・イメージ削除しdocker-compose upを再度実行すれば、以下のように成功しました。

> sample-app@1.0.0 start /code
> node app.js

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

Node.js(axios)からDiscordに通知を送るメモ

忘れがちなのでコピペできる簡単なサンプルをメモしておきます。

スクリーンショット 2020-01-22 13.25.38.png

準備

$ mkdir myapp
$ cd myapp
$ npm init -y

インストール

$ npm i axios

コード

app.js
'use strict'

const axios = require('axios');
const URL = `DiscordのWebhook URL`;

//ヘッダーなどの設定
const config = {
    headers: {
        'Accept': 'application/json',
        'Content-type': 'application/json',
    }
}

//送信するデータ
const postData = {
    username: 'n0bisuke BOT',
    content: 'Node.jsからポストしてるよ :)'
}

const main = async () => {
    const res = await axios.post(URL, postData, config);
    console.log(res);    
}

main();

実行するとPOSTされます。

$ node app.js

ちなみにcurl版

curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"username":"n0bisuke BOT","content":"Node.jsからポストしてるよ :)"}' 'DiscordのWebhook URL'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript: 変数の初期化では`undefined` と `null` のどちらを使うのがよい?

概要

JavaScriptには undefinednull があります。

先ほど以下のようなコードを見かけました。

let callback = undefined;

私個人としては初期化の時は null を入れておくことが多いので、変数の初期化ではundefinednull のどちらを使うのがよいのか考えました。

個人的な結論

undefined はその名の通りundefinedを示すものです。
変数を初期化している以上、その変数はundefinedとは呼べないのではないかと。

そんなこんなで 「初期化の時は null を入れておく」 に落ち着きました。

補足

ググり力が足りないためか良い感じの初期化に関するドキュメントが見つけられませんでした。
何かあれば教えていただけると嬉しいです。

補足2

いろんなところに書かれている内容ではありますが、udefinednull の比較について。

% node -v
v12.14.1
> undefined == undefined
true
> undefined == null
true
> null == null
true

> undefined === undefined
true
> undefined === null
false
> null === null
true

ポイント: undefined == nulltrue

参考

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

Microsoft Bot FrameworkをMicrosoft Azureにデプロイするチュートリアルをかみ砕いてみた

はじめに

タイトルの通りです。Microsoft Bot Frameworkのチュートリアルで詰まりまくって具体的なパラメータをどう与えればいいのかわからなかったので、具体的な例を作って整理してみました。CMD上からのAzureログインからデプロイまで。

参考資料・前提条件

これの「ボットをデプロイする」の直前までが終わっていることが前提です。
基本的なボットの作成とデプロイに関するチュートリアル - Bot Service | Microsoft Docs

作業

1. Microsoft Azureにログインする。

Microsoft Azureにログインします。cmdでコマンドを叩くとそのままブラウザが立ち上がり、ブラウザ上でログインすることができます。

cmd
az login

2. アカウントリストを取得する

下記のコマンドを入力し、アカウントリストを取得します。

cmd
az account list

すると、このような感じでサブスクリプションのデータが出てきます。

cmd-こんなサブスクリプションデータだったとする
[
  {
    "cloudName": "AzureCloud",
    "id": "piyopiyo-piyo-nyan-nyan-hogehogehoge",
    "isDefault": true,
    "name": "無料試用版",
    "state": "Enabled",
    "tenantId": "hoge-hoge-fuga-fuga-piyopiyo",
    "user": {
      "name": "*****@hogehoge.com",
      "type": "user"
    }
  }
]

以降、これを使って説明していきます。

3. Azureのサブスクリプションにアクセスする

サブスクリプションの指定はcmd上で次のように入れます。チュートリアルの<azure-subscription>とは、上でいうところの"id"が対応します。

cmd
az account set --subscription "piyopiyo-piyo-nyan-nyan-hogehogehoge"

4. アプリケーションを登録する

アプリを作ります。

cmd
az ad app create --display-name "samplebot_hoge2" --password "password_hogefuga1" --available-to-other-tenants

--display-name:名前です。サンプルは適当(samplebot_hoge2)です。
--password:パスワードです。サンプルは適当(password_hogefuga1)です。

これを実行して問題なく作成できると、JSON形式でいろいろと出てきますが、appIdというGUIDをそのまま使用するので、控えておきましょう。

出てくるもの
{
  "acceptMappedClaims": null,
  "addIns": [],
  "allowGuestsSignIn": null,
  "allowPassthroughUsers": null,
  "appId": "fugafuga-piyo-piyo-piyo-hogehogehoge",
  "appLogoUrl": null,
...
控えておくべき情報
  "appId": "fugafuga-piyo-piyo-piyo-hogehogehoge",

5. ARM テンプレートを使用してデプロイする

ここからがめちゃくちゃ詰まりました。値のそれぞれの意味を整理しています。

そもそもARMテンプレートってなに

ARMはAzure Resource Managerの略であり、そのテンプレートをベースにすることでAzure内でうまくデプロイできるようです。すごい便利なんだなぁ、と思いました(小並感)
より詳しくは@t-tsurumiさんのAzureのARMテンプレートを理解する part1(基本編)が参考になるかと思います。

App Service Planがないとき

最初からやってみているときにはチュートリアルの「App Service Planがないとき」を実施しましょう。

cmd
az deployment create 
--name "samplebot-1gou" 
--template-file "./deploymentTemplates/template-with-new-rg.json" 
--location "centralus" 
--parameters 
appId="fugafuga-piyo-piyo-piyo-hogehogehoge" 
appSecret="password_hogefuga1" 
botId="samplebotkun03" 
botSku=F0 
newAppServicePlanName="new-sample-bot-plan-99" 
newWebAppName="newsamplebotkun-0X" 
groupName="atarashii-group" 
groupLocation="Central US" 
newAppServicePlanLocation="japaneast"

与える値の内容は下記

項目 項目名 任意 備考
--name - 任意 わかりやすいボットの名称。適当につけてOK
--template-file - 既存 テンプレートファイルtemplate-with-new-rg.jsonが参照できるようにパスを入れてあげる。template-with-new-rg.jsonはボットの作成時に自動で生成される
--location - 既存 ロケーション。値はaz account list-locationsをcmd上で叩いて確認。jsonの形式で出力されるのでname項目を入れる
--parameters appId 既存 4で作成したappIdのGUID
--parameters appSecret 既存 4で作成した--passwordのパスワード
--parameters botId 任意 自分が作ったボットの名称。任意
--parameters botSku 既定 価格レベル。F0 (無料) または S1 (Standard) を指定できる
--parameters newWebAppName 任意 Webアプリとして展開するための名称。任意
--parameters newAppServicePlanName 任意 アプリサービスの名称。任意
--parameters newWebAppName 任意 アプリサービスの名称。任意
--parameters newAppServicePlanLocation 既定 リソースタイプに応じて決まったロケーションが定義されている。エラーの記載で詳しく教えてくれる。

6. デプロイ用のコードを準備する

ボットのルートディレクトリ上で、下記コマンドをそのまま実行します。
言語ごとに決まっていますが、下記の例はTypescriptです。成功するとweb.configができます。

cmd
az bot prepare-deploy --code-dir "." --lang Typescript

Kuduと呼ばれるAzure WebAppsで利用されているデプロイエンジンを用いてデプロイします。
そのために、まずは、フォルダの中身を下記のようにすべて選択してzip圧縮します。zipファイル名をcode.zipとします。

sample.png

その後、下記のようにコマンドを叩きます。

cmd
az webapp deployment source config-zip --resource-group "atarashii-group" --name "newsamplebotkun-0X" --src "code.zip" 
項目 項目名 任意 備考
--resource-group - 既存 アプリケーションを作成したリソースグループ名
--name - 既存 5で定義したnewWebAppNameの値
--src - 既存 直前の手順で作成したzipファイル名

これが正常に終了して、結果のJSONが出力されればデプロイは完了です。

7.実際に動かしてみる

のこりはチュートリアルに従えばあまり詰まらずに実行することができます。
Web チャットでのテスト | 基本的なボットの作成とデプロイに関するチュートリアル - Bot Service | Microsoft Docs

エラー対応

Deployment failed. Correlation ID: ***

デプロイが失敗したことを示しています。Correlation ID(関連ID)に基づいて、ポータルなどでエラーの詳細を参照できます。

詳細はこちらを見ると結構わかりやすいと思います。
Azure Resource Manager でのデプロイ履歴の表示

The Microsoft App ID property was not recognized as a GUID and may be invalid.

原因

MicrosoftAppID が正しく選択されていないのが問題です。

解決策

アプリケーションを初回登録した際に発行されるJSONに含まれているappIdを参照してください。cmdに自分で打ち込んだアプリの名称ではないことに注意しましょう。

参考資料

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

nvmを使ったNode.jsのバージョン管理

これまでWindowsならnodist、Macならnodebrewを使ってきましたが、nvmがユーザー数多いみたい( Google Trend によると)なのでnvm使うことにしたい。

nvmのGitHub上に手順や使い方があるけれど英語でさらに初心者にはさっぱりな部分もあるので自分用の備忘録もかねてのメモです。

(nvmリポジトリ)[https://github.com/nvm-sh/nvm]

Git経由でインストール

インストール方法は他にもあるけどnvmそのものの更新に対応するためには、Git経由でGitHub上のレポジトリクローンがよいみたいです。
更新された場合はプルするだけです。

1. nvm をインストール

github.com から nvm を clone する

$ git clone https://github.com/nvm-sh/nvm.git .nvm

clone したら最新バージョンに checkout してください。

2. nvm を使えるようにする

nvm.sh を実行して nvm を使えるようにする

$ source ~/.nvm/nvm.sh

これで以下が動けば成功です。

$ nvm --version

3. ~/.bashrcに追加

起動時に使えるように設定追加

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

以下で再読み込み

source .bashrc

3. Node.jsをインストール

利用可能なバージョン確認

$ nvm ls-remote

バージョン指定してインストール

$ nvm install <version>

以下が動けば成功

$ node -v
$ npm -v

4. その他よく使うコマンド

インストールしたバージョン一覧

$ nvm ls

使用するバージョンの指定

$ nvm use <version>

nvmの機能一覧

$ nvm --help

▼参考
https://ikkyu.hateblo.jp/entry/2019/05/03/003636
https://phiary.me/nvm-node-js-install/

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

node.jsのsvg変換パッケージconvert-svg-to-jpeg/pngの日本語文字化け対策

問題

svg画像をjpegやpngに変換する際にはconvert-svgを使っています。NodeコードからやCLIからも使えたりと高機能なことに加えて、内部的にブラウザに描画したSVGをラスター化しているので変換後の仕上がりが素直で気に入っています。

以前、日本語を含んだSVG画像を変換した際に文字化けに遭遇したので、その原因、対策をメモしておきます。

文字化けした画像はこんな感じ。

原因

内部的にSVGをブラウザ上で表示する際に利用するHTMLテンプレート上に文字コードの指定がされていないため。

具体的には、変換の共通処理を記述しているconvert-svg-coreに含まれる以下の箇所

Converter.js
...
    let html = `<!DOCTYPE html>
<base href="${options.baseUrl}">
<style>
* { margin: 0; padding: 0; }
html { background-color: ${provider.getBackgroundColor(options)}; }
</style>`;
...

https://github.com/neocotic/convert-svg/blob/master/packages/convert-svg-core/src/Converter.js#L194

対策

HTMLテンプレートにメタタグでcharsetを明記してあげる。

Converter.js
...
    let html = `<!DOCTYPE html>
<base href="${options.baseUrl}">
<meta charset="utf-8">
<style>
* { margin: 0; padding: 0; }
html { background-color: ${provider.getBackgroundColor(options)}; }
</style>`;
...

おわりに

Forkして手元で修正したけど本家にPRしてもいいのか迷う。
charsetが固定とも限らないし...。

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