Node-RED と Svelte が連携したプロジェクトで axios を導入し Node-RED http ノードからデータ取得するメモです。
やりたいこと
先日の Node-RED と Svelte が連携したプロジェクトに Bootstrap が導入できたので axios で Node-RED http ノードで作った API からデータ取得します。
2021/09/15 時点の情報で進めます。
Node-RED + Vue 連携のときのナレッジをつかう
おもに axios や開発時の CORS 対応などNode-RED + Vue 連携のときのナレッジをつかいます。
Node-RED と Vue 3 が連携したプロジェクトで Vue 側に axios を導入し Node-RED http ノードと連携するメモ
では、開発時の CORS 対応。
Node-RED と Vue 3 が連携したプロジェクトで Vue 側に vue-axios を使わずよりシンプルに axios を導入するメモ
では、axios の導入。おそらく import で行けるはずなので。参考 → Svelte 3 – How to connect your app with a Rest API Axios – DEV Community
では、開発サーバーの時だけ、APIの向き先を変えるナレッジを参考にします。
Node-RED http ノードでデータのやり取りする API をつくる
http://localhost:18801/admin/
にアクセスして Node-RED でデータのやり取りする API をつくります。
このようなフローで、http://localhost:18801/api1
にアクセスすると
タイムスタンプを返答します。
インポートした実際に動作する JSON はこちらです。
[{"id":"357c66447b2fa80b","type":"http in","z":"381bab81f5f2e31e","name":"","url":"/api1","method":"get","upload":false,"swaggerDoc":"","x":160,"y":220,"wires":[["c6028d3ea1bc4d91"]]},{"id":"9f1b50a74ca8a564","type":"http response","z":"381bab81f5f2e31e","name":"","statusCode":"","headers":{},"x":530,"y":220,"wires":[]},{"id":"c6028d3ea1bc4d91","type":"change","z":"381bab81f5f2e31e","name":"タイムスタンプ","rules":[{"t":"set","p":"payload.timestamp","pt":"msg","to":"","tot":"date"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":220,"wires":[["9f1b50a74ca8a564"]]}]
Node-RED の CORS 調整する
Node-RED と Vue 3 が連携したプロジェクトで Vue 側に vue-axios を使わずよりシンプルに axios を導入するメモ を参考に、Node-RED 側の setting.js のほうで同じ localhost サーバーでやり取りできるように CORS を調整します。
httpNodeCors パラメータを以下のように修正して、HTTP Inノードの HTTP エンドポイントの CORS を有効にします。
httpNodeCors: { origin: [ "http://localhost:5000" ], methods: "GET,PUT,POST,DELETE" },
Svelte は開発サーバーのポートが 5000 なので合わせておきます。
設定を変更したら反映するために Node-RED を再起動しておきます。
ターミナルの2つ目を起動する
Node-RED を動かしているターミナルをで他の作業をしてしまうと Node-RED が終了してしまうので、ターミナルの2つ目を起動します。私の場合は Visual Studio Code のターミナルで+ボタンをクリックして新しいターミナルを開きます。
Svelte 側に axios を導入
cd svelte-app
ターミナル 2 つ目で、Svelte のプロジェクトフォルダ svelte-app
に入ります。
npm i axios
axios をインストールします。
App.svelte を書き換える
svelte-app/src/App.svelte を以下のように書き換えます。対応は Svelte 3 – How to connect your app with a Rest API Axios – DEV Community の記事を参考にしました。
<script> import axios from "axios"; // axios 対応追記 import { onMount } from "svelte"; // axios 対応追記 let name = "Node-RED"; // world -> Node-RED let timeStamp = 0; // axios 対応追記 onMount(async () => { const res = await getTimestamp(); }); // axios 対応追記 async function getTimestamp() { // 開発サーバーと本番サーバーでの分岐処理 ここから let urlTimeStampAPI = "/api1"; let localEndPoint = "//localhost:18801"; if (window.location.host == "localhost:5000") { // Svelte 開発サーバーのポートは 5000 // 開発サーバー(npm run dev) urlTimeStampAPI = localEndPoint + urlTimeStampAPI; } // ここまで console.log("urlTimeStampAPI ", urlTimeStampAPI); const response = await axios.get(urlTimeStampAPI); console.log(response); timeStamp = response.data.timestamp; } </script> <div class="container"> <div class="row"> <div class="row"> <div class="col-sm"> <h1>Hello {name}!</h1> </div> </div> <div class="row"> <div class="col-sm"> <!-- axios 対応追記 --> <h3>Timestamp : {timeStamp}</h3> </div> </div> <div class="row"> <div class="col-sm"> <div class="card" style="width: 18rem;"> <div class="card-body"> <h5 class="card-title">Card title</h5> <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6> <p class="card-text"> Some quick example text to build on the card title and make up the bulk of the card's content. </p> <a href="#" class="card-link">Card link</a> <a href="#" class="card-link">Another link</a> </div> </div> </div> </div> <div class="row"> <div class="col-sm"> <ul class="list-group"> <li class="list-group-item">An item</li> <li class="list-group-item">A second item</li> <li class="list-group-item">A third item</li> <li class="list-group-item">A fourth item</li> <li class="list-group-item">And a fifth one</li> </ul> </div> </div> </div> </div>
<h3>Timestamp : {timeStamp}</h3>
の timeStamp の値を onMount 時に getTimestamp で読み込むようにしています。また、Node-RED と Vue 3 が連携したプロジェクトで開発時だけ API の向き先を調整する 対応もいれています。
Rollup.js を axios に対応させるため修正
npm run dev
で開発サーバーを動かしたら、以下のようなエラーが出ました。
[!] Error: Unexpected token (Note that you need @rollup/plugin-json to import JSON files) node_modules\axios\package.json (2:9) 1: { 2: "_from": "axios", ^ 3: "_id": "axios@0.21.4", 4: "_inBundle": false, Error: Unexpected token (Note that you need @rollup/plugin-json to import JSON files) at error (C:\*************\svelte-node-red\svelte-app\node_modules\rollup\dist\shared\rollup.js:151:30) at Module.error (C:\*************\svelte-node-red\svelte-app\node_modules\rollup\dist\shared\rollup.js:10059:16) at Module.tryParse (C:\*************\svelte-node-red\svelte-app\node_modules\rollup\dist\shared\rollup.js:10462:25) at Module.setSource (C:\*************\svelte-node-red\svelte-app\node_modules\rollup\dist\shared\rollup.js:10365:24) at ModuleLoader.addModuleSource (C:\*************\svelte-node-red\svelte-app\node_modules\rollup\dist\shared\rollup.js:19708:20) at ModuleLoader.fetchModule (C:\*************\svelte-node-red\svelte-app\node_modules\rollup\dist\shared\rollup.js:19761:9) at async Promise.all (index 0) at ModuleLoader.fetchStaticDependencies (C:\*************\svelte-node-red\svelte-app\node_modules\rollup\dist\shared\rollup.js:19792:34) at async Promise.all (index 0) at ModuleLoader.fetchModule (C:\*************\svelte-node-red\svelte-app\node_modules\rollup\dist\shared\rollup.js:19768:9)
どうも、rollup-plugin-json が必要なようで、これを Rollup.js に組み込む必要があるようです。
npm install --save-dev rollup-plugin-json
まず、Svelte フォルダで rollup-plugin-json をインストールします。
JS 製フレームワーク Svelte を使うにあたって Rollup でビルドをする時の設定 の記事を参考に svelte-app/rollup.config.js を以下のように設定しました。
import svelte from 'rollup-plugin-svelte'; import commonjs from '@rollup/plugin-commonjs'; import resolve from '@rollup/plugin-node-resolve'; import livereload from 'rollup-plugin-livereload'; import { terser } from 'rollup-plugin-terser'; import css from 'rollup-plugin-css-only'; import json from 'rollup-plugin-json'; // axios 対応追記 const production = !process.env.ROLLUP_WATCH; function serve() { let server; function toExit() { if (server) server.kill(0); } return { writeBundle() { if (server) return; server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { stdio: ['ignore', 'inherit', 'inherit'], shell: true }); process.on('SIGTERM', toExit); process.on('exit', toExit); } }; } export default { input: 'src/main.js', output: { sourcemap: true, format: 'iife', name: 'app', file: 'public/build/bundle.js' }, plugins: [ svelte({ compilerOptions: { // enable run-time checks when not in production dev: !production } }), // we'll extract any component CSS out into // a separate file - better for performance css({ output: 'bundle.css' }), // If you have external dependencies installed from // npm, you'll most likely need these plugins. In // some cases you'll need additional configuration - // consult the documentation for details: // https://github.com/rollup/plugins/tree/master/packages/commonjs resolve({ browser: true, dedupe: ['svelte'] }), commonjs(), // In dev mode, call `npm run start` once // the bundle has been generated !production && serve(), // Watch the `public` directory and refresh the // browser on changes when not in production !production && livereload('public'), // If we're building for production (npm run build // instead of npm run dev), minify production && terser(), // axios 対応追記 json(), ], watch: { clearScreen: false } };
対応は @rollup/plugin-json のドキュメントを参考にしました。このライブラリは、A Rollup plugin which Converts .json files to ES6 modules.
とのことで、.jsonファイル をES6モジュールに変換するプラグインのようです。
宣言で、
import json from 'rollup-plugin-json'; // axios 対応追記
と、plugins 内で
// axios 対応追記 json(),
を行っています。axios をライブラリとして読めるように構成ファイルを作って橋渡ししている感じですね。おそらく。つまり Svelte 内部でライブラリ読み込みを対応というよりは、Rollup である程度良い感じにライブラリ関連のコンパ色のハンドリングを任しているということでしょう。疎結合な感じがいいですね。
この設定を行ったら無事コンパイルが通るようになりました。
開発サーバーで試してみる
npm run dev
開発サーバーを動かします。
このように、開発サーバー http://localhost:5000/
で表示されて <h3>Timestamp : {timeStamp}</h3>
の timeStamp の値が、Node-RED から受け取ったタイムスタンプの値に置き換わっています。
ビルドしてみる
npm run build
ビルドしてみます。
Node-RED が動いている http://localhost:18801/
でも同じように表示されました!