20200322のNode.jsに関する記事は9件です。

Progate無料版をやってみる【Node.js】

前回に引き続きProgate無料レッスンをやっていこうと思います。

今回はNode.jsです。
Progateの無料版のレッスンはこれで終わります。
以前のレッスンで既にインストール済みです。

Node.js

公式レッスン

Expressの導入

・ExpressとはNode.jsでWebアプリを開発するためのフレームワーク。
RubyでいうところのRailsになんでしょうね。C#でいうところのASP.NETみたいな。
・おなじみのパッケージ。便利な機能、メソッドが揃った塊、ライブラリの事。
npmコマンドでExpressをインストールする。
npmとはNode Package Manager その名の通り、Node.jsのパッケージを管理するツール。これを使ってパッケージを取得する。

環境
最近こればっかりですが、VSCode使っていきます。

適当なデイレトリを作成し
image.png
VSVodeで開きます。
image.png
ターミナルを開きます。
image.png
まずinitします。

npm init

package name: (node)と聞かれた作成するpackage.jsonの名前をいれます。任意な値。nodeにしました。

次に、以下を実行してExpressをインストールします。

npm install express

こんな感じになるかと思います。
image.png

Progateのレッスンにもどります。

Progateのディレクトリ構成を再現します。

C:\job\Node
│  app.js
│  package-lock.json
│  package.json
│
├─node_modules
└─public
    └─images

app.js等の中身もコピペします。

app.js

const express = require('express');
const app = express();

サーバーの起動

app.listen(3000);と記述することで、ポート3000のhttp通信を受けつけることになるらしい。

app.js

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.render('hello.ejs');
});

// サーバーを起動するコードを貼り付けてください
app.listen(3000);

getのところは、TOP/GET リクエストがあった場合にhello.ejsをレンダリングする意味だと思います。
ejsってなんすかw

Progateを真似すると、Viewsディレクトリが新たにできていて、その中にhello.ejsがあります。
image.png
hello.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello World</title>
    <script src="/send_url.js"></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

/send_url.jsってなんだ?w
ターミナルで

node app.js

と打って実行します。

http://localhost:3000にアクセスすると以下のエラーとなった
image.png
package.jsonの内容がちがったから、そのせいかな?
一緒にしてみる。

package.json

{
  "name": "nodejs_lesson",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "eslint": "eslint ./",
    "start": "nodemon -r './.module' ./app.js"
  },
  "author": "Progate",
  "license": "ISC",
  "dependencies": {
    "ejs": "^2.6.1",
    "express": "^4.16.4"
  },
  "devDependencies": {
    "nodemon": "^1.18.10"
  }
}

でも同じエラー。
あ、書き換えたpackage.jsonを適用するのかな?と思い

npm update

これで、package.jsonに記載した"ejs": "^2.6.1"が適用されずはず・・・。

実行後にhttp://localhost:3000にアクセス。
image.png
表示できました!

ページの表示の仕組み

・見た目部分にはejsという形式のファイルを使い、viewsディレクトリの下に配置するらしい。HTMLと同じと思えとのこと。

演習
・新たにtop.ejsが追加になる。

app.js

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.render('hello.ejs');
});

// トップ画面を表示するルーティングを作成してください
app.get('/top', (req, res) => {
  res.render('top.ejs');
});

app.listen(3000);

top.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <script src="/send_url.js"></script>
  </head>
  <body>
    <div class="top-wrapper">
      <div class="top-detail">
        <h2 class="subtitle">買い物リストアプリ</h2>
        <h1 class="title">LIST APP</h1>
        <p class="description">
          LIST APPは、買い物をリストアップするサービスです。
          <br>
          買いたいものをリストに追加してみましょう。
        </p>
        <a class="index-button">一覧を見る</a>
      </div>
      <div class="top-image">

      </div>
    </div>
  </body>
</html>

npm app.jsしてからhttp://localhost:3000/topにアクセス
image.png

CSSの適用と画像の表示

・「Expressでは、CSSや画像などのファイルがどこに置かれているかを指定する必要があります」らしい。
publicにある。
・app.jsでapp.use(express.static('public'));を行う必要がある。
・Progateの説明の通り、style.cssを追加する。top.ejsで読み込む。

app.js

const express = require('express');
const app = express();

// CSSや画像ファイルを置くフォルダを指定するコードを貼り付けてください
app.use(express.static('public'));

app.get('/', (req, res) => {
  res.render('hello.ejs');
});

app.get('/top', (req, res) => {
  res.render('top.ejs');
});

app.listen(3000);

public/css/style.css

/* reset ================================ */
* {
  box-sizing: border-box;
}

html {
  font-size: 100%;
  font-family: 'Hiragino Sans', sans-serif;
  line-height: 1.7;
  letter-spacing: 1px;
}

body {
  margin: 0;
  background-color: #f6faff;
  color: #6c7686;
}

