feat: remove react-unity-webgl

main
khanhlp 2025-06-06 16:23:58 +07:00
parent c62d531e8d
commit 88127dc3da
6 changed files with 233 additions and 100 deletions

View File

@ -1,3 +1,3 @@
APP_ID=2984220425889259895
ZMP_TOKEN=
VITE_GAME_LINK=
VITE_API_URL=https://api.play4promo.online/graphql

View File

@ -53,74 +53,34 @@
1. **Install dependencies**:
```bash
npm install react-unity-webgl
npm install promogame-game-component
```
or
```bash
pnpm install react-unity-webgl
pnpm install promogame-game-component
```
or
```bash
yarn install react-unity-webgl
```
1. **Create** the game component:
```tsx
import clsx from 'clsx';
import { useEffect } from 'react';
import { Unity, useUnityContext } from 'react-unity-webgl';
import zmpSdk from 'zmp-sdk';
export const UnityGame = () => {
const gameLink = import.meta.env.VITE_GAME_LINK;
const { unityProvider, isLoaded, loadingProgression, UNSAFE__unityInstance } = useUnityContext({
loaderUrl: `${gameLink}/Build/Build.loader.js`,
dataUrl: `${gameLink}/Build/Build.data.unityweb`,
frameworkUrl: `${gameLink}/Build/Build.framework.js.unityweb`,
codeUrl: `${gameLink}/Build/Build.wasm.unityweb`,
});
useEffect(() => {
window.ZaloMiniAppSDK = zmpSdk;
window.unityInstance = UNSAFE__unityInstance;
}, [UNSAFE__unityInstance]);
return (
<>
{!isLoaded && (
<div className={'h-full w-full items-center justify-center text-center'}>
Loading {loadingProgression * 100 + 10}%
</div>
)}
<Unity
id='unity-canvas'
unityProvider={unityProvider}
className={clsx('h-full w-full', !isLoaded && 'hidden')}
devicePixelRatio={window.devicePixelRatio}
/>
</>
);
};
```
1. **Add** game link to env:
```
APP_ID=
ZMP_TOKEN=
VITE_GAME_LINK=[your game link]
yarn install promogame-game-component
```
1. **Import** and use it anywhere:
```tsx
export default function MainApp() {
return (
<div className={'flex h-dvh w-screen flex-col items-center justify-center'}>
<UnityGame />
</div>
);
}
export default function MainApp() {
const Loading = ({ progress }: { progress: number }) => {
return (
<div className={'h-full w-full items-center justify-center text-center'}>
Loading {progress * 100}%
</div>
);
};
return (
<div className={'flex h-dvh w-screen flex-col items-center justify-center'}>
<PromogameGame loadingComponent={Loading} className={'h-full w-full'} apiUrl={import.meta.env.VITE_API_URL} />
</div>
);
}
```

View File

