20210109のNode.jsに関する記事は11件です。

NodejsでWebアプリケーション作成 with Docker

前提

ProgateのNodejsコース完了程度の知識があること。
Docker使える。
VSCodeでDocker入門

本記事の対象者

ProgateでNodejs学んだ。次は自分のプロジェクトを作ってみたいって人

本記事でやること

  • DockerでNodejs環境を作る
  • プロジェクトの作成
  • ライブラリのインストール
  • ブラウザ上でページを確認

環境

Docker
VSCode
Node 14.15
Git

プロジェクトの作成

まず適当な場所にプロジェクトのフォルダを作成。
本記事では nodejs-sample-app という名前で作った。

そして、そのフォルダをVSCodeで開く。

以下のファイルを作成

docker-compose.yml
version: "3"
services:
    node:
        image: node:14.15
        volumes:
            - .:/project
        tty: true
        working_dir: /project
        command: bash

Nodeのバージョンは14.15を指定しておく。

コンテナに入ってバージョンを確認。

root@cf2295d42525:/project# node -v
v14.15.4

そしたらプロジェクトを作る準備が完了。

ここからnpmコマンドを使ってプロジェクトを構築する。

以下のコマンドを打つと、プロジェクトに package.jsonというファイルが作成される。

$ npm init -y

npm init リファレンス

root@cf2295d42525:/project# npm init -y
Wrote to /project/package.json:

{
  "name": "project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

package.json は Nodejsプロジェクトの様々な情報をかくところと把握しておけばOK

次に Webアプリケーション において一番最初に呼ばれるjsファイルを作る。
package.json と同じ階層に以下のように作成

app.js
console.log("Hello nodejs");

そうしたら、以下のコマンドで実行されるか確かめる

root@cf2295d42525:/project# node app.js
Hello nodejs

Hello nodejs と表示されたらOK

次に package.json を以下のように変更

package.json
{
  "name": "project",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

mainを修正 testの末尾にカンマ追加, scripts.start追加

そうすると、 npm startでscripts.startで指定したコマンドが呼ばれるようになる。

root@cf2295d42525:/project# npm start

> project@1.0.0 start /project
> node app.js

Hello nodejs

これでひと段落。

このタイミングでgit initすると良い。

expressのインストールとルーティング

expressのインストール

$ npm install express

package.jsonに以下のように追記される

{
...
  "dependencies": {
    "express": "^4.17.1"
  }
}

そして、node_modulesというフォルダと package-lock.jsonというファイルができる。

node_modulesにはインストールしたpackageが入る。
これはプッシュしたくないのでgitignoreを作成してつっこむ。

.gitignore
node_modules/

スクリーンショット 2021-01-09 19.24.06.png

installして差分がでてるのでここでcommit。

ルーティングを作成

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

app.get('/', (req, res) => {
    res.send({message: "ok!"});
});

const port = process.env.PORT || 3000
app.listen(port, () => console.log(`server started port ${port}`));

npm startすると、以下のように表示される。

root@cf2295d42525:/project# npm start

> project@1.0.0 start /project
> node app.js

server started port 3000

しかし、今のままではブラウザでひらけない

スクリーンショット 2021-01-09 19.30.11.png

docker-composeにportについて記述する必要がある。

docker-compose.yml
version: "3"
services:
    node:
        image: node:14.15
        volumes:
            - .:/project
        tty: true
        working_dir: /project
        ports:
            - "3000:3000"
        command: npm start

portsを追加し、コンテナを立ち上げた時に npm start 実行するように変更した。

docker-compose を編集したら、コンテナを作り直す必要がある。
一度コンテナを消して以下を実行

$ docker-compose up -d

ちゃんとサーバーとして起動しているかログを確認

nodejs-sample-app(main)$ docker-compose logs       
Attaching to nodejs-sample-app_node_1
node_1  | 
node_1  | > project@1.0.0 start /project
node_1  | > node app.js
node_1  | 
node_1  | server started port 3000

いけてそう。

ブラウザで確認

スクリーンショット 2021-01-09 19.34.54.png

ejs

ejsを使うためにインストール

$ npm install ejs

viewsフォルダを作成し、その中にejsファイルを作成

views/index.ejs
<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <title>Document</title>
</head>
<body>
    <p><%= message %></p>
</body>
</html>
app.js
const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.render("index.ejs", {message: "うおおおおおお"})
});

const port = process.env.PORT || 3000
app.listen(port, () => console.log(`server started port ${port}`));

renderでejsを描画し、「message」を埋め込む

スクリーンショット 2021-01-09 23.05.26.png

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

ESモジュールでexpressを使うサンプル(babel利用)

