💫

Electron + Express + Nuxt.jsでローカルAPIサーバ x フロントエンド開発を実現する

2021/11/19に公開

はじめに

本記事は卒業研究で制作したアプリケーションのシステム構成を参考に、環境構築をする記事です。
Electronでなにかローカルで動くWebアプリケーション × APIサーバーを作りたいという人の参考になれば幸いです。

https://github.com/karuhi/electron-express-nuxt-app/
今回の作業内容は、私のGithubのリポジトリにありますので、良かったら参考にしてください。

開発環境

  • Node.js (v16.13.0)
  • Electron (v16.0.0)
  • Express
  • Nuxt.js

環境構築

目標のディレクトリの構成はこんな感じです。

├─server
│  ├─index.js
│  └─api.js
├─src
│  ├─electron
│  └─nuxtjs
├─dist
├─main.js
└─package.json

Nuxt.jsのアプリケーションと、Electronのブラウザウィンドウを共存させるため、ディレクトリ構成をカスタマイズしています。

それでは早速始めていきます。

# Clone this repository
git clone https://github.com/electron/electron-quick-start
# Go into the repository
cd electron-quick-start
# Install dependencies
yarn
# Run the app
yarn start

とりあえず、最初はひな形に沿って進めていくので、Electron公式が出している、electron/electron-quick-startを使用します。
https://github.com/electron/electron-quick-start
yarn startで次のような画面が起動すれば準備完了です。
electron-quick-startを起動した画面
yarn startした際にElectronが無いといわれる場合は、yarn global add electronなどをして、Electronを入れておきましょう。

Electronの準備

mkdir src
mkdir src/electron
mv preload.js renderer.js styles.css index.html src/electron

最初に、electron-quick-startのそのままだと、少しファイルが散らかっているので、それらのファイルをまとめます。

yarn add electron-builder --dev

Electronのビルドの準備をします。

package.json
"scripts": {
    "start": "electron .",
    "dist": "cd src/nuxtjs && yarn build && yarn generate && cd ../../ && yarn build",
    "build": "electron-builder"
},

electron-builderのscriptも追加しておきます。buildは、Electronのビルドだけですが、distはElectronとNuxt.jsのビルドをまとめてしてくれます。

package.json
"build": {
    "appId": "work.karuhi.app.test",
    "win": {
      "target": "nsis"
    },
    "nsis": {
      "oneClick": false,
      "allowToChangeInstallationDirectory": true
    }
},

Electronのビルド設定です。今回はWindows向けにビルドします。
macOS向けにビルドしたい際など、他のオプションはこちらを参照してください。
https://www.electron.build/configuration/configuration

Expressの準備

yarn add express
yarn add cors

クライアント側に提供するNuxt.jsのホストと、APIを動かすサーバーを書きます。

main.js
~~~ 中略
function createWindow() {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "src/electron/preload.js"),
    },
  });

  // and load the index.html of the app.
  mainWindow.loadFile("src/electron/index.html");

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()
}
~~~ 中略
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
var express = require("express");
var expressApp = express();
const cors = require("cors");

const server = require("./server");
const api = require("./server/api");

expressApp.use(cors());
expressApp.use(
  express.urlencoded({
    extended: true,
  })
);
expressApp.use(express.json());
expressApp.use("/", server);
expressApp.use("/api", api);

// Listen the server
var listener = expressApp.listen(8080, "0.0.0.0", function () {
  console.log("server is running:" + listener.address().port);
});

ディレクトリ構成を変更しているので、webPreferenceで読み込むpreload.jsと、mainWindowで読み込むindex.htmlの場所の変更をします。
また、SSGしたNuxt.jsとAPIをホストするサーバーを書いています。

server/index.js
const Router = require("express");
const router = Router();
const path = require("path");

const CLIENT_PATH = "src/nuxtjs/dist/";

router.get("/", (req, res) => {
  res.sendFile(path.resolve(__dirname, "..", CLIENT_PATH, "index.html"));
});
router.use(Router.static(path.resolve(__dirname, "..", CLIENT_PATH)));

module.exports = router;
server/api.js
const Router = require("express");
const router = Router();

router.get("/hello", function (req, res, next) {
  var param = { result: "Hello World !" };
  res.header("Content-Type", "application/json; charset=utf-8");
  res.send(param);
});

module.exports = router;

Nuxt.jsの準備

次に、Nuxt.jsをクライアントで動くアプリケーションとして構築します。
Expressで動かすAPIと通信する用にaxiosを選択しています。

> cd src
> npx create-nuxt-app nuxtjs
create-nuxt-app v3.7.1
✨  Generating Nuxt.js project in nuxtjs
? Project name: nuxtjs
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: None
? Nuxt.js modules: Axios - Promise based HTTP client
? Linting tools: Prettier
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Static (Static/Jamstack hosting)
? Development tools: (Press <space> to select, <a> to
toggle all, <i> to invert selection)
? Continuous integration: None
? Version control system: None

これでNuxt.jsがapp配下に準備できました。
※LintingとかTestingとかはご自由にどうぞ。また、アプリケーション自体をGit管理するため、Version control systemはNoneにしています。

cd nuxtjs
yarn dev

これでhttp://localhost:3000が次のようになっていれば成功です。
Nuxt.jsをデバッグモードで起動した画面

フロントエンドの実装

ここからは、バックエンドAPIと通信できるようにしていきます。
さきほどオプションで導入したaxiosを使用していきます。

yarn start
cd src/nuxtjs
yarn dev

2つのコマンドラインでバックエンドとNuxt.jsを起動します。

pages/index.vue
<template>
  <div>{{ ApiResponse }}</div>
</template>

<script>
export default {
  data() {
    return {
      ApiResponse: '',
    }
  },
  mounted() {
    this.$axios
      .get(`http://${window.location.hostname}:8080/api/hello`)
      .then((response) => {
        this.ApiResponse = response.data
      })
      .catch((error) => {
        this.ApiResponse = error
      })
  },
}
</script>

正常に通信できた場合、http://localhost:3000を開くと、以下のようになるはずです。
Nuxt.jsのフロントエンドコードを書いた結果

ビルド

必要ない方は読み飛ばしてください。ただ、ビルドをすると、Electronやってるなーという気分になるのでおススメです(雑)

といっても、最初の #Electronの準備 の項にて紹介した、package.jsonにスクリプトを記載しているので、そちらを実行するだけです。

yarn dist

exeファイルの完成です!
exeファイルができた図

まとめ

今回は卒研で使用しましたが、もともとはeSportsで使用するオーバーレイを開発するために使用していた構成で、オーバーレイ単体でデバッグできること、Webにはのせないけど、簡単にアクセス/インストールできる構成として今回の構成を使用しています。
注記にもありますが、もっと賢い構成(Express.jsのMiddlewareにNuxt.jsを置いてNuxt.jsのserverMiddlewareに…etc)とかありますので、目的に応じて使い分けていただけると手段が広がるんじゃないかと思っています。

これで当記事は終わりです!ここまでご覧いただきありがとうございました。

Zennでの記事投稿は初めてですので、ご意見、ご感想頂けると幸いです。
また、Likeも頂けると励みになります💚
それではほかの記事でお会いしましょう。

Discussion