20200101のNode.jsに関する記事は4件です。

Express \(Node.js\) の Graceful shutdown

基本的な実装の仕方と、実装した場合 / しなかった場合、で実際にどういう動作をするか〜、について書きます。

Linux, Node.js 12.13.0, での話だけをします。

Graceful shutdown ?

Express に限りませんが、Web サーバーを停止する際、クライアントから接続中のリクエスト (リクエスト受付してまだレスポンスしていない接続) はどうなるでしょうか?

Graceful shutdown とは一般的に以下の停止を指します。

  • 停止指示後に、新しい接続を受付しない
  • 残った処理中の接続が完了するのを待ってから、プロセスを安全に停止する

SIGNALs

そもそも Web サーバープロセスはどうやって停止するかというと、 SIGNAL を用いて停止します。

具体的には下表の通り、コマンド等によって SIGNAL を送信できます。

SIGNAL kill command Linux Terminal Kubernetes 実装依存 説明
SIGHUP kill -SIGHUP {pid} -- -- Yes プロセスが端末から切断された際のシグナル
SIGINT kill -SIGINT {pid} CTRL + C -- Yes 割り込み
SIGKILL kill -SIGKILL {pid} -- SIGTERM 送信から30秒後に送信 NO プロセスの実装に依存しないOSからの強制終了
SIGTERM kill {pid} -- 最初に送信 Yes プロセスの終了

最近では、プロセスを Docker コンテナ化して、 Kubernetes 等のプラットフォーム上で動かす事が多いと思います。

例えば Kubernetes では、プロセス (Docker コンテナ) を終了する際は、まず SIGTERM が送信され、30秒待ってもプロセスが終了しない場合、最終的に SIGKILL が送信されます。

実装例

URL /sleep と、 SIGNAL SIGTERM での Graceful shutdown を Express で実装しました。

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

const SLEEP_MSEC = 30 * 1000;
const app = express();

app.get('/sleep', (req, res) => {
  setTimeout(() => res.send('OK'), SLEEP_MSEC);
});

const server = app.listen(3000, () => console.log('Example app listening on port 3000!'));

process.on('SIGTERM', () => {
  server.close(() => {
    console.log('Process terminated.')
  })
});

実行します。

$ node index.js

Example app listening on port 3000!

ブラウザで以下の URL にアクセスすると、30秒待たされた後 OK と表示されます。

[未実装で] 実際に停止してみる

まずは 未実装の状態で どう動作するか検証します。

Express サーバーを起動した後、ブラウザで http://localhost:3000/sleep にアクセスします。
まだリクエストの処理中に SIGNAL を送信します。

(1) SIGHUP

シグナルを送信でプロセスが即座に停止。

kill -SIGHUP {pid}
Hangup: 1

(2) SIGINT

シグナルを送信でプロセスが即座に停止。

kill -SIGINT {pid}
(terminal 上の出力はなし)

(3) SIGKILL

シグナルを送信でプロセスが即座に停止。

kill -SIGKILL {pid}
Killed: 9

(4) SIGTERM

シグナルを送信でプロセスが即座に停止。

kill {pid}
Terminated: 15

[SIGTERM 実装で] 実際に停止してみる

実装していない SIGTERM 以外のシグナルは省略。

(5) SIGTERM

ブラウザで http://localhost:3000/sleep にアクセスする。

応答がすぐには帰ってこず、ローディング状態になります。

シグナルを送信します。

kill {pid}

プロセスは実行されたまま、無反応。

(terminal 上の出力はなし)

ブラウザから新しいタブを開いて http://localhost:3000/sleep に追加でアクセスする。

TCP 接続が拒否され、ブラウザ上に「正常に接続できませんでした」と表示される。

1度目のブラウザからのリクエストが 30 秒後に正常に応答が返り、プロセスが終了する。

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

Express (Node.js) の Graceful shutdown

基本的な実装の仕方と、実装した場合 / しなかった場合、で実際にどういう動作をするか〜、について書きます。

Linux, Node.js 12.13.0, での話だけをします。

Graceful shutdown ?

Express (Node.js) に限りませんが、Web サーバーを停止する際、クライアントから接続中のリクエスト (リクエスト受付してまだレスポンスしていない接続) はどうなるでしょうか?

