[Electron] Vite+Electron+React+Three.js 1 (環境構築)

2023-04-27

2023-05-15

Windows環境でViteでElectron+React+TypeScriptの開発環境を構築し、react-three-fiber,dreiを使用して3Dモデルを表示する方法を解説します。

実行環境

Windows 10 Pro 22H2

インストール

electron-viteのGetting Startedに従いインストールを行います。

electron-viteのインストール

ワーキングディレクトリを作成し、npm install electron-vite --save-devを実行します。

プロジェクト作成

npm create @quick-start/electronでプロジェクトを作成します。

vite_1

Project nameは任意の名前を入力します。

Select a frameworkでは、react を選択します。

Typescriptを使用したいので、Add TypescriptはYesを選択します。

Electronの実行

ワーキングディレクトリにプロジェクトが作成されるので、cdでディレクトリを移動しnpm installを実行します。

モジュールのインストール完了後、npm run devで開発モードでElectronアプリが起動します。

electron_1

ホットリロード対応

レンダープロセスはデフォルトでホットリロードに対応していますが、メインプロセスは対応していません。

メインプロセスもホットリロードに対応させるには、package.jsonのscripts内のdevを修正します。

"scripts": {
  ...
    "dev": "electron-vite dev --watch",
  ...
  },

React-three-fiberインストール

プロジェクトディレクトリで npm install three @types/three @react-three/fiberを実行します。

コード修正

App.tsxとcssを修正し、ウィンドウ全体を描画エリアに設定、球と床を表示します。

src/renderer/src/App.tsx

import { Canvas } from "@react-three/fiber"

function App(): JSX.Element {
  return (
    <div className="container">
      <Canvas shadows camera={{ position: [0.0, 2.0, 10.0], fov: 45 }}>
        <directionalLight position={[2.0, 2.0, 2.0]} castShadow />
        <mesh
          castShadow
          receiveShadow
          position={[0.0, 0.0, 0.0]}
          rotation={[-Math.PI / 2, 0.0, 0.0]}
        >
          <planeGeometry args={[10, 10]} />
          <meshPhongMaterial color="gray"  />
        </mesh>
        <mesh castShadow receiveShadow position={[0.0, 1.0, 0.0]}>
          <sphereGeometry args={[1]} />
          <meshPhongMaterial color="gray" />
        </mesh>
        <gridHelper />
      </Canvas>
    </div>
  )
}

export default App

src/renderer/src/assets/index.css

body {
  background-color: #ffffff;
}

* {
  padding: 0;
  margin: 0;
}

.container {
  width: 100%;
  height: 100vh;
}

実行結果

electron_2

react-three-dreiを使用する

プロジェクトディレクトリで、npm install @react-three/dreiを実行します。

renderer/src/App.tsxにOrbitControlsStatsを追加します。

また、マテリアルを物理ベースレンダリング対応のmeshPhysicalMaterialに変更し、Environmentも用意します。

src/renderer/src/App.tsx

import { Canvas } from '@react-three/fiber'
import { Environment, OrbitControls, Stats } from '@react-three/drei'

function App(): JSX.Element {
  return (
    <div className="container">
      <Canvas shadows camera={{position: [0.0, 2.0, 10.0], fov: 45 }}>
        <directionalLight position={[2.0, 2.0, 2.0]} castShadow />
        <mesh
          castShadow
          receiveShadow
          position={[0.0, 0.0, 0.0]}
          rotation={[-Math.PI / 2, 0.0, 0.0]}
        >
          <planeGeometry args={[10, 10]} />
          <meshPhysicalMaterial color="gray" roughness={0.0} metalness={0.0} />
        </mesh>
        <mesh castShadow receiveShadow position={[0.0, 1.0, 0.0]}>
          <sphereGeometry args={[1]} />
          <meshPhysicalMaterial color="gray" roughness={0.0} metalness={0.0} />
        </mesh>
        <gridHelper />
        <OrbitControls makeDefault />
        <Stats />
        <Environment preset="city" background blur={0.1}/>
      </Canvas>
    </div>
  )
}

export default App

そのまま実行すると以下のような、コンテンツセキュリティーポリシーのエラーが出るため、htmlファイルのmetaタグを修正する必要があります。

electron_3

troika-worker-utils.esm.js:212 Refused to create a worker from 'blob:http://localhost:5173/072e13ec-ca86-4c7d-a690-506cd2926ae9' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'worker-src' was not explicitly set, so 'script-src' is used as a fallback.

three.module.js:41173 Refused to connect to 'https://market-assets.fra1.cdn.digitaloceanspaces.com/market-assets/hdris/potsdamer-platz/potsdamer_platz_1k.hdr' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.

renderer/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Electron</title>
    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    <meta
      http-equiv="Content-Security-Policy"
      content="worker-src blob: ; connect-src 'self' https://market-assets.fra1.cdn.digitaloceanspaces.com/ https://fonts.gstatic.com/; default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
    />
  </head>

  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

Content-Security-Policyのmetaタグに、worker-src blob: ; を追加しています。

また、開発モードでは、<Environment /> のプリセットで使用しているパノラマHDR画像を、外部から取ってきているようなので、connect-src 'self' https://market-assets.fra1.cdn.digitaloceanspaces.com/ ; も追加しています。

ちなみに、Textを表示する際に使用するフォントも外部サーバーから取得しているので、 https://fonts.gstatic.com/も追加します。

実行結果

electron_4

ビルド

Windows向けにビルドする場合、npm run build:winを実行します。

問題なくビルドが完了すると、プロジェクトフォルダ内のdistフォルダにインストーラーが作成されます。

electron_5