【nodejsアプリ開発】pkg/Express.js/Svelteでポータブルなバイナリ起動のウェブブラウザアプリを作る


※ 当ページには【広告/PR】を含む場合があります。
2023/01/06
【nodejsシェルアプリ開発】vercel/pkgでCLI版スネークゲームを作ってみる
【nodejsアプリ開発】SvelteKitでポータブルなバイナリアプリを作れるか(しかし現状では失敗)
蛸壺の技術ブログ|pkg/Express.js/Svelteでポータブルなバイナリ起動のウェブブラウザアプリを作る



以前のブログの内容で、Nodejsアプリをバイナリアプリ化してくれる
『vercel/pkg』 (以降、pkg)について触れてみました。

合同会社タコスキングダム|蛸壺の技術ブログ
【nodejsシェルアプリ開発】vercel/pkgでCLI版スネークゲームを作ってみる

vercel/pkgを使って簡単なCLIスネークゲームのバイナリをビルドして動かしてみます。



pkgの魅力はなんと言ってもビルド後のバイナリサイズが小さいことです。
小さければ小さいほどプログラムを使ってもらえるユーザーに配布しやすくなるのがメリットです。
今回はこのpkgの利用を考えていく一例として、
「Express.js」 によるローカルサーバー化と、 「Svelte」 によるSPA(Single Page Application)を組み合わせた、簡単なミニゲームを起動してみるまでを手順化してみます。



合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート・2025年最新】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

Svelte側のSPAアプリを準備する



pkgとExpress.jsとSvelteのプロジェクトを全てひとまとめにして開発を進めても良いのですが、ここでは、アプリの中身をサッと変えられるように、バックエンドの実行処理側(pkg/Express.js)と、フロントエンド(Svelte)を分離したプロジェクトで別々に管理していきます。
まずはアプリの中身にあたる部分を「Svelte」と「Vite」で作っていきます。 なお、SvelteでなくてもAngularやVueやReactなど別のフレームワークで作っても結構です。
以前の回で、
「SvelteとViteでアプリ開発」 というネタを紹介していました。

合同会社タコスキングダム|蛸壺の技術ブログ
【Svelte Framework入門】Viteを使って素早くSvelteアプリ開発環境を始めてみる

Svelteアプリ開発環境をViteでサクッと立ち上げる手順



今回は、そちらの内容を起点にして、適当なSvelteプロジェクトを以下のコマンドでビルドしてみます。

            $ yarn build
#もしくは
$ ./node_modules/.bin vite build

        

ビルドするとVite:Svelteでの開発の場合、デフォルトでは
dist フォルダの中にビルド済みのリソースが固められて出力されています。


            $ tree dist/
dist/
├── assets
│   ├── index.501bb487.css
│   ├── index.a7c6f463.js
│   ├── hoge.a93068e7.svg
│   └── piyo.f6732df8.svg
├── favicon.png
└── index.html

        

どのJSフレームワークでもプロダクションビルドするほぼこんな感じで、ここではひとまずビルド出力したリソースファイル一式を準備できれば結構です。
次の節で、このアプリの中身を使うための
「pkg/Express.js」 を別プロジェクトで作成していきます。



合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート・2025年最新】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

バイナリで動くpkg/Express.jsのバックエンドアプリを作成する



こちらが本題で、
「ポータブルなpkg/Express.jsのバイナリアプリ」 を作成する手順を説明していきます。

pkg のバイナリアプリの作り方は前回詳しく掘り下げました。

合同会社タコスキングダム|蛸壺の技術ブログ
【nodejsシェルアプリ開発】vercel/pkgでCLI版スネークゲームを作ってみる

vercel/pkgを使って簡単なCLIスネークゲームのバイナリをビルドして動かしてみます。



まだpkgの使い方に慣れていない方は是非ともまずそちらを一読ください。
以降ではポイントを絞ってプロジェクトを作成していきます。

pkgプロジェクトの作成



適当なプロジェクトフォルダを作って、以下のように
package.json を新規追加します。


            {
  "name": "pkg-express",
  "version": "0.0.1",
  "description": "To execise to use pkg with Express.js."
}

        

また今回はtypescriptでトランスパイルするので、以下のようにインストールを済ませておきましょう。

            $ yarn add typescript tslib -D

        

typescriptの初期化(tsconfig.json)を行います。


            $ yarn tsc --init

        

後は、
pkg 本体をインストールします。

            $ yarn add pkg -D

        

インストール後は、
package.json も以下のように更新しておきましょう。

            {
    "name": "pkg-express",
    "version": "0.0.1",
    "description": "To execise to use pkg with Express.js.",
    "bin": "index.js",
    "scripts": {
        "pkg": "pkg",
        "build": "tsc && yarn pkg ."
    },
    "devDependencies": {
        "pkg": "^5.8.0",
        "tslib": "^2.4.1",
        "typescript": "^4.9.4"
    }
}

        


ひとまず準備はこれでOKです。


Express.js用のコードを実装する




pkgアプリを作成した
前回の内容 と違うところは、 Express.js を使うところです。
ここでのプロジェクト自体は至ってシンプルに作れますが、サーバー側のプログラムを作成するときに特有の考え方が凝縮されているため、
Express.jsの扱い方自体にバックエンド技術の学習が必要 です。

それはさておいて、以前「nexe」でExpress.jsのバイナリアプリ化の話はすでに紹介しておりました。

合同会社タコスキングダム|蛸壺の技術ブログ
【nodejs活用】nexeでポータブルなExpress.jsサーバーを手軽に持ち歩く〜Linux編

