Next.js Setup Guide
Guided setup for Zerve + Typescript + React Native Web in a Next app
This is the manual setup guide. You can also copy the complete example on GitHub here.
Alternatively, you can follow Expo's Next.js guide and jump to the Zerve Setup.
Create a Next.js App
npx create-next-app zerve-example-app
Add React-Native-Web
We are starting from the Next.js Example support for React Native Web. First, install the dependencies:
yarn add react-native-web
yarn add -D babel-plugin-react-native-web
Then, copy each of the following files into your app:
Now, you are ready to rewrite pages/index.js
to use RNW:
import { StyleSheet, Text, View } from "react-native";
export default function Home() {
return (
<View style={styles.container}>
<Text style={styles.headline}>Welcome to React-Native-Web!</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
headline: {
fontSize: 32,
},
});
Start your app with yarn dev
, and now React Native Web should be working! At this point you can remove the styles/
folder, because RNW will handle styling for us.
Set up TypeScript
First, install the relevant typescript packages:
yarn add -D typescript @types/react @types/node @types/react-native
Then, rename pages/index.js
to index.tsx
. At the top of this file, add import React from 'react'
or else TS will get confused.
If you restart your server, Next sees that you're using TS, and it auto-creates a tsconfig.json
for you.
Then, set "moduleResolution": "node"
so that TS can see the definition files of modules we install.
Now, your tsconfig.json
should look like this:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"incremental": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
Great, now the app supports React Native Web and TypeScript! You're ready to install Zerve.
Set up Zerve CLI
Get started by installing the Zerve CLI:
yarn add -D @zerve/cli
Now, add the following to your package:
"zerve": {
"dynamicSync": {
"DemoStore": "https://alpha.zerve.app/.z/store/ev/demo"
}
}
If you have an account on the Zerve Alpha, you should replace "ev/demo" above with "my-user/my-store". You can rename "DemoStore" to anything you prefer– it is only used in this codebase.
yarn zerve-sync
The CLI creates zerve/DemoStore
for you, with relevant code and types. You may also add the prepare
script to your package, so that the sync happens automatically when you run yarn
.
"scripts": {
"prepare": "yarn zerve-sync",
Set up Zerve Client
Now install the client-side libraries. Zerve Client relies on React Query, so you should install that as well:
yarn add @zerve/client
yarn add react-query
You're ready to run zerve-sync
to auto-generate your app's client code.
Before we use the client, we need to set up the QueryClient for React Query. Here we add it to _app.js
, but the provider can also be added on each page:
import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient();
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<QueryClientProvider client={queryClient}>
<Component {...pageProps} />
</QueryClientProvider>
</>
);
}
Use the Zerve Client in your App
Now you're ready to use your Zerve store from your app. The demo store has a "Banner" text entry. Here's an example where we display it from the index page:
import React from "react";
import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
import { useBanner } from "../zerve/DemoStore";
export default function Home() {
const { data, isLoading } = useBanner({
onError: (err) => alert(err),
});
return (
<View style={styles.container}>
{isLoading ? <ActivityIndicator /> : null}
<Text style={styles.headline}>{data}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
headline: {
fontSize: 32,
},
});
Now you have a type-safe way to load content from the Zerve Store! At this point you may add entries and schemas to your store, and re-run zerve-sync
to update your client.
See Client for more details on the client.
Zerve Content
You may optionally use Zerve's react-native-content
presentation components for displaying content to the user. Currently the only one included is <HumanText />
.
To set up the content views, you need to use next-transpile-modules
. This allows the internal reference of "react-native" to be converted to "react-native-web"
First, install it:
yarn add @zerve/react-native-content
Then, run:
yarn add -D next-transpile-modules
Finally, modify next.config.js
so that the content module gets transpiled:
require("next-transpile-modules")(["@zerve/react-native-content"])(nextConfig);
Your final next config should look like this:
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
webpack: (config) => {
config.resolve.alias = {
...(config.resolve.alias || {}),
// Transform all direct `react-native` imports to `react-native-web`
"react-native$": "react-native-web",
};
config.resolve.extensions = [
".web.js",
".web.jsx",
".web.ts",
".web.tsx",
...config.resolve.extensions,
];
return config;
},
};
const withTM = require("next-transpile-modules")([
"@zerve/react-native-content",
]);
module.exports = withTM(nextConfig);
For a more complicated example that includes
next-compose-plugins
and@expo/next-adapter
see the web app next.config.js in the Zerve repo.
Present formatted HumanText in your App
Now you are ready to render <HumanText />
in your app. Modify it with the following:
import { HumanText } from "@zerve/react-native-content/HumanText";
export default function Home() {
const { data, isLoading } = useHeadline({
onError: (err) => alert(err),
});
return (
<View style={styles.container}>
{isLoading ? <ActivityIndicator /> : null}
{data && <HumanText value={data} />}
</View>
);
}
Run the next app with yarn dev
and you should see the "Headline" content loaded from the demo store API.
See HumanText for more details on this component.