目的

フロントエンドはESモジュール形式で記載するのに、バックエンド側はrequire()を使うという課題?を揃えたいという願望です。
(babelにするかtypescriptにするかで悩んでいます)

  • 実現したら、おまけにsequelizeも追加するかも

実現手段

  • expessをES6(import)で利用できるようにするため、babelでトランスパイルする。
    ⇒package.json に 「type: module」を追加すればESモジュールを使えますが、jsファイルの拡張子(.cjs、.mjs)の切り分けが面倒なのでbabelにします。

  • express-generatorでひな形を生成する。

  • 開発時は「babel-node」で実行(ビルド不要)可能とする。トランスパイルしたjsファイルが必要な場合はbuildを行う。

  • sequelizeと組み合わせて使用する(sequelizeはnodeモジュール形式で生成される。ES6形式で記載したexpress側で問題なく利用できることを確認する)

前提

  • nodeとyarnがインストール済みであること (npmを使う場合は適宜読み替えてください)

利用モジュール

{
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "morgan": "~1.9.1"
  },
  "devDependencies": {
    "@babel/cli": "^7.12.10",
    "@babel/core": "^7.12.10",
    "@babel/node": "^7.12.10",
    "@babel/preset-env": "^7.12.11"
  }
}

手順詳細

1. express-generatorでひな形を作成(viewは生成しない。.gitignoreは生成する)

npx express-generator express-generator-babel --no-view --git

2. (作成されたフォルダに移動し)必要なライブラリをインストール

yarn install

3. expressが起動することを確認

yarn start

B397.tmp.png

ブラウザで「http://localhost:3000」 を表示する
515.tmp.png

4. babelインストール

yarn add @babel/cli  @babel/core @babel/preset-env -D

5. babelの設定ファイル(.babelrc)を作成する

targetにcurrentを入れることで、インストールされているnode.jsが理解できる形でトランスパイルされます。
(最近のnodeであればawaitやasyncなどがヘルパー関数ではなく、そのまま出力されます(pollyfill不要))

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "node": "current"
                }
            }
        ]
    ]
}

6. babelでビルドするため、フォルダ構成を変更する。

  • jsファイルを「/src」フォルダ配下にすべて移動する
mkdir src
mv  bin/ routes/ app.js src/

※「bin」「routes」フォルダと、app.jsファイルを「src」フォルダに移動している。

  • フォルダ階層が変わったためソースを一部修正する

app.js (publicフォルダの位置を修正)

app.use(express.static(path.join(__dirname, 'public')));
 ↓
app.use(express.static(path.join(__dirname, '../public')));
  • トランスパイル先フォルダを作成する
mkdir dist

7. ビルド用コマンドをpackage.jsonに追加する

package.json の "scripts"に下記コマンドを追加する。

"build": "babel src --out-dir dist --copy-files && babel ./src/bin/www --out-file ./dist/bin/www"

※.src/bin/www は拡張子がないjsファイル。フォルダ指定では対象にならないため、個別にトランスパイルをしている。

8. babelでトランスパイルを行う

yarn build

9. トランスパイルしたソースで動作確認を行う

  • package.json の "scripts"に下記コマンドを追加する。
"serve": "node ./dist/bin/www"
  • サーバを起動する
yarn serve

ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。
515.tmp.png

10. ESモジュールに変更して動作確認を行う

  • require()をimportに変更しても動作することを確認する。
  1. module.exportsからES6のexportに変更した場合、読み込み元も「import」に修正する必要がある。
  2. ソース内でrequire()をimportに変更しても、外部にエクスポートする「module.export」を変更しなければ、呼び出し元は変更不要。

/src/routes/index.js

// var express = require('express');  //コメントアウト
import express from 'express';        //追加
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
    res.render('index', { title: 'Express' });
});

// module.exports = router;  //コメントアウト
export default router;       //追加

/src/app.js

// var express = require('express');  //コメントアウト
// var path = require('path');
// var cookieParser = require('cookie-parser');
// var logger = require('morgan');

import express from 'express';        //追加
import path from 'path';
import cookieParser from 'cookie-parser';
import logger from 'morgan';

// var indexRouter = require('./routes/index');  //コメントアウト
import indexRouter from './routes/index';        //追加
var usersRouter = require('./routes/users');

var app = express();

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, '../public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

module.exports = app;  //コメントアウトしない。読み込み元(bin/www)を変更せず、require()のままとするため。
//export default app;  // exportに書き換えると、読み込み元をimportに書き換える必要がある。

11. ESモジュール化後の動作確認

yarn build
yarn serve
  • ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。

