LoginSignup
3
0

More than 1 year has passed since last update.

React.js+WebAssembly+webpackでbuildする(地獄の環境構築から)

Last updated at Posted at 2022-03-31

はじめに

web関係初めて1ヶ月未満の超初心者です しかも高校生です

ここら辺難しすぎて発狂しそう

要求

React環境下でWebAssemblyを使いたい!!!!!!!!!!!!!!!!!!!

要件

Reactを入れる
Webpackを導入して各種ファイルを読み込めるようにする
Emscriptenを使いC++をビルドしてjs側が読み込める形にする
jsからC++コードをビルドしたものを読み込む

Reactとは

UIを作るためのフロントエンドライブラリ
Facebook社が開発したらしい
12月ぐらいからノリで触っている
まだまだ初心者

Webpackとは

複数のモジュールをひとつにまとめるツールらしい
難しい 使ってる最中吐きそうになってた えーん

WebAssemblyとは

高水準の言語をバイナリー形式に変換してウェブ上から動かすことができるもの
インタプリンタのJavaScriptよりも高速に動作させるためにあるもの

第一章 ReactとWebpackの導入

Reactを入れる

npx create-react-app webpack_test
cd webpack_test/

以下のファイルが生成されている

生成ファイル一覧
README.md		package-lock.json	public
node_modules	package.json		src

必要なものがあれば追加する

yarn add react-router-dom
yarn add react-select

Webpackを入れる

yarn add --dev webpack webpack-cli webpack-dev-server

ちゃんと増えました

package.json
  "devDependencies": {
    "webpack": "^5.66.0",
    "webpack-cli": "^4.9.1"
  }

yarn.lockが増えた

生成ファイル一覧
README.md		node_modules		package.json		src
build			package-lock.json	public			yarn.lock

webpack.config.jsを生成する

yarn add --dev @webpack-cli/generators 
npx webpack init

yarn add --dev @webpack-cli/generatorsを忘れていてもnpx webpack init実行時にインストールするかどうかを聞かれます

対話内容と日本語訳

Which of the following JS solutions do you want to use?
次のJSソリューションのうち、どれを使用したいですか?

Do you want to use webpack-dev-server?
webpack-dev-serverを使用しますか?

Do you want to simplify the creation of HTML files for your bundle?
バンドル用のHTMLファイルの作成を簡素化したいですか?

Do you want to add PWA support?
PWA対応にするか?
(PWAはモバイル向けWebサイトをスマートフォンアプリのように使えるようにするための仕組みのこと、、、らしい)

Which of the following CSS solutions do you want to use?
以下のCSSソリューションのうち、どれを使用したいですか?

Will you be using PostCSS in your project?
あなたのプロジェクトではPostCSSを使うのですか?

Do you want to extract CSS for every file?
ファイルごとにCSSを抽出しますか?

Do you like to install prettier to format generated configuration?
フォーマットするためにprettierを使いますか?(生成されたコンフィギュレーションをフォーマットするためにprettierをインストールするのが好きですか?)

Pick a package manager
パッケージマネージャを選ぶ

以降ファイルを上書きするかどうか聞かれます

補足

devDependencies(yarn add --div したときの行先)
パッケージとして公開したとき、利用側でインストールされない 
サイトの開発に関わるもの

dependencies
パッケージとして公開したときに利用側でインストールされる
サイトの動作に関わるもの

詳しくはこの記事が参考になります

babelを入れる

babel関連を入れる

yarn add --dev @babel/core @babel/runtime @babel/plugin-transform-runtime @babel/preset-env babel-loader

ちゃんと増えました

package.json
  "devDependencies": {
    "@babel/core": "^7.16.10",
    "@babel/plugin-transform-runtime": "^7.16.10",
    "@babel/preset-env": "^7.16.11",
    "@babel/runtime": "^7.16.7",
    "babel-loader": "^8.2.3",
    "webpack": "^5.66.0",
    "webpack-cli": "^4.9.1"
  }

増えました

README.md		node_modules		public			yarn.lock
build			package-lock.json	src
package.json		webpack.config.js

作業ディレクトリ直下にindex.htmlが生成されても使わないので消してもらって大丈夫です

.babelrcを作ります

touch .babelrc

書きます

.babelrc
{
    "presets": ["@babel/preset-env", "@babel/preset-react"]
}

babelについてはこの記事が参考になります

各種ローダーを設定する

最低限 js,css,各種画像ファイルの読み込みの設定はしておきましょう
npx webpack init時の対話時の設定項目によっては既に生成されてるかと思います

