-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(create-mud): move react template to zustand, add react-ecs templ…
…ate (#1851)
- Loading branch information
Showing
60 changed files
with
1,491 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"create-mud": major | ||
--- | ||
|
||
Replaced the `react` template with a basic task list app using the new Zustand storage adapter and sync method. This new template better demonstrates the different ways of building with MUD and has fewer concepts to learn (i.e. just tables and records, no more ECS). | ||
|
||
For ECS-based React apps, you can use `react-ecs` template for the previous RECS storage adapter. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"root": true, | ||
"parser": "@typescript-eslint/parser", | ||
"plugins": ["@typescript-eslint"], | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/eslint-recommended", | ||
"plugin:@typescript-eslint/recommended" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# suppress diffs for generated files | ||
**/pnpm-lock.yaml linguist-generated=true | ||
**/codegen/**/*.sol linguist-generated=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"recommendations": ["NomicFoundation.hardhat-solidity"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"name": "mud-template-react-ecs", | ||
"private": true, | ||
"scripts": { | ||
"build": "pnpm recursive run build", | ||
"dev": "concurrently -n contracts,client -c cyan,magenta \"cd packages/contracts && pnpm run dev\" \"cd packages/client && pnpm run dev\"", | ||
"dev:client": "pnpm --filter 'client' run dev", | ||
"dev:contracts": "pnpm --filter 'contracts' dev", | ||
"foundry:up": "curl -L https://foundry.paradigm.xyz | bash && bash $HOME/.foundry/bin/foundryup", | ||
"mud:up": "pnpm mud set-version --tag main && pnpm install", | ||
"prepare": "(forge --version || pnpm foundry:up)", | ||
"test": "pnpm recursive run test" | ||
}, | ||
"devDependencies": { | ||
"@latticexyz/cli": "link:../../packages/cli", | ||
"@typescript-eslint/eslint-plugin": "5.46.1", | ||
"@typescript-eslint/parser": "5.46.1", | ||
"concurrently": "^8.0.1", | ||
"eslint": "8.29.0", | ||
"rimraf": "^3.0.2", | ||
"typescript": "5.1.6" | ||
}, | ||
"engines": { | ||
"node": "18.x", | ||
"pnpm": "8.x" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
VITE_CHAIN_ID=31337 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": ["../../.eslintrc", "plugin:react/recommended", "plugin:react-hooks/recommended"], | ||
"plugins": ["react", "react-hooks"], | ||
"rules": { | ||
"react/react-in-jsx-scope": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules | ||
dist | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>a minimal MUD client</title> | ||
</head> | ||
<body> | ||
<div id="react-root"></div> | ||
<script type="module" src="/src/index.tsx"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "client", | ||
"version": "0.0.0", | ||
"private": true, | ||
"license": "MIT", | ||
"type": "module", | ||
"scripts": { | ||
"build": "vite build", | ||
"dev": "wait-port localhost:8545 && vite", | ||
"preview": "vite preview", | ||
"test": "tsc --noEmit" | ||
}, | ||
"dependencies": { | ||
"@latticexyz/common": "link:../../../../packages/common", | ||
"@latticexyz/dev-tools": "link:../../../../packages/dev-tools", | ||
"@latticexyz/react": "link:../../../../packages/react", | ||
"@latticexyz/recs": "link:../../../../packages/recs", | ||
"@latticexyz/schema-type": "link:../../../../packages/schema-type", | ||
"@latticexyz/services": "link:../../../../packages/services", | ||
"@latticexyz/store-sync": "link:../../../../packages/store-sync", | ||
"@latticexyz/utils": "link:../../../../packages/utils", | ||
"@latticexyz/world": "link:../../../../packages/world", | ||
"contracts": "workspace:*", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"rxjs": "7.5.5", | ||
"viem": "1.14.0" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "18.2.22", | ||
"@types/react-dom": "18.2.7", | ||
"@vitejs/plugin-react": "^3.1.0", | ||
"eslint-plugin-react": "7.31.11", | ||
"eslint-plugin-react-hooks": "4.6.0", | ||
"vite": "^4.2.1", | ||
"wait-port": "^1.0.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { useComponentValue } from "@latticexyz/react"; | ||
import { useMUD } from "./MUDContext"; | ||
import { singletonEntity } from "@latticexyz/store-sync/recs"; | ||
|
||
export const App = () => { | ||
const { | ||
components: { Counter }, | ||
systemCalls: { increment }, | ||
} = useMUD(); | ||
|
||
const counter = useComponentValue(Counter, singletonEntity); | ||
|
||
return ( | ||
<> | ||
<div> | ||
Counter: <span>{counter?.value ?? "??"}</span> | ||
</div> | ||
<button | ||
type="button" | ||
onClick={async (event) => { | ||
event.preventDefault(); | ||
console.log("new counter value:", await increment()); | ||
}} | ||
> | ||
Increment | ||
</button> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { createContext, ReactNode, useContext } from "react"; | ||
import { SetupResult } from "./mud/setup"; | ||
|
||
const MUDContext = createContext<SetupResult | null>(null); | ||
|
||
type Props = { | ||
children: ReactNode; | ||
value: SetupResult; | ||
}; | ||
|
||
export const MUDProvider = ({ children, value }: Props) => { | ||
const currentValue = useContext(MUDContext); | ||
if (currentValue) throw new Error("MUDProvider can only be used once"); | ||
return <MUDContext.Provider value={value}>{children}</MUDContext.Provider>; | ||
}; | ||
|
||
export const useMUD = () => { | ||
const value = useContext(MUDContext); | ||
if (!value) throw new Error("Must be used within a MUDProvider"); | ||
return value; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import ReactDOM from "react-dom/client"; | ||
import { App } from "./App"; | ||
import { setup } from "./mud/setup"; | ||
import { MUDProvider } from "./MUDContext"; | ||
import mudConfig from "contracts/mud.config"; | ||
|
||
const rootElement = document.getElementById("react-root"); | ||
if (!rootElement) throw new Error("React root not found"); | ||
const root = ReactDOM.createRoot(rootElement); | ||
|
||
// TODO: figure out if we actually want this to be async or if we should render something else in the meantime | ||
setup().then(async (result) => { | ||
root.render( | ||
<MUDProvider value={result}> | ||
<App /> | ||
</MUDProvider> | ||
); | ||
|
||
// https://vitejs.dev/guide/env-and-mode.html | ||
if (import.meta.env.DEV) { | ||
const { mount: mountDevTools } = await import("@latticexyz/dev-tools"); | ||
mountDevTools({ | ||
config: mudConfig, | ||
publicClient: result.network.publicClient, | ||
walletClient: result.network.walletClient, | ||
latestBlock$: result.network.latestBlock$, | ||
storedBlockLogs$: result.network.storedBlockLogs$, | ||
worldAddress: result.network.worldContract.address, | ||
worldAbi: result.network.worldContract.abi, | ||
write$: result.network.write$, | ||
recsWorld: result.network.world, | ||
}); | ||
} | ||
}); |
File renamed without changes.
51 changes: 51 additions & 0 deletions
51
templates/react-ecs/packages/client/src/mud/createSystemCalls.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Create the system calls that the client can use to ask | ||
* for changes in the World state (using the System contracts). | ||
*/ | ||
|
||
import { getComponentValue } from "@latticexyz/recs"; | ||
import { ClientComponents } from "./createClientComponents"; | ||
import { SetupNetworkResult } from "./setupNetwork"; | ||
import { singletonEntity } from "@latticexyz/store-sync/recs"; | ||
|
||
export type SystemCalls = ReturnType<typeof createSystemCalls>; | ||
|
||
export function createSystemCalls( | ||
/* | ||
* The parameter list informs TypeScript that: | ||
* | ||
* - The first parameter is expected to be a | ||
* SetupNetworkResult, as defined in setupNetwork.ts | ||
* | ||
* Out of this parameter, we only care about two fields: | ||
* - worldContract (which comes from getContract, see | ||
* https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L63-L69). | ||
* | ||
* - waitForTransaction (which comes from syncToRecs, see | ||
* https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L77-L83). | ||
* | ||
* - From the second parameter, which is a ClientComponent, | ||
* we only care about Counter. This parameter comes to use | ||
* through createClientComponents.ts, but it originates in | ||
* syncToRecs | ||
* (https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L77-L83). | ||
*/ | ||
{ worldContract, waitForTransaction }: SetupNetworkResult, | ||
{ Counter }: ClientComponents | ||
) { | ||
const increment = async () => { | ||
/* | ||
* Because IncrementSystem | ||
* (https://mud.dev/templates/typescript/contracts#incrementsystemsol) | ||
* is in the root namespace, `.increment` can be called directly | ||
* on the World contract. | ||
*/ | ||
const tx = await worldContract.write.increment(); | ||
await waitForTransaction(tx); | ||
return getComponentValue(Counter, singletonEntity); | ||
}; | ||
|
||
return { | ||
increment, | ||
}; | ||
} |
91 changes: 91 additions & 0 deletions
91
templates/react-ecs/packages/client/src/mud/getNetworkConfig.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* Network specific configuration for the client. | ||
* By default connect to the anvil test network. | ||
* | ||
*/ | ||
|
||
/* | ||
* By default the template just creates a temporary wallet | ||
* (called a burner wallet) and uses a faucet (on our test net) | ||
* to get ETH for it. | ||
* | ||
* See https://mud.dev/tutorials/minimal/deploy#wallet-managed-address | ||
* for how to use the user's own address instead. | ||
*/ | ||
import { getBurnerPrivateKey } from "@latticexyz/common"; | ||
|
||
/* | ||
* Import the addresses of the World, possibly on multiple chains, | ||
* from packages/contracts/worlds.json. When the contracts package | ||
* deploys a new `World`, it updates this file. | ||
*/ | ||
import worlds from "contracts/worlds.json"; | ||
|
||
/* | ||
* The supported chains. | ||
* By default, there are only two chains here: | ||
* | ||
* - mudFoundry, the chain running on anvil that pnpm dev | ||
* starts by default. It is similar to the viem anvil chain | ||
* (see https://viem.sh/docs/clients/test.html), but with the | ||
* basefee set to zero to avoid transaction fees. | ||
* - latticeTestnet, our public test network. | ||
* | ||
* See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface | ||
* for instructions on how to add networks. | ||
*/ | ||
import { supportedChains } from "./supportedChains"; | ||
|
||
export async function getNetworkConfig() { | ||
const params = new URLSearchParams(window.location.search); | ||
|
||
/* | ||
* The chain ID is the first item available from this list: | ||
* 1. chainId query parameter | ||
* 2. chainid query parameter | ||
* 3. The VITE_CHAIN_ID environment variable set when the | ||
* vite dev server was started or client was built | ||
* 4. The default, 31337 (anvil) | ||
*/ | ||
const chainId = Number(params.get("chainId") || params.get("chainid") || import.meta.env.VITE_CHAIN_ID || 31337); | ||
|
||
/* | ||
* Find the chain (unless it isn't in the list of supported chains). | ||
*/ | ||
const chainIndex = supportedChains.findIndex((c) => c.id === chainId); | ||
const chain = supportedChains[chainIndex]; | ||
if (!chain) { | ||
throw new Error(`Chain ${chainId} not found`); | ||
} | ||
|
||
/* | ||
* Get the address of the World. If you want to use a | ||
* different address than the one in worlds.json, | ||
* provide it as worldAddress in the query string. | ||
*/ | ||
const world = worlds[chain.id.toString()]; | ||
const worldAddress = params.get("worldAddress") || world?.address; | ||
if (!worldAddress) { | ||
throw new Error(`No world address found for chain ${chainId}. Did you run \`mud deploy\`?`); | ||
} | ||
|
||
/* | ||
* MUD clients use events to synchronize the database, meaning | ||
* they need to look as far back as when the World was started. | ||
* The block number for the World start can be specified either | ||
* on the URL (as initialBlockNumber) or in the worlds.json | ||
* file. If neither has it, it starts at the first block, zero. | ||
*/ | ||
const initialBlockNumber = params.has("initialBlockNumber") | ||
? Number(params.get("initialBlockNumber")) | ||
: world?.blockNumber ?? 0n; | ||
|
||
return { | ||
privateKey: getBurnerPrivateKey(), | ||
chainId, | ||
chain, | ||
faucetServiceUrl: params.get("faucet") ?? chain.faucetUrl, | ||
worldAddress, | ||
initialBlockNumber, | ||
}; | ||
} |
Oops, something went wrong.