Nexeを利用して、nodejsの開発環境なしでもLinuxOS上でコマンドライン一つで立ち上がるモックなExpress.jsサーバーとして使えるツールを作成します。



まずはプロジェクトにExpress.jsを導入します。

            $ yarn add express -S
$ yarn add @types/express -D

        

次に
index.ts を新規作成して、コードの中身を以下のように編集します。

            import express from "express";
import { join } from 'path';

const endpoint = 'http://localhost:3000';
process.stdout.write(`\x1b[0;32m\x1b[6m👇をCtrl+クリックしてブラウザで開こう!\x1b[0m\n\x1b[0;43;1;37m${endpoint}\x1b[0m`);

const app = express();
const distFolder = join(process.cwd(), 'browser');

app.get('/', (req, res) => {
    res.sendFile(distFolder + '/index.html');
});
app.get(`/*.*`, express.static(distFolder));
app.get(`/assets/*.*`, express.static(distFolder + '/assets/'));
app.listen(3000, () => {});

        

この時点ではまだSvelteで出力したアプリの中身を入れるためのルートフォルダを作っていませんが、ルートフォルダの名前を
browser とします。 このフォルダの使い方は後述します。
ローカルサーバーを起動してルートパス(
/ )にだけアクセスすると、アプリのルートフォルダにある index.html を直接ファイル送信させています。
ただし、index.htmlを読み込んだ後に、さらに必要なファイルを読み込む場合がありますので、
/*.* や、 /assets/*.* のリクエストにも、静的ファイルの保存先を express.static を使って教えてあげることも忘れないようにしましょう。
ちなみに標準出力させる文字をエスケープシークエンス(
\x1b[... )で修飾しています。 こういうCLIツールを作る際にはエスケープシークエンスもやっていて楽しいので、興味があれば以下のブログ記事もご覧ください。

合同会社タコスキングダム|蛸壺の技術ブログ
【シェルスクリプト実践講座】ANSIエスケープシークエンスを使おう①〜基本的な使い方

シェルアプリを作成する上で欠かせない「ANSIエスケープシークエンス」のテクニックを整理していきます。

pkgバイナリアプリをビルド



次に
pkg でのバイナリビルドを行います。
コマンドオプションにビルド設定をすべて指定していくのは結構しんどいので、package.jsonにpkgタグを作成し、ビルドオプションをそこに記述します。

            {
    "name": "pkg-express",
    "version": "0.0.1",
    "description": "To execise to use pkg with Express.js.",
    "bin": "index.js",
    "scripts": {
        "pkg": "pkg",
        "build": "tsc && yarn pkg ."
    },
    "pkg": {
        "targets": ["latest-linux-x64"],
        "outputPath": "dist"
    },
    "devDependencies": {
        "pkg": "^5.8.0",
        "tslib": "^2.4.1",
        "typescript": "^4.6.4",
        "@types/express": "^4.17.15"
    },
    "dependencies": {
        "express": "^4.18.2"
    }
}

        

エンドポイントとなるjsファイルは
"bin" タグに指定しているか確認し、ビルドターゲットとバイナリの出力先を与えておきます。
ではいよいよビルドの時間です。

            $ yarn build

        

無事にビルドできたら
dist フォルダ以下にpkgバイナリアプリが出力されているはずです。

            $ tree dist
dist/
└── pkg-express

        

ちなみにバイナリのサイズを確認すると、

            $ du -sSk dist/
47060   dist/

        

おおよそ47MB程度になっています。
ここからさらにzipで固めてまとめておくと、アプリ配布にも軽量かつ利便性が高いのではないかと思います。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート・2025年最新】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

DebianOS(Linux)でpkgバイナリアプリの起動確認



では最後にSvelteで作ったSPA(index.html側)と、pkg/Express.jsで作ったバイナリアプリを統合して、起動するか試してみましょう。
シェルスクリプトなどで2つのプロジェクトのビルド生成物を自動でまとめてくれるようにすれば楽なのですが、ここでは手動でまとめてみます。

まずは、バイナリプログラム・
pkg-express のあるフォルダの同階層に browser という名前のフォルダを作ります。

            $ mkdir browser
$ ls
browser  pkg-express

        

この
browser フォルダに、Svelteでビルドして生成された dist の中身のファイルをコピーしましょう。
フォルダ構造の一例を挙げると、

            $ tree
.
├── browser
│   ├── assets
│   │   ├── index.501bb487.css
│   │   ├── index.a7c6f463.js
│   │   ├── hoge.a93068e7.svg
│   │   └── piyo.f6732df8.svg
│   ├── favicon.png
│   └── index.html
└── pkg-express

        

のようになっていると思います。
なお、静的なリソース用に
assets という名前で下位のフォルダを作っていましたが、別の名前のフォルダが存在している場合には、Express.jsで express.static(<アセットフォルダまでのパス>) という形で登録しておく必要があります。
ということで、ようやく起動準備まで出来上がりました。
あとは実際に動かしてみましょう。




(※動作中のSPAアプリは適当に作った自作シューティングのデモを動かしています。デフォルトのViteのものではないのでご注意ください。)
これでネットが繋がっていなくてもスタンドアロンなHTMLゲーム等の実行環境が出来上がりました。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート・2025年最新】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

まとめ



ネットワーク環境がなくてもブラウザで動作するタイプのバイナリアプリの作り方を取り上げてみました。
最近のブラウザはかなり高性能なAPIが充実しており、アイデア次第ではかなり有用な使いみちが可能ではないかと思います。
今後また面白い使い道があれば、このブログにて紹介していこうかと思います。
記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。

合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート・2025年最新】nodejsをこれから学びたい人のためのオススメ書籍&教材特集