ul, li {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

a {
  display: block;
  text-decoration: none;
  color: #2d3133;
  font-size: 14px;
}

a:hover {
  transition: all 0.3s ease;
}


h1, h2, h3, h4, h5, h6, p {
  margin: 0;
}

h1 {
  font-weight: 600;
}


/* top ================================ */
.top-wrapper {
  max-width: 1200px;
  min-width: 920px;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 auto;
  padding: 60px;
}

.top-detail {
  width: 36%;
  min-width: 320px;
  margin-top: -40px;
}

.top-detail .subtitle {
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 4px;
}

.top-detail .title {
  font-size: 54px;
  line-height: 66px;
  letter-spacing: 2px;
  margin-bottom: 24px;
}

.top-detail .description {
  font-size: 14px;
  line-height: 28px;
  letter-spacing: 0.5px;
  margin-bottom: 40px;
}

.top-detail .index-button {
  width: 184px;
  height: 48px;
  text-align: center;
  line-height: 45px;
  font-weight: 600;
  color: #42cea9;;
  background-color: #ffffff;
  border: 2px solid #58d2b2;
  border-radius: 2px;
}

.top-detail .index-button:hover {
  color: #ffffff;
  background-color:  #58d2b2;
}


.index-button {
  cursor: pointer;
}

.top-image {
  width: 64%;
  text-align: center;
  overflow: hidden;
}

.top-image img {
  width: 88%;
}

/* header ================================ */
header {
  height: 56px;
  background-color: #ffffff;
  border-bottom: 1px solid #f0f4f9;
}

.header-logo {
  margin-left: 56px;
  font-weight: 600;
  font-size: 20px;
  line-height: 56px;
  color: #6c7686;
  display: inline;
}

.header-logo:hover {
  color: #58d2b2;
}

/* container ================================ */
.container {
  width: 80%;
  min-width: 360px;
  max-width: 720px;
  margin: 0 auto;
  margin-top: 56px;
}

.container-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.container-header h1 {
  font-size: 24px;
}

/* index ================================ */
.table-head {
  display: flex;
  background-color: #b7cadc;
  border-radius: 2px 2px 0 0;
  height: 44px;
  font-size: 16px;
  line-height: 46px;
  color: #ffffff;
}

.id-column {
  width: 72px;
  text-align: center;
}

.table-body {
  background-color: #ffffff;
}

.table-body li {
  height: 72px;
  border: 1px solid #f0f4f9;
  border-top: none;
  line-height: 74px;
  display: flex;
}

.table-body .id-column {
  font-size: 16px;
  color: #bac6d3;
}

.table-body .name-column {
  font-size: 14px;
  font-weight: 500;
  color: #8491a5;
}

top.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <!-- CSSファイルを読み込んでください -->
    <link rel="stylesheet" href="/css/style.css">

    <script src="/send_url.js"></script>
  </head>
  <body>
    <div class="top-wrapper">
      <div class="top-detail">
        <h2 class="subtitle">買い物リストアプリ</h2>
        <h1 class="title">LIST APP</h1>
        <p class="description">
          LIST APPは、買い物をリストアップするサービスです。
          <br>
          買いたいものをリストに追加してみましょう。
        </p>
        <a class="index-button">一覧を見る</a>
      </div>
      <div class="top-image">
        <!-- 画像ファイルを読み込んでください -->
        <img src="/images/top.png">

      </div>
    </div>
  </body>
</html>

http://localhost:3000/topにアクセスして

実行結果
image.png

一覧画面の作成

ndex.ejsというファイルで一覧画面を作成する。

/indexのGETをapp.jsに実装する。
app.js

const express = require('express');
const app = express();

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

app.get('/', (req, res) => {
  res.render('hello.ejs');
});

app.get('/top', (req, res) => {
  res.render('top.ejs');
});

// 一覧画面を表示するルーティングを作成してください
app.get('/index', (req, res) => {
  res.render('index.ejs');
});

app.listen(3000);

index.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <link rel="stylesheet" href="/css/style.css">
    <script src="/send_url.js"></script>
  </head>
  <body>
    <header>
      <a class="header-logo">LIST APP</a>
    </header>
    <div class="container">
      <div class="container-header">
        <h1>買い物リスト</h1>
      </div>
      <div class="index-table-wrapper">
        <div class="table-head">
          <span class="id-column">ID</span>
          <span>買うもの</span>
        </div>
        <ul class="table-body">
          <li>
            <span class="id-column">1</span>
            <span class="name-column">じゃがいも</span>
          </li>
          <li>
            <span class="id-column">2</span>
            <span class="name-column">にんじん</span>
          </li>
          <li>
            <span class="id-column">3</span>
            <span class="name-column">たまねぎ</span>
          </li>
        </ul>
      </div>
    </div>
  </body>
</html>

http://localhost:3000/topにアクセスして
image.png

EJSを使って値を表示しよう

ejsとは「EJSは、HTMLとJavaScriptのコード両方を記述できるNode.jsのパッケージ」らしい。
Embedded javaScript
HTMLの中にJavaScriptを埋め込む
らしい。ReactはJSにHTMLを埋め込むイメージでしたよね。
・なんとnpm install ejsを最初にやる必要があったらしい。
 紛らわしい。なぜその手順を最初に解説しなかったのか・・・。

・JavaScritpを埋め込むには<% %>または<%= %>を使用するらしい。Rubyと一緒かな?

forEachを使ったHTMLの表示

ejs上でforEachできる。
 ただし、forEachの閉じは<% });%>とかなり独特。

ページ間リンク

・リンクはaタグのhref=""のところにパスを記載する。

app.js

const express = require('express');
const app = express();

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

// 下記のルーティングを削除してください
// 削除ここまで

// ルートURLで表示されるように変更してください
app.get('/', (req, res) => {
  res.render('top.ejs');
});

app.get('/index', (req, res) => {
  res.render('index.ejs');
});

app.listen(3000);

index.js

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <link rel="stylesheet" href="/css/style.css">
    <script src="/send_url.js"></script>
  </head>
  <body>
    <header>
      <!-- href属性を追加してください -->
      <a class="header-logo" href="/" >LIST APP</a>
    </header>
    <div class="container">
      <div class="container-header">
        <h1>買い物リスト</h1>
      </div>
      <div class="index-table-wrapper">
        <div class="table-head">
          <span class="id-column">ID</span>
          <span>買うもの</span>
        </div>
        <% const items = [
          {id: 1, name: 'じゃがいも'},
          {id: 2, name: 'にんじん'},
          {id: 3, name: 'たまねぎ'}
        ]; %>
        <ul class="table-body">
          <% items.forEach((item) => { %>
            <li>
              <span class="id-column"><%= item.id %></span>
              <span class="name-column"><%= item.name %></span>
            </li>
          <% }); %>
        </ul>
      </div>
    </div>
  </body>
</html>

top.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <link rel="stylesheet" href="/css/style.css">
    <script src="/send_url.js"></script>
  </head>
  <body>
    <div class="top-wrapper">
      <div class="top-detail">
        <h2 class="subtitle">買い物リストアプリ</h2>
        <h1 class="title">LIST APP</h1>
        <p class="description">
          LIST APPは、買い物をリストアップするサービスです。
          <br>
          買いたいものをリストに追加してみましょう。
        </p>
        <!-- href属性を追加してください -->
        <a class="index-button" href="/index" >一覧を見る</a>
      </div>
      <div class="top-image">
        <img src="/images/top.png">
      </div>
    </div>
  </body>
</html>

http://localhost:3000/topにアクセスして
ダウンロード.gif

クリアしました
image.png

感想

・比較的簡単にWebが作れました。
 DBから引っ張ってくるところとかはおそらく有料の上級編でやっているんだろうなぁ・・・。
・Node.jsに言えたことではないが、今まで無料レッスンやってきた言語のWeb系のデプロイってどうやるんだろうw

今回でProgate無料版はすべてこなしました。
いつも書いているように、無料版なので、基礎や基本的なことしかやらないので、即何かアプリを作れるかと言ったら、この内容だけじゃ難しいですが、他無料サイトをみながらアプリ作成を始めてみる際にはこのレッスンの経験が少しは生きてくると思いました。

次回はReactのチュートリアルの三目並べゲームをやってみたいと思います。

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

Progate無料版をやってみる【Node.js】

前回に引き続きProgate無料レッスンをやっていこうと思います。

今回はNode.jsです。
Progateの無料版のレッスンはこれで終わります。
以前のレッスンで既にインストール済みです。

Node.js

公式レッスン

Expressの導入

・ExpressとはNode.jsでWebアプリを開発するためのフレームワーク。
RubyでいうところのRailsになんでしょうね。C#でいうところのASP.NETみたいな。
・おなじみのパッケージ。便利な機能、メソッドが揃った塊、ライブラリの事。
npmコマンドでExpressをインストールする。
npmとはNode Package Manager その名の通り、Node.jsのパッケージを管理するツール。これを使ってパッケージを取得する。

環境
最近こればっかりですが、VSCode使っていきます。

適当なデイレトリを作成し
image.png
VSVodeで開きます。
image.png
ターミナルを開きます。
image.png
まずinitします。

npm init

package name: (node)と聞かれた作成するpackage.jsonの名前をいれます。任意な値。nodeにしました。

次に、以下を実行してExpressをインストールします。

npm install express

