7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

symbol-qr-libraryをNode.js v22&ARM Macに対応させた話

Last updated at Posted at 2025-12-01

はじめに

Symbolでアカウント情報やトランザクションをQRコード化して共有するための symbol-qr-library ライブラリ。
便利なライブラリなのですが、2020年頃から更新が止まっており、2025年現在のNode.js環境ではビルドは愚か開発環境構築すら困難な状態になっていました。

特にApple Silicon Macではnpm installの段階で失敗してしまい、開発環境を構築することができません。Symbol界隈ではQRコード周りのライブラリがほぼこれ一択なのに、これではちょっと困ります。

なので、最新のLTSであるNode.js v22およびARM macで実行できる環境を作りました。

symbol-qr-libraryとは

このライブラリは、Symbolブロックチェーンで使用する以下のような情報をQRコード化するためのものです:

  • アカウント情報: 秘密鍵を暗号化して安全に共有
  • ニーモニック: ウォレット復元用のフレーズ
  • トランザクション情報: 署名リクエストの共有
  • コンタクト情報: アドレスと名前のセット

内部的には、これらの情報をJSON形式に整形・暗号化し、node-canvasを使ってQRコード画像として出力します。Data URL形式やファイル出力、コンソール表示にも対応しています。

何が問題だったのか

Node.js 12とPython 2への依存

ライブラリが最後に更新されたのは2020年頃で、Node.js 12を前提としていました。しかし:

  • Node.js 12: 2022年4月にEOL(サポート終了)
  • Python 2: 2020年1月にEOL
  • canvas 2.x: ネイティブモジュールで、ビルドにPython 2が必要

つまり、すでにサポートが終了した技術スタックに依存している状態でした。

Apple Silicon Macでビルドできない

個人的に最も深刻な問題は、Apple Silicon(M1〜)搭載のMacで全く動作しないことでした:

  1. プリビルドバイナリが存在しない: canvas@2.xのプリビルドバイナリはdarwin-x64(Intel Mac)のみで、ARM64版が提供されていない
  2. ネイティブビルドが失敗する: ソースからビルドしようとしても、Node.js 12 + Python 2 + 最新Xcodeの組み合わせでnode-gypがエラーを吐く
  3. Rosettaでも解決しない: Intel版Node.jsをRosetta経由で動かしても、Homebrewのpkg-configや依存ライブラリのパス解決が壊れる

なので2回のフェーズに分けてこれを解消しました。

フェーズ1: Dockerで古い環境を再現可能にする

まず最初に、「古い依存関係をそのまま維持しつつ、どの環境でも動くようにする」ようにやってみます。

解決策: Docker環境の構築

ARM Mac上で直接ビルドするのは困難なので、Dockerを使ってLinux AMD64環境を用意することにしました。

Dockerfileのポイント:

  • ベースイメージ: node:12-buster (ここでx86版のlinuxコンテナを指定する)
  • 古いDebian Busterのパッケージリポジトリがアーカイブに移動していたため、URLを修正
  • Python 2とcanvasのビルドに必要なネイティブライブラリ(libcairo2-dev, libpango1.0-devなど)をインストール
# x86(amd64) + node v12なコンテナを指定
FROM --platform=linux/amd64 node:12-buster
SHELL ["/bin/bash","-lc"]

# コンテナが既にアーカイブされてるので取得先を変更
RUN sed -i -e 's|deb.debian.org/debian|archive.debian.org/debian|g' \
           -e 's|security.debian.org/debian-security|archive.debian.org/debian-security|g' \
           /etc/apt/sources.list \
 && printf 'Acquire::Check-Valid-Until "false";\n' >/etc/apt/apt.conf.d/99no-check-valid