12. 開発用に「babel-node」を導入する(ビルド無しで動作させるため)

  • babel-nodeをインストールする
yarn add @babel/node -D
  • package.jsonの startを修正する
"start": "node ./bin/www",
 ↓
"start": "babel-node ./src/bin/www",
  • babel-nodeで起動することを確認する(build不要)
yarn start

ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。

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

expressをESモジュールに変更する手順(babel利用)

目的

バックエンドをESモジュールで記載できるようにしたい(フロントエンドに合わせる)という目的です。

結果

  • ESMとしてexportしたモジュールはimportする、module.exportの場合(node)はrequire()を利用するということに気を付ければ、混在していても問題なく動く。

実現手段

  • expessをES6(import)で利用できるようにするため、babelでトランスパイルする。
    ⇒package.json に 「type: module」を追加すればESモジュールを使えますが、jsファイルの拡張子(.cjs、.mjs)の切り分けが面倒なのでbabelにします。

  • express-generatorでひな形を生成する。

  • 開発時は「babel-node」で実行(ビルド不要)可能とする。トランスパイルしたjsファイルが必要な場合はbuildを行う。

  • sequelizeと組み合わせて使用する(sequelizeはnodeモジュール形式で生成される。ES6形式で記載したexpress側で問題なく利用できることを確認する)

前提

  • nodeとyarnがインストール済みであること (npmを使う場合は適宜読み替えてください)

利用モジュール

{
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "morgan": "~1.9.1"
  },
  "devDependencies": {
    "@babel/cli": "^7.12.10",
    "@babel/core": "^7.12.10",
    "@babel/node": "^7.12.10",
    "@babel/preset-env": "^7.12.11"
  }
}

手順

①expressのひな形をESモジュールに変更し、babelでコンパイルする

1. express-generatorでひな形を作成(viewは生成しない。.gitignoreは生成する)

npx express-generator express-generator-babel --no-view --git

2. (作成されたフォルダに移動し)必要なライブラリをインストール

yarn install

3. expressが起動することを確認

yarn start

B397.tmp.png

ブラウザで「http://localhost:3000」 を表示する
515.tmp.png

4. babelインストール

yarn add @babel/cli  @babel/core @babel/preset-env -D

5. babelの設定ファイル(.babelrc)を作成する

targetにcurrentを入れることで、インストールされているnode.jsが理解できる形でトランスパイルされます。
(最近のnodeであればawaitやasyncなどがヘルパー関数ではなく、そのまま出力されます(pollyfill不要))

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "node": "current"
                }
            }
        ]
    ]
}

6. babelでビルドするため、フォルダ構成を変更する。

  • jsファイルを「/src」フォルダ配下にすべて移動する
mkdir src
mv  bin/ routes/ app.js src/

※「bin」「routes」フォルダと、app.jsファイルを「src」フォルダに移動している。

変更前後.png

  • フォルダ階層が変わったためソースを一部修正する

app.js (publicフォルダの位置を修正)

app.use(express.static(path.join(__dirname, 'public')));
 ↓
app.use(express.static(path.join(__dirname, '../public')));
  • トランスパイル先フォルダを作成する
mkdir dist

7. ビルド用コマンドをpackage.jsonに追加する

package.json の "scripts"に下記コマンドを追加する。

"build": "babel src --out-dir dist --copy-files && babel ./src/bin/www --out-file ./dist/bin/www"

※.src/bin/www は拡張子がないjsファイル。フォルダ指定では対象にならないため、個別にトランスパイルをしている。

8. babelでトランスパイルを行う

yarn build

9. トランスパイルしたソースで動作確認を行う

  • package.json の "scripts"に下記コマンドを追加する。
"serve": "node ./dist/bin/www"
  • サーバを起動する
yarn serve

ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。
515.tmp.png

10. ESモジュールに変更して動作確認を行う

  • require()をimportに変更しても動作することを確認する。
  1. module.exportsからES6のexportに変更した場合、読み込み元も「import」に修正する必要がある。
  2. ソース内でrequire()をimportに変更しても、外部にエクスポートする「module.export」を変更しなければ、呼び出し元は変更不要。

/src/routes/index.js

// var express = require('express');  //コメントアウト
import express from 'express';        //追加
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
    res.render('index', { title: 'Express' });
});

// module.exports = router;  //コメントアウト
export default router;       //追加

/src/app.js

// var express = require('express');  //コメントアウト
// var path = require('path');
// var cookieParser = require('cookie-parser');
// var logger = require('morgan');

import express from 'express';        //追加
import path from 'path';
import cookieParser from 'cookie-parser';
import logger from 'morgan';