こんな感じになるかと思います。
image.png

Progateのレッスンにもどります。

Progateのディレクトリ構成を再現します。

C:\job\Node
│  app.js
│  package-lock.json
│  package.json
│
├─node_modules
└─public
    └─images

app.js等の中身もコピペします。

app.js

const express = require('express');
const app = express();

サーバーの起動

app.listen(3000);と記述することで、ポート3000のhttp通信を受けつけることになるらしい。

app.js

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.render('hello.ejs');
});

// サーバーを起動するコードを貼り付けてください
app.listen(3000);

getのところは、TOP/GET リクエストがあった場合にhello.ejsをレンダリングする意味だと思います。
ejsってなんすかw

Progateを真似すると、Viewsディレクトリが新たにできていて、その中にhello.ejsがあります。
image.png
hello.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello World</title>
    <script src="/send_url.js"></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

/send_url.jsってなんだ?w
ターミナルで

node app.js

と打って実行します。

http://localhost:3000にアクセスすると以下のエラーとなった
image.png
package.jsonの内容がちがったから、そのせいかな?
一緒にしてみる。

package.json

{
  "name": "nodejs_lesson",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "eslint": "eslint ./",
    "start": "nodemon -r './.module' ./app.js"
  },
  "author": "Progate",
  "license": "ISC",
  "dependencies": {
    "ejs": "^2.6.1",
    "express": "^4.16.4"
  },
  "devDependencies": {
    "nodemon": "^1.18.10"
  }
}

でも同じエラー。
あ、書き換えたpackage.jsonを適用するのかな?と思い

npm update

これで、package.jsonに記載した"ejs": "^2.6.1"が適用されずはず・・・。

実行後にhttp://localhost:3000にアクセス。
image.png
表示できました!

ページの表示の仕組み

・見た目部分にはejsという形式のファイルを使い、viewsディレクトリの下に配置するらしい。HTMLと同じと思えとのこと。

演習
・新たにtop.ejsが追加になる。

app.js

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.render('hello.ejs');
});

// トップ画面を表示するルーティングを作成してください
app.get('/top', (req, res) => {
  res.render('top.ejs');
});

app.listen(3000);

top.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <script src="/send_url.js"></script>
  </head>
  <body>
    <div class="top-wrapper">
      <div class="top-detail">
        <h2 class="subtitle">買い物リストアプリ</h2>
        <h1 class="title">LIST APP</h1>
        <p class="description">
          LIST APPは、買い物をリストアップするサービスです。
          <br>
          買いたいものをリストに追加してみましょう。
        </p>
        <a class="index-button">一覧を見る</a>
      </div>
      <div class="top-image">

      </div>
    </div>
  </body>
</html>

npm app.jsしてからhttp://localhost:3000/topにアクセス
image.png

CSSの適用と画像の表示

・「Expressでは、CSSや画像などのファイルがどこに置かれているかを指定する必要があります」らしい。
publicにある。
・app.jsでapp.use(express.static('public'));を行う必要がある。
・Progateの説明の通り、style.cssを追加する。top.ejsで読み込む。

app.js

const express = require('express');
const app = express();

// CSSや画像ファイルを置くフォルダを指定するコードを貼り付けてください
app.use(express.static('public'));

app.get('/', (req, res) => {
  res.render('hello.ejs');
});

app.get('/top', (req, res) => {
  res.render('top.ejs');
});

app.listen(3000);

public/css/style.css

/* reset ================================ */
* {
  box-sizing: border-box;
}

html {
  font-size: 100%;
  font-family: 'Hiragino Sans', sans-serif;
  line-height: 1.7;
  letter-spacing: 1px;
}

body {
  margin: 0;
  background-color: #f6faff;
  color: #6c7686;
}

ul, li {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

a {
  display: block;
  text-decoration: none;
  color: #2d3133;
  font-size: 14px;
}

a:hover {
  transition: all 0.3s ease;
}


h1, h2, h3, h4, h5, h6, p {
  margin: 0;
}

h1 {
  font-weight: 600;
}


/* top ================================ */
.top-wrapper {
  max-width: 1200px;
  min-width: 920px;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 auto;
  padding: 60px;
}

.top-detail {
  width: 36%;
  min-width: 320px;
  margin-top: -40px;
}

.top-detail .subtitle {
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 4px;
}

.top-detail .title {
  font-size: 54px;
  line-height: 66px;
  letter-spacing: 2px;
  margin-bottom: 24px;
}

.top-detail .description {
  font-size: 14px;
  line-height: 28px;
  letter-spacing: 0.5px;
  margin-bottom: 40px;
}

.top-detail .index-button {
  width: 184px;
  height: 48px;
  text-align: center;
  line-height: 45px;
  font-weight: 600;
  color: #42cea9;;
  background-color: #ffffff;
  border: 2px solid #58d2b2;
  border-radius: 2px;
}

.top-detail .index-button:hover {
  color: #ffffff;
  background-color:  #58d2b2;
}


.index-button {
  cursor: pointer;
}

.top-image {
  width: 64%;
  text-align: center;
  overflow: hidden;
}

.top-image img {
  width: 88%;
}

/* header ================================ */
header {
  height: 56px;
  background-color: #ffffff;
  border-bottom: 1px solid #f0f4f9;
}

.header-logo {
  margin-left: 56px;
  font-weight: 600;
  font-size: 20px;
  line-height: 56px;
  color: #6c7686;
  display: inline;
}

.header-logo:hover {
  color: #58d2b2;
}

/* container ================================ */
.container {
  width: 80%;
  min-width: 360px;
  max-width: 720px;
  margin: 0 auto;
  margin-top: 56px;
}

.container-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.container-header h1 {
  font-size: 24px;
}

/* index ================================ */
.table-head {
  display: flex;
  background-color: #b7cadc;
  border-radius: 2px 2px 0 0;
  height: 44px;
  font-size: 16px;
  line-height: 46px;
  color: #ffffff;
}

.id-column {
  width: 72px;
  text-align: center;
}

.table-body {
  background-color: #ffffff;
}

.table-body li {
  height: 72px;
  border: 1px solid #f0f4f9;
  border-top: none;
  line-height: 74px;
  display: flex;
}

.table-body .id-column {
  font-size: 16px;
  color: #bac6d3;
}

.table-body .name-column {
  font-size: 14px;
  font-weight: 500;
  color: #8491a5;
}

top.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <!-- CSSファイルを読み込んでください -->
    <link rel="stylesheet" href="/css/style.css">

    <script src="/send_url.js"></script>
  </head>
  <body>
    <div class="top-wrapper">
      <div class="top-detail">
        <h2 class="subtitle">買い物リストアプリ</h2>
        <h1 class="title">LIST APP</h1>
        <p class="description">
          LIST APPは、買い物をリストアップするサービスです。
          <br>
          買いたいものをリストに追加してみましょう。
        </p>
        <a class="index-button">一覧を見る</a>
      </div>
      <div class="top-image">
        <!-- 画像ファイルを読み込んでください -->
        <img src="/images/top.png">

      </div>
    </div>
  </body>
</html>

http://localhost:3000/topにアクセスして

実行結果
image.png

一覧画面の作成

ndex.ejsというファイルで一覧画面を作成する。

/indexのGETをapp.jsに実装する。
app.js

const express = require('express');
const app = express();

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

app.get('/', (req, res) => {
  res.render('hello.ejs');
});

app.get('/top', (req, res) => {
  res.render('top.ejs');
});

// 一覧画面を表示するルーティングを作成してください
app.get('/index', (req, res) => {
  res.render('index.ejs');
});

app.listen(3000);

index.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <link rel="stylesheet" href="/css/style.css">
    <script src="/send_url.js"></script>
  </head>
  <body>
    <header>
      <a class="header-logo">LIST APP</a>
    </header>
    <div class="container">
      <div class="container-header">
        <h1>買い物リスト</h1>
      </div>
      <div class="index-table-wrapper">
        <div class="table-head">
          <span class="id-column">ID</span>
          <span>買うもの</span>
        </div>
        <ul class="table-body">
          <li>
            <span class="id-column">1</span>
            <span class="name-column">じゃがいも</span>
          </li>
          <li>
            <span class="id-column">2</span>
            <span class="name-column">にんじん</span>
          </li>
          <li>
            <span class="id-column">3</span>
            <span class="name-column">たまねぎ</span>
          </li>
        </ul>
      </div>
    </div>
  </body>
</html>

http://localhost:3000/topにアクセスして
image.png

EJSを使って値を表示しよう

ejsとは「EJSは、HTMLとJavaScriptのコード両方を記述できるNode.jsのパッケージ」らしい。
Embedded javaScript
HTMLの中にJavaScriptを埋め込む
らしい。ReactはJSにHTMLを埋め込むイメージでしたよね。
・なんとnpm install ejsを最初にやる必要があったらしい。
 紛らわしい。なぜその手順を最初に解説しなかったのか・・・。

・JavaScritpを埋め込むには<% %>または<%= %>を使用するらしい。Rubyと一緒かな?

forEachを使ったHTMLの表示

ejs上でforEachできる。
 ただし、forEachの閉じは<% });%>とかなり独特。