# node-canvasに必要なネイティブモジュールの追加 & npm install
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    python2 \
    pkg-config \
    git \
    libcairo2-dev \
    libpango1.0-dev \
    libjpeg-dev \
    libgif-dev \
    librsvg2-dev \
 && ln -sf /usr/bin/python2 /usr/bin/python \
 && npm i -g npm@6 \
 && rm -rf /var/lib/apt/lists/*

WORKDIR /work

Docker Composeの設定:

※今考えると別に常駐させるプロセスでもないのでdocker composeは不要でしたが作ったので念の為。

  • platform: linux/amd64を明示的に指定し、ARM Macでも強制的にAMD64エミュレーションで動作
  • 環境変数でnpm_config_python=/usr/bin/python2を設定し、node-gypが正しいPythonを使用するように
  • ソースコードをボリュームマウントして、コンテナ内で開発できるように
services:
  dev:
    build: .
    platform: linux/amd64   # ARMでもamd64を強制
    working_dir: /work
    volumes:
      - .:/work:cached
    environment:
      - npm_config_python=/usr/bin/python2
      - npm_config_build_from_source=true
    tty: true
    stdin_open: true
    command: bash

これにより、以下のコマンドだけで開発環境が立ち上がるようになりました:

docker compose up -d dev
docker compose exec dev bash
npm install
npm run build

この段階での成果

✅ ARM Macを含む、あらゆる環境で確実にビルドできるようになった
✅ 環境構築の手順が明確化され、再現性が確保された
⚠️ ただし、Node.js 12とPython 2という古い技術スタックはそのまま

この時点では「とにかく動かせる状態にする」ことを最優先としました。

⚠️ セキュリティ上の注意点

フェーズ1で使用しているnode:12-busterには、以下のセキュリティリスクがあります:

  • Debian Buster: 2022年8月にLTSサポートが終了し、セキュリティアップデートが提供されていない
  • Node.js 12: 2022年4月にEOLとなり、既知の脆弱性が修正されていない可能性
  • アーカイブリポジトリ: archive.debian.orgから取得するパッケージは最新のセキュリティパッチが適用されていない

推奨事項:

  • このフェーズ1の環境は開発・検証目的のみに使用してください
  • 本番環境やインターネットに公開するサービスでは使用しないでください
  • 可能な限り早くフェーズ2(Node.js 20/22)に移行することを強く推奨します

フェーズ2: Node.js 20/22への移行

次のステップは、現代のNode.js環境で動作するようにアップデートすることでした。

主な変更内容

1. Dockerイメージの更新

  • ベースイメージをnode:12-busterからnode:22-bookworm
  • Python 2からPython 3へ移行
  • npm 6の固定を解除し、Node.jsに付属する最新版を使用
FROM node:22-bookworm # x86の視程を解除して使ってる端末に合わせる
SHELL ["/bin/bash","-lc"]

# Install build dependencies for node-canvas (Cairo, Pango, etc.)
# and common native build toolchain (python3, make, g++, pkg-config)
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    python3 \
    python3-pip \
    pkg-config \
    git \
    libcairo2-dev \
    libpango1.0-dev \
    libjpeg-dev \
    libgif-dev \
    librsvg2-dev \
 && rm -rf /var/lib/apt/lists/*

ENV npm_config_python=/usr/bin/python3 \
    npm_config_build_from_source=true

WORKDIR /work

2. canvas 3.xへのアップデート

canvas@2.xからcanvas@3.xへアップデートすることで以下のような感じでシンプルになります:

  • Node.js 22のサポート
  • Python 3でのビルドに対応
  • より新しいプリビルドバイナリの提供

package.jsonの変更:

{
  "dependencies": {
    "canvas": "^3.2.0"
  }
}

これにより、ホスト側とコンテナ側で異なるアーキテクチャのバイナリが混在する問題を回避できます。

また、platform: linux/amd64の強制指定を削除し、Docker Desktopのアーキテクチャ自動検出に任せるようにしました。これでARM MacでもネイティブでDockerが動作し、パフォーマンスが向上します。

この段階での成果

✅ Node.js 20/22で動作するようになった
✅ Python 3ベースのビルド環境に移行
✅ ARM MacでもネイティブDockerで高速に動作
✅ ブラウザでの動作確認が簡単に

技術的なポイント

なぜDockerを使ったのか

ネイティブモジュールのビルドは環境依存が激しく、特に以下の問題があります:

  • OSごとに異なるビルドツールチェーン(Xcode, Visual Studio, gcc)
  • システムライブラリのバージョン違い
  • Python 2/3の混在

Dockerを使うことで、これらの環境差異を吸収し、「どこでも同じように動く」環境を提供できます。

canvas 3.xへの移行の意義

canvas 3.xは単なるバージョンアップではなく、以下の重めな変更が含まれています:

  • Node-API(N-API)への移行: Node.jsのバージョンに依存しないネイティブモジュールの仕組み
  • プリビルドバイナリの充実: より多くのプラットフォーム向けにビルド済みバイナリを提供
  • モダンなビルドツールチェーン: Python 3とnode-gyp最新版に対応

これにより、将来的なNode.jsのアップデートにも追従しやすくなります。

ここまでの変更について

近日中に 本家のリポジトリ に対してPR投げます。
投げたら追記します。

(だれか見てくれるかな・・・)

今後の展望

現在の状態でも一応動くようになりますが、思い切ってforkして別ライブラリとして公開しちゃおうかなと思っています。
主な変更点は以下

1. node-canvas依存の削除

これまではライブラリ側で画像の生成までやっていましたが、その機能を削ぎ落とします。
QR画像生成を呼び出し側に委譲し、ライブラリはJSON整形と暗号化に専念する設計に変更する予定です。これにより:

  • ✅ ネイティブモジュールのビルドが不要になり、JSで完結する
  • ✅ ブラウザ・Node.js・React Native(Expo含む)を同一コードでサポート
  • ✅ WebWorkersやDenoでも動作する軽量モジュールに
  • ✅ バンドルサイズの大幅な削減

2. 暗号化ライブラリの刷新(crypto-js → noble)

現在使用しているcrypto-jsは古く、以下の問題があります:

  • CommonJS形式でTree-shakingが効かない
  • TypeScript型定義が不完全

noble-cryptoに移行することで:

  • ✅ モダンなESM形式でTree-shakingに対応
  • ✅ TypeScriptファーストな設計
  • ✅ バンドルサイズの削減

まとめ

4年間放置されていたsymbol-qr-libraryを、2段階のアプローチで現代の開発環境に対応させました:

フェーズ1: Docker環境の構築

  • 古い依存関係をそのまま維持しつつ、Dockerで再現可能な環境を構築
  • ARM Macでも確実にビルドできるように

フェーズ2: Node.js 20/22への移行

  • canvas 3.xへのアップデート
  • Python 3ベースのビルド環境へ移行

今回の記事は以上となります。
まだ絶賛作業途中なので今後も進捗あるごとにこの記事に追記していくのでたまに見に来てください。

では!

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?