- 投稿日:2020-01-01T18:29:04+09:00
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
と、 SIGNALSIGTERM
での Graceful shutdown を Express で実装しました。index.jsconst 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.
- 投稿日:2020-01-01T18:29:04+09:00
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
が送信されます。実装例
URL
/sleep
と、 SIGNALSIGTERM
での Graceful shutdown を Express で実装しました。index.jsconst 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.
- 投稿日:2020-01-01T15:28:54+09:00
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.4nodeのバージョンは一個前のLTS?であるv10.18.0でないと動作しません。
後続のtruffleboxのnpm install
で死にます。
初めv12.13.1とかでやってると死んでました。
まだtruffleかweb3のサポートが追いついてないようです。手順
Kaleidoのコンソーシアム作成
Kaleidoのコンソーシアム作成については、先人の記事を参考ください。
ぽちぽちやれば良い感じになるはずです。Ethereumベースのブロックチェーンを構築できるKaleidoを触ってみた
truffle環境の構築
Kaleido.ioが下記にtrufflebox置いてくれているので、基本ここに準拠するだけです。
下記コマンドがローカルでうまく機能するかどうかを確認しましょう。
mkdir truffle-kaleido-box cd truffle-kaleido-box npx truffle unbox kaleido-io/truffle-kaleido-box truffle develop # 以下、truffle console上で compile test migrateKaleidoへの接続・コントラクトデプロイ
ローカルでうまく動作することが確認できれば、次はコントラクトをKaleidoにデプロイしてみます。
これもぶっちゃけtruffle-kaleido-boxの「Connect to Kaleido」に従うだけです。
デプロイしたいノードで「+ Connect Node」をクリック(下記ボタン)「Native JSON/RPC」を選択
必要なCredentialsを選択or新規作成
入れたら下記をクリック表示されている「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 consoleconsole上で下記コマンドでデプロイ済のコントラクトを取得
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が一番軽い感じで良いのではないのでしょうか。
何より無料、これがすごい。(どうやって収益化してるんだろう、、、)これでコンソーシアムでの検証をやってみたいと思います。
参考
- 投稿日:2020-01-01T10:58:41+09:00
「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>しかし、「npm」を使ってbootstrapを導入すると、後々、CSSのカスタムに便利らしいです。
なので、今回はそちらの手法を採用します。
「npm」を使うに当たって、PCの「node.js」「npm」のバージョンを確認します。バージョンの確認% node -v v12.2.0 % npm -v 6.9.02.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 vulnerabilitiesjqueryとpopper.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-loader
がsass
とfibers
を欲しているようなので、これもインストールしておきましょう。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.js3.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 files3.4. 「index.js」の配置
こちらも、最新版で学ぶwebpack 4入門 Bootstrapをバンドルする方法の記事を丸パクリで、大変申し訳ございません。「src」配下に「index.js」と「index.scss」を保存します。
index.jsimport "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が読まれていれば、下の画像のように表示されると思います。
一方、正しく読み込めていなければ、次のように悲しいページになるはずです。
4.2. index.scssの編集
では、webpackを導入した理由にあった、カスタマイズをさせてみたいと思います。
先に作成した「src」下の「index.scss」を書き換えます。index.scss$theme-colors: ( "primary": #b0c4de ); @import "~bootstrap/scss/bootstrap.scss";そして、webpackを実行すると、CSSが更新されます。
その結果、WEBページを更新すると、次のような画面に変わるでしょう。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">×</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>すると、正しく動いていることが確認できると思います。
5. おわりに
ここまで書いてきたことより、「node.js」「npm」を使って「bootstrap」を導入し、実際に動いている(読み込めている)様子を確認できたこと、また、SASSを編集して自作テーマを作ることができる可能性も見えたと思います。
しかし、これで終わりではありません。SASSを編集してオリジナルのテーマを作るだけならば、node.jsを動かさなくとも、rubyなどでもできるのですから。
これらを「React」や「Express」などと組み合わせて動かすことができることで、素敵なSPAが作れることでしょう。気づきがあり次第、また、Qiitaに投稿したいと思います。参考WEBサイト
- 最新版で学ぶwebpack 4入門 Bootstrapをバンドルする方法
- Webpack 3 を使ってどのように Bootstrap をインストールするか学びましょう。
- Bootstrap - ダウンロード
- webpack 4 入門