// var indexRouter = require('./routes/index');  //コメントアウト
import indexRouter from './routes/index';        //追加
var usersRouter = require('./routes/users');

var app = express();

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, '../public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

module.exports = app;  //コメントアウトしない。読み込み元(bin/www)を変更せず、require()のままとするため。
//export default app;  // exportに書き換えると、読み込み元をimportに書き換える必要がある。

11. ESモジュール化後の動作確認

yarn build
yarn serve
  • ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。

12. 開発用に「babel-node」を導入する(ビルド無しで動作させるため)

  • babel-nodeをインストールする
yarn add @babel/node -D
  • package.jsonの startを修正する
"start": "node ./bin/www",
 ↓
"start": "babel-node ./src/bin/www",
  • babel-nodeで起動することを確認する(build不要)
yarn start

ブラウザで「localhost:3000」を開き、expressのトップページが開くことを確認する。

②sequelize+sqliteを追加してデータを取得する

sequelize-cliを利用して生成したひな形(node module形式)を、express側から利用できることを確認する。

13. sequelize導入(DBはsqliteを利用する。別にサーバを作る必要がないため)

yarn add sequelize sqlite3
yarn add sequelize-cli -D
  • 初期化時に自動生成されるフォルダを「/src」配下にするため、先に「.sequelizerc」ファイルを作成する(プロジェクトルート)
touch .sequelizerc
  • sequelize関連ファイルを「/src/seqelize」で管理するように設定する(指定しない場合は、プロジェクトルートに作成される)
const path = require('path');

module.exports = {
    'config': path.resolve('./src/sequelize/config', 'config.json'),
    'models-path': path.resolve('./src/sequelize/models'),
    'seeders-path': path.resolve('./src/sequelize/seeders'),
    'migrations-path': path.resolve('./src/sequelize/migrations'),
};
  • マイグレーションのための初期化を行う
yarn sequelize init

※コマンドは、sequelize, sequelize-cli どちらでもよい(エイリアス)

プロジェクトルートではなく、/src/sequelizeに作成されます。
sequelize-init.png

  • config.jsonをsqlite用に書き換える。
{
  "development": {
    "database": "database_development",
    "dialect": "sqlite",
    "storage":"db/proto_app_dev.sqlite"
  },
  "test": {
    "database": "database_test",
    "dialect": "sqlite",
    "storage":"db/proto_app_test.sqlite"
  },
  "production": {
    "database": "database_production",
    "dialect": "sqlite",
    "storage":"db/proto_app.sqlite"
  }
}

14. sequelize-cli でテーブル定義のひな形を作成後、マイグレーションを行う

  • sequelize model:generateでmodel定義と、マイグレーション用のひな形を生成する。
yarn sequelize model:generate --name User --attributes name:string,birth:date,email:string

migrationsにひな形が生成されます。
sequelize-generate.png

  • マイグレーションを行い、テーブルを作成する
yarn sequelize db:migrate

db-migrate.png

15. テスト用データを登録(db:seed)する

  • ひな形を作成する
yarn sequelize seed:generate --name user
  • ひな形を修正(登録データを用意する)
'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    const now = new Date();
    const birth = new Date(now);
    const seeds = []; 
    const subtractYear = ( date, year ) => new Date( date.setYear(date.getFullYear() - year) );

    seeds.push({ name:"name1", birth:subtractYear(birth, 1), email:"mail1@example.com", createdAt: now, updatedAt: now });
    seeds.push({ name:"name2", birth:subtractYear(birth, 1), email:"mail2@example.com", createdAt: now, updatedAt: now });
    seeds.push({ name:"name3", birth:subtractYear(birth, 1), email:"mail3@example.com", createdAt: now, updatedAt: now });
    return await queryInterface.bulkInsert("users",seeds, {});
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.bulkDelete('users', null, {});
  }
};
  • seedを登録する
 yarn sequelize  db:seed:all

※やり直す場合は「yarn sequelize db:seed:undo:all」

16. 作成したmodelをexpress側から利用し、登録したデータが取得できることを確認する

  • ./route/users.jsを修正し、sequelizeのmodel(users)を全レコードjson形式で返すように修正する

修正前

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
    res.send('respond with a resource');
});

module.exports = router;

修正後

import db from "../sequelize/models/index";
import express from 'express';
const router = express.Router();

/* GET users listing. */
router.get('/', async function(req, res, next) {
  //res.send('respond with a resource');
  const users = await db.User.findAll();
  res.json( users );
});

// module.exports = router;
export default router;

呼び出し元(app.js)も変更する。

// var usersRouter = require('./routes/users');
import usersRouter from './routes/users';

