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

【個人メモ】Node.js LINEBOT雛形

プロジェクト作成とハローワールド

$ mkdir linebot
$ cd linebot 
$ npm init -y
$ npm i @line/bot-sdk express 
$ npm install dotenv --save
$ touch index.js $$ .env
$ code .
index.js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;
const dotenv = require('dotenv')
dotenv.config()

const config = {
    channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
  channelSecret: process.env.CHANNEL_SECRET
};

const app = express();

app.get('/', (req, res) => res.send('Hello(GET)')); 
app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);

     if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
        res.send('Hello!(POST)');
        console.log('疎通確認用');
        return; 
    }

    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: event.message.text 
  });
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);
.env.sample
CHANNEL_ACCESS_TOKEN = "xxxxxxxxxxxxxxxxxxx"
CHANNEL_SECRET = "xxxxxxxxxxxxxx"
BASE_URL = 'xxxxxxxxxxxxx.ngrok.io'
$ ngrok http 3000

BASE_URLの書き換え

$ node index.js

webhookURLの設定

https://xxxxxxxxxxxxxxxxxx.ngrok.io/webhook

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

Windowsでgulpの環境構築。yarn編

yarnでgulpの環境構築

gulpの環構築の時にサラッと出来るように自分用に投稿。
完璧に初心者なのであしからず

※ちなみにyarnもgulpもnodeもインストール済みとして書きます。

環境

