{"id":21466547,"url":"https://github.com/permafrost-dev/nextjs-tauri-template","last_synced_at":"2025-03-17T05:47:59.961Z","repository":{"id":176364868,"uuid":"657482459","full_name":"permafrost-dev/nextjs-tauri-template","owner":"permafrost-dev","description":"Tauri template with Next.js, Typescript \u0026 TailwindCSS","archived":false,"fork":false,"pushed_at":"2025-03-10T01:37:29.000Z","size":1882,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-10T02:33:44.305Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/permafrost-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-23T06:51:22.000Z","updated_at":"2025-03-10T01:08:41.000Z","dependencies_parsed_at":"2023-10-02T03:40:13.827Z","dependency_job_id":"ef50da88-1fdc-4108-bf63-dc723a60b2f1","html_url":"https://github.com/permafrost-dev/nextjs-tauri-template","commit_stats":null,"previous_names":["permafrost-dev/nextjs-tauri-template"],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/permafrost-dev%2Fnextjs-tauri-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/permafrost-dev%2Fnextjs-tauri-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/permafrost-dev%2Fnextjs-tauri-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/permafrost-dev%2Fnextjs-tauri-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/permafrost-dev","download_url":"https://codeload.github.com/permafrost-dev/nextjs-tauri-template/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243982136,"owners_count":20378606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-23T08:14:26.322Z","updated_at":"2025-03-17T05:47:59.942Z","avatar_url":"https://github.com/permafrost-dev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tauri, Next.js, Typescript \u0026 TailwindCSS Template\n\n![Tauri window screenshot](public/tauri-nextjs-template_screenshot.png)\n\nThis is a [Tauri](https://tauri.app/) project template using [Next.js](https://nextjs.org/),\nbootstrapped by combining [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app)\nand [`create tauri-app`](https://tauri.app/v1/guides/getting-started/setup).\n\n## Template Features\n\n-   TypeScript frontend using Next.js React framework\n-   [TailwindCSS](https://tailwindcss.com/) as a utility-first atomic CSS framework\n    -   The example page in this template app has been updated to use only TailwindCSS\n    -   The `@tailwindcss/aspect-ratio`, `@tailwindcss/forms`, and `@tailwindcss/typography` TailwindCSS plugins are installed by default.\n-   Opinionated formatting and linting already setup and enabled\n    -   [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) for frontend,\n    -   [clippy](https://github.com/rust-lang/rust-clippy) and\n    -   [rustfmt](https://github.com/rust-lang/rustfmt) for Rust code\n-   GitHub Actions to keep dependencies updated automatically\n\n## Getting Started\n\n### Running development server and use Tauri window\n\nAfter cloning for the first time, set up git pre-commit hooks:\n\n```shell\nnpm run prepare\n```\n\nTo develop and run the frontend in a Tauri window:\n\n```shell\nnpm run dev\n```\n\nThis will load the Next.js frontend directly in a Tauri webview window, in addition to\nstarting a development server on `localhost:3000`.\n\n### Building for release\n\nTo export the Next.js frontend via SSG and build the Tauri application for release:\n\n```shell\nnpm run build\n```\n\nPlease remember to change the bundle identifier in\n`tauri.conf.json \u003e tauri \u003e bundle \u003e identifier`, as the default value will yield an\nerror that prevents you from building the application for release.\n\n### Source structure\n\nNext.js frontend source files are located in `src/` and Tauri Rust application source\nfiles are located in `src-tauri/`. Please consult the Next.js and Tauri documentation\nrespectively for questions pertaining to either technology.\n\n## Caveats\n\n### Static Site Generation / Pre-rendering\n\nNext.js is a great React frontend framework which supports server-side rendering (SSR)\nas well as static site generation (SSG or pre-rendering). For the purposes of creating a\nTauri frontend, only SSG can be used since SSR requires an active Node.js server.\n\nUsing Next.js and SSG helps to provide a quick and performant single-page-application\n(SPA) frontend experience. More information regarding this can be found here:\n\u003chttps://nextjs.org/docs/basic-features/pages#pre-rendering\u003e\n\n### `next/image`\n\nThe [`next/image` component](https://nextjs.org/docs/basic-features/image-optimization)\nis an enhancement over the regular `\u003cimg\u003e` HTML element with additional optimizations\nbuilt in. However, because we are not deploying the frontend onto Vercel directly, some\noptimizations must be disabled to properly build and export the frontend via SSG.\nAs such, the\n[`unoptimized` property](https://nextjs.org/docs/api-reference/next/image#unoptimized)\nis set to true for the `next/image` component in the `next.config.js` configuration.\nThis will allow the image to be served as-is from source, without\nchanges to its quality, size, or format.\n\n### error[E0554]: `#![feature]` may not be used on the stable release channel\n\nIf you are getting this issue when trying to run `npm run dev`, it may be that you\nhave a newer version of a Rust dependency that uses an unstable feature.\n`npm run build` should still work for production builds, but to get the dev command\nworking, either downgrade the dependency or use Rust nightly via\n`rustup override set nightly`.\n\n### ReferenceError: navigator is not defined\n\nIf you are using Tauri's `invoke` function or any OS related Tauri function from within\nJavaScript, you may encounter this error when importing the function in a global,\nnon-browser context. This is due to the nature of Next.js' dev server effectively\nrunning a Node.js server for SSR and hot module replacement (HMR), and Node.js does not\nhave a notion of `window` or `navigator`.\n\n#### Solution 1 - Dependency Injection (may not always work)\n\nMake sure that you are calling these functions within the browser context, e.g. within a\nReact component inside a `useEffect` hook when the DOM actually exists by then. If you\nare trying to use a Tauri function in a generalized utility source file, a workaround is\nto use dependency injection for the function itself to delay the actual importing of the\nreal function (see example below for more info).\n\nExample using Tauri's `invoke` function:\n\n`src/lib/some_tauri_functions.ts` (problematic)\n\n```typescript\n// Generalized file containing all the invoke functions we need to fetch data from Rust\nimport { invoke } from '@tauri-apps/api/tauri';\n\nconst loadFoo = (): Promise\u003cstring\u003e =\u003e {\n    return invoke\u003cstring\u003e('invoke_handler_foo');\n};\n\nconst loadBar = (): Promise\u003cstring\u003e =\u003e {\n    return invoke\u003cstring\u003e('invoke_handler_bar');\n};\n\nconst loadBaz = (): Promise\u003cstring\u003e =\u003e {\n    return invoke\u003cstring\u003e('invoke_handler_baz');\n};\n\n// and so on ...\n```\n\n`src/lib/some_tauri_functions.ts` (fixed)\n\n```typescript\n// Generalized file containing all the invoke functions we need to fetch data from Rust\n//\n// We apply the idea of dependency injection to use a supplied invoke function as a\n// function argument, rather than directly referencing the Tauri invoke function.\n// Hence, don't import invoke globally in this file.\n//\n// import { invoke } from \"@tauri-apps/api/tauri\"  \u003c-- remove this!\n//\n\nimport { InvokeArgs } from '@tauri-apps/api/tauri';\ntype InvokeFunction = \u003cT\u003e(cmd: string, args?: InvokeArgs | undefined) =\u003e Promise\u003cT\u003e;\n\nconst loadFoo = (invoke: InvokeFunction): Promise\u003cstring\u003e =\u003e {\n    return invoke\u003cstring\u003e('invoke_handler_foo');\n};\n\nconst loadBar = (invoke: InvokeFunction): Promise\u003cstring\u003e =\u003e {\n    return invoke\u003cstring\u003e('invoke_handler_bar');\n};\n\nconst loadBaz = (invoke: InvokeFunction): Promise\u003cstring\u003e =\u003e {\n    return invoke\u003cstring\u003e('invoke_handler_baz');\n};\n\n// and so on ...\n```\n\nThen, when using `loadFoo`/`loadBar`/`loadBaz` within your React components, import the\ninvoke function from `@tauri-apps/api` and pass `invoke` into the loadXXX function as\nthe `InvokeFunction` argument. This should allow the actual Tauri API to be bundled\nonly within the context of a React component, so it should not be loaded by Next.js upon\ninitial startup until the browser has finished loading the page.\n\n#### Solution 2: Wrap Tauri API behind dynamic `import()`\n\nSince the Tauri API needs to read from the browser's `window` and `navigator` object,\nthis data does not exist in a Node.js and hence SSR environment. One can create an\nexported function that wraps the Tauri API behind a dynamic runtime `import()` call.\n\nExample: create a `src/lib/tauri.ts` to re-export `invoke`\n\n```typescript\nimport type { InvokeArgs } from '@tauri-apps/api/tauri';\n\nconst isNode = (): boolean =\u003e Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]';\n\nexport async function invoke\u003cT\u003e(cmd: string, args?: InvokeArgs | undefined): Promise\u003cT\u003e {\n    if (isNode()) {\n        // This shouldn't ever happen when React fully loads\n        return Promise.resolve(undefined as unknown as T);\n    }\n    const tauriAppsApi = await import('@tauri-apps/api');\n    const tauriInvoke = tauriAppsApi.invoke;\n    return tauriInvoke(cmd, args);\n}\n```\n\nThen, instead of importing `import { invoke } from \"@tauri-apps/api/tauri\"`, use invoke\nfrom `import { invoke } from \"@/lib/tauri\"`.\n\n## Learn More\n\nTo learn more about Next.js, take a look at the following resources:\n\n-   [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.\n-   [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.\n\nAnd to learn more about Tauri, take a look at the following resources:\n\n-   [Tauri Documentation - Guides](https://tauri.app/v1/guides/) - learn about the Tauri toolkit.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpermafrost-dev%2Fnextjs-tauri-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpermafrost-dev%2Fnextjs-tauri-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpermafrost-dev%2Fnextjs-tauri-template/lists"}