17. ビルド後、データが取得できることを確認する

yarn build
yarn serve
  • localhost:3000/users にアクセスして、DBからデータが取得できることを確認する
[{"id":1,"name":"name1","birth":"2020-01-10T09:51:38.737Z","email":"mail1@example.com","createdAt":"2021-01-10T09:51:38.737Z","updatedAt":"2021-01-10T09:51:38.737Z"}
,{"id":2,"name":"name2","birth":"2019-01-10T09:51:38.737Z","email":"mail2@example.com","createdAt":"2021-01-10T09:51:38.737Z","updatedAt":"2021-01-10T09:51:38.737Z"}
,{"id":3,"name":"name3","birth":"2018-01-10T09:51:38.737Z","email":"mail3@example.com","createdAt":"2021-01-10T09:51:38.737Z","updatedAt":"2021-01-10T09:51:38.737Z"}]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.jsを勉強する⑦ - npmモジュールyargsを使った引数のオプションの処理

はじめに

前回はコマンドライン引数の受け取りについてまとめました。
今回はnpmモジュールyargsを使ったオプションの変換を記事にします。yargsを利用することで、ターミナルでコマンドを実行する際に、引数のオプションを入れた場合、それを引数として変換できます。

教材

Udemy
The Complete Node.js Developer Course (3rd Edition)
https://www.udemy.com/course/the-complete-nodejs-developer-course-2/

解決したいこと

processを用いることで、コマンドライン引数の受け取りはできましたが、引数のオプションを入力しても上手く変換されません。
まずは、こちらから見ていきましょう。app.jsというファイルを作成し、コマンドライン引数がconsoleに表示されるようにコードを書きます。

app.js
console.log(process.argv[2])

それでは、こちらのファイルを引数addBookとオプション title="Kokoro"を入れて実行してみます。

ターミナル
node app.js addBook --title="Kokoro"

結果は以下のようになり、オプションである"Kokoro"をうまく読み込んでくれません。(--title="Kokoro"全体が2つめの引数として認識されている)

ターミナル
addBook

こちらをnpmのyargsを使って解決します。

yargsのインストール

ターミナルにてインストールのコマンドを実行します。npm公式のyargsのページはこちら

ターミナル
//npmを開始していない場合はこちらも実行
 npm init
 npm i yargs

次に、requireを用いて、yargsをapp.js内で使えるようにします。コマンドライン引数をyargs.argvを用いて表示してみます。

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

console.log(yargs.argv);

同じ引数を入れて、ファイルを実行すると、以下のように出力されます。

ターミナル
node app.js addBook --title="Kokoro"

{ _: [ 'addBook' ], title: 'Kokoro', '$0': 'app.js' }

引数 addBookに対して、titleをプロパティとして認識し、Kokoroを値として出力できています。
ちなみに、'$0'は実行されたファイル名を指します。app.jsが実行されていることがわかります。

コマンドをカスタマイズする

次に、yargsのコマンドをカスタマイズしてみます。

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

// 以下のコマンドを作作成します。
yargs.command({
     //コマンド名
     command: 'addBook',
     //以下で、コメントを残しておきます。
     describe: 'Add a new Book',
     //以下の処理を実行します
     handler: function(){
     console.log("Add a new book!");
     }
})

//yargsを実行する 
yargs.parse()

コマンドが作成されているかターミナルから確認してみます。

ターミナル
node app.js --help

Commands:
  app.js addBook  Add a new Book

Options:
  --help     Show help                                                 [boolean]
  --version  Show version number                                       [boolean]

コマンドに、 addBookと設定したコメントが追加されています。

実際に、コマンドを実行してみましょう。

ターミナル
node app.js addBook


Add a new book!

処理には、"Add a new book!"をコンソールに出力する処理を書きましたが、無事に表示されました。

コマンドに引数のオプションを追加する

作成したコマンドには、builderを用いて、オプションを追加できます。

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

yargs.command({
     command: 'addBook',
     describe: 'Add a new Book',
    //オプション引数を追加
     builder: {
       title:{
          //処理の内容をメモ
          describe: "Add a book title",
          //必須の引数にするか指定
          demandOption: true,
         //データ型を指定
          type: "string"
       }
   },
     //オプションを表示するように変更する
     handler: function(argv){
     console.log("Adding " + argv.title);
     },
})

yargs.parse();

ターミナルでオプションのtitleを入れてファイルを実行します。

ターミナル
node app.js addBook --title="Kokoro"

Adding Kokoro

オプションが上手く変換されて、コンソールに出力されました。

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

メンバーをBANする方法 Discord.js(GBAN前編)