Graceful shutdown とは一般的に以下の停止を指します。

  • 停止指示後に、新しい接続を受付しない
  • 残った処理中の接続が完了するのを待ってから、プロセスを安全に停止する

SIGNALs

そもそも Web サーバープロセスはどうやって停止するかというと、 SIGNAL を用いて停止します。

具体的には下表の通り、コマンド等によって SIGNAL を送信できます。

SIGNAL kill command Linux Terminal Kubernetes 実装依存 説明
SIGHUP kill -SIGHUP {pid} -- -- Yes プロセスが端末から切断された際のシグナル
SIGINT kill -SIGINT {pid} CTRL + C -- Yes 割り込み
SIGKILL kill -SIGKILL {pid} -- SIGTERM 送信から30秒後に送信 NO プロセスの実装に依存しないOSからの強制終了
SIGTERM kill {pid} -- 最初に送信 Yes プロセスの終了

最近では、プロセスを Docker コンテナ化して、 Kubernetes 等のプラットフォーム上で動かす事が多いと思います。

例えば Kubernetes では、プロセス (Docker コンテナ) を終了する際は、まず SIGTERM が送信され、30秒待ってもプロセスが終了しない場合、最終的に SIGKILL が送信されます。

Kubernetes - Pods - Termination of Pods

実装例

URL /sleep と、 SIGNAL SIGTERM での Graceful shutdown を Express で実装しました。

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

const SLEEP_MSEC = 30 * 1000;
const app = express();

app.get('/sleep', (req, res) => {
  setTimeout(() => res.send('OK'), SLEEP_MSEC);
});

const server = app.listen(3000, () => console.log('Example app listening on port 3000!'));

process.on('SIGTERM', () => {
  server.close(() => {
    console.log('Process terminated.')
  })
});

実行します。

$ node index.js

Example app listening on port 3000!

ブラウザで以下の URL にアクセスすると、30秒待たされた後 OK と表示されます。

[未実装で] 実際に停止してみる

まずは 未実装の状態で どう動作するか検証します。

Express サーバーを起動した後、ブラウザで http://localhost:3000/sleep にアクセスします。
まだリクエストの処理中に SIGNAL を送信します。

(1) SIGHUP

シグナルを送信でプロセスが即座に停止。

kill -SIGHUP {pid}
Hangup: 1

(2) SIGINT

シグナルを送信でプロセスが即座に停止。

kill -SIGINT {pid}
(terminal 上の出力はなし)

(3) SIGKILL

シグナルを送信でプロセスが即座に停止。

kill -SIGKILL {pid}
Killed: 9

(4) SIGTERM

シグナルを送信でプロセスが即座に停止。

kill {pid}
Terminated: 15

[SIGTERM 実装で] 実際に停止してみる

実装していない SIGTERM 以外のシグナルは省略。

(5) SIGTERM

ブラウザで http://localhost:3000/sleep にアクセスする。

応答がすぐには帰ってこず、ローディング状態になります。

シグナルを送信します。

kill {pid}

プロセスは実行されたまま、無反応。

(terminal 上の出力はなし)

ブラウザから新しいタブを開いて http://localhost:3000/sleep に追加でアクセスする。

TCP 接続が拒否され、ブラウザ上に「正常に接続できませんでした」と表示される。

1度目のブラウザからのリクエストが 30 秒後に正常に応答が返り、プロセスが終了する。

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

EnterpriseEthereum/Kaleidoをローカルtruffleからアクセスする

What's this?

パーミッションドのブロックチェーン勉強中です。

BaaS色々使いたいですが如何せんお金がかかります。
そんな中、EthereumベースのBaaS「Kaleido」は永久無料プランがあるのでそれは使いやすい、ということで勉強しています。

あんまり情報ないですが、マルチリージョンとかにもできるしEnterpriseEthereumのBaaSとしてはかなり優秀なのでは、という印象です。
詳しくは下記をみてください。

「Kaleido」企業向けイーサリアム開発のフルスタックBaaSとは?

今回はコンソーシアムを立ててコントラクトをデプロイ、ローカルのアプリケーションからパーミッションドアクセスできるところまでを確認します。
ここまでできればDAppが作れるはずです。

環境

下記で検証

