I'm creating a simple twitter clone with Next and TRPC, I already got tRPC working, but I would like to move all my code into the src
directory. I noticed that just by simply moving everything, TRPC stops working with the following error:
TypeError: Cannot read properties of null (reading 'client')
First, here's my project's file structure, everything is located at the project's root.
.
├── components
├── containers
├── model
├── next.config.js
├── next-env.d.ts
├── package.json
├── pages
├── postcss.config.js
├── prettier.config.js
├── prisma
├── README.md
├── routers
├── tailwind.config.js
├── tsconfig.json
├── utils
└── yarn.lock
7 directories, 9 files
In here, I followed tRPC's set up guide for Next.js which instructed me to perform the following changes.
Create a tRPC router
I created a router at routers/TweetRouter.ts
.
export const tweetRouter = createRouter().query("all", {
resolve() {
const tweets: Tweet[] = [
{
id: 1,
user: "Je12emy",
text: "Hello world",
likes: 2,
},
{
id: 2,
user: "Je12emy",
text: "TRPC + Nextjs + Tailwind = T3 App",
likes: 0,
},
];
return tweets;
},
});
Which is then merged in pages/api/trpc/[trpc].ts
import * as trpc from "@trpc/server";
import * as trpcNext from "@trpc/server/adapters/next";
import { tweetRouter } from "../../../routers/tweetRouter";
export function createRouter() {
return trpc.router();
}
const router = createRouter().merge('tweet.', tweetRouter);
export const appRouter = router;
export type AppRouter = typeof router;
export default trpcNext.createNextApiHandler({
router,
onError({ error }) {
if (error.code === "INTERNAL_SERVER_ERROR") {
// send to bug reporting
console.error("Something went wrong", error);
}
},
});
Create tRPC hooks
This should be done at utils/trpc.ts
import { createReactQueryHooks } from '@trpc/react';
import type { AppRouter } from '../pages/api/trpc/[trpc]';
export const trpc = createReactQueryHooks<AppRouter>();
Configure _app.tsx
I just copied over the code in the documentation, I would like to remove the getURL
function down the line.
function MyApp({ Component, pageProps }: AppProps) {
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<Component {...pageProps} />{" "}
</QueryClientProvider>
);
}
function getBaseUrl() {
if (typeof window !== 'undefined') {
return '';
}
// reference for vercel.com
if (process.env.VERCEL_URL) {
return `https://${process.env.VERCEL_URL}`;
}
// reference for render.com
if (process.env.RENDER_INTERNAL_HOSTNAME) {
return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;
}
// assume localhost
return `http://localhost:${process.env.PORT ?? 3000}`;
}
export default withTRPC<AppRouter>({
config({ ctx }) {
/**
* If you want to use SSR, you need to use the server's full URL
* @link https://trpc.io/docs/ssr
*/
return {
url: `${getBaseUrl()}/api/trpc`,
/**
* @link https://react-query-v3.tanstack.com/reference/QueryClient
*/
// queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },
};
},
/**
* @link https://trpc.io/docs/ssr
*/
ssr: true,
})(MyApp);
Make API Requests
Finally, I can import the client and send API requests, this works as expected
import type { NextPage } from "next";
import TweetCard from "../components/TweetCard";
import PageContainer from "../containers/Page";
import { trpc } from "../utils/trpc";
const Home: NextPage = () => {
const { data, isLoading } = trpc.useQuery(["tweet.all"]);
if (isLoading) {
return (
<PageContainer className="flex items-center justify-center">
<p> loading... </p>
</PageContainer>
);
}
if (!data) {
return (
<PageContainer className="flex items-center justify-center">
<p> No Tweets </p>
</PageContainer>
);
}
return (
<PageContainer className="flex flex-col space-y-3">
{data.map((tweet) => (
<TweetCard key={tweet.id} {...tweet} />
))}
</PageContainer>
);
};
export default Home;
And so, I decided to commit this code and to move it into a src
directory just to clean up my project's root. Here were the problem materializes at src/pages/index.ts
at line 7, which is where the query is being done. I updated my file structure a bit, and fixed all the imports, so here's my current file structure.
src
├── backend
│ ├── model
│ │ ├── tweet.ts
│ │ └── user.ts
│ └── router
│ ├── index.ts
│ └── tweet.ts
├── components
│ ├── LikesCounter.tsx
│ └── TweetCard.tsx
├── containers
│ └── Page.tsx
├── pages
│ ├── api
│ │ └── trpc
│ │ └── [trpc].ts
│ ├── _app.tsx
│ └── index.tsx
├── styles
│ └── globals.css
└── utils
└── trpc.ts
10 directories, 14 files
You can check the complete code in my repository: https://github.com/Je12emy/twitter-nextjs/tree/trpc_port