@ -23,10 +23,10 @@
"dependencies": {
"clsx": "^2.1.1",
"parse-path": "^7.0.0",
"promogame-game-component": "^0.0.12",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-unity-webgl": "^9.6.0",
"usehooks-ts": "^3.1.0",
"zmp-sdk": "latest",
"zmp-ui": "latest",

View File

@ -14,6 +14,9 @@ importers:
parse-path:
specifier: ^7.0.0
version: 7.1.0
promogame-game-component:
specifier: ^0.0.12
version: 0.0.12(@babel/core@7.27.1)(@types/react@18.3.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
prop-types:
specifier: ^15.8.1
version: 15.8.1
@ -23,9 +26,6 @@ importers:
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-unity-webgl:
specifier: ^9.6.0
version: 9.8.0(react@18.3.1)
usehooks-ts:
specifier: ^3.1.0
version: 3.1.1(react@18.3.1)
@ -92,6 +92,24 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
'@apollo/client@3.13.8':
resolution: {integrity: sha512-YM9lQpm0VfVco4DSyKooHS/fDTiKQcCHfxr7i3iL6a0kP/jNO5+4NFK6vtRDxaYisd5BrwOZHLJpPBnvRVpKPg==}
peerDependencies:
graphql: ^15.0.0 || ^16.0.0
graphql-ws: ^5.5.5 || ^6.0.3
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc
subscriptions-transport-ws: ^0.9.0 || ^0.11.0
peerDependenciesMeta:
graphql-ws:
optional: true
react:
optional: true
react-dom:
optional: true
subscriptions-transport-ws:
optional: true
'@babel/cli@7.27.2':
resolution: {integrity: sha512-cfd7DnGlhH6OIyuPSSj3vcfIdnbXukhAyKY8NaZrFadC7pXyL9mOL5WgjcptiEJLi5k3j8aYvLIVCzezrWTaiA==}
engines: {node: '>=6.9.0'}
@ -377,6 +395,11 @@ packages:
cpu: [x64]
os: [win32]
'@graphql-typed-document-node/core@3.2.0':
resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==}
peerDependencies:
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@ -705,6 +728,22 @@ packages:
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0
'@wry/caches@1.0.1':
resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==}
engines: {node: '>=8'}
'@wry/context@0.7.4':
resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==}
engines: {node: '>=8'}
'@wry/equality@0.5.7':
resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==}
engines: {node: '>=8'}
'@wry/trie@0.5.0':
resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==}
engines: {node: '>=8'}
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
@ -1018,6 +1057,16 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
graphql-tag@2.12.6:
resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==}
engines: {node: '>=10'}
peerDependencies:
graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
graphql@16.11.0:
resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==}
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@ -1026,6 +1075,9 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@ -1183,6 +1235,9 @@ packages:
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
optimism@0.18.1:
resolution: {integrity: sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==}
p-limit@2.3.0:
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
engines: {node: '>=6'}
@ -1445,6 +1500,12 @@ packages:
resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==}
engines: {node: '>= 0.8'}
promogame-game-component@0.0.12:
resolution: {integrity: sha512-LNELuHnll0M/pQmyZbh82MjTo5/BdiYN9yl/72iOaUIYKjq9KOhLhgfPQfsY7vmh3ipjyrqJpec3hXDtTrohLQ==}
peerDependencies:
react: '*'
react-dom: '*'
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@ -1517,6 +1578,17 @@ packages:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
rehackt@0.1.0:
resolution: {integrity: sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==}
peerDependencies:
'@types/react': '*'
react: '*'
peerDependenciesMeta:
'@types/react':
optional: true
react:
optional: true
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
@ -1620,6 +1692,13 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
symbol-observable@4.0.0:
resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
engines: {node: '>=0.10'}
tailwind-merge@3.3.0:
resolution: {integrity: sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==}
tailwindcss@3.4.17:
resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==}
engines: {node: '>=14.0.0'}
@ -1642,6 +1721,10 @@ packages:
ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
ts-invariant@0.10.3:
resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==}
engines: {node: '>=8'}
tsconfck@3.1.5:
resolution: {integrity: sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==}
engines: {node: ^18 || >=20}
@ -1777,9 +1860,18 @@ packages:
resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
engines: {node: '>=10'}
zen-observable-ts@1.2.5:
resolution: {integrity: sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==}
zen-observable@0.8.15:
resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==}
zmp-sdk@2.45.1:
resolution: {integrity: sha512-yN/rSzSIm/KVi02Syz3JTPA9I1w3GdAbI4lbhzlYvIkg0dH70vcmzcDlP+8ldLihhz+t968C8DqMjqsunJ/IWw==}
zmp-sdk@2.46.2:
resolution: {integrity: sha512-abmtpuM0z5j0g+2RkHdvKOljI3zEb857G5S85kyGYm3ThBSfeH4LIWF1XVrIER6MrYA5JGTMMxryY70tmLGw7g==}
zmp-ui@1.11.7:
resolution: {integrity: sha512-/EWmrcTuhjiMRdqUqUgaC7ZSsD1ZttQSBIYAERKgfX7lYtpEORO8y9o+ByU7OlJUZ2cKj+/nvWiV7DA3yA5fXg==}
@ -1815,6 +1907,28 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.8
'@jridgewell/trace-mapping': 0.3.25
'@apollo/client@3.13.8(@types/react@18.3.21)(graphql@16.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0)
'@wry/caches': 1.0.1
'@wry/equality': 0.5.7
'@wry/trie': 0.5.0
graphql: 16.11.0
graphql-tag: 2.12.6(graphql@16.11.0)
hoist-non-react-statics: 3.3.2
optimism: 0.18.1
prop-types: 15.8.1
rehackt: 0.1.0(@types/react@18.3.21)(react@18.3.1)
symbol-observable: 4.0.0
ts-invariant: 0.10.3
tslib: 2.8.1
zen-observable-ts: 1.2.5
optionalDependencies:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
transitivePeerDependencies:
- '@types/react'
'@babel/cli@7.27.2(@babel/core@7.27.1)':
dependencies:
'@babel/core': 7.27.1
@ -2047,6 +2161,10 @@ snapshots:
'@esbuild/win32-x64@0.21.5':
optional: true
'@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)':
dependencies:
graphql: 16.11.0
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
@ -2350,6 +2468,22 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@wry/caches@1.0.1':
dependencies:
tslib: 2.8.1
'@wry/context@0.7.4':
dependencies:
tslib: 2.8.1
'@wry/equality@0.5.7':
dependencies:
tslib: 2.8.1
'@wry/trie@0.5.0':
dependencies:
tslib: 2.8.1
ansi-regex@5.0.1: {}
ansi-regex@6.1.0: {}
@ -2662,12 +2796,23 @@ snapshots:
graceful-fs@4.2.11: {}
graphql-tag@2.12.6(graphql@16.11.0):
dependencies:
graphql: 16.11.0
tslib: 2.8.1
graphql@16.11.0: {}
has-flag@4.0.0: {}
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
hoist-non-react-statics@3.3.2:
dependencies:
react-is: 16.13.1
ignore@5.3.2: {}
immutable@5.1.2: {}
@ -2794,6 +2939,13 @@ snapshots:
dependencies:
wrappy: 1.0.2
optimism@0.18.1:
dependencies:
'@wry/caches': 1.0.1
'@wry/context': 0.7.4
'@wry/trie': 0.5.0
tslib: 2.8.1
p-limit@2.3.0:
dependencies:
p-try: 2.2.0
@ -3102,6 +3254,23 @@ snapshots:
pretty-hrtime@1.0.3: {}
promogame-game-component@0.0.12(@babel/core@7.27.1)(@types/react@18.3.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@apollo/client': 3.13.8(@types/react@18.3.21)(graphql@16.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0)
clsx: 2.1.1
graphql: 16.11.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-unity-webgl: 9.8.0(react@18.3.1)
tailwind-merge: 3.3.0
zmp-sdk: 2.46.2(@babel/core@7.27.1)
transitivePeerDependencies:
- '@babel/core'
- '@types/react'
- graphql-ws
- subscriptions-transport-ws
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
@ -3171,6 +3340,11 @@ snapshots:
readdirp@4.1.2: {}
rehackt@0.1.0(@types/react@18.3.21)(react@18.3.1):
optionalDependencies:
'@types/react': 18.3.21
react: 18.3.1
require-directory@2.1.1: {}
require-main-filename@2.0.0: {}
@ -3285,6 +3459,10 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
symbol-observable@4.0.0: {}
tailwind-merge@3.3.0: {}
tailwindcss@3.4.17:
dependencies:
'@alloc/quick-lru': 5.2.0
@ -3328,6 +3506,10 @@ snapshots:
ts-interface-checker@0.1.13: {}
ts-invariant@0.10.3:
dependencies:
tslib: 2.8.1
tsconfck@3.1.5: {}
tslib@1.14.1: {}
@ -3438,6 +3620,12 @@ snapshots:
y18n: 5.0.8
yargs-parser: 20.2.9
zen-observable-ts@1.2.5:
dependencies:
zen-observable: 0.8.15
zen-observable@0.8.15: {}
zmp-sdk@2.45.1(@babel/core@7.27.1):
dependencies:
'@babel/cli': 7.27.2(@babel/core@7.27.1)
@ -3450,6 +3638,18 @@ snapshots:
transitivePeerDependencies:
- '@babel/core'
zmp-sdk@2.46.2(@babel/core@7.27.1):
dependencies:
'@babel/cli': 7.27.2(@babel/core@7.27.1)
'@sentry/browser': 6.19.7
'@sentry/tracing': 6.19.7
'@swc/helpers': 0.4.37
eventemitter3: 4.0.7
qrcode: 1.5.4
raven-js: 3.27.2
transitivePeerDependencies:
- '@babel/core'
zmp-ui@1.11.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@babel/runtime': 7.27.1

View File

@ -1,9 +1,17 @@
import { UnityGame } from './components/unity-game';
import {PromogameGame} from "promogame-game-component";
export default function MainApp() {
const Loading = ({ progress }: { progress: number }) => {
return (
<div className={'h-full w-full items-center justify-center text-center'}>
Loading {progress * 100}%
</div>
);
};
return (
<div className={'flex h-dvh w-screen flex-col items-center justify-center'}>
<UnityGame />
<PromogameGame loadingComponent={Loading} className={'h-full w-full'} apiUrl={import.meta.env.VITE_API_URL} />
</div>
);
}

View File

@ -1,35 +0,0 @@
import clsx from 'clsx';
import { useEffect } from 'react';
import { Unity, useUnityContext } from 'react-unity-webgl';
import zmpSdk from 'zmp-sdk';
export const UnityGame = () => {
const gameLink = import.meta.env.VITE_GAME_LINK;
const { unityProvider, isLoaded, loadingProgression, UNSAFE__unityInstance } = useUnityContext({
loaderUrl: `${gameLink}/Build/Build.loader.js`,
dataUrl: `${gameLink}/Build/Build.data.unityweb`,
frameworkUrl: `${gameLink}/Build/Build.framework.js.unityweb`,
codeUrl: `${gameLink}/Build/Build.wasm.unityweb`,
});
useEffect(() => {
window.ZaloMiniAppSDK = zmpSdk;
window.unityInstance = UNSAFE__unityInstance;
}, [UNSAFE__unityInstance]);
return (
<>
{!isLoaded && (
<div className={'h-full w-full items-center justify-center text-center'}>
Loading {loadingProgression * 100 + 10}%
</div>
)}
<Unity
id='unity-canvas'
unityProvider={unityProvider}
className={clsx('h-full w-full', !isLoaded && 'hidden')}
devicePixelRatio={window.devicePixelRatio}
/>
</>
);
};