$ sw_vers
> ProductName:  Mac OS X
> ProductVersion:   10.14.5
> BuildVersion: 18F2058
$ node -v
> v10.18.0
$ npm -v
> 6.13.4

nodeのバージョンは一個前のLTS?であるv10.18.0でないと動作しません。
後続のtruffleboxのnpm installで死にます。
初めv12.13.1とかでやってると死んでました。
まだtruffleかweb3のサポートが追いついてないようです。

手順

Kaleidoのコンソーシアム作成

Kaleidoのコンソーシアム作成については、先人の記事を参考ください。
ぽちぽちやれば良い感じになるはずです。

Ethereumベースのブロックチェーンを構築できるKaleidoを触ってみた

truffle環境の構築

Kaleido.ioが下記にtrufflebox置いてくれているので、基本ここに準拠するだけです。

truffle-kaleido-box

下記コマンドがローカルでうまく機能するかどうかを確認しましょう。

mkdir truffle-kaleido-box
cd truffle-kaleido-box
npx truffle unbox kaleido-io/truffle-kaleido-box
truffle develop
# 以下、truffle console上で
compile
test
migrate

Kaleidoへの接続・コントラクトデプロイ

ローカルでうまく動作することが確認できれば、次はコントラクトをKaleidoにデプロイしてみます。
これもぶっちゃけtruffle-kaleido-boxの「Connect to Kaleido」に従うだけです。
デプロイしたいノードで「+ Connect Node」をクリック(下記ボタン)

image.png

「Native JSON/RPC」を選択

image.png

必要なCredentialsを選択or新規作成
入れたら下記をクリック

image.png

表示されている「App Credential」、「Connection Url」をtruffleのconfigに記述します。
truffle-config.jsを開いて下記を修正。

const appCred = 'yourappcred'; // from application credential widget
const connectionURL = 'nodeConnectionURL'; // without protocol (https://)

※作成したコンソーシアムがQuorumであれば、type: 'quorum'のコメントアウトを外しておく。

下記コマンドでコントラクトをデプロイします

npx truffle migrate --reset

デプロイに成功したら、コンソールにデプロイしたコントラクトのアドレスが出ています。

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.

Running migration: 1_initial_migration.js
Deploying Migrations...
Migrations: 0xf38a1E94A9F65118caa957D60806688397BD147c
Saving successful migration to network...
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying SimpleStorage...
SimpleStorage: 0xAAbDE02d23eD1Fe769d22e2666E1490dAb9F58B6 ←これ
Saving successful migration to network...
Saving artifacts...

KaleidoのBlockExplorer上で、デプロイしたコントラクトを確認できます。

デプロイしたコントラクトを触ってみる

truffle consoleから確認

下記コマンドでtruffle consoleへ

npx truffle console

console上で下記コマンドでデプロイ済のコントラクトを取得

let deployedContract = await SimpleStorage.deployed()

処理実行に必要なアドレスを取得

let accounts = await web3.eth.getAccounts()

下記でコントラクトにアクセス、storedData変数に格納されている数値を確認できる。

deployedContract.contract.methods.storedData().call()
> '(なんらかの数字)'

下記でstoreされている数値を更新する。

deployedContract.contract.methods.set([数字]).send({from: accounts[0]})
// ex) >deployedContract.contract.methods.set(99999).send({from: accounts[0]})

もう一度値を確認すると、値が更新されていることがわかる。

deployedContract.contract.methods.storedData().call()
> '(さっき指定した数字)'

※ちなみにRPC接続だけでなく、KaleidoではREST APIサーバーも置いてくれるので、
REST API経由でも今回デプロイしたコントラクトにアクセスできます。
デプロイしたアドレスを指定して簡単に実行できます。


以上です。

ここまでできれば、あとはコントラクトアクセスするようなDAppを作れるはずです。
他の参加者もノードをポチって追加して、Credentialsを提供するだけで良い感じにできる、はずです。
運用方針あってんのか、もうちょっとコントラクトをセキュアにするとかワークフロー的なこともできると思いますが、そこの作り込みは勉強中です。

重ねてですが、パーミッションドなEthereumを利用するのは、Kaleidoが一番軽い感じで良いのではないのでしょうか。
何より無料、これがすごい。(どうやって収益化してるんだろう、、、)