ページ間リンク

・リンクはaタグのhref=""のところにパスを記載する。

app.js

const express = require('express');
const app = express();

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

// 下記のルーティングを削除してください
// 削除ここまで

// ルートURLで表示されるように変更してください
app.get('/', (req, res) => {
  res.render('top.ejs');
});

app.get('/index', (req, res) => {
  res.render('index.ejs');
});

app.listen(3000);

index.js

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <link rel="stylesheet" href="/css/style.css">
    <script src="/send_url.js"></script>
  </head>
  <body>
    <header>
      <!-- href属性を追加してください -->
      <a class="header-logo" href="/" >LIST APP</a>
    </header>
    <div class="container">
      <div class="container-header">
        <h1>買い物リスト</h1>
      </div>
      <div class="index-table-wrapper">
        <div class="table-head">
          <span class="id-column">ID</span>
          <span>買うもの</span>
        </div>
        <% const items = [
          {id: 1, name: 'じゃがいも'},
          {id: 2, name: 'にんじん'},
          {id: 3, name: 'たまねぎ'}
        ]; %>
        <ul class="table-body">
          <% items.forEach((item) => { %>
            <li>
              <span class="id-column"><%= item.id %></span>
              <span class="name-column"><%= item.name %></span>
            </li>
          <% }); %>
        </ul>
      </div>
    </div>
  </body>
</html>

top.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>LIST APP</title>
    <link rel="stylesheet" href="/css/style.css">
    <script src="/send_url.js"></script>
  </head>
  <body>
    <div class="top-wrapper">
      <div class="top-detail">
        <h2 class="subtitle">買い物リストアプリ</h2>
        <h1 class="title">LIST APP</h1>
        <p class="description">
          LIST APPは、買い物をリストアップするサービスです。
          <br>
          買いたいものをリストに追加してみましょう。
        </p>
        <!-- href属性を追加してください -->
        <a class="index-button" href="/index" >一覧を見る</a>
      </div>
      <div class="top-image">
        <img src="/images/top.png">
      </div>
    </div>
  </body>
</html>

http://localhost:3000/topにアクセスして
ダウンロード.gif

クリアしました
image.png

感想

・比較的簡単にWebが作れました。
 DBから引っ張ってくるところとかはおそらく有料の上級編でやっているんだろうなぁ・・・。
・Node.jsに言えたことではないが、今まで無料レッスンやってきた言語のWeb系のデプロイってどうやるんだろうw

今回でProgate無料版はすべてこなしました。
いつも書いているように、無料版なので、基礎や基本的なことしかやらないので、即何かアプリを作れるかと言ったら、この内容だけじゃ難しいですが、他無料サイトをみながらアプリ作成を始めてみる際にはこのレッスンの経験が少しは生きてくると思いました。

次回はReactのチュートリアルの三目並べゲームをやってみたいと思います。

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

TypeORMのconnection設定はormconfig.jsに書くのがおすすめ

はじめに

TypeORMのcreateConnectionメソッドを呼ぶ際の設定値は、色々な指定方法があります。
色々あって迷っちゃったので、整理して考えた結果、ormconfig.jsに書くのが分かりやすいのではという結論に至りました。

createConnectionメソッドの引数として直接渡す方法は避けたかった

createConnectionメソッドでは、引数としてconnectionの設定値を直接渡す方法があります。

https://typeorm.io/#/connection/creating-a-new-connection

メソッド引数として直接渡す例(公式ドキュメントの引用)
import {createConnection, Connection} from "typeorm";

const connection = await createConnection({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "test",
    password: "test",
    database: "test"
});

バックエンドのアプリケーションにおいて、createConnectionを呼ぶのは大抵の場合、サーバー起動時に一回だけでしょう。そのため、一見するとこの方法でもさほど問題なさそうに思えます。

ところがTypeORMは、バックエンドアプリケーション用の本番コードからだけでなく、何らかのテストコードからとか、DBマイグレーション用のCLIコマンドから呼ばれる場合もあるはずです。
それらを視野に入れると、createConnectionの引数として直接渡すだけではカバーしにくい場面がでてきそうです。似たような設定を何箇所かに重複して書く羽目になるかもしれません。

引数として直接渡す以外の方法は色々ある

では他の方法はというと、大別すると2種類があります。このあと紹介するそれらの方法で設定した上で、引数なしでcreateConnectionメソッドを呼べば、その設定が参照されます(Creating a new connectionの節の後半で、そう説明されています)。

環境変数TYPEORM_XXXを設定する

1つ目は、何らかの手段によって、所定の名前の環境変数を設定する方法です。

TYPEORM_CONNECTIONTYPEORM_HOSTなど、TYPEORM_XXXという名前の環境変数を設定しておくと、TypeORMはその値を参照します。参照される環境変数名は、以下のURLにまとめられています。

https://typeorm.io/#/using-ormconfig/using-environment-variables

この方法の亜種として、環境変数を設定する代わりに、ormconfig.envというファイルにそれらの設定を書く方法もあります。

ormconfigファイルを作る

