Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Next.jsのClient-side RenderingでPHPを動かす
Search
uutan1108
May 31, 2024
Programming
680
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
エンジニアとQAエンジニアを繋いでくれた振る舞い駆動開発(Behaviour-Driven Development)
ohmori_yusuke
0
260
Designing a Cross-Disciplinary Engineering Community Through Anime
ohmori_yusuke
3
110
コミュニティ・勉強会を作るのは目的じゃない
ohmori_yusuke
1
400
映画のエンドロール風の動画を自動生成するツールを作った
ohmori_yusuke
2
96
アウトプットは“成果物”じゃなく“副産物”だった話
ohmori_yusuke
1
130
MDN Web Docs に日本語翻訳でコントリビュート
ohmori_yusuke
0
900
仕様がそのままテストになる!Javaで始める振る舞い駆動開発
ohmori_yusuke
8
6.2k
勉強会から始まった僕のDevRel~新卒エンジニアがつないだ2年間の軌跡~
ohmori_yusuke
2
530
WebエンジニアがSwiftをブラウザで動かすプレイグラウンドを作ってみた
ohmori_yusuke
0
380
Other Decks in Programming
See All in Programming
SREの越境 / SRE Collaboration
y0hgi
2
280
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
360
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
3
380
iOSDC2026登壇資料.pdf
riofujimon
0
180
スマート反転とウェブアクセシビリティ
camiha
0
210
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
540
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
620
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
130
IBM Bob Dojo #1 仕様駆動開発入門
oniak3ibm
PRO
0
220
Verilogで学ぶCPU自作入門.pdf
uyuki234
8
3.2k
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
300
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
300
Featured
See All Featured
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
510
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
6.2k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
500
Statistics for Hackers
jakevdp
799
230k
Designing for Timeless Needs
cassininazir
1
510
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
540
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
240
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
310
We Have a Design System, Now What?
morganepeng
55
8.3k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
710
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
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
ご清聴ありがとうございました!