Skip to content

Commit fb17d94

Browse files
authored
Update nextjs docs to adapt 13.4 changes (tauri-apps#1250)
* Update nextjs docs to adapt 13.4 changes * mention nextjs version for app router feature
1 parent 2c10a50 commit fb17d94

File tree

1 file changed

+43
-74
lines changed

1 file changed

+43
-74
lines changed

docs/guides/getting-started/setup/next-js.mdx

Lines changed: 43 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,27 @@ Here's a preview of what we will be building:
3030
[Next.js] is a React Framework that comes with both Server-Side Rendering (SSR) and Static-Site Generation (SSG) capabilities. To make Next.js work with Tauri we are going to use the SSG mode since it generates only static files that can be included in the final binary.
3131

3232
Next.js comes with a scaffolding utility similar to [`create-tauri-app`] that can quickly setup a new project from many pre-defined templates.
33-
For this guide, we will use the TypeScript template to create a simple project.
33+
For this guide, we will use the suggested default for all questions, including TypeScript support and the new `App Router` feature stabilized in v13.4. In case you use the the old `routes/` directory instead or on top of the `app/` directory, you still need to change the config as explained in the [Next.js Static Exports](#nextjs-static-exports) section but the way you use Tauri specific JS APIs will be different than described below.
3434

3535
<Tabs groupId="package-manager">
3636
<TabItem value="npm">
3737

3838
```shell
39-
npx create-next-app@latest --use-npm --typescript
39+
npx create-next-app@latest --use-npm
4040
```
4141

4242
</TabItem>
4343
<TabItem value="Yarn">
4444

4545
```shell
46-
yarn create next-app --typescript
46+
yarn create next-app --use-yarn
4747
```
4848

4949
</TabItem>
5050
<TabItem value="pnpm">
5151

5252
```shell
53-
pnpm create next-app --use-pnpm --typescript
53+
pnpm create next-app --use-pnpm
5454
```
5555

5656
</TabItem>
@@ -59,58 +59,24 @@ pnpm create next-app --use-pnpm --typescript
5959
1. _Project name_
6060
This will be the name of your project. It corresponds to the name of the folder this utility will create but has otherwise no effect on your app. You can use any name you want here.
6161

62-
2. _Experimental `app/` directory_
63-
Next.js will ask you if you want to try the new and experimental `app/` directory. You must select `No` because it does not yet support the `next export` command.
62+
## Next.js Static Exports
6463

65-
When starting or building the frontend, Next.js will look for a config file named `next.config.js` inside the project root.
66-
We want to customize this file to get the best compatibility with Tauri.
64+
Because Tauri does not have a Node.js runtime you must set Next.js to SSG/SPA mode. This will typically result in faster page loads but also has a few caveats to be aware of, therefore we recommend to carefully read through Next.js' official docs on [Static Exports].
6765

68-
Update the file with the following content:
66+
These docs also show one required configuration change we will always have to change for a Tauri + Next.js app. To do this, edit the `next.config.js` file in the project's root directory and add the following:
6967

70-
```typescript title=next.config.js
68+
```js title=next.config.js
7169
/** @type {import('next').NextConfig} */
72-
7370
const nextConfig = {
74-
reactStrictMode: true,
75-
// Note: This feature is required to use NextJS Image in SSG mode.
76-
// See https://nextjs.org/docs/messages/export-image-api for different workarounds.
77-
images: {
78-
unoptimized: true,
79-
},
71+
output: 'export',
8072
}
8173

8274
module.exports = nextConfig
8375
```
8476

85-
To be able to build in production we must add a `next export` command in `package.json`.
86-
This will produce a static HTML/JavaScript version of your Next.js application in the `out` folder.
87-
We'll also add the `tauri` command to `package.json`.
88-
89-
Your `package.json` should look like this:
90-
91-
```json title=package.json
92-
{
93-
"scripts": {
94-
"dev": "next dev",
95-
"build": "next build",
96-
"export": "next export",
97-
"start": "next start",
98-
"tauri": "tauri",
99-
"lint": "next lint"
100-
},
101-
```
102-
103-
## Next.js in SSG mode
104-
105-
The "benefit" of using SSG mode is pre-rendered React code in static HTML/JavaScript. This means your page can load faster.
106-
React doesn't have to render the HTML on the client-side but will hydrate it on the first load if needed.
107-
The "downside" is that we cannot use `getServerSideProps` or use any type of "data fetching" for rendering our page for a request.
108-
109-
:::tip
110-
111-
You can use `getStaticProps` to generate HTML/JavaScript pages at build time. Since it is executed in the Node.js context, calling the Tauri api won't work. You can learn more about Next.js SSG in the [official documentation](https://nextjs.org/docs/basic-features/pages#static-generation-recommended).
77+
This will change the behavior of the `next build` to produce an `out/` folder containing the HTML/CSS/JS assets for your application instead of writing them to a `.next/` directory specific to Next.js' runtime.
11278

113-
:::
79+
There are a few more possible configuration options, so make sure to read through the [Static Exports] docs as mentioned above and adapt the configuration file according to the needs of your project.
11480

11581
## Create the Rust Project
11682

@@ -120,10 +86,12 @@ You can use `getStaticProps` to generate HTML/JavaScript pages at build time. Si
12086
__html: 'Use <code>http://localhost:3000</code> for this value.',
12187
}}
12288
beforeBuildCommandExplination={{
123-
__html: 'Use <code>npm run build && npm run export</code> for this value.',
89+
__html:
90+
'Use <code>npm run build</code> for this value (make sure to adapt this to use the package manager of your choice).',
12491
}}
12592
beforeDevCommandExplination={{
126-
__html: 'Use <code>npm run dev</code> for this value.',
93+
__html:
94+
'Use <code>npm run dev</code> for this value (make sure to adapt this to use the package manager of your choice).',
12795
}}
12896
/>
12997

@@ -132,7 +100,7 @@ Now that we have scaffolded our frontend and initialized the Rust project you're
132100
```json title=src-tauri/tauri.conf.json
133101
{
134102
"build": {
135-
"beforeBuildCommand": "npm run build && npm run export",
103+
"beforeBuildCommand": "npm run build",
136104
"beforeDevCommand": "npm run dev",
137105
"devPath": "http://localhost:3000",
138106
"distDir": "../out"
@@ -154,41 +122,40 @@ To call our newly created command we will use the [`@tauri-apps/api`] JavaScript
154122

155123
<InstallTauriApi />
156124

157-
With the library installed, you can modify your `pages/index.tsx` file to call the Command:
158-
159-
```typescript title=src/pages/index.tsx
160-
import { invoke } from '@tauri-apps/api/tauri'
161-
162-
// Note: When working with Next.js in development you have 2 execution contexts:
163-
// - The server (nodejs), where Tauri cannot be reached, because the current context is inside of nodejs.
164-
// - The client (webview), where it is possible to interact with the Tauri rust backend.
165-
// To check if we are currently executing in the client context, we can check the type of the window object;
166-
const isClient = typeof window !== 'undefined'
167-
168-
// Now we can call our Command!
169-
// Right-click on the application background and open the developer tools.
170-
// You will see "Hello, World!" printed in the console.
171-
isClient &&
172-
invoke('greet', { name: 'World' }).then(console.log).catch(console.error)
173-
```
174-
175-
A better approach would be to use Tauri calls in `componentDidMount` or `useEffect` that are only run on the client-side by [Next.js].
125+
One important thing to note is that all of Tauri's JS APIs require access to browser-only APIs which means they can only be used in [Client Components]. If you don't need Server Components you can add `'use client'` at the very top of the `app/page.tsx` file, in this guide however, we will create a separate component so that we don't have to convert the whole app.
176126

177-
So to make it cleaner we should rewrite it like this:
127+
```tsx title=app/greet.tsx
128+
'use client'
178129

179-
```tsx title=src/pages/index.tsx
180-
// ...
130+
import { useEffect } from 'react'
181131
import { invoke } from '@tauri-apps/api/tauri'
182132

183-
const Greet = () => {
133+
export default function Greet() {
184134
useEffect(() => {
185-
invoke('greet', { name: 'World' }).then(console.log).catch(console.error)
135+
invoke<string>('greet', { name: 'Next.js' })
136+
.then(console.log)
137+
.catch(console.error)
186138
}, [])
139+
140+
// Necessary because we will have to use Greet as a component later.
141+
return <></>
187142
}
143+
```
144+
145+
Now we will use this component in the default `Home` component in `app/page.tsx`. Note that it must be in the actual component tree and can't be a simple function call as long as the parent (in this case the `Home` component) is a Server Component.
146+
147+
```tsx title=app/page.tsx
148+
// ...
149+
import Greet from './greet'
188150

189151
export default function Home() {
190-
Greet()
191-
// ...
152+
return (
153+
<main className="flex min-h-screen flex-col items-center justify-between p-24">
154+
// highlight-next-line
155+
<Greet />
156+
...
157+
</main>
158+
)
192159
}
193160
```
194161

@@ -207,3 +174,5 @@ If you want to know more about the communication between Rust and JavaScript, pl
207174
[`@tauri-apps/api`]: ../../../api/js/
208175
[inter-process-communication]: ../../../references/architecture/inter-process-communication/readme.md
209176
[`create-tauri-app`]: https://github.com/tauri-apps/create-tauri-app
177+
[static exports]: https://nextjs.org/docs/app/building-your-application/deploying/static-exports
178+
[client components]: https://nextjs.org/docs/getting-started/react-essentials#client-components

0 commit comments

Comments
 (0)