これでコンソーシアムでの検証をやってみたいと思います。

参考

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

「node.js」「npm」を使って「bootstrap」を導入するまでのまとめ

1. はじめに

1.1. 背景

「node.js」でSPA(シングル・ページ・アプリケーション)を作りたい。
それにあたって、「bootstrap」を使いたい!

1.2. 目的

「node.js」の「npm」を使って「bootstrap」を読み込むこと。

2. 「npm」で「bootstrap」の導入

早速、「npm」コマンドでbootstrapをインストールします。

2.1. 筆者の開発環境の確認

bootstrapの導入にはCDNを使うのが一番楽です。

(なんらかのHTMLにて)CDNでの導入
<!-- CSS only -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

<!-- JS, Popper.js, and jQuery -->
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

bootstrap
BootstrapCDN

しかし、「npm」を使ってbootstrapを導入すると、後々、CSSのカスタムに便利らしいです。
なので、今回はそちらの手法を採用します。
「npm」を使うに当たって、PCの「node.js」「npm」のバージョンを確認します。

バージョンの確認
% node -v
v12.2.0
% npm -v
6.9.0

2.2. 「npm」を初期化する

node-js-bootstrapというフォルダを作成して、npm init --forceで、package.jsonを作ります。

新規プロジェクト用のフォルダを作成し、npmを初期化
% mkdir node-js-bootstrap
% cd node-js-bootstrap 
% npm init --force
npm WARN using --force I sure hope you know what you are doing.
Wrote to ~/node-js-bootstrap/package.json:

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

% ls
package.json

package.jsonが作られました。

2.3. 「npm」を使って「bootstrap」をインストールする

公式サイトに示されているように、npm install bootstrapを実行します。

npmでbootstrapをインストール
% npm i -S bootstrap 
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN bootstrap@4.4.1 requires a peer of jquery@1.9.1 - 3 but none is installed. You must install peer dependencies yourself.
npm WARN bootstrap@4.4.1 requires a peer of popper.js@^1.16.0 but none is installed. You must install peer dependencies yourself.
npm WARN node-js-bootstrap@1.0.0 No description
npm WARN node-js-bootstrap@1.0.0 No repository field.

+ bootstrap@4.4.1
added 1 package from 2 contributors and audited 1 package in 0.923s
found 0 vulnerabilities

jquerypopper.jsがないと怒られました。
こちらも導入しましょう。

npmによるjqueryとpopper.jsの導入
% npm i -S jquery popper.js
npm WARN node-js-bootstrap@1.0.0 No description
npm WARN node-js-bootstrap@1.0.0 No repository field.

+ popper.js@1.16.0
+ jquery@3.4.1
added 2 packages from 3 contributors and audited 3 packages in 0.979s
found 0 vulnerabilities

ここから先は、目的によって行うことが異なります。
今回は、CSSをカスタマイズできるようにするために「Webpack」を導入します。

3. 「webpack」を用いて「bootstrap」を読み込む

3.1. 「webpack」の引用

こちらのWEBサイトがとても参考になります。
このWEBページを参照して、今回必要になるWebpackを導入します。

webpackなどの導入
% npm i -D webpack webpack-cli css-loader node-sass sass-loader postcss-loader autoprefixer extract-text-webpack-plugin@next

> fsevents@1.2.11 install ~/node-js-bootstrap/node_modules/fsevents
> node-gyp rebuild

  SOLINK_MODULE(target) Release/.node
  CXX(target) Release/obj.target/fse/fsevents.o
  SOLINK_MODULE(target) Release/fse.node

> node-sass@4.13.0 install ~/node-js-bootstrap/node_modules/node-sass
> node scripts/install.js

Cached binary found at ~/.npm/node-sass/4.13.0/darwin-x64-72_binding.node

> node-sass@4.13.0 postinstall ~/node-js-bootstrap/node_modules/node-sass
> node scripts/build.js

Binary found at ~/node-js-bootstrap/node_modules/node-sass/vendor/darwin-x64-72/binding.node
Testing binary
Binary is fine
npm WARN sass-loader@8.0.0 requires a peer of sass@^1.3.0 but none is installed. You must install peer dependencies yourself.
npm WARN sass-loader@8.0.0 requires a peer of fibers@>= 3.1.0 but none is installed. You must install peer dependencies yourself.
npm WARN node-js-bootstrap@1.0.0 No description
npm WARN node-js-bootstrap@1.0.0 No repository field.