サーバーから人をBANする方法

荒らす人、イライラする人にはBANができます。
その動作をBOTにさせる方法を教えます!

動作環境

バージョン サービス
v.12以上 Glitch

document

公式ドキュメント(英語):Link

動き方

!ban メンションorID

理由を聞く(BANをする理由)

BAN完了!

コード

const discord = require("discord.js");
const client = new discord.Client();
const prefix = "!";//ここは好きに変えてもいいです

client.on("message", async message => {
if (!message.content.match(/^!/)) return; //!が最初にない場合は処理をしない
var command = message.content;
command = command.replace("!", "");
if (command == "ban") {
if (message.mentions.members.size == 1) { //メンションがあるかを確認

          const member = await message.mentions.members.first();//メンションの内容
          const id = member.user.id; //ユーザーID
          const mee = await message.channel.send({ //あとで編集などができるようにawait(非同期処理)をつける
            embed: {
              color: 16757683,
              description: "60秒以内に理由を入力してください。"
            }
          });
          const filter = msg => msg.author.id === message.author.id;
          const collected = await message.channel.awaitMessages(filter, {
            max: 1,
            time: 60000
          });
          const response = collected.first();
          if (!response)
            return mee.edit({
              embed: {
                description: "タイムアウト…"
              }
            });
          mee.edit({
            embed: {
              description: "BANしています…"
            }
          });
          message.guild.members.ban(id, { reason: response.content });
          mee.edit({
            embed: {
              description: `<@${id}>をBANしました。`
            }
          });
        } else { //IDの場合
          let me = message.content;
          me = me.replace("!ban ", "");
          let id = me
          const mee = await message.channel.send({
            embed: {
              color: 16757683,
              description: "60秒以内に理由を入力してください。"
            }
          });
          const filter = msg => msg.author.id === message.author.id; //検索内容を設定
          const collected = await message.channel.awaitMessages(filter, {
            max: 1,
            time: 60000
          });
          const response = collected.first();
          if (!response)
            return mee.edit({
              embed: {
                description: "タイムアウト…"
              }
            });
          mee.edit({
            embed: {
              description: "BANしています…"
            }
          });
          message.guild.members.ban(id, { reason: response.content });//BANをする
          mee.edit({
            embed: {
              description: `<@${id}>をBANしました。`
            }
          });

        }
}
})

動かない場合

①使うBOTに管理者権限、BANの権限、チャンネルへのアクセス権がない
②tokenが間違っている
③BOTが招待されていない
④コードが間違っている
など…

使う上での注意

※サーバーにいないひとをBANする場合、IDでしかBANができません。一応反応はします。(エラーを出すこともできるけど→別の記事で)サーバー内にいる人ならメンションでOKです。


質問など

Discordの場合:ライグー/racoon#1010
コメントでもOKです

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

(小ネタ)TypeScriptで型定義ファイルが無いモジュールの読み込み方法

はじめに

ml5を利用しようとしたところ、型定義が無く、エラーが発生したため、型定義が無い時のモジュールの読み込み方法について調べました。
*なお、ml5の型定義は現在draft版を作成中。
https://gist.github.com/dikarel/38a12ce263199a41ad67c15eac7f4b45

型定義が無い時のエラー

ml5を以下のようにモジュールをインポートするとエラーとなる。

import * as ml5 from "ml5";

具体的には以下のようなコンパイルエラーが発生する。

Could not find a declaration file for module 'ml5'.
Try npm install @types/ml5 if it exists or add a new declaration (.d.ts) file containing declare module 'ml5';

型定義が無い時の読み込み方法

型定義ファイル( d.ts )を自作すれば良いが、面倒な時はrequire でモジュールを読み込みます。
暗黙的に any 型になるので、型定義ファイル d.ts が見つからないエラーは消えます。

const ml5 = require('ml5')

ただし TSLint の設定によっては [tslint] require statement not part of an import statement (no-var-requires) という警告がでます。
// tslint:disable-next-line:no-var-requires とコメントで require('ml5') についてだけ警告を無効にします。

// tslint:disable-next-line:no-var-requires
const ml5 = require('ml5')

この状態では ml5any 型になり、型チェックも賢い補完も行われません。
自分の使う API だけ型付けして置くと、開発がスムーズです。

App.tsx
type ImageClassifierOptions = {
  alpha: number;
  topk: number;
  version: number;
};

interface IMl5 {
   imageClassifier(
    model: "MobileNet" | "Darknet" | "Darknet-tiny" | string,
    callback?: (error: any, result: any) => void
  ): undefined | Promise<any>;