2つ目は、ormconfig.xxx(ただし、xxx ≠ env)というファイルをpackage.jsonと同じ階層に置き、そこに設定を書く方法です。拡張子はjs、json、ymlなどから選べます。

jsにおける例(公式ドキュメントの引用)
module.exports = {
   "type": "mysql",
   "host": "localhost",
   "port": 3306,
   "username": "test",
   "password": "test",
   "database": "test"
}

環境変数TYPEORM_XXXとormconfigの併用はできない

下記のURLで述べられている通り、上記2種類の設定方法を併用することはできません。環境変数TYPEORM_XXXが設定されていると、ormconfigファイルは無視されます。

https://typeorm.io/#/using-ormconfig/which-configuration-file-is-used-by-typeorm

TypeORMの設定値の中には、環境変数で指定したいものもあるでしょうし(例えばDBのパスワード)、分かりやすくどこかにハードコードしたいものもあるでしょう。ところがあいにく、環境変数TYPEORM_XXXとormconfigファイルの併用はできません。

そこで

そこで、以下のようにすればちょうど良い落とし所になるのではと考えました。

  • ormconfig.jsファイルを用意する。
  • ormconfig.jsの中で必要に応じて、環境変数を参照する。

この時、ormconfig.jsに書く環境変数名はTYPEORM_XXXではなく、TypeORMが予約していない何らかの独自の名前にします。そうすれば、「環境変数TYPEORM_XXXが設定されていると、ormconfigファイルは無視される」という制約を気にせず、柔軟に設定をかけるようになります。
jsファイルなので、環境変数の値に応じたちょっとした分岐を書きやすい利点もあります。

まとめ

TypeORMは、バックエンドアプリケーション用の本番コードからだけでなく、何らかのテストコードからとか、DBマイグレーション用のCLIコマンドから呼ばれる場合もあるので、1個の設定用ファイルにまとめて書いておけば、どこから呼んだ場合でも対応できます。

そして、設定用ファイルの種類としてormconfig.jsを使えば、jsファイルの中で環境変数(TYPEORM_XXXでない独自名)を参照させたり、ちょっとした分岐を書いたりと、柔軟に設定を書くことができます。

その環境変数はどこでどう設定するんかっていう点は残りますが、それはTypeORMの専用知識とは切り離した汎用的な問題として、独立して検討しやすいでしよう。また、TypeORM設定の入り口がormconfig.jsという一箇所に集約されるので、(jsファイルの中で、どこかで設定されている環境変数を参照しているとはいえ、)見通しもそこそこ良くなります。

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

『Node.js 超入門』の express-validation を最新の仕様に修正する

概要

Node.js 超入門(第2版) を読んでいたところ、バリデーションの箇所が本の通り書いているにも関わらずエラーが発生。 正誤表 を確認したところ、以下のような説明がありました。

本書で使用している Express Validator は、現在 ver.6 となり、仕様が変更されているため、本書の記述の通りでは正常に動作しなくなっています。

ver.5 にバージョンダウンすることでサンプルコードのまま実行することが出来たのですが、折角なので最新バージョンに修正して実行をしてみました。
本記事では、express-validator公式ドキュメントを参考に行った修正内容について紹介したいと思います。

修正内容

サンプルコード(ver.5 の書き方)

  • P.334~335 リスト6-4 より、修正の必要があるPOST時の処理について抜粋
    ※修正後と形式を統一するためフォーマッタで一部書き方等を修正してます
hello.js
router.post("/add", (req, res, next) => {
  req.check("name", "NAME は必ず入力して下さい。").notEmpty();
  req.check("mail", "MAIL はメールアドレスを記入して下さい。").isEmail();
  req.check("age", "AGE は年齢(整数)を入力下さい。").isInt();

  req.getValidationResult().then(result => {
    if (!result.isEmpty()) {
      var re = '<ul class="error">';
      var result_arr = result.array();
      for (var n in result_arr) {
        re += "<li>" + result_arr[n].msg + "</li>";
      }
      re += "</ul>";
      var data = {
        title: "Hello/Add",
        content: re,
        form: req.body
      };
      res.render("hello/add", data);
    } else {
      var nm = req.body.name;
      var ml = req.body.mail;
      var ag = req.body.age;
      var data = { name: nm, mail: ml, age: ag };

      var connection = mysql.createConnection(mysql_setting);
      connection.connect();
      connection.query("insert into mydata set ?", data, function(
        error,
        results,
        fields
      ) {
        res.redirect("/hello");
      });
      connection.end();
    }
  });
});

修正後コード(ver.6 の書き方)

  • express-validationの最新バージョン(記事作成時は6.4.0)で実行できるようPOST処理を修正
    ※バリデーション設定箇所以外にも今時のJavaScriptの書き方に変更している箇所もあります(varでなくconstかletで変数を宣言するなど)
hello.js
const { check, validationResult } = require("express-validator");

router.post(
  "/add",
  [
    check("name")
      .not()
      .isEmpty()
      .withMessage("NAME は必ず入力して下さい。"),
    check("mail")
      .isEmail()
      .withMessage("MAIL はメールアドレスを記入して下さい。"),
    check("age")
      .isInt()
      .withMessage("AGE は年齢(整数)を入力して下さい。")
  ],
  (req, res, next) => {
    const results = validationResult(req);
    if (!results.isEmpty()) {
      let re = "<ul class='error'>";
      const result_arr = results.array();
      for (const err of result_arr) {
        re += `<li>${err.msg}</li>`;
      }
      re += "</ul>";
      const data = {
        title: "Hello/Add",
        content: re,
        form: req.body
      };
      res.render("hello/add", data);
    } else {
      const name = req.body.name;
      const mail = req.body.mail;
      const age = req.body.age;
      const data = { name, mail, age };

      const connection = mysql.createConnection(mysql_setting);
      connection.connect();

      connection.query(
        "INSERT INTO mydata SET ?",
        data,
        (error, results, fields) => {
          if (error === null) {
            res.redirect("/hello");
          }
        }
      );

      connection.end();
    }
  }
);

修正概要

今回でexpress-validationを使った処理に関しては以下の部分を修正しています

  • requireによるモジュールのロードをapp.jsではなくhello.jsの冒頭で行う
    • サンプルの通りapp.jsで宣言した場合には『TypeError: check is not a function』が発生するため変更
    • エラー原因は調査しましたがわからなかったので、ご存知の方がいましたらコメントで教えていただけたら幸いです
  • check内容をpostメソッドの第2引数に記載
  • ver.5 ではエラー情報をreq.getValidationResult().then()resultを引数としてコールバック関数で処理していたが、ver.6ではvalidationResult(req)を定数resultに代入し、関数の中でその値を使って処理
  • notEmpty()はなくなっているので、not().isEmpty()のように宣言
  • エラーメッセージはwithMessage()をメソッドチェーンにして使用し設定

まとめ

以上のように修正することで、記事作成時の最新バージョン(ver.6.4.0)のexpress-validatorでもバリデーションを実行することができました。
よかったら参考にしてみて下さい。

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

[Visual Studio Code] [MacOS] .nvmrcで指定したバージョンに自動で切り替えてプロジェクトをスタートする

