Node-RED と Svelte が連携したプロジェクトで axios を導入し Node-RED http ノードからデータ取得するメモ

Node-RED と Svelte が連携したプロジェクトで axios を導入し Node-RED http ノードからデータ取得するメモです。

やりたいこと

Node-RED と Svelte が連携したプロジェクトに Bootstrap を導入するメモ

先日の 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

Node-RED と Vue 3 が連携したプロジェクトで開発時だけ API の向き先を調整するメモ

では、開発サーバーの時だけ、APIの向き先を変えるナレッジを参考にします。

Node-RED http ノードでデータのやり取りする API をつくる

image

http://localhost:18801/admin/

にアクセスして Node-RED でデータのやり取りする API をつくります。

image

このようなフローで、http://localhost:18801/api1 にアクセスすると

image

タイムスタンプを返答します。

インポートした実際に動作する 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つ目を起動する

image

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

開発サーバーを動かします。

image

このように、開発サーバー http://localhost:5000/ で表示されて <h3>Timestamp : {timeStamp}</h3> の timeStamp の値が、Node-RED から受け取ったタイムスタンプの値に置き換わっています。

ビルドしてみる

npm run build

ビルドしてみます。

image

Node-RED が動いている http://localhost:18801/ でも同じように表示されました!