🐷

[note] node.js

2022/03/04に公開

node.jsとは

Node.js is an asynchronous, event-driven JavaScript environment designed for building scalable network applications.

Node.jsは、スケーラブルなネットワークアプリケーションを構築するために設計された非同期、イベントドリブンなJavaScript環境です。

https://www.tohoho-web.com/ex/nodejs.html#whatis

Node.jsをバックエンドに使うべきユースケース
https://qiita.com/baby-degu/items/860b78d2d1cd4894bc02

環境構築

こちら

環境構築(docker)

nodeを実行するには

REPL

ユーザーとインタプリタが対話的にコード片を実行できるもの

 !  ~/W/d/dandyyy   *…  node                        2022-02-16 14:05:12
Welcome to Node.js v14.0.0.
Type ".help" for more information.
> console.log("test")
test
undefined
> 

jsファイル(ここではvscode)

pwd
/Users/tanokentaro/Workspace/develop/dandyyy
// vscodeのbackend/index.jsを起動
code backend/index.js

backend/index.js ~編集~

console.log("test");
// backend/index.jsを実行
 !  ~/W/d/dandyyy   *…  node backend/index.js       2022-02-16 14:18:57
test

vscode 拡張機能

  • npm intellisense
  • eslint
  • prettier
  • document this
  • rest client

新規プロジェクトを作成

プロジェクトの初期化

質問にはよしなに答える
完了すればpackage,json(メタ情報、依存関係、ソースコードの場所などのnodepjの中で最も重要なファイル)が作られる

npm init

package.json

{
  // メタ情報
  "name": "dandyyy",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  // スクリプト
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node backend/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  // pjに使用するライブラリを記述する追加のプロパティ
  "dependencies": {
    "express": "^4.17.2"
  }
}

NPM スクリプトで開発タスクを自動化

実行、テスト、ビルドなど
package.jsに関連づけられたターミナルコマンドを定義することで自動化
基本タスク

  • start 実行
  • test
  • build
  • lint

開発者間で一貫したスクリプト名にする

  "scripts": {
    "start": "node index.js",
    "build": "tsc",
    "lint": "eslint",
    "test": "jest"
  }

スクリプトを実行するには
terminal上で
startの場合はnpm startだけでOK

npm run {スクリプト名}

Node.js プロジェクトで依存パッケージを追加する

たいていの場合はライブラリやツールなど外部のコードに依存する = 依存関係と呼ばれる

npm install express

node_modulesファイルがプロジェクト上に追加される

{
  "name": "dandyyy",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node backend/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.2" // 追加
  }
}

commitしないものを.gitignoreで管理
理由

  • 膨大な量
  • npm installだけで依存パッケージがインストールされるのでわざわざcommit必要ない
touch .gitignore

.gitignore

node_modules

npmはcli及びパッケージインストーラーとして機能する

開発環境だけで使う

npm install --save-dev jest
  "devDependencies": {
    "jest": "^4.17.2"
  }

パッケージのアンインストール

npm uninstall jest

package-lock.json

依存関係を更新すると作成される
npmによって依存関係が更新されるたびに更新される
全ての依存関係を推移する役割を果たすため、リポジトリにコミットする
npm ciコマンドがこれがないと実行できない

パッケージが頻繁に更新されても余計な更新をしないように自動的にロックしてくれる = パッケージの更新は自分らでしないといけない

パッケージの更新

更新が必要なパッケージの表示
赤で表示される部分は全て最新にできる
今はない

npm outdated

更新

npm update

パッケージバージョンは3つの数字で作られる

セマンティックバージョニング

  • 更新範囲を示す特殊文字
    • ^(キャレット):デフォルト、マイナーとパッチのみ更新
    • ~:パッチ更新のみ、コンパイラやリンターなどユーザー側で変更が必要
    • なし(バージョン番号のみ):更新なし
    • *:常に最新に更新する
  • 4:メジャーバージョン(コードの互換性に影響を与える可能性)
  • 17:マイナーバージョン(機能追加)
  • 2:パッチバージョン(コードない動作の修正、安全)
"express": "^4.17.2"

脆弱性を npm audit でチェック

今はなし
解決方法などの情報を取得できる

 ~/W/d/dandyyy   *…  npm audit
                                                                                
                       === npm audit security report ===                        
                                                                                