・yarn
1.21.1
・gulp
CLI version: 2.2.0
Local version: 4.0.2 `
・node(楽だからnodistで管理したほうがいいかも)
v11.13.0

手順

test(任意)フォルダの中に移動します

 C:\Users\(ユーザー名) > CD test
 C:\Users\(ユーザー名)\test >

ちなみにtestフォルダの中は下記になります

 test─┬─css
      ├─scss
      │  └─main.scss
      └─index.html

package.jsonを生成しないとダメなので下記を実行

 C:\Users\(ユーザー名)\test > yarn init

実行すると色々聞かれるけどエンター連打。
そうするとtest直下にpackage.jsonが生成される。

 test─┬─css
      ├─scss
      │  └─main.scss
      ├─package.json
      └─index.html

macはこの時にgulpのローカルインストールをする

 C:\Users\(ユーザー名)\test > yarn add gulp

パッケージをインストールします。なのでとりあえず下記を実行。
(後で色々変更できるけどとりあえず)

 C:\Users\(ユーザー名)\test > yarn add --dev gulp
 C:\Users\(ユーザー名)\test > yarn add --dev gulp-sass
 C:\Users\(ユーザー名)\test > yarn add --dev gulp-autoprefixer
 C:\Users\(ユーザー名)\test > yarn add --dev gulp-plumber

次にgulpfile.jsの生成。これは自分で作らないとだめなやーつ。
作ったらtestフォルダに放り投げといて下さい。
中身はざっくりこんな感じ。

const { watch, series, task, src, dest } = require('gulp');
const sass                               = require('gulp-sass');
const autoprefixer                       = require('gulp-autoprefixer');
const plumber                            = require('gulp-plumber');

const convertToCss = () =>
    src('scss/*.scss')
      .pipe(plumber())
      .pipe(sass())
      .pipe(autoprefixer())
      .pipe(dest('css/'));

const watchscss = () =>
    watch('scss/*.scss', convertToCss);

exports.default = watchscss;

.pipe(dest('css/'));の部分を
.pipe(dest('css'));にしててそれに気づかず大変でした。

最後に下記を実行して終了

 C:\Users\(ユーザー名)\test > yarn gulp

これでちゃんとコンパイルが出来ているはず。
何故かこれだけの作業なのに結構時間がかかった。

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

Nodejs(TypeScript)とcacとinquirer.jsでサクッとCLIを作成する

はじめに

NodejsでCLIツールを作成するときに良さそうなパッケージを見つけて、実際に使ってみたら良かったので紹介していきます。

使ったパッケージ

cac

シンプルでパワフルなコマンドラインインターフェイスを作るためのフレームワーク

https://www.npmjs.com/package/cac

inquirer.js

対話型のインターフェースを組み込むのに便利

https://www.npmjs.com/package/inquirer

インストール

$ npm i cac inquirer
$ npm i --save-dev @types/inquirer

サンプル

cac を使ってCLIの骨組みを書いていきます。
下記の例では cli hello hoge みたいなコマンドを入力されたときに処理が実行されるようにしています。

cli.ts
import index from '../src/index'
import cac from 'cac'

const cli = cac()

cli.command('hello [name]', 'Enter your name').action(() => {
  index()
})

cli.help()
cli.parse()

inquirer を使って対話型のインタフェースを定義していきます。
下記の例では、入力とリストとチェックボックスの対話型インターフェースを定義しています。

index.ts
import { prompt, Separator, QuestionCollection } from 'inquirer'

export default async (): Promise<void> => {
  const name = process.argv[3]

  if (!name) {
    console.error('Please pass one argument!!')
    process.exit(1)
  }

  const msg = `
    Hello!! ${name} !!!
  `
  console.log(msg)

  // Input
  const inputQuestions: QuestionCollection = [
    {
      type: 'input',
      message: "What's your name",
      name: 'name'
    }
  ]
  await prompt(inputQuestions).then((answers: any) => {
    console.log(JSON.stringify(answers, null, '  '))
  })

  // List
  const listQuestions: QuestionCollection = [
    {
      type: 'list',
      name: 'color',
      message: 'What do you like color?',
      choices: [
        'black',
        'red',
        {
          name: 'orange',
          disabled: 'disabled'
        },
        'green'
      ]
    }
  ]
  await prompt(listQuestions).then((answers: any) => {
    console.log(JSON.stringify(answers, null, '  '))
  })

  // Checkbox
  const checkboxQuestions: QuestionCollection = [
    {
      type: 'checkbox',
      message: 'select',
      name: 'select',
      choices: [
        new Separator(' = Choise A = '),
        { name: 'hoge' },
        { name: 'fuga' },
        { name: 'foo' }
      ],
      validate: (answer: any): boolean | string => {
        if (answer.length < 1) {
          return 'You must choose'
        }

        return true
      }
    }
  ]
  await prompt(checkboxQuestions).then((answers: any) => {
    console.log(JSON.stringify(answers, null, '  '))
  })
}

実行する

ビルドするのが面倒なので ts-node で実行してきます。

$ npx ts-node bin/cli.ts hello test

    Hello!! test !!!

? What's your name is_ryo
{
  "name": "is_ryo"
}
? What do you like color? red
{
  "color": "red"
}
? select hoge, fuga, foo
{
  "select": [
    "hoge",
    "fuga",
    "foo"
  ]
}

さいごに

サクッと対話型のCLIを作ることができました。
これでCLIを作るときの雛形はできるので、自作CLIを作っていきましょう!
ではまた!!!

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

Symbol Testnet node 構築備忘録

これは

https://billing.time4vps.com

借りたサーバーで

テストネットノードを構築した際の 備忘録である

この構築にあたっては

mikun氏@mikunNEM

の協力無くしては

成し得ませんでした 今一度 感謝の意を表します

セキュリティー編----------------------------------------------
ここでは 例として
usernameを "pasomi"
sshdportを "20023"
として 作業を進めます

rootでログイン

新しいuser作成
adduser pasomi(任意の名前)

新しいuserにsudo権限付与
gpasswd -a pasomi sudo

sshポート変更とrootログイン禁止
vim /etc/ssh/sshd_config

"i"で編集を開始

接続Poetの変更
"#Port 22"を"Port 20023"(任意の数字)に変更

rootログインを禁止
"PermitRootLogin yes"を"PermitRootLogin no"に変更

ESC keyで編集を終了

":wq"で保存して終了
※間違った時は":q!"で保存せず終了

設定変更を反映させる
systemctl restart sshd

※rebootの方がいいかも

これより後は変更したsshポートでないとログイン不可
rootでのログインも不可

port20023でpasomiにログイン

dockerインストール編----------------------------------------------------------------------
(参考サイト https://qiita.com/youtangai/items/ff67ceff5497a0e0b1af)

dockerがインストールのシェルスクリプトを用意しているので,それを実行します
curl https://get.docker.com | sh

デフォルトだと,sudoなしではdockerを実行できません.
ユーザをdockerグループに追加すると,sudoなしでdockerコマンドを実行できるので追加します.
sudo usermod -aG docker pasomi

その後,ユーザ情報を更新するために再起動します.
sudo reboot

ターミナルが消える(再起動が掛かる)
ターミナル再起動

pasomiでログイン

dockerを起動し,常時起動するようにします
sudo systemctl start docker
sudo systemctl enable docker

dockerが正常にインストールできたか確認します
docker --version

ここでは"Docker version 19.03.5, build 633a0ea838"と出れば完了

docker-composeインストール編-----------------------------------------------------
(参考サイトhttps://qiita.com/youtangai/items/ff67ceff5497a0e0b1af)

↓でdocker-composeの最新のバージョンを確認しましょう(メモしてください)
https://github.com/docker/compose/releases

ここでは"1.25.4"と出る

docker-composeをインストール
sudo curl -L https://github.com/docker/compose/releases/download/1.25.4/docker-compose-`uname -s-uname -m` -o /usr/local/bin/docker-compose
("1.25.4"は確認したバージョンを入力する)
※☝ちょっとココうまくコピペ出来なかったんで参考サイトの方使ってね?

docker-composeコマンドを実行できるように,実行権限を与えます
sudo chmod +x /usr/local/bin/docker-compose

docker-composeが正常にインストールできたか確認します
docker-compose --version

ここでは"docker-compose version 1.25.4, build 8d51620a"と出る

bootstrapのダウンロード--------------------------------------------------------

Gitをインストール--------------
(参考サイト https://qiita.com/tommy_g/items/771ac45b89b02e8a5d64)

Gitをインストール
sudo apt-get install git

以下のコマンドを叩き、バージョンが表示されていればOK
dpkg -l git

以下のコマンドを叩き、初期設定を行う
git config --global user.name pasomi
git config --global user.email pasomi

ufw(FairWall)のインストールと設定--------------------------------------------------------
(参考サイト https://qiita.com/_takeuchi_/items/2a1ee9b53c6a863bf844)

ufwをインストール
sudo apt-get install ufw

SSHで使用しているポート以外を閉じる
sudo ufw allow 20023/tcp(前に設定したsshポート)

ポート3000と7900を開ける
sudo ufw allow 3000
sudo ufw allow 7900

設定を反映させる
sudo ufw enable

FireWall設定の確認
sudo ufw status

bootstrapをインストール
git clone https://github.com/nemfoundation/symbol-testnet-bootstrap.git

bootstrap起動の為にディレクトリに移動
cd symbol-testnet-bootstrap/api-harvest-assembly

(又は"cd symbol-testnet-bootstrap/peer-assembly")

IPとフレンドリネームの設定ファイルを編集する
vi api-node/userconfig/resources/config-node.properties.template

[localnode]の下にある
"host ="を"host = 176.223.130.232"に変更(自分のIP)

"friendlyName = FRIENDLY_NAME"を "xym_pasomi:wehihi_from_dusanjp"に変更

docker-composeを実行する
sudo docker-compose up --build --detach

dockerを停止する
sudo docker-compose down

更新の方法 例②-----------------------------------------------------------------------------
Bootstrapのアップデートがあった時は、

Bootstrapを停止してから、
sudo docker-compose down

※ここでdockerのキャッシュを削除するといいかも
sudo docker system prune -a

そのディレクトリを全て削除して、
sudo rm -rf symbol-testnet-bootstrap

新しいBootstrapをダウンロードして、やり直してみてください?
git clone https://github.com/nemfoundation/symbol-testnet-bootstrap.git

IPとフレンドリネームの設定ファイルを編集する
vi api-node/userconfig/resources/config-node.properties.template

docker-composeを実行する
sudo docker-compose up --build --detach

更新の方法 例②----------------------------------------------------------------------------
更新の確認 https://github.com/nemfoundation/symbol-testnet-bootstrapで確認

"api-harvest-assembly"ディレクトリへ移動
cd /api-harvest-assembly

api-harvest-assemblyを停止
sudo docker-compose down

上のディレクトリ"symbol-testnet-bootstrap"へ移動
cd ../

bootstrapを更新
git pull

ディレクトリ"api-harvest-assembly"へ移動
cd api-harvest-assembly

api-harvest-assemblyを開始

sudo docker-compose up -d

再立ち上げに失敗した時は

一旦 サーバーを再起動
sodo reboot

cd symbol-testnet-bootstrap/api-harvest-assembly

docker-compose up -d

これで行けます


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

Knexあれこれ(雑多メモ)

はじめに(次の見出しまで飛ばしてOK)

最近仕事に対する楽しみ方を意識するようになり、今のつまらない仕事が続くのも嫌だったので、6月で辞めますと退職連絡を済ませてきた。
コーディングしてる最中はプライベートでも仕事でも楽しいので、コードをびっしり書くような会社に転職したいと思ったが、個人での活動実績はない。
とりあえず就活に繋がる作品を何か作ってみようと思い立ちこれ1本で大体何とか済ませちゃうNode.jsの勉強を1週間前に始めた。
が、DB処理があまり好きになれなかった。

適当に買った参考書に書いてたDB処理は以下のようなもの

sql.js
connection.query('SELECT * FROM hoge ', function (error, results, fields) { //取得結果に対する処理 });

新卒配属された闇プロジェクトのシステム構成がこれに近い形式で実装されていたことが大体の原因ではあるが。

便利なnpmパッケージ Knex

PHP/Laravelあたりに言語/フレームワークを変更しようかなとこっそり考えつつ、何かいいnpmパッケージはないものかと探してみた。
あった(Knex公式)
記事を書いてくれている方もいた

個人的に良いなと思った点

  • チェーン形式で処理を書ける
  • マイグレーションにも対応してる

軽く記事を流し読みるするだけでも結構便利に思えたのでリファレンス読みつつ色々試してみた。
で、ちょっと一々リファレンスを見に行くのもあれなのでちょっとメモを残そうと思いこの記事を書き始めた。正直公式リファレンスのは読みづらかった
割と参考記事とかぶってる点が多いので、多分knex回りを調べてこの記事を開いてくれた方は↑の参考記事を見ることをお勧めします。

マイグレーションのあれこれメモ(本題)

実行前準備

初期構築 マイグレーションをするためのアレコレの準備

$ knex init 

マイグレーション実行に当たる必要となる設定

module.exports = {
  // 開発環境の設定(デフォルトで参照される設定 NODE_ENVを書き換えればデフォルトではなくなる)
  development: {
    // データベースの種類
    client: 'mysql', 

    // DB接続設定
    connection: {
      host     : '127.0.0.1',
      user     : 'root',
      password : '',
      database : 'node_app'
    },
    // コネクションプールの設定
    pool: {
      min: 2,
      max: 10
    },
    // マイグレーション設定
    migrations: {
      // マイグレーションファイルの配置先(knexfile.jsからの相対)
      directory:'./db/migrations',
      // マイグレーションを管理するテーブル名 (マイグレーションの実行と同時にDBに作成される)
      tableName: 'knex_migrations'
    }
  },
  // 開発環境とは異なる環境のマイグレーション実行設定定義 (本番環境,検証環境の差別化等)
  staging: { ... },
  production: { ... },
};

マイグレーションファイルの作成

<タイムスタンプ>_<ファイル名>.jsというファイルが、migrations.directoryで設定したパス配下に配置される

$ knex migrate:make <ファイル名>

マイグレーションファイルの中身の設定

細かく解説すると助長になるので、コメント参照

20200208161057_items.js
// 後述する実行コマンドで呼び出されるメソッド
exports.up = function(knex, Promise) {
  // connection.databaseで設定しているスキーマに引数で渡したテーブルがあるかチェック
  return knex.schema.hasTable('テーブル名')
    // hasTableのチェーンメソッド 判定結果を引数existsに渡して無名関数をコールバック
    .then(function(exists) {
      if (!exists) {
           // 接続先のスキーマに指定した名前でテーブルを作成する
          return knex.schema.createTable('テーブル名', 
            // 作成したテーブルにカラムを作成する
            function(table) {
               // テーブルの要素設定 別途記載
              table.increments('id').primary();
              table.string('name', 100);
              table.integer('price');
          });
      }else{
          return new Error("The table already exists. 2");
      }
  });
};

// 後述する切り戻しコマンドで呼び出されるメソッド
exports.down = function(knex, Promise) {
  return knex.schema.hasTable('items').then(function(exists) {
      if (exists) {
          // 指定したテーブルを削除する
          return knex.schema.dropTable('items');
      }
  });
};

接続先データベース/スキーマに対して実行するメソッド各種 (使いそうな奴だけ)

function(knex, Promise) {
    // テーブル作成メソッド コールバック内でカラム設定を忘れずに
    knex.schema.createTable(tableName, callback)

    // 指定したテーブル名を変更する
    knex.schema.renameTable(from, to)

    // 指定したテーブルを削除する           
    knex.schema.dropTable(tableName)

    // 指定したテーブルが存在しないか確認する 上例のように.then()でチェーンするとスマート
    knex.schema.hasTable(tableName)

    // 指定したテーブルが存在すれば、そのテーブルを削除する. has,dropをチェーンしなくて済む
    knex.schema.dropTableIfExists(tableName)

    // 指定したテーブルに関する変更処理を実行する
    knex.schema.table(tableName, callback)
};

接続先のデータベース/スキーマが持つテーブルに対して実行するメソッド各種

createTableや、table関数のコールバック内で利用する

knex.schema.createTable('posts', function(table) {
    // 指定したカラムを削除する
    table.dropColumn(name)

    // 指定した複数のカラムを削除
    table.dropColumns(*columns)

    // 指定したカラム名を変更
    table.renameColumn(from, to)

    // オートインクリメント形式のカラムを追加
    table.increments(name)

    // 文字列型のカラムを追加 オプション引数で長さも指定できる
    table.string(name, [length])

    // 数値型のカラムを追加
    table.integer(name)
});

主キーとか外部キーとかindexとかの使い方

カラム設定の関数にチェーンする

knex.schema.createTable('posts', function(table) {
    // 主キーの設定
    table.increments(name).primary()

    // knexインスタンスがMySQLとPostgreSQLの場合のみ使える
    table.index(columns, [indexName], [indexType])

    // 外部キーの設定 table.foreign(カラム名).references('参照テーブル.カラム名')
    table.string(name)
    table.foreign(name).references(table.name) 
});

実行手順

未実行のマイグレーションファイルのupメソッドを、タイムスタンプの古い順に全ファイル実行

$ knex migrate:latest

envオプション: 実行対象の環境を指定してマイグレーションを実行する

$ knex migrate:latest --env production

直前に実行した全てのマイグレーションファイルのdownメソッドを、タイムスタンプの新しい順に実行する

Latestでバッチ実行したなら、すべてのファイルをタイムスタンプの新しい順に実行する。
Upで個別実行したなら、そのマイグレーションファイルのみを実行する

$ knex migrate:rollback

allオプション:過去に実行した全てのマイグレーションファイルのdownメソッドを実行する

$ knex migrate:rollback --all

タイムスタンプが最も古い未実行のマイグレーションファイルのUpメソッドを実行する

$ knex migrate:up 

マイグレーションファイルを指定してそのUpメソッドを実行する

$ knex migrate:up <ファイル名>.js

タイムスタンプが最も新しい実行済のマイグレーションファイルのdownメソッドを実行する

$ knex migrate:down

マイグレーションファイルを指定してそのdownメソッドを実行する

$ knex migrate:down <ファイル名>.js

マイグレーションファイルを一覧表示する

実行済みのものと未実行のものに分割してリスト表示してくれる

$ knex migrate:list
Using environment: development
Found 1 Completed Migration file/files.
20200208145923_items.js 
Found 1 Pending Migration file/files.
20200208161057_items.js 

作成日の異なるマイグレーションファイルがある場合のmigrate:latestの挙動

タイムスタンプの古い方から実行される

/project
|--migration
|  |--20200208161057_items.js
|  |--20200208161542_items.js
20200208161057_items.js
exports.up = function(knex, Promise) {
  console.log('items oldest');
}
20200208161542_items.js
exports.up = function(knex, Promise) {
  console.log('items lastest');
}
実行結果
$ knex migrate:latest
Using environment: development
items oldest
items latest

作成日の異なるマイグレーションファイルがある場合のmigrate:rollbackの挙動

タイムスタンプの新しい方から実行される

/project
|--migration
|  |--20200208161057_items.js
|  |--20200208161542_items.js
20200208161057_items.js
exports.up = function(knex, Promise) {
  console.log('items oldest');
}
20200208161542_items.js
exports.up = function(knex, Promise) {
  console.log('items lastest');
}
実行結果
$ knex migrate:rollback
Using environment: development
items latest
items oldest

オプション引数類は一例で上げてるだけになります。詳細は公式へ

migrate:latestの後にもう1回migrate:latestをした場合のmigrate:rollbackの挙動

上述した通り、migrate:rollback は直前の1回の実行を戻す
2回に分けた場合は2回実行するか、--allオプション を使う

ぼやき

結構前からあるパッケージなのにknexの日本語記事少ないってことは、
割とNode.jsを書いてる人からは不人気なのだろうか。

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

Node12系 AWS LambdaでHTMLをPDFに変換しようとしたらいろいろハマった

Node8系でwkhtmktopdfを使ってHTMLをPDFに変換するLambdaを使っていたのだが、Node8系で動いていた。
Node8系がサポートされなくなるということで、12系にそのままあげたら動かなくなってしまったのでNode12系でHTMLをPDFに変換するLambdaを作り直す必要が出てきた。

HTMLをPDFに変換するLambdaについては結構多くの記事が見つかったが、なかなか上手くいかなかった。

やりたかったこと

Lambdaで日本語を含むHTMLをPDFに変換し、S3に保存する

試したが上手くいかなかった方法

  • wkhtmlpdf
    • 自分が見つけられなかっただけかもしれないが、Node12系でも問題なく動くソースを見つけられなかった
  • html-pdf
    • phantomjsの128エラーでちっとも動かなかった
  • puppeteer
    • 動きそうな気配はあったが、node_modulesのサイズが大きすぎてLambdaの最大ソースサイズをオーバーしてしまった

上手く行った方法

使用モジュール

chrome-aws-lambda を使った。
puppeteer-coreもnpm installする必要があるが、puppeteerだと大きすぎるから必要なcoreだけ使ってるっぽい。

注意点

  • Lambdaのメモリ設定を512MBにする必要があった
    • 最初256MBにしていて、browserがlaunchできなかったいうようなエラーが出て、chrome-aws-lambdaもダメかあと思っていたところBUG報告で512MBにしたらできたで、って書いてあった
  • .fontsをちゃんとzipファイルに含める
    • Lambda環境に日本語フォントはない。自分で.fontsとして読み込ませる必要があるが、日本語が反映されへんな〜と思ったら.fontsをzipファイルに含むのが漏れていたというオチだった

コード

構造

┣ pdfGenerator.js
┣ package.json
┣ package-lock.json
┣ .fonts
  ┣ ipaexg.ttf
  ┣ ipaexm.ttf

コード

pdfGenerator.js
/* Lambda環境でも日本語フォントを使えるようにするには.fontsを読み込ませるためにHOMEを設定する必要ある */
process.env['HOME'] = "/var/task";
process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'];

const AWS = require("aws-sdk");
const S3 = new AWS.S3({ signatureVersion: "v4" });
const chromium = require("chrome-aws-lambda");

exports.handler = async function(event, context, callback) {
    try {
        if (!event.html) {
            callback("unable to get html");
            return;
        }

        const fileName = event.filename,
            tmpFileName = `/tmp/${Math.random().toString(36).slice(2)}.pdf`,
            bucket =  event.bucket,
            pageSize = event.pageSize || "A4",
            html = event.html;

        const executablePath = await chromium.executablePath,
            browser = await chromium.puppeteer.launch({
                args: chromium.args,
                defaultViewport: chromium.defaultViewport,
                executablePath,
                headless: chromium.headless,
                ignoreHTTPSErrors: true
            });

        const page = await browser.newPage();
        await page.setContent(html);
        const pdf = await page.pdf({
            path: tmpFileName,
            format: pageSize
        });

        browser.close();

        S3.putObject({
            Bucket: bucket,
            Key: fileName,
            Body: pdf,
            ContentType: "application/pdf"
        }, (error) => {
            callback(error);
        });
    } catch(e) {
        callback(e);
    }
};

参考リンク

https://github.com/alixaxel/chrome-aws-lambda/issues/82

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

Vue.js勉強会に参加してみた

はじめに

WantedlyでVue.jsの勉強会を見つけたので、参加してきました。
Vue.jsは前々から勉強しようと思っていたのですが、後回しになっていたので、これを機会に本腰を入れよう!

環境構築

今回、事前に環境構築をしてきてとお願いされたのは以下のもの

  • Visual Studio Code
  • 拡張機能でVetur(Vue.js用の拡張機能)もインストール
  • githubアカウント
  • Node.js
    • versionは10以上
  • git
    • versionは2.20以上

このうち、(僕のパソコンはWindowsなこともあり)Node.jsとgitのインストールを行いました。

nodistのインストール

WindowsでNode.jsのバージョンを管理するには、nodistを使うらしい。
インターン先ではnodebrewを使っていたので、「あれ?」と思ったが、nodebrewは基本的にmac環境で使っているそうです。

以下のサイトの手順通りに進めました。
[Node.js] Node.js の導入(Windows編)

1. 公式ページにアクセス

2. インストーラーをダウンロード

実行時のversionは0.9.1

3. インストーラーに従ってインストール

ここでインストール終了時に「PATH not updated, original length 1183 > 1024」というエラーが。
取り敢えず、「OK」を押すと、何事もなかったかのように「Install Finished」と出る。

しかしコマンドプロンプトを開いて、$ nodist -vと打っても

'nodist'は、内部ファイルまたは~

というエラーが返ってくる。これはPATHが通ってないときに出てくるやつですね。
まぁ、さっきの時点でそんな気はしましたが、、、

4. nodistのPATHを通す

こちらの方の記事を参考にしたら、うまくいきました!
node.js インストール備忘録(windows7)

5. nodistのversion確認

$ nodist -v
0.9.1

無事インストールできました!

Node.jsのインストール

続いてNode.jsをインストールしていきます。

1. インストール可能なNode.jsのバージョンを確認

$ nodist dist

めちゃくちゃ出てきてビックリ(笑)。

2. 任意のバージョンをインストール

「偶数バージョンの方がいい」みたいなことを聞いたことがあったので、調べてみると以下のような記事が。
node.jsのバージョンごとの違い

今回は安全に使いたいので、偶数バージョンの最新版(12.14.1)をインストール。

$ nodist + v12.14.1

3. インストールされている Node.js を確認

$ nodist
  (x64)
> 12.14.1

4. Node.js のバージョンを切り替える

$ nodist v12.14.1

5. 現在使用可能なNode.jsのバージョンを確認

$ node -v
v12.14.1

6. npmのアップデート

npmはNode.jsのパッケージを管理するもの。

$ npm -v
$ npm install npm -g

以上でNode.jsのインストールは終了!

Gitのインストール

今までGitを使いたいときはSourseTreeを使っていたのですが、インターン先ではGitをコマンドで打つので、自分のパソコンにも入れたいと思いつつ、後回しにしていた。。。
今回やっとGitをインストール!

以下の記事を参考にしました。
Git インストール for Windows

特に問題はなく成功

$ git --version
git version 2.25.0.windows.1

Vueとは

  • オープンソース
  • WebアプリケーションのUIを構築
  • SPAを高速に構築することが可能
  • 学習コスト低い

Gitを使ってみる

ここは今回のメインではないので、箇条書きで進めます

  1. GitHubでリポジトリを作る
  2. リモートに適当なディレクトリを作る
  3. README.mdを作成し、# Hello, GitHub! と入力して保存
  4. git init をして、gitの初期化
  5. git remote add origin git@github.com:xxxx/yyyy.git
    • git remote -v でリモートを確認できる
  6. git add . をして、先ほど編集した差分をstage (commit待ちのファイル群) に乗せる
  7. git status で、stageに乗ったか確認 (緑色になってたらstaged)
  8. git commit -m "first commit" で、差分をコミット
  9. git push origin master で、作ったコミットをoriginリモートのmasterブランチ (デフォルトのブランチ) にpush

Vue.jsについて

Vue.jsはドキュメントがとても優秀、わからなくなったらここを読めばほとんど全て理解できる
- https://jp.vuejs.org/v2/guide/index.html
- そのドキュメントの日本語がよく分からず後回しにした人間がここに1人

Vueで書いてみよう

今回はscriptタグで、CDNからVueを読みます。
Todoリストを作成して、練習していきます。

sample.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>Step1 ToDo Application</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

</html>

Vueインスタンスの作成

ではbody要素を足していきます。
まずはVueのインスタンスを作ります。更に、elプロパティでappというidの要素を指定すると、それ以下をVueが管理してくれます。

sample.html
<body>
  <div id="app">
    <!-- ここをvueが管理 -->
  </div>
  <script>
    const app = new Vue({
      el: '#app'    // "id=app"を指定
    })
  </script>
</body>

データを持つ

動的に変化するデータを扱うには、data プロパティに宣言します。
そして{{}}内に囲むことで、そのデータを表示できます。

sample.html
<body>
  <div id="app">
    {{ hoge }}
  </div>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        hoge: "sample"
      }
    })
  </script>
</body>

ここでVueの特徴の一つreactive性が出てきます。
これは、変更されたdataが直ちに再描画されるというものです。

フォームデータの束縛(バインディング)

v-model="~"の形で記述された場合、~の変数にデータを格納します。

sample.html
<body>
  <div id="app">
    <label>ToDoの内容<input type="text" v-model="todoText"></label>
    {{ todoText }}
  </div>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        todoText: "sample"
      }
    })
  </script>
</body>

こうすると、inputタグのデータがtodoTextという変数と結びつくため、フォーム内に初めから"sample"という文字列が表示されます。

リストの表示

リストを表示するにはv-forを使います。

sample.html
<body>
  <div id="app">
    <label>ToDoの内容<input type="text" v-model="todoText"></label>
    <ul>
      <li v-for="todo in todoList">{{ todo }}</li>
    </ul>
  </div>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        todoText: "sample",
        todoList: ['掃除', '洗濯', '料理']
      }
    })
  </script>
</body>

算出プロパティ

テンプレートで表示するのに計算が必要な場合は算出プロパティcomputedを使用します。

sample.html
<body>
  <div id="app">
    <label>ToDoの内容<input type="text" v-model="todoText"></label>
    <p>あと{{ todoCount }}個のtodo</p>
    <ul>
      <li v-for="todo in todoList">{{ todo }}</li>
    </ul>
  </div>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        todoText: "sample",
        todoList: ['掃除', '洗濯', '料理']
      },
      computed: {
        todoCount() {
          return this.todoList.length
        }
      }
    })
  </script>
</body>

メソッド

DOMイベントに対して何かのアクションをするには、v-onディレクティブを使用します。
これにより、呼び出したいメソッドを呼ぶことができます。

sample.html
<body>
  <div id="app">
    <label>ToDoの内容<input type="text" v-model="todoText"></label>
    <button v-on:click="register">登録</button>
    <p>あと{{ todoCount }}個のtodo</p>
    <ul>
      <li v-for="todo in todoList">{{ todo }}</li>
    </ul>
  </div>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        todoText: "",
        todoList: []
      },
      computed: {
        todoCount() {
          return this.todoList.length
        }
      },
      methods: {
        register: function() {
          this.todoList.push(this.todoText);
          this.todoText = "";
        }
      }
    })
  </script>
</body>

より本格的な開発のために

コンポーネントシステム

コンポーネントとは、ざっくり言うと「部品」のこと。
ページをコンポーネント化して、各部品として管理することで、再利用性や保守性が高まる。

Vueでは.vueファイルとして保存します。
更にVueの特徴は、.vueファイル一枚にtemplate,style,scriptを書けることです。(単一ファイルコンポーネント)
このおかげで、ファイル管理が楽になります。

Vuex

状態管理のためのライブラリ(+パターン)。
共通の状態やデータを複数のコンポーネントで管理する場合に活用できる。

参考:ざっくり理解、Vuexって何?VuexとAPIの関係を図解してみた

Nuxt.jsについて

Nuxt.jsとは

Nuxtは、モダンな web アプリケーションを作成する Vue.js に基づいたプログレッシブフレームワークです。Vue.js 公式ライブラリ(vue、vue-router や vuex)および強力な開発ツール(webpack、Babel や PostCSS)に基づいています。 Nuxt の目標は、優れた開発者エクスペリエンスを念頭に置き、Web 開発を強力かつ高性能にすることです。

先ほど説明したものや、cssフレームワーク、SSRなどもろもろのベストプラクティスを適用したプロジェクトを一瞬で構築可能。
本格的なWebアプリケーション作成ができる。

Nuxt.jsをセットアップする

npxのインストール

npxを使うと、ローカルにインストールしたnpmパッケージを、npxコマンドだけで実行できるようになります。
これにより、面倒なコマンドを打たなくて済みます。
言わば"便利コマンド集"のようなもの。

普通はnpmが入れば自動的にインストールされる。
しかしnodist経由だと、npxが自動でインストールされないらしい...

そこで個別にインストールします。

$ npm install -g npx

プロジェクト作成

npm create-nuxt-app <プロジェクト名>でNuxt.jsのプロジェクトを作成可能です。
ただし、プロジェクトを作る場所はカレントディレクトリではなく、キャッシュに残っている場所になってしまいます。

しかもその場所のパスにスペースが入っていると、

operation not permitted, mkdir '~'

のエラーが出てプロジェクトを作れない。。。

そこで、エラーが出る場合は以下のコマンドでキャッシュの場所を変えます。

$ npm config set cache <プロジェクトを作りたいディレクトリのパス> --global

その上で改めて

$ npm create-nuxt-app <プロジェクト名>

を実行します。

プロジェクト作成中、UIフレームワークなど、設定を聞かれるので、適宜選択してください。

プロジェクトのディレクトリ構成

  • layouts
    • 全ページで使用されるテンプレートファイルを規定する。ページの外観を変更するために使用される(例えばサイドバーなど)。
    • page の layout プロパティで変更可能
  • pages
    • アプリケーションのビュー及びルーティングファイルを入れる。
    • Nuxt.js フレームワークはこのディレクトリ内のすべての .vue ファイルを読み込み、Vue Routerによって自動的にルーティングされる
      • pages/index.vue/
      • pages/hoge/fuga.vue/hoge/fuga
  • components
    • pages から利用するコンポーネントを入れておく
    • components から components も使ったりする
  • stores
    • Vuex ストアのファイルを入れる
    • デフォルトではVuexストアは無効。このディレクトリに index.js ファイルを作成するとストアが有効になる。

Nuxt.jsでカレンダーアプリを作ってみる

サンプルとしてカレンダーアプリ(と言えるかすら微妙なもの)を作ってみました。

index.vueの作成

まずはindex.vueです。pagesディレクトリ内に作ります。
コンポーネントとして作ったCalender.vueをscript内で読み込みます。
これにより、Calender.vueの内容を、<calender />タグの部分にはめ込むことができます。

index.vue
<template>
  <div class="container">
    <calendar />
  </div>
</template>

<script>
import Calendar from '~/components/Calendar'

export default {
  components: {
    Calendar,
  }
}
</script>

<style></style>

コンポーネントの作成(Calendar.vueとCalendarDay.vue)

Calendar.vueにカレンダーの全体像、CalendarDay.vueにカレンダーの一日の部分を入れます。

Calendar.vue
<template>
  <div class="calendar">
    <calendar-day v-for="day in dayList" :key="day" :day="day" />
  </div>
</template>

<script>
import CalendarDay from '~/components/CalendarDay'
export default {
  components: {
    CalendarDay,
  },
  data() {
    return {
      dayList: []
    }
  },
  created() {
    for (let i = 1; i <= 31; i++) {
      this.dayList.push(i)
    }
  }
}
</script>

<style scoped>
.calendar {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}
</style>
CalendarDay.vue
<template>
  <div class="calendar-day">
    {{ day }}
    <input type="text" v-model="text">
    <button @click="addSchedule({ day, text })">追加</button>
    <ul>
      <li v-for="schedule in scheduleList" :key="schedule.id">{{ schedule.text }}</li>
    </ul>
  </div>
</template>

<style scoped>
.calendar-day {
  border: solid 1px black;
  width: 150px;
  height: 150px;
}
</style>

<script>
import { mapGetters, mapMutations } from 'vuex'
export default {
  data() {
    return {
      text: '',
    }
  },
  props: {
    day: 0,
  },
  computed: {
    ...mapGetters({
      getScheduleListByDay: 'schedule/getScheduleListByDay',
    }),
    scheduleList() {
      return this.getScheduleListByDay(this.day)
    }
  },
  methods: {
    ...mapMutations({
      addSchedule: 'schedule/addSchedule'
    }),
  }
}
</script>

storeの作成(schedule.js)

storeディレクトリにschedule.jsを作成し、予定データを保存・加工します。

schedule.js
export const state = () => ({
    scheduleList: [], // Array<{ id: Number, day: Number, text: String }>
    lastScheduleId: 0,
})

export const getters = {
    getScheduleListByDay: (state) => (day) => {
        return state.scheduleList.filter(schedule => schedule.day === day)
    },
}

export const mutations = {
    addSchedule (state, { day, text }) {
        state.scheduleList.push({
        id: ++state.lastScheduleId,
        day,
        text,
        })
    },
}

おわりに

Vueを使うと、コンポーネントとしての管理がしやすいなぁと思いました。

ただ、アロー関数などJSの記法をしっかり覚えないと...

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