複数の Node.js プロジェクトに参加していると、利用すべき Node のバージョンがプロジェクト毎に異なる場合があって、毎回手動で切り替えるのは大変面倒なので自動化します。

動作確認環境

  • MacOS
  • Visual Studio Code

にて動作を確認しております。Mac かつ VSCode で開発をしていて、ビルドなども VSCode 上のターミナルで行なっている方は参考になると思います。

ロードマップ

  1. nvmのインストール
  2. Visual Studio Code のターミナルをzshに設定する
  3. .zshrc を作成、または編集する
  4. 自動バージョン切り替えを実行したいプロジェクトで .nvmrc を作成する

1.nvmのインストール

日本語の参考記事がたくさんありますのでそちらを参照してください。

nvm use <バージョン>

コマンドでいくつかの node バージョンを切り替えられるようになればOKです。

2.Visual Studio Code のターミナルをzshに設定する

まずは現在の VSCode のターミナルのシェルが何か、確認します。
Image from Gyazo

青枠部分がzshでない場合は設定で変更します。Mac 自体が2019年に、デフォルトの処理を bash から zsh に切り替えているので、基本的には VSCode もそれに沿う形で問題ないはずです。既に bash でいろいろ設定やってるよという方は zsh に切り替えることの影響を考慮する必要があります。
Image from Gyazo

⌘ + ,で設定パネルを開き、
Terminal › Integrated › Automation Shell: Osx
の項目で Edit in settings.jsをクリックします。

Image from Gyazo

"terminal.integrated.shell.osx": "/bin/zsh"
terminal.integrated.shell.osx の値を上記のようにします。基本的にこちらの値で問題ないと思いますが、環境によって、zshがインストールされていない、場所が違うなどあるかもしれませんのでご確認ください。

編集したら改めて VSCode 上のターミナルを確認し、zsh となっていればOKです。

.zshrc を作成、または編集する

基本これで良いはず。

