7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

nem / symbolAdvent Calendar 2024

Day 6

ブロックチェーンSymbolに静的ページを分散型ホスティングする

Last updated at Posted at 2024-12-17

はじめに

アドカレ何か書くことあるかなー、今年は何事もなく終えるかなー、と考えていたところにXでのある投稿が目に入りました

それは

Symbolで静的ファイルのWebページをホスティングしたりできるのかな

というものでしたが、これはいいネタだと思いアドカレ執筆を始めます。

SymbolなんですがMetalというプロトコルを使います。Metalに関しては以下を読んでみてください。面白いです。
手数料さえ払えばどんな大きいサイズのファイルでも理論上は可能です。

静的ページはなんでもいいんですが、ちょっとそれっぽくVite + Reactでシンプルなページ遷移ができるモノにします。なお僕はReactの知識はあんまりありません。ここは本題じゃないのでなんでもいいです。

ポイントは1枚のファイルにすることです。(デコードを自分でするなら別に1枚じゃなくてもいいけど)今回はViteで生成したWebサイトのbundleファイルをhtmlに全部直接書き込むという方法を取ります。

静的ページを作成

ここは本題じゃないのでささっと

npm create vite@latest static-page --template react
// 今回は tsx にした
cd static-page
static-page install

作成したら

vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'

export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      output: {
        entryFileNames: 'bundle.js',
        chunkFileNames: 'bundle.js',
        assetFileNames: 'assets/[name].[ext]',
      },
    },
  },
})
/src/App.tsx
import React, { useState } from 'react';

type Page = 'page1' | 'page2';

const App: React.FC = () => {
  const [currentPage, setCurrentPage] = useState<Page>('page1');

  const handleTabClick = (page: Page) => {
    setCurrentPage(page);
  };

  return (
    <div>
      <div style={{ display: 'flex', marginBottom: '20px' }}>
        <button onClick={() => handleTabClick('page1')}>Page 1</button>
        <button onClick={() => handleTabClick('page2')}>Page 2</button>
      </div>

      {currentPage === 'page1' && (
        <div>
          <h1>Page 1</h1>
          <p>This is Page 1 content.</p>
        </div>
      )}
      {currentPage === 'page2' && (
        <div>
          <h1>Page 2</h1>
          <p>This is Page 2 content.</p>
        </div>
      )}
    </div>
  );
}

export default App;

最下部にスタイル追加

/src/index.css
.app-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100vh;
  text-align: center;
}

#root {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  width: 100%;
}

.tabs {
  display: flex;
  margin-bottom: 20px;
}

.tabs button {
  margin: 0 10px;
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
}

.content {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  width: 100%;
}

これだけです。
ビルドします

npm run build

indexファイルのjsとcss読み込み箇所に直接書き込む

/dist/index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>    
    <style>
      /* ここにassets/index.cssをコピペする */
    </style>
  </head>
  <body>
    <div id="root"></div>
    <script>
      // ここにbundle.jsをコピペする
    </script>
  </body>
</html>

これだけです。もし画像などを使用したい場合には

  1. base64にしてファイルに直接書き込む
  2. 画像をmetalでオンチェーンにする

という選択肢があるかなーと思いますが今回は使ってません

Metalを使ってチェーンに刻む

metal cliのインストール

npm install -g metal-on-symbol

NODE情報をセットする

僕はMACなので

export NODE_URL=https://example.jp:3001

ちなみにNODEは
メインネットなら
https://symbolnodes.org/nodes/
テストネットなら
https://symbolnodes.org/nodes_testnet/
ここからAPIノードを選ぶ

さっそくForgeする

viteで作成したアプリケーションのrootで作業する場合

metal forge ./dist/index.html --seal 2

--seal 2というオプションを必ずつけます
これによりmimeTypeとファイルサイズが付加情報としてオンチェーンになります

秘密鍵を聞かれるので貼り付けてEnter

アナウンスするか聞かれるのでYESを選択し承認を待ちます。
承認されるとこんな感じで結果が表示されます。

スクリーンショット 2024-12-17 17.18.03.png

METAL IDを控えてノードに以下のようなエンドポイントでアクセスすると

そのまま作成したWEBサイトが表示されます

注意点

Forgeするときはどのノードにアナウンスしてもいいんですが、REST経由で表示できるのは特定のノードのみです。
ノード側にちょっとした設定が必要で以下のノードの運営者さんが協力してくれました。
※なお、このリストは2024/12/17日時点で表示が確認できていますが、ノードのアップデートなどがあれば表示されない可能性があります。

REST経由で直接表示できなくともデコードはSDKを使用すれば可能です
https://github.com/OPENSPHERE-Inc/metal-on-symbol?tab=readme-ov-file#6-sdk-typescript--ecmascript

さいごに

ざくっと書いたので言葉足らずな点もあるかもしれませんが、ひとまず以上で記事を終えます。
ちなみにbundle.jsやcssファイル単体をmetalでforgeしてそれをhtmlファイルで読み込むという方法でも良いと思います

分散型ホスティング面白いですね

追記。ちなみに静的じゃなくて動的でもMetalを使ってわりと簡単に実現できると思います

7
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?