はじめに
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
ちゃんと増えました
"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
ちゃんと増えました
"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
書きます
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
babelについてはこの記事が参考になります
各種ローダーを設定する
最低限 js,css,各種画像ファイルの読み込みの設定はしておきましょう
npx webpack init
時の対話時の設定項目によっては既に生成されてるかと思います
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
追加記入
const HtmlWebpackPlugin = require('html-webpack-plugin');
追加記入
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html',
}),
templateの指定先のファイルは、Reactのindex.htmlファイルにしてください
ReactでRouterを使うときには
const config = {}の中に書きます
devServer: {
historyApiFallback: true, //これで複数ページ対応
},
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';
を追加する必要があります
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の追加以外操作していなければ、よくみるこの画面が出てくるかと思います
ビルドもしてみましょう
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;
と記述されていることを確認しました)
import createModule from "./cpp/wasm_forweb.mjs";
利用にはthen構文を使います
関数コンポーネントを利用するときはuseEffect
ですが、クラスコンポーネントを利用するときはcomponentDidMount
になります
useEffect(() => {
// Update the document title using the browser API
createModule().then((Module) => {
var hoge= new Module.ClassName();
hoge.FunctionName();
});
});
またuseEffectを利用するときは別途importが必要です
import React, { useEffect } from 'react';
起動してみましょう
yarn webpack-dev-server --open
ちゃんと「おうどん食べたい」が出力されました お疲れ様でした
その他参考にしたもの
[Emscriptenを使ったC/C++の関数のエキスポート方法まとめ]
(https://qiita.com/chikoski/items/462b34db61daf13a7897)