  imageClassifier(
    model: "MobileNet" | "Darknet" | "Darknet-tiny" | string,
    options?: ImageClassifierOptions,
    callback?: (error: any, result: any) => void
  ): undefined | Promise<any>;

  imageClassifier(
    model: "MobileNet" | "Darknet" | "Darknet-tiny" | string,
    video?: MediaElement | HTMLVideoElement,
    options?: ImageClassifierOptions,
    callback?: (error: any, result: any) => void
  ): undefined | Promise<any>;

}
const ml5 = require('ml5') as IMl5;

終わりに

以上。

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

npmに自作モジュールを公開する方法

はじめに

先日Node.jsの勉強中にnpmについて改めて学ぶ機会がありました。その際npmにサンプルのモジュールを公開したので、具体的なやり方をシェアします。

npmとは

Node Package Managerが正式な名称です。その名の通りNode.jsのパッケージを管理するためのツールです。ホームページは下記リンク先からアクセスできます。

https://www.npmjs.com/

npmはNode.jsをインストールする際にインストールされます。インストール済みの場合、下記コマンドでバージョンが表示されます。

npm --version

npmに自作モジュールを公開する方法

公開までの流れ

流れは下記の通りです。

  • npmのアカウントを作成する。
  • 公開したいモジュールを作成する。
  • npmへログインする。
  • npmへ公開する。

それでは1つずつ見ていきます。

npmのアカウントを作成する

まずはnpmのアカウントを作成します。下記リンク先からSign Upできます。

https://www.npmjs.com/signup

公開したいモジュールを作成する

npm initでpackage.jsonを作成します。package nameを聞かれるので、npmレポジトリ上に存在していない名前を入力します。あらかじめnpmのサイトで利用されていない名前であることを確認しておきましょう。

npm init

package.jsonができたら、private属性をpackage.jsonに追記して公開設定にします。

"private": false

次に、README.mdファイルを準備します。ここにはどういった動きをするモジュールなのか、プロジェクトの概要を記述しておきます。

npmへログインする

ターミナルを起動し、プロジェクトのルートで下記コマンドを入力します。ユーザーネーム、パスワード、メールアドレスを聞かれるので入力します。

npm login

npmへ公開

ログインができたら、下記コマンドで公開できます。

npm publish —access public

※—dry runオプションをつけることで、お試しで実行することができます(実際には公開されません)。

npm publish —access public —dry run

最後に

簡単ですがサンプルのモジュールをGitHub上にpushしたので、package.json等の参考までに見てください。

https://github.com/n199603/npm-study

以上、npmに自作モジュールを公開する方法でした。見ていただきありがとうございました。

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

NimのコードをNode.js用のJavaScriptコードにトランスコンパイルする

概要

  • NimのコードをJSバックエンドでコンパイルしてNode.jsスクリプトとして実行してみます
  • NimのコードからNode.js用のライブラリを生成して、Node.jsスクリプトからライブラリを読み込んで関数を呼び出してみます

NimはJavaScriptを生成できる

Nimは公式でNimのコードからJavaScriptのコードにトランスコンパイル可能です。

例えば、以下のようなNimコードに対して

index.nim
proc plus*(x, y: cint): cint {.exportc.} =
  return x + y

以下のコマンドでコンパイルします。すると、index.nimからindex.jsが生成されます。

$ nim js index.nim

$ ls index*
index.js index.nim

このようにJavaScriptコードを生成できます。

しかしここで生成されるJavaScriptはフロントエンド用で、HTMLから読み込む想定のものです。
Node.jsからは扱うことはできません。

NimはNode.jsのコードも生成できる

しかし、コンパイル時にオプションを渡すことにより、Node.js用のJavaScriptコードを生成できます。
Nim Backend Integration - Nim

前述のコードを手直ししてNode.js用コンパイルを実施し、Node.jsで実行してみます。

index.nim
proc plus*(x, y: cint): cint {.exportc.} =
  return x + y

echo plus(1, 2)
$ nim js -d:nodejs index.nim

$ node index.js
3

node.jsで実行できました。

NimのコードからNode.js用ライブラリを生成してみる

Node.js用の単体のスクリプトとして実行できることがわかりました。
次はNode.js用ライブラリを生成してNode.jsスクリプトから読み込めることを確認します。

以下のNimコードを用意します。
以下のNimコードでは、plus関数を定義して、Node.jsからplus関数を呼び出せるようにするものです。

lib.nim
import jsffi

var module {.importc.}: JsObject

proc plus*(x, y: cint): cint =
  return x + y

module.exports.plus = plus

次に、上記ライブラリを読み込んで使用するindex.jsを定義します。

