Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Next.jsのClient-side RenderingでPHPを動かす
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
uutan1108
May 31, 2024
Programming
660
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Next.jsのClient-side RenderingでPHPを動かす
エンジニアコネクト【LT勉強会&交流会】vol.3
https://cnctor-japan.connpass.com/event/317526/
uutan1108
May 31, 2024
More Decks by uutan1108
See All by uutan1108
コミュニティ・勉強会を作るのは目的じゃない
ohmori_yusuke
1
330
映画のエンドロール風の動画を自動生成するツールを作った
ohmori_yusuke
2
62
アウトプットは“成果物”じゃなく“副産物”だった話
ohmori_yusuke
1
100
MDN Web Docs に日本語翻訳でコントリビュート
ohmori_yusuke
0
820
仕様がそのままテストになる!Javaで始める振る舞い駆動開発
ohmori_yusuke
8
6k
勉強会から始まった僕のDevRel~新卒エンジニアがつないだ2年間の軌跡~
ohmori_yusuke
2
510
WebエンジニアがSwiftをブラウザで動かすプレイグラウンドを作ってみた
ohmori_yusuke
0
350
アニメがエンジニアをつなぐ!「エンジニアニメ」勉強会が巻き起こすCo-Creationの波
ohmori_yusuke
0
320
組織が大きく変わろうとするとき、自分はどうありたいかを考えている
ohmori_yusuke
19
7.7k
Other Decks in Programming
See All in Programming
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
220
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
990
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
7
1.5k
AI時代のUIはどこへ行く?その2!
yusukebe
22
7.6k
どこまでゆるくて許されるのか
tk3fftk
0
280
A2UI という光を覗いてみる
satohjohn
1
170
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
800
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
210
AIを活用したE2Eテスト実装効率化のあゆみ / ebisu-mobile-14-kotetu
kotetuco
0
150
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
240
スマートグラスで並列バイブコーディング
hyshu
0
270
はてなアカウント基盤 State of the Union
cockscomb
1
1.1k
Featured
See All Featured
Paper Plane
katiecoart
PRO
1
52k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
170
New Earth Scene 8
popppiees
3
2.4k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
240
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
170
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.8k
Between Models and Reality
mayunak
4
360
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
Bash Introduction
62gerente
615
220k
Transcript
Next.jsの Client-side RenderingでPHPを 動かす エンジニアコネクト【LT勉強会&交流会】vol.3 うーたん
自己紹介
自己紹介 • うーたん ◦ X:@uutan1108 • 株式会社ゆめみ ◦ 新卒2年目 ◦
サーバーサイドエンジニア • 趣味 ◦ アニメを観ること 3
今日はブラウザでPHPを実行する方法を 紹介します
None
サーバーにPOSTしない
ソースコード https://github.com/OHMORIYUSUKE/php-web 7
サーバー側で実行したい場合は、 プログラミング&実行 できるWEBアプリを手作り PyCon Kyushu 2024 KAGOSHIMA を見てください!
https://speakerdeck.com/ohmori_yusuke/hurokuraminku-and-shi-xing-tekiruweba huriwoshou-zuo-ri
見てください!
Next.jsのClient-side Renderingで PHPを動かしていく
Client-side Rendering とは
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
作る
これを作る! - テキストエリアにPHP のコードを入力 - [Run PHP]のボタンを 押下 - 実行結果が表示される
コード
src/app/page.tsx 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); 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
package.json package.json について
{ "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" }, ライブラリ
これだけ
ライブラリについて 22
{ "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 とは
php-wasm とは PHPをWebAssembly(Wasm)上で動作させるための技術で す。これにより、ブラウザ上でPHPコードを実行することが 可能になります。 https://github.com/seanmorris/php-wasm
WebAssembly(Wasm) とは
WebAssembly(Wasm) とは WebAssembly は現代のウェブブラウザーで実行できる新し い種類のコードです。ネイティブに近いパフォーマンスで動 作する、コンパクトなバイナリー形式の低レベルなアセンブ リー風言語です。さらに、 C/C++、C# や Rust
などの言語 のコンパイル先となり、それらの言語をウェブ上で実行する ことができます。 WebAssembly は JavaScript と並行して 動作するように設計されているため、両方を連携させること ができます。 WebAssembly https://developer.mozilla.org/ja/docs/WebAssembly
php-wasm の使い方
"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 が実行さ れる
完成! - テキストエリアにPHP のコードを入力 - [Run PHP]のボタンを 押下 - 実行結果が表示される
おまけ
None
None
リッチなエディターにしてみる
@monaco-editor/react
@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; これだけです
Visual Studio Code のようなエディタを Web に組み込めます https://monaco-react.surenatoyan.com/
Ruby を Next.js で実行するのもあるので 見てください!
https://speakerdeck.com/ohmori_yusuke/next-dot-js-de-ruby-wopuroguramingu-a nd-shi-xing-dekiruapuriwozuo-ru
宣伝 59
ゆめみ大技林 '24 技術書典で頒布している技術同人誌に 寄稿したので読んでください!ダウン ロードできます! 「読むとLTがしたくてたまらなくなる マニュアル」で書きました! 60
61
62
ご清聴ありがとうございました!