+ postcss-loader@3.0.0
+ css-loader@3.4.0
+ autoprefixer@9.7.3
+ sass-loader@8.0.0
+ webpack-cli@3.3.10
+ webpack@4.41.5
+ node-sass@4.13.0
+ extract-text-webpack-plugin@4.0.0-beta.0
added 639 packages from 338 contributors and audited 6056 packages in 17.326s
found 0 vulnerabilities

sass-loadersassfibersを欲しているようなので、これもインストールしておきましょう。

sassとfibersのインストール
% npm i -D sass fibers

> fibers@4.0.2 install ~/node-js-bootstrap/node_modules/fibers
> node build.js || nodejs build.js

`darwin-x64-72` exists; testing
Binary is fine; exiting
npm WARN node-js-bootstrap@1.0.0 No description
npm WARN node-js-bootstrap@1.0.0 No repository field.

+ fibers@4.0.2
+ sass@1.24.0
added 3 packages from 4 contributors and audited 8209 packages in 2.926s
found 0 vulnerabilities

また、ここで必要になるwebpack-cliですが、$PATHを正しく通していないと、「見つからないからインストールするよ」という無限ループになるかもしれません(私の環境ではなりました。)

に丁寧に解説されています。
私の場合は$PATHをとおして、次のところを見るようになりました。

webpack-cliの場所
% which webpack-cli
~/.nodebrew/current/bin/webpack-cli

ここに$PATHが通ればOKです。

3.2. webpackのconfigファイルの作成

まるまる引用で申し訳ないですが、こちらのファイルを参照して、webpack.config.jsを作成しましょう。

ics-creative「webpack.config.js」インターネット, https://github.com/ics-creative/170330_webpack/blob/master/tutorial-bootstrap-style-js/webpack.config.js(2020/01/01閲覧)

webpack.config.js(ics-creative)
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  // モード値を production に設定すると最適化された状態で、
  // development に設定するとソースマップ有効でJSファイルが出力される
  mode: 'production',
  module: {
    rules: [
      {
        // 対象となるファイルの拡張子(scss)
        test: /\.scss$/,
        // Sassファイルの読み込みとコンパイル
        use: ExtractTextPlugin.extract([
          // CSSをバンドルするための機能
          {
            loader: 'css-loader',
            options: {
              // オプションでCSS内のurl()メソッドの取り込まない
              url: false,
              // ソースマップの利用有無
              sourceMap: true,
              // Sass+PostCSSの場合は2を指定
              importLoaders: 2
            },
          },
          // PostCSSのための設定
          {
            loader: 'postcss-loader',
            options: {
              // PostCSS側でもソースマップを有効にする
              sourceMap: true,
              // ベンダープレフィックスを自動付与する
              plugins: () => [require('autoprefixer')]
            },
          },
          // Sassをバンドルするための機能
          {
            loader: 'sass-loader',
            options: {
              // ソースマップの利用有無
              sourceMap: true,
            }
          }
        ]),
      },
    ],
  },
  plugins: [
    new ExtractTextPlugin('style.css'),
  ],
  // source-map方式でないと、CSSの元ソースが追跡できないため
  devtool: "source-map"
};

現時点でのファイルはこういう配置になっているはずです。

% tree -L 1
.
├── node_modules
├── package-lock.json
├── package.json
└── webpack.config.js

3.3. 「src」フォルダと「dist」フォルダの配置

webpackは、多くのファイルをまとめて整理してくれる素敵なユーティリティです。
そのため、多くのファイルが格納されている「src」フォルダと、それらのファイルを素敵に整理する「dist」フォルダを用意する必要があります。
それらのフォルダを作りましょう。

「src」「dist」フォルダの作成
% mkdir src dist && tree -L 1
.
├── dist
├── node_modules
├── package-lock.json
├── package.json
├── src
└── webpack.config.js

3 directories, 3 files

3.4. 「index.js」の配置

