Share
Embed
Next.jsのClient-side RenderingでPHPを動かす
エンジニアコネクト【LT勉強会&交流会】vol.3
https://cnctor-japan.connpass.com/event/317526/
uutan1108
May 31, 2024
Transcript
63 slides
-
自己紹介 • うーたん ◦ X:@uutan1108 • 株式会社ゆめみ ◦ 新卒2年目 ◦
サーバーサイドエンジニア • 趣味 ◦ アニメを観ること 3 -
Client-side Rendering とは Reactによるクライアント・サイド・レンダリング(CSR) では、ブラウザは最小限のHTMLページと、そのページに必 要なJavaScriptをダウンロードする。 In Client-Side Rendering (CSR)
with React, the browser downloads a minimal HTML page and the JavaScript needed for the page. Client-side Rendering (CSR) https://nextjs.org/docs/pages/building-your-application/rendering/client-side-r endering -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); useEffect(() => { const initializePhp = async () => { const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if (phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } }; return ( <div> <textarea value={phpCode} onChange={(e) => setPhpCode(e.target.value)} rows={20} cols={50} /> <button onClick={handleSubmit}>Run PHP</button> <pre>{output}</pre> </div> ); }; export default PHPWasmComponent; page.tsx -
{ "name": "php-web", "version": "0.1.0", "private": true, "scripts": { "dev":
"next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "next": "14.2.3", "php-wasm": "^0.0.8", "react": "^18", "react-dom": "^18" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", "eslint-config-next": "14.2.3", "typescript": "^5" } } package.json "dependencies": { "next": "14.2.3", "php-wasm": "^0.0.8", "react": "^18", "react-dom": "^18" }, ライブラリ -
{ "name": "php-web", "version": "0.1.0", "private": true, "scripts": { "dev":
"next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "next": "14.2.3", "php-wasm": "^0.0.8", "react": "^18", "react-dom": "^18" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", "eslint-config-next": "14.2.3", "typescript": "^5" } } package.json "dependencies": { "next": "14.2.3", "php-wasm": "^0.0.8", "react": "^18", "react-dom": "^18" }, ライブラリ php-wasm とは -
WebAssembly(Wasm) とは WebAssembly は現代のウェブブラウザーで実行できる新し い種類のコードです。ネイティブに近いパフォーマンスで動 作する、コンパクトなバイナリー形式の低レベルなアセンブ リー風言語です。さらに、 C/C++、C# や Rust
などの言語 のコンパイル先となり、それらの言語をウェブ上で実行する ことができます。 WebAssembly は JavaScript と並行して 動作するように設計されているため、両方を連携させること ができます。 WebAssembly https://developer.mozilla.org/ja/docs/WebAssembly -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); useEffect(() => { const initializePhp = async () => { const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if (phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } }; return ( <div> <textarea value={phpCode} onChange={(e) => setPhpCode(e.target.value)} rows={20} cols={50} /> <button onClick={handleSubmit}>Run PHP</button> <pre>{output}</pre> </div> ); }; export default PHPWasmComponent; page.tsx -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); インポート -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); 入力された PHP の実行結果を管理 -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); 入力された PHP のコードを管理 -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); PhpWeb インスタ ンスをステートで 管理 -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); useEffect(() => { const initializePhp = async () => { const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if (phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } }; return ( <div> <textarea value={phpCode} onChange={(e) => setPhpCode(e.target.value)} rows={20} cols={50} /> <button onClick={handleSubmit}>Run PHP</button> <pre>{output}</pre> </div> ); }; export default PHPWasmComponent; page.tsx -
useEffect(() => { const initializePhp = async () => {
const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); -
useEffect(() => { const initializePhp = async () => {
const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); インスタンス化 -
useEffect(() => { const initializePhp = async () => {
const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); PhpWeb インスタンスに イベントリスナーを設定 -
useEffect(() => { const initializePhp = async () => {
const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); output, error, ready を 設定 -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); useEffect(() => { const initializePhp = async () => { const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if (phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } }; return ( <div> <textarea value={phpCode} onChange={(e) => setPhpCode(e.target.value)} rows={20} cols={50} /> <button onClick={handleSubmit}>Run PHP</button> <pre>{output}</pre> </div> ); }; export default PHPWasmComponent; page.tsx -
return ( <div> <textarea value={phpCode} onChange={(e) => setPhpCode(e.target.value)} rows={20} cols={50}
/> <button onClick={handleSubmit}>Run PHP</button> <pre>{output}</pre> </div> ); }; export default PHPWasmComponent; -
return ( <div> <textarea value={phpCode} onChange={(e) => setPhpCode(e.target.value)} rows={20} cols={50}
/> <button onClick={handleSubmit}>Run PHP</button> <pre>{output}</pre> </div> ); }; export default PHPWasmComponent; 管理している PHP のコード -
return ( <div> <textarea value={phpCode} onChange={(e) => setPhpCode(e.target.value)} rows={20} cols={50}
/> <button onClick={handleSubmit}>Run PHP</button> <pre>{output}</pre> </div> ); }; export default PHPWasmComponent; handleSubmit 関数 を実行 -
"use client"; import React, { useState, useEffect, FormEvent } from
"react"; import { PhpWeb } from "php-wasm/PhpWeb.mjs"; const PHPWasmComponent: React.FC = () => { const [output, setOutput] = useState<string>(""); const [phpCode, setPhpCode] = useState<string>( `<?php\nprint("hello php");\n?>` ); const [phpInstance, setPhpInstance] = useState<PhpWeb | null>(null); useEffect(() => { const initializePhp = async () => { const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if (phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } }; return ( <div> <textarea value={phpCode} onChange={(e) => setPhpCode(e.target.value)} rows={20} cols={50} /> <button onClick={handleSubmit}>Run PHP</button> <pre>{output}</pre> </div> ); }; export default PHPWasmComponent; page.tsx -
const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if
(phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } }; -
const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if
(phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } }; PhpWeb インスタンスの run メソッドを実行 -
useEffect(() => { const initializePhp = async () => {
const php = new PhpWeb(); php.addEventListener("output", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("error", (event: any) => { setOutput((prevOutput) => prevOutput + event.detail + "\n"); }); php.addEventListener("ready", () => { setPhpInstance(php); }); }; initializePhp(); }, []); イベントリスナー output, error が実行さ れる -
@monaco-editor/react とは Monaco Editor は、Microsoft がオープンソースとして開発 しているコードエディターです。Monaco Editor は VSコー
ドを動かすコード・エディターです。 Monaco Editor を React で簡単に扱えるようにしたラッパー です。 https://monaco-react.surenatoyan.com/ -
"use client"; import React from "react"; import Editor from "@monaco-editor/react";
const PHPWasmComponent: React.FC = () => { return ( <Editor height="100%" width="50%" language="php" theme="vs-dark" /> ); }; export default PHPWasmComponent; これだけです