webpack.config.js(configの中)
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/i,
        loader: "babel-loader",
      },
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
        type: "asset",
      },
    ],
  },

ビルド時にhtmlファイルを生成できるようにする

yarn add --dev html-webpack-plugin

追加記入

webpack.config.js(configの外)
const HtmlWebpackPlugin = require('html-webpack-plugin');

追加記入

webpack.config.js(config-pluginsの中)
    new HtmlWebpackPlugin({
      template: './public/index.html',
      filename: 'index.html',
    }),

templateの指定先のファイルは、Reactのindex.htmlファイルにしてください

ReactでRouterを使うときには

const config = {}の中に書きます

webpack.config.js(configの中)
  devServer: {
    historyApiFallback: true, //これで複数ページ対応
  },

webpack.config.js - 最終的にこんな感じになるはずです

webpack.config.js
// Generated using webpack-cli https://github.com/webpack/webpack-cli

const path_require = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
//~~~なんか色々~~~

const isProduction = process.env.NODE_ENV == "production";

const config = {
  //~~~なんか色々~~~
  devServer: {
    historyApiFallback: true, //これで複数ページ

    open: true,
    host: "localhost",//対話時の設定によればこの2つが追加されているかもしれません
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      filename: 'main.html',
    }),
    //~~~なんか色々~~~
  ],

  rules: [
    {
      test: /\.(js|jsx)$/i,
      loader: "babel-loader",
    },
    {
      test: /\.css$/i,
      use: ["style-loader", "css-loader"],
    },
    {
      test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
      type: "asset",
    },
  ],
  //~~~なんか色々~~~
}
//~~~なんか色々~~~

動かしてみる

reactの標準ページでテストする場合は
src/App.js の先頭に import React from 'react';を追加する必要があります

App.js
import logo from './logo.svg';
import './App.css';
import React from 'react';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

起動してみましょう

yarn webpack-dev-server --open

src以下のファイルを先述のimport Reactの追加以外操作していなければ、よくみるこの画面が出てくるかと思います
Reactぐるぐる

ビルドもしてみましょう

yarn webpack build

/distディレクトリ以下にファイルが生成されるはずです

index.html
main.js (new HtmlWebpackPlugin - filenameで設定した名前で出力されます)
node_modules_web-vitals_dist_web-vitals_js.main.js

第二章 cppのビルドをその読み込み

準備

webpack等を一切使わないでのEmscriptenでのビルド方法はこの記事を参照してください

また今回は記事にあるC++コードを利用します

ビルドします。設定項目が多いためmakefileに記入するのがおすすめです

emcc --bind forjs.cpp --no-entry -s SINGLE_FILE=1 -s ENVIRONMENT="web" -s WASM=1 -s EXPORT_NAME='createModule' -o wasm_forweb.mjs -std=c++14 -s USE_ES6_IMPORT_META=0

出力拡張子はwasmではなくmjsです

WASM=1
出力をwasmにする

--bind
EMSCRIPTEN_BINDINGS によるjsとC++の対応付けのため

--no-entry
main関数がないことを示します

ENVIRONMENT="web"
web環境で実行するためシェル環境を無効にする

SINGLE_FILE=1
wasmファイルをmjsファイルにする

EXPORT_NAME='createModule'
モジュールの名前がModuleだとややこしいから変更

USE_ES6_IMPORT_META=0
あんまり理解していないがpolyfillが関わってくるらしい

-o wasm_forweb.mjs
wasm_forweb.mjsという名前で出力します

js拡張子を指定した場合は wasm+jsが出てきますが、mjsの場合はmjs単体で出力されます

呼び出す

mjsファイルをimportします
import時の名前はなんでも大丈夫です
(mjsファイル内で export default createModule;と記述されていることを確認しました)

App.js
import createModule from "./cpp/wasm_forweb.mjs";

利用にはthen構文を使います
関数コンポーネントを利用するときはuseEffectですが、クラスコンポーネントを利用するときはcomponentDidMountになります

App.js
useEffect(() => {
  // Update the document title using the browser API
  createModule().then((Module) => {
    var hoge= new Module.ClassName();
    hoge.FunctionName();
  });
});

またuseEffectを利用するときは別途importが必要です

App.js
import React, { useEffect } from 'react';

起動してみましょう

yarn webpack-dev-server --open

おうどん食べたい

ちゃんと「おうどん食べたい」が出力されました お疲れ様でした

その他参考にしたもの

[Emscriptenを使ったC/C++の関数のエキスポート方法まとめ]
(https://qiita.com/chikoski/items/462b34db61daf13a7897)

3
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
3
0