Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Next.jsのClient-side RenderingでPHPを動かす

Next.jsのClient-side RenderingでPHPを動かす

エンジニアコネクト【LT勉強会&交流会】vol.3
https://cnctor-japan.connpass.com/event/317526/

uutan1108

May 31, 2024
Tweet

More Decks by uutan1108

Other Decks in Programming

Transcript

  1. 自己紹介 • うーたん ◦ X:@uutan1108 • 株式会社ゆめみ ◦ 新卒2年目 ◦

    サーバーサイドエンジニア • 趣味 ◦ アニメを観ること 3
  2. 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
  3. "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
  4. { "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" }, ライブラリ
  5. { "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 とは
  6. WebAssembly(Wasm) とは WebAssembly は現代のウェブブラウザーで実行できる新し い種類のコードです。ネイティブに近いパフォーマンスで動 作する、コンパクトなバイナリー形式の低レベルなアセンブ リー風言語です。さらに、 C/C++、C# や Rust

    などの言語 のコンパイル先となり、それらの言語をウェブ上で実行する ことができます。 WebAssembly は JavaScript と並行して 動作するように設計されているため、両方を連携させること ができます。 WebAssembly https://developer.mozilla.org/ja/docs/WebAssembly
  7. "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
  8. "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);
  9. "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); インポート
  10. "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 の実行結果を管理
  11. "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 のコードを管理
  12. "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 インスタ ンスをステートで 管理
  13. "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
  14. 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(); }, []);
  15. 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(); }, []); インスタンス化
  16. 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 インスタンスに イベントリスナーを設定
  17. 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 を 設定
  18. "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
  19. 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;
  20. 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 のコード
  21. 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 関数 を実行
  22. "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
  23. const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if

    (phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } };
  24. const handleSubmit = async (event: FormEvent) => { event.preventDefault(); if

    (phpInstance) { setOutput(""); try { await phpInstance.run(phpCode); } catch (error) { setOutput((error as Error).message); } } }; PhpWeb インスタンスの run メソッドを実行
  25. 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 が実行さ れる
  26. @monaco-editor/react とは Monaco Editor は、Microsoft がオープンソースとして開発 しているコードエディターです。Monaco Editor は VSコー

    ドを動かすコード・エディターです。 Monaco Editor を React で簡単に扱えるようにしたラッパー です。 https://monaco-react.surenatoyan.com/
  27. "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; これだけです
  28. 61

  29. 62