found 0 vulnerabilities
 in 50 scanned packages

Express で Web API を構築

ヘルパーをインストール

  • bosy-parser
  • cors
  • nodemon
npm install bosy-parser cors
npm install --save-dev nodemon
{
  "name": "dandyyy",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node backend/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.2",
    "cors": "^2.8.5",
    "express": "^4.17.2"
  },
  "devDependencies": {
    "nodemon": "^2.0.15"
  }
}

api作成

Build the server
server.js

// expressを読み込む
const express = require("express");
// ポート番号を読み込む(環境変数から読み取る or デフォルトとして5000を設定)
const port = process.env.port || process.env.PORT || 5000;
// expressオブジェクトのインスタンスを作成(初期化)
const app = express();

// イベントハンドラを設定(port番号をここでリッスンさせる)
// サーバが起動した時に
app.listen(port, () => {
  console.log("server api!!");
});

Setting up cors and bodyparser

// expressを読み込む
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");

// ポート番号を読み込む(環境変数から読み取る or デフォルトとして5000を設定)
const port = process.env.port || process.env.PORT || 5000;

// expressオブジェクトのインスタンスを作成(初期化)
const app = express();
// configure app
// ユーザーがサーバーに送信した情報を読み取る
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors({ origin: /http: \/\/localhost/ }));
app.options("*", cors());

// イベントハンドラを設定(port番号をここでリッスンさせる)
// サーバが起動した時に
app.listen(port, () => {
  console.log("server api!!");
});

package.jsonのメタデータを出力するテスト用api作成

// expressを読み込む
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
// テストとしてpackage.jsonからのデータを表示させる
const package = require("../package.json");

// ポート番号を読み込む(環境変数から読み取る or デフォルトとして5000を設定)
const port = process.env.port || process.env.PORT || 5000;
// api routerを設定
const apiRoot = "/api";

// expressオブジェクトのインスタンスを作成(初期化)
const app = express();

// configure app
// ユーザーがサーバーに送信した情報を読み取る
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// apiとクライアントアプリのホスティング環境が別々の場所にあっても読み出し可能にする
app.use(cors({ origin: /http: \/\/localhost/ }));
app.options("*", cors());

// configure routes
const router = express.Router();
router.get("/", (req, res) => {
  // テストとしてpackage.jsonからのデータを表示させる
  res.send(`${package.description} - v${package.version}`);
});

// register all our routes
app.use(apiRoot, router);

// イベントハンドラを設定(port番号をここでリッスンさせる)
// サーバが起動した時に
app.listen(port, () => {
  console.log("server api!!");
});

各調査

require
process.env.port
process.env.PORT
app.use
bodyParser.urlencoded
/http: //localhost/
app.listen構文

フォルダ構成

dbとの連携

crud api

ejs テンプレエンジンExpress使うのでざつと

<%= obj.id %>

こんな感じで値を出力できる

フロントとの連携

デプロイ

Expressの基本おさらい

Expressの基本手順

  1. expressオブジェクトの用意
  2. appオブジェクトの作成(実体化)
  3. ルーティングの設定
  4. 待ち受け

app.jsとroutes配下ファイルの役割

routes配下に***.jsファイル作成
そこにrouterオブジェクトを使った処理を用意

const express = require("express");
const router = express.Router();

router.get("/", (req, res, next) => {
  var msg = "※何か書いて送信して下さい。";
  if (req.session.message != undefined) {
    msg = "Last Message: " + req.session.message;
  }
  var data = {
    title: "Hello!",
    content: msg,
  };
  res.render("hello", data);
});

router.post("/post", (req, res, next) => {
  var msg = req.body["message"];
  req.session.message = msg;
  var data = {
    title: "Hello!",
    content: "Last Message: " + req.session.message,
  };
  res.render("hello", data);
});

module.exports = router;

appjsで***.jsをロードし、/***(url)に割り当てる

var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
var hello = require("./routes/hello");//ここ
const session = require("express-session"); 

var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");

var app = express();

// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");

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")));
var session_opt = {
  secret: "keyboard cat",
  resave: false,
  saveUninitialized: false,
  cookie: { maxAge: 60 * 60 * 1000 },
};
app.use(session(session_opt));

app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/hello", hello);//ここ

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render("error");
});

module.exports = app;

Discussion