index.js
const lib = require("./lib");
console.log(lib.plus(1, 2));

これらのファイルを同じディレクトリに配置し、以下のコマンドを実行します。

$ nim js -d:nodejs lib.nim

$ ls lib*
lib.js lib.nim

$ node index.js
3

無事、Node.jsスクリプトから、Nimで生成したNode.js用ライブラリを読み込んで、関数を呼び出すことができました。

まとめ

以下の内容について記載しました。

  • NimのコードをJSバックエンドでコンパイルしてNode.jsスクリプトとして実行できる
    • コンパイルするときはjsバックエンドで -d:nodejs を付ける
  • NimのコードからNode.js用ライブラリを生成してNode.jsスクリプトからライブラリを読み込み、関数を実行できる
    • module {.importc.}: JsObjectでモジュールを読み込んで関数をセットする

以上です

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

herokuデプロイ後sequelizeでPostgreSQLに接続できないときの解決法

sequelizeを使ってPostgreSQLと接続したい。

ローカル環境では接続に成功していたが、herokuにデプロイした後は失敗する。

失敗

const Sequelize = require('sequelize');

// herokuまたはローカル環境のPostgreSQLに接続する
const sequelize = new Sequelize(process.env.DATABASE_URL || 'postgres://postgres:postgres@localhost/hogehoge');

成功

const Sequelize = require('sequelize');

const sequelize = new Sequelize(
  process.env.DATABASE_URL || 'postgres://postgres:postgres@localhost/hogehoge', 
  {dialectOptions: { ssl: true }}
);

ログを見るとssl off(うろ覚え)とあったので、このようにオプションを追加してみると接続に成功した。

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

【Node.js】現在日時を取得する方法3選

目標

Node.jsで現在日時をYYYYMMDDHHmmssの14桁のフォーマットで出力します。
nodeコマンドで下記のような出力が得られるプログラムですね。

$ node index.js
202101082341

前提

Node.js 14.15.4
date-utils 1.2.21
moment 2.29.1

Javascriptで頑張る

index.js
const date = new Date();
const currentTime = formattedDateTime(date);
console.log(currentTime)

function formattedDateTime(date) {
  const y = date.getFullYear();
  const m = ('0' + (date.getMonth() + 1)).slice(-2);
  const d = ('0' + date.getDate()).slice(-2);
  const h = ('0' + date.getHours()).slice(-2);
  const mi = ('0' + date.getMinutes()).slice(-2);
  const s = ('0' + date.getSeconds()).slice(-2);

  return y + m + d + h + mi + s;
}

date-utiliesを利用

index.js
require('date-utils');
const date = new Date();
const currentTime = date.toFormat('YYYYMMDDHH24MISS');
console.log(currentTime);

Moment.jsを利用

index.js
const moment = require('moment');
const currentTime = moment();
console.log(currentTime.format("YYYYMMDDHHmmss"));

結論

モジュールって便利!!

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

【Node.js】現在日時を取得する方法4選

目標

Node.jsで現在日時をYYYYMMDDHHmmssの14桁のフォーマットで出力します。
nodeコマンドで下記のような出力が得られるプログラムですね。

$ node index.js
202101082341

前提

Node.js 14.15.4
date-utils 1.2.21
moment 2.29.1

更新情報

【2020/01/09 toLocaleStringメソッドを利用 追加】
@il9437 様、ありがとうございます!

Javascriptで頑張る

index.js
const date = new Date();
const currentTime = formattedDateTime(date);
console.log(currentTime)

function formattedDateTime(date) {
  const y = date.getFullYear();
  const m = ('0' + (date.getMonth() + 1)).slice(-2);
  const d = ('0' + date.getDate()).slice(-2);
  const h = ('0' + date.getHours()).slice(-2);
  const mi = ('0' + date.getMinutes()).slice(-2);
  const s = ('0' + date.getSeconds()).slice(-2);

  return y + m + d + h + mi + s;
}

date-utiliesを利用

index.js
require('date-utils');
const date = new Date();
const currentTime = date.toFormat('YYYYMMDDHH24MISS');
console.log(currentTime);

Moment.jsを利用

index.js
const moment = require('moment');
const currentTime = moment();
console.log(currentTime.format("YYYYMMDDHHmmss"));

toLocaleStringメソッドを利用 (@il9437 様からのご教示)

記事を出した時点では上記のやり方で実装する必要があるとの認識でしたが、
@il9437 様にtoLocaleStringメソッドでスウェーデン語を指定してから加工する効率的な方法を教えて頂いたので記事内でも紹介します

index.js
const date = new Date().toLocaleString('sv').replace(/\D/g, '');
console.log(date);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む