$ vim .zshrc
source ~/.nvm/nvm.sh
# place this after nvm initialization!
autoload -U add-zsh-hook
load-nvmrc() {
  if [[ -f .nvmrc && -r .nvmrc ]]; then
    nvm use
  elif [[ $(nvm version) != $(nvm version default)  ]]; then
    echo "Reverting to nvm default version"
    nvm use default
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc

既に .zshrc ファイルが存在している場合は既存の設定内容に影響がないか注意が必要です。また、1行目の nvm のパスも環境によっては違うかもしれません。

4.自動バージョン切り替えを実行したいプロジェクトで .nvmrc を作成する

ここまでくればただただバージョン番号が書かれた.nvmrcファイルがプロジェクトディレクトリの直下に存在していれば、プロジェクトを開いた際にnvmによるバージョン切り替えを行なってくれます。バージョン番号指定ではなくlts/*のように安定バージョンの最新というような書き方もできます。(が、該当バージョンをnvmでインストール済みでないと動かないと思います。私は常にバージョン番号で指定しているので未確認です。)

.nvmrc はコマンドラインでサクッと作成してしまいましょう。

$ echo "8.13.0" > .nvmrc #番号指定
$ echo "lts/*" > .nvmrc #最新バージョン

以上で設定完了です。VSCode で該当プロジェクトを開き、VSCode 上のターミナルを立ち上げれば .nvmrc で指定したバージョンに切り替えたことを示すメッセージがターミナルで確認できるはずです。

また、複数でプロジェクトを進める際に node のバージョンをバシッと統一するときもこの形がスマートだと思います。

参考リンク

https://qiita.com/ysd_marrrr/items/e58df8dfd509b25ff9c9
https://medium.com/fbdevclagos/updating-visual-studio-code-default-terminal-shell-from-bash-to-zsh-711c40d6f8dc
https://medium.com/@kinduff/automatic-version-switch-for-nvm-ff9e00ae67f3

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

WebSocket の負荷テストは Artillery でシュッと簡単に実行しよう

Artillery は yaml ファイルに宣言的にシナリオを記述し、シンプルなインタフェースで負荷をかけることができる Nodejs 製の負荷テストツールです。
本記事では Artillery を使用して簡単に WebSocket サーバの負荷テストを実行する方法を紹介します。

最小構成の WebSocket サーバ

まずはじめに WebSocket サーバを実装しましょう。今回は Node.js を使用します。
必要最小限の機能だけを提供します。ws ライブラリを使用して簡単に実装しましょう。

server.js
const WebSocket = require("ws");

const wss = new WebSocket.Server({ port: 3000 }, () => {
  console.log("server is now listening localhost:3000");
});

let connections = [];

wss.on("connection", ws => {
  connections.push(ws);
  console.log(`new connection established. connections: ${connections.length}`);
  ws.on("close", () => {
    console.log(`connection closeed: ${connections.length}`);
    connections = connections.filter((conn, i) => conn !== ws);
  });
  ws.on("message", message => {
    broadcast(JSON.stringify(message));
  });
});

const broadcast = message => {
  connections.forEach((con, i) => {
    con.send(message);
  });
};

起動して以下のメッセージが表示されれば準備完了です。

$ node server.js
server is now listening localhost:3000

wscat で接続を確認する

サーバを起動したらまず wscat を使用して動作の確認をしましょう。wscat は npm でインストールできます。

$ npm install -g wscat

WebSocket サーバを起動し、wscat で接続したら任意のメッセージを送信してみましょう。1つのクライアントからの送信を受けて、他のクライアントへ broadcast していることがわかります。

wscat

Artillery を使用して負荷テストを実行する

さて、ようやく本題です。Artillery を使用して負荷テストをかけてみましょう。
最小限のシナリオファイルのサンプルです。シナリオファイルは senario.yml のような名前をつけておきます。

senario.yaml
config:
  target: "ws://localhost:3000"
  phases:
    - duration: 20
      arrivalRate: 10
scenarios:
  - engine: "ws"
    flow:
      - send: "hello"

以下、コマンドで実行します。

$ artillery run senario.yml

run

アクティブなコネクション数を調整する

実際に WebSocket を用いたアプリケーションでは、常に多くのコネクションが張られていることが一般的です。上記のシナリオでは hello というメッセージを送ったらすぐにコネクションを切断してしまうので、常時アクティブなコネクションが少ない状態であまり現実的ではありません。まずは、think を指定してアクティブなコネクション数が増えるように調整しましょう。また、同じメッセージを繰り返し送信する loop も指定できます。

senario.yaml
scenarios:
  - engine: "ws"
    flow:
      - send: "hello"
      - think: 1 # pause for 1 second
      - loop:
          - send: "world"
        count: 5

オブジェクトの送信に対応する

さて先ほどまでは string 形式のデータだけに限定していましたが、{"name":"john", "age":24} のようにオブジェクト形式で送信する方が良いこともあるでしょう。以下のように記述すれば、送信時に Stringify してくれます。

senario.yaml
scenarios:
  - engine: "ws"
    flow:
      # the following will be stringified and sent as '{"name":"john","age":24}'
      - send:
          name: "john"
          age: 24

カスタムコードを使用してタイムスタンプを付与する

また、送信したタイムスタンプを付与したいこともあります。このようなケースに対応するためにはカスタムコードを使用して柔軟に値を差し込むことができます。

senario.yaml
config:
  target: "ws://localhost:3000"
  processor: "./custom.js"
scenarios:
  - engine: "ws"
    flow:
      # custom code for timestanp
      - function: "createTimestampedObject"
      - send: "{{ data }}"

非常にシンプルに記述し、シュッと実装することができました。Artillery は WebSocket だけではなく、HTTPのプロトコルもサポートしています。本記事は公式ドキュメントから参照していますので、詳細に理解されたい方は一度ドキュメントに目を通してみるのも良いでしょう。

また、CircleCIで継続的に負荷テストを実行するTipsをこちらの記事で紹介していますのでぜひご参照ください。

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

arduino + leapmotion でmidi ドラム Play!

ドラムマシーンを足で演奏することを目指しています。
手で演奏するプロトタイプを作成しました。

・arduino uno
・SparkFun midiシールド
・leapmotion
・node.js
・CASIO キーボード CTK-530


leapmotionとarduinoでシリアル通信

参考サイト:
ArduinoとNode.jsでシリアル通信で文字列を送受信するスクリプト
ArduinoとLeapmotionのシリアル接続

まずはleapmotion側(node.js)
準備物は↑を参照願います。

leap-arduino.js
"use strict"
const serialport = require('serialport');
// arduinoポート名指定(arduino IDEから取得)
var portName = '/dev/cu.usbmodem1421';
/* jsライブラリ読込 */
var Leap = require("leapjs");
var five = require('johnny-five');
var yPosi = 0; //座標
var G_KICK_TIME = new Date();//センサーキック時刻
var C_WAITE_TIME = 100; //ミリ秒
//Leap Motionコントローラー作成
var controller = new Leap.Controller();
//leapmotionと接続開始
controller.connect();
//手を認識
controller.on('hand', function (gesture,e) {
  //y軸取得
  yPosi = gesture.palmPosition[1];
  yPosi = parseInt(yPosi);
  var ss = new Date();
  //前回のarduino送信からの時間比較
  if(ss.getTime() - G_KICK_TIME.getTime() >= C_WAITE_TIME  ){
    //C_WAITE_TIME経過した場合
    //arduino通信発生時刻
    G_KICK_TIME = new Date();
    console.log("ON");
    //arduinoへ送信する関数
    write(yPosi);
  }
});
const Readline = serialport.parsers.Readline;
const parser = new Readline();
const spp = new serialport(portName,{
    baudRate: 31250,//midiのボーレートが31250
    dataBits: 8,
    parity: 'none',
    stopBits: 1,
    flowControl: false,
    parser: parser
});
//シリアル通信開始
spp.on('open', function () {
  console.log('Serial open.');
});
//arduinoから受信した場合の処理(今回は未使用)
//spp.on('data', function (data) {
//  //console.log('spp.on-data:' + data);
//});
//arduinoへ送信
function write(data) {
  //y軸座標の範囲で値を設定;
  var sendData;
  if (data > 0 && data <= 160){
    //スネアドラム
    sendData = 'a';
  } else if (data > 160 && data <= 200){
    //ハイハットclose
    sendData = 'b';
  } else if (data > 200 && data <= 250){
    //ハイハットopen
    sendData = 'c';
  } else {
    //上記以外
    sendData = '0';
  }
  data = sendData;
  //送信データ表示
  console.log('Mac:' + data);
  //arduinoへ値送信!
  spp.write(new Buffer.from(data), function(err, results) {
    if(err) {
      //エラーメッセージ表示
      console.log('Err: ' + err);
    }
  });
}

続いてarduino側です。
参考サイト
Arduino MIDI Library の使い方

手をかざすとC_WAITE_TIMEの間隔でCASIOキーボードのドラムを鳴らします。

//MIDIライブラリ使用のためのヘッダファイル読み込み
#include <MIDI.h> 
// MIDIクラスのインスタンスとして"MIDI"を生成する。
MIDI_CREATE_DEFAULT_INSTANCE(); 
#define LED 13
int recieveByte = 0;
String bufferStr = "";
String okStr = "OK";
//送信ONフラグ
const bool C_ON = true;
const bool C_OFF = false;
//ノート情報
const int C_NOTE_VEROCITY = 40;
const int C_NOTE_CHANNEL = 1; 

bool bLedState = false; //受信状態 true:on false:off
int pitchNo = 0; 

void setup() {
  Serial.begin(31250);   //midiのボーレートが31250
  MIDI.begin();          // MIDIインスタンスの初期化
}
void loop() {
  bufferStr = ""; 
  while (Serial.available() > 0) {
    recieveByte = Serial.read();
    if (recieveByte == (int)'\n') break;
    bufferStr.concat((char)recieveByte);
  }

  //受信信号実行中の場合無視して次へ 
  if(bLedState == C_OFF){
    //受信データによりCASIOキーボードへMIDI送信
    if (bufferStr.length() > 0) {        
        if (bufferStr == "a") {
            bLedState = C_ON;
            pitchNo = 38;//スネア
        } else if (String(bufferStr) == "b") {
            bLedState = C_ON;
            pitchNo = 44;//ハイハットclose
        } else if (String(bufferStr) == "c") {
            bLedState = C_ON;
            pitchNo = 46;//ハイハットopen
        } else {
          bLedState = C_OFF;
          pitchNo = 36;//バスドラ
        }
        //ノートオン(pitch, velocity, channel)
        MIDI.sendNoteOn(pitchNo, C_NOTE_VEROCITY, C_NOTE_CHANNEL);
        //待機後信号受付状態にする
        bLedState = C_OFF;
        MIDI.sendNoteOff(pitchNo, C_NOTE_VEROCITY, C_NOTE_CHANNEL);       
    }
  }
}

MIDIのボーレートの既定値が31250のため、シリアル通信もそれに合わせています。

そうしないとarduino側で受信データが文字化けしてしまいます。
これでハマりました。

スイッチサイエンスで距離計測センサーを購入したので、届き次第leapmotionからこのセンサーに変更します。

記事は着手次第アップします。

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

Node.js+Express+Passportでログイン認証をしたい

はじめに

「Node.jsってどんなもんなんだろう?」ってところから始まり。
  ↓
「へぇ〜APIとか簡単にできるじゃん」となり。
  ↓
「ログイン認証とかも割と簡単なんじゃね」と思ったのでやってみました。

環境

  • macOS Mojave

Express

npmを使ってExpressをインストールする。
entry pointはapp.jsに設定する。

$ mkdir myapp
$ cd myapp
$ npm init
$ npm install express

myappにapp.jsを作成し、以下を実装する。

app.js
const express = require('express')
const app = express()

app.get('/', (req, res) => {
    res.send('Hello World')
})

app.listen(3000, () => {
  console.log('Listening on prot 3000')
})

普通にnode app.jsで起動しても良いが、変更に対して自動的に起動するようにしてほしいのでnodemonをインストールする。
起動したら、http://localhost:3000にアクセスし期待通りの動きをしているか確認する。

$ npm install nodemon -g
$ npx nodemon app.js
    [nodemon] starting `node app.js`
    Listening on prot 3000

Passport

ログイン認証に必要なものをインストールします。
(詳しく説明しませんが、ググれば大丈夫)

$ npm install body-parser
$ npm install cookie-parser
$ npm install express-session
$ npm install passport
$ npm install passport-local
$ npm install connect-ensure-login

publicフォルダを作成し、login.htmlok.htmlng.htmlを作成する

app.js
const express = require('express')
const app = express()
const path = require('path')
const session = require('express-session')
const passport = require('passport')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const LocalStrategy = require('passport-local').Strategy;

app.use(express.static(path.join(__dirname, 'public')))
app.use(cookieParser())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(session({ 
  secret: 'secret',
  resave: false,
  saveUninitialized: false,
}))
app.use(passport.initialize())
app.use(passport.session())
passport.use(new LocalStrategy((username, password, done) => {
  if (username !== 'user' || password !== 'passwd') {
    return // ログイン失敗
  }
  return done(null, username) // ログイン成功
}))

passport.serializeUser((user, done) => {
  done(null, user)
})
passport.deserializeUser((user, done) => {
  done(null, user)
})
// ...
login.html
<html>
  <head lang="ja">
    <meta charset="UTF-8">
    <title>ログイン</title>
  </head>
  <body>
    <form action="/login" method="post">
      <div>
        <label>ユーザID:</label>
        <input type="text" name="username">
      </div>
      <div>
        <label>パスワード:</label>
        <input type="password" name="password">
      </div>
      <div>
        <input type="submit" value="Login">
      </div>
    </form>
  </body>
</html>

その他

ログインに成功したら/login/okへリダイレクト、失敗したら/login/ngへリダイレクトするような実装をします。
ただ、普通にやってしまうとログインに成功していないにも関わらず、http://localhost:3000/login/okと叩けばアクセスできてしまいます。。。
そこで便利なものがあります!
require('connect-ensure-login').ensureLoggedIn('/login')を挟んでやれば、ログインしていない場合は指定した/loginにリダイレクトされるようにできます。

app.js
// ...
app.get('/', (req, res) => {
  res.redirect('/login')
})

app.get('/login', (req, res) => {
  res.sendFile('login.html', { root: path.join(__dirname, 'public') })
})

app.post('/login',
  passport.authenticate('local', { failureRedirect: '/login/ng', session: true }),
      (req, res) => {
        res.redirect('/login/ok')
      }
)

app.get('/login/ng', (req, res) => {
  res.sendFile('ng.html', { root: path.join(__dirname, 'public') })
})

app.get('/login/ok', 
    require('connect-ensure-login').ensureLoggedIn('/login'), // <--- こいつ!!
        (req, res) => {
            res.sendFile('ok.html', { root: path.join(__dirname, 'public') })
});

app.get('/logout', (req, res) => {
  req.logout()
  res.redirect('/login')
})
// ...

最後に

ログイン認証のセッション管理などをreq.isAuthenticated()で制御させてみたんですけど、想定通りの動きはしなかった。。。

これからはconnect-ensure-loginを使っていこーっと
一応、ソースコードを載せておきます。

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

最速Svelteを速攻デプロイするなら、Zeit NOW一択というメモ。

Svelteで何かデプロイしたい時には。

普段、バックエンドに引きこもっているデータエンジニアだが、たまにはフロントエンドに出ていってみようかと思い、最速JSに近しい存在という爆速(=>死語?)なSvelteいじって三日目。そろそろ(無料で)デプロイなるものをしてみたい今日このごろ。

...ということで、nodejs系を始めいろいろと無料でお気楽にデプロイできそうなZeit NOWを試してみた。
参考 Now でクラウドの複雑さから解放されよう、今すぐに

github(かgitlabなど)の個人アカウントを持っているならば、たしかに、すぐさまデプロイできたのでメモを残しておく。Zeit now初体験だったが、10分ほどでデプロイをできた。

デプロイしたもの(カス):
sve.PNG
アクセス先:
https://svelte1.now.sh

・・・デプロイしたものは、Svelteの公式チュートリアルの一部を改悪しただけのカス。

SvelteをNOWにデプロイする手法(2020年版)

① NOW用Svelteをfolk

『zeit svelte』でググると出てくる以下から、
https://zeit.co/guides/deploying-svelte-with-zeit-now
自分が使っているgitリポジトリのアカウントを選ぶだけ。githubの場合
https://zeit.co/import/git?tab=github
あとは、SSOの認証を行うとディフォルトでprivateリポジトリにfolkしてくれる。
公開すると恥ずかしいサービスを作りたいとか、一山当てたいサービスを作りたい際には、privateリポジトリがディフォルトなのはありがたい限り。

② NOW用Svelteをcloneして編集

folkたら当然、git cloneの類を持ってきて編集することになる。
フォルダ構成は以下の通り。ほぼSvelteのフォルダ構成通りだが.nowフォルダ配下がZeit NOWとの周りの調整を担ってくれているらしい。

sv.PNG

とりあえず、お試ししたい場合は、↑のApp.svelteを編集する。今回の場合。

<script>
    let count = 1
    $: doubled = count * 2
    $: tripled = count * 3

    let handleClick = () =>{
        count = tripled+3
    }

</script>
<style>
    p {
        color: purple;
        font-family: 'Comic Sans MS', cursive;
        font-size: 2em;
    }
</style>

<main>
  <h1>滑る手おぢさん(仮)。</h1>
  <h2>
    <a href="https://zeit.co/docs" target="_blank" rel="noreferrer noopener">
      ZEIT Now
    </a>
    Svelteしてみる。突然だが、おい、オマイラ、掛け算という奴をしてみないか。すごく大きくなるぞ。
  </h2>
  <br />
<p>元の数{count} しかして、け奴の×2は、 {doubled} 然らば、×3 {tripled}。けだし大きな数なり。</p>
<button on:click={handleClick}>
    クリックしてみて  只今の元の数:{count} 
</button>
</main>

③ デプロイ

node/npm入っている人ならば、ひとまず、npm i -g nowした後に、メール認証などを済ませた後は、
編集しているフォルダにて、
now --prod
するだけで、git add/git commit / git push、そしてNOWを介して本番デプロイという手順を一気に済ませられる。
セキュリティ云々を考えないなら、ほんとにお気軽。

終わりに

少なくとも個人開発でのnodejsでの開発工程ならば、Zeit NOWは現時点では文句なしの存在ということを確認した。Svelteのバックエンドは数十分で始めた、Svelte+Firebaseのアプリ生活。で、firebaseが良さげと分かっている。
フロントエンド素人として悩ましいのが、node上でSvelteを動かす方法。絶賛開発中のSapperを試してはみたが、(英語でも)文書がなさすぎて素人にはつらすぎる(セキュリティ云々を気にするとfirebaseをバックエンドにしたアプリを公開できるは先になりそう、、)。

どなたかSvelte/Sapperのベストプラクティスを紹介してくださらぬものかのぅ.(コーダー老人的堕ち)。とりあえず、Svelteお試しする分には楽しいので良しとするが。

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