こちらも、最新版で学ぶwebpack 4入門 Bootstrapをバンドルする方法の記事を丸パクリで、大変申し訳ございません。「src」配下に「index.js」と「index.scss」を保存します。

index.js
import "bootstrap";
import "./index.scss";
index.scss
@import "~bootstrap/scss/bootstrap.scss";
.
├── dist
├── node_modules
├── package-lock.json
├── package.json
├── src
│   ├── index.js
│   └── index.scss
└── webpack.config.js

このように「src」の下に2つファイルが保存された形になるはずです。

3.5. 「webpack」の実行

では、早速「webpack」を実行しましょう。

webpackの実行
% webpack
Hash: 4fbcfa08db41b1bd330b
Version: webpack 4.41.5
Time: 4600ms
Built at: 2020-01-01 01:49:17
        Asset     Size  Chunks                   Chunk Names
      main.js  169 KiB       0  [emitted]        main
  main.js.map  778 KiB       0  [emitted] [dev]  main
    style.css  157 KiB       0  [emitted]        main
style.css.map  432 KiB       0  [emitted] [dev]  main
Entrypoint main [big] = main.js style.css main.js.map style.css.map
[0] ./src/index.js 42 bytes {0} [built]
[4] (webpack)/buildin/global.js 472 bytes {0} [built]
[5] ./src/index.scss 41 bytes [built]
    + 4 hidden modules

WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
  main (326 KiB)
      main.js
      style.css


WARNING in webpack performance recommendations: 
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--4-1!node_modules/postcss-loader/src/index.js??ref--4-2!node_modules/sass-loader/dist/cjs.js??ref--4-3!src/index.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [0] ./node_modules/css-loader/dist/cjs.js??ref--4-1!./node_modules/postcss-loader/src??ref--4-2!./node_modules/sass-loader/dist/cjs.js??ref--4-3!./src/index.scss 591 KiB {0} [built]
        + 1 hidden module

生成されたmain.jsファイルが、244KiBより大きいので注意されていますが、現時点では放置しておきましょう。

4. 「index.html」の作成

では、distディレクトリ以下に、簡単なindex.htmlを作成して、正しく動いているか確認します。

index.html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="stylesheet" href="./style.css" />

    <title>Hello, world!</title>
  </head>
  <body>
    <div class="container">
      <h1>Hello, world!</h1>

      <div class="card text-white bg-primary">
        <div class="card-body">
           カードのレイアウトを表示
        </div>
      </div>
    </div>
    <script src="./main.js"></script>
  </body>
</html>

正しくCSSが読まれていれば、下の画像のように表示されると思います。

2020-01-01 WEBページ例.png

一方、正しく読み込めていなければ、次のように悲しいページになるはずです。

2020-01-01 WEBページ例-2.png

4.2. index.scssの編集

では、webpackを導入した理由にあった、カスタマイズをさせてみたいと思います。
先に作成した「src」下の「index.scss」を書き換えます。

index.scss
$theme-colors: (
"primary": #b0c4de
);
@import "~bootstrap/scss/bootstrap.scss";

そして、webpackを実行すると、CSSが更新されます。
その結果、WEBページを更新すると、次のような画面に変わるでしょう。

2020-01-01 WEBページ例-3.png

SASSについては、公式サイト:Bootstrap テーマで丁寧に解説されているので参照すると良いでしょう。

4.3. Javascript の確認

CSSの確認ばかりしていて、JavaScriptが正しく動いているかを確認していませんでした。
簡単に確認してみましょう。

次の公式サイトから拾ってきたコードを、index.html<body>内のどこかに貼り付けます。

index.htmlに追記
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

2020-01-01 WEBページ例-4.png

すると、正しく動いていることが確認できると思います。

5. おわりに

ここまで書いてきたことより、「node.js」「npm」を使って「bootstrap」を導入し、実際に動いている(読み込めている)様子を確認できたこと、また、SASSを編集して自作テーマを作ることができる可能性も見えたと思います。

しかし、これで終わりではありません。SASSを編集してオリジナルのテーマを作るだけならば、node.jsを動かさなくとも、rubyなどでもできるのですから。
これらを「React」「Express」などと組み合わせて動かすことができることで、素敵なSPAが作れることでしょう。気づきがあり次第、また、Qiitaに投稿したいと思います。

参考WEBサイト

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