├── .docs ├── .navigation.yml ├── 0.hello-world.md ├── 1.features │ ├── 1.auto-imports.md │ ├── 2.data-fetching.md │ ├── 3.state-management.md │ ├── 4.meta-tags.md │ └── 5.layouts.md ├── 2.routing │ ├── middleware.md │ ├── pages.md │ └── universal-router.md ├── 4.advanced │ ├── config-extends.md │ ├── error-handling.md │ ├── jsx.md │ ├── locale.md │ ├── module-extend-pages.md │ ├── teleport.md │ ├── testing.md │ ├── use-cookie.md │ └── use-custom-fetch-composable.md └── 7.experimental │ └── wasm.md ├── .e2e ├── README.md ├── __snapshots__ │ └── ui │ │ ├── daisyui.spec.ts │ │ └── Matches-snapshot-visual-1.png │ │ ├── sass.spec.ts │ │ └── Matches-snapshot-visual-1.png │ │ ├── tailwindcss.spec.ts │ │ └── Matches-snapshot-visual-1.png │ │ └── vuetify.spec.ts │ │ └── Matches-snapshot-visual-1.png ├── augments.d.ts ├── package.json ├── playwright.config.ts ├── tests │ ├── advanced │ │ ├── config-extends.spec.ts │ │ ├── error-handling.spec.ts │ │ ├── jsx.spec.ts │ │ ├── locale.spec.ts │ │ ├── module-extend-pages.spec.ts │ │ └── use-cookie.spec.ts │ ├── experimental │ │ └── wasm.spec.ts │ ├── features │ │ ├── auto-imports.spec.ts │ │ ├── data-fetching.spec.ts │ │ ├── meta-tags.spec.ts │ │ └── state-management.spec.ts │ ├── hello-world.spec.ts │ ├── routing │ │ ├── middleware.spec.ts │ │ ├── pages.spec.ts │ │ └── universal-router.spec.ts │ └── ui │ │ ├── daisyui.spec.ts │ │ ├── sass.spec.ts │ │ ├── tailwindcss.spec.ts │ │ └── vuetify.spec.ts ├── tsconfig.json └── utils │ └── index.ts ├── .editorconfig ├── .github └── workflows │ ├── ci.yml │ └── playwright.yml ├── .gitignore ├── .npmrc ├── .nuxtrc ├── .scripts ├── build.mjs └── typecheck.mjs ├── .vercelignore ├── CODEOWNERS ├── LICENSE ├── README.md ├── eslint.config.mjs ├── examples ├── advanced │ ├── config-extends │ │ ├── app.config.ts │ │ ├── base │ │ │ ├── app.config.ts │ │ │ ├── components │ │ │ │ ├── BaseButton.vue │ │ │ │ └── FancyButton.vue │ │ │ ├── composables │ │ │ │ └── foo.ts │ │ │ ├── middleware │ │ │ │ └── foo.ts │ │ │ ├── nuxt.config.ts │ │ │ ├── pages │ │ │ │ └── foo.vue │ │ │ ├── plugins │ │ │ │ └── my-plugin.ts │ │ │ ├── server │ │ │ │ └── api │ │ │ │ │ └── base.ts │ │ │ └── utils │ │ │ │ └── bar.ts │ │ ├── components │ │ │ └── FancyButton.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ │ └── index.vue │ │ ├── server │ │ │ ├── api │ │ │ │ └── hello.ts │ │ │ └── tsconfig.json │ │ ├── tsconfig.json │ │ └── ui │ │ │ ├── components │ │ │ └── Button.vue │ │ │ └── nuxt.config.ts │ ├── error-handling │ │ ├── app.vue │ │ ├── components │ │ │ ├── FaultyComponent.vue │ │ │ └── ThrowError.vue │ │ ├── error.vue │ │ ├── middleware │ │ │ └── error.global.ts │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ │ ├── index.vue │ │ │ └── other.vue │ │ ├── plugins │ │ │ └── error.ts │ │ ├── server │ │ │ ├── middleware │ │ │ │ └── error.ts │ │ │ └── tsconfig.json │ │ └── tsconfig.json │ ├── jsx │ │ ├── app.vue │ │ ├── components │ │ │ └── MyComponent.tsx │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── locale │ │ ├── app.vue │ │ ├── composables │ │ │ └── locale.ts │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── module-extend-pages │ │ ├── layouts │ │ │ └── default.vue │ │ ├── modules │ │ │ └── pages │ │ │ │ ├── index.ts │ │ │ │ └── pages │ │ │ │ └── test.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ │ └── index.vue │ │ └── tsconfig.json │ ├── teleport │ │ ├── app.vue │ │ ├── components │ │ │ └── MyModal.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── testing │ │ ├── app.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── tests │ │ │ └── basic.test.ts │ │ └── tsconfig.json │ ├── use-cookie │ │ ├── app.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ └── tsconfig.json │ └── use-custom-fetch-composable │ │ ├── app.vue │ │ ├── composables │ │ └── useCustomFetch.ts │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── plugins │ │ └── customFetch.ts │ │ └── tsconfig.json ├── auth │ └── local │ │ ├── .env.example │ │ ├── .gitignore │ │ ├── .npmrc │ │ ├── README.md │ │ ├── app.vue │ │ ├── auth │ │ ├── composables │ │ │ └── auth.ts │ │ ├── nuxt.config.ts │ │ ├── plugins │ │ │ └── 0.auth.ts │ │ └── server │ │ │ ├── api │ │ │ └── auth │ │ │ │ ├── login.post.ts │ │ │ │ ├── logout.post.ts │ │ │ │ ├── register.post.ts │ │ │ │ └── session.get.ts │ │ │ └── utils │ │ │ ├── db.ts │ │ │ └── session.ts │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ ├── index.vue │ │ ├── login.vue │ │ ├── profile.vue │ │ └── secret.vue │ │ ├── server │ │ ├── api │ │ │ └── secret.ts │ │ └── tsconfig.json │ │ └── tsconfig.json ├── experimental │ └── wasm │ │ ├── app.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── server │ │ ├── api │ │ │ └── sum.ts │ │ ├── tsconfig.json │ │ └── wasm │ │ │ ├── sum.wasm │ │ │ └── sum.wat │ │ └── tsconfig.json ├── features │ ├── README.md │ ├── auto-imports │ │ ├── app.vue │ │ ├── components │ │ │ └── CustomInput.vue │ │ ├── composables │ │ │ └── hello.ts │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── utils │ │ │ └── string.ts │ ├── data-fetching │ │ ├── app.vue │ │ ├── components │ │ │ └── TheQuote.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ │ ├── component.vue │ │ │ ├── external.vue │ │ │ └── index.vue │ │ ├── server │ │ │ ├── api │ │ │ │ └── hello.ts │ │ │ └── tsconfig.json │ │ └── tsconfig.json │ ├── layouts │ │ ├── app.vue │ │ ├── layouts │ │ │ ├── custom.vue │ │ │ ├── default.vue │ │ │ └── other.vue │ │ ├── middleware │ │ │ └── other.ts │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ │ ├── custom.vue │ │ │ ├── dynamic.vue │ │ │ ├── index.vue │ │ │ └── other.vue │ │ └── tsconfig.json │ ├── meta-tags │ │ ├── app.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ │ ├── about.vue │ │ │ └── index.vue │ │ └── tsconfig.json │ └── state-management │ │ ├── app.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ └── tsconfig.json ├── hello-world │ ├── app.vue │ ├── package.json │ ├── public │ │ └── favicon.ico │ └── tsconfig.json ├── routing │ ├── middleware │ │ ├── app.vue │ │ ├── middleware │ │ │ ├── always-run.global.ts │ │ │ └── redirect-me.ts │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ │ ├── forbidden.vue │ │ │ ├── index.vue │ │ │ ├── redirect.vue │ │ │ └── secret.vue │ │ ├── plugins │ │ │ └── add.ts │ │ └── tsconfig.json │ ├── pages │ │ ├── app.vue │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── pages │ │ │ ├── about.vue │ │ │ ├── catchall │ │ │ │ └── [...id].vue │ │ │ ├── index.vue │ │ │ ├── parent.vue │ │ │ └── parent │ │ │ │ ├── b.vue │ │ │ │ ├── index.vue │ │ │ │ ├── reload-[id].vue │ │ │ │ └── static-[id].vue │ │ └── tsconfig.json │ └── universal-router │ │ ├── app.vue │ │ ├── middleware │ │ └── always-run.global.ts │ │ ├── nuxt.config.ts │ │ ├── package.json │ │ ├── plugins │ │ └── add.ts │ │ └── tsconfig.json └── ui │ ├── daisyui │ ├── app.vue │ ├── nuxt.config.ts │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── tailwind.config.js │ └── tsconfig.json │ ├── sass │ ├── app.vue │ ├── assets │ │ └── styles │ │ │ └── _colors.sass │ ├── nuxt.config.ts │ ├── package.json │ ├── pages │ │ └── index.vue │ ├── public │ │ └── favicon.ico │ └── tsconfig.json │ ├── tailwindcss │ ├── app.vue │ ├── components │ │ └── TButton.vue │ ├── nuxt.config.ts │ ├── package.json │ ├── pages │ │ ├── about.vue │ │ └── index.vue │ ├── public │ │ ├── favicon.ico │ │ └── mountains.jpg │ ├── tailwind.config.js │ └── tsconfig.json │ └── vuetify │ ├── app.vue │ ├── nuxt.config.ts │ ├── package.json │ ├── plugins │ └── vuetify.ts │ ├── public │ └── favicon.ico │ └── tsconfig.json ├── package.json ├── patches └── @nuxtjs__tailwindcss.patch ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── renovate.json ├── shared ├── README.md ├── assets │ └── main.css ├── components │ ├── Logo.vue │ └── NuxtExample.vue ├── nuxt.config.ts ├── package.json └── tsconfig.json └── turbo.json /.docs/.navigation.yml: -------------------------------------------------------------------------------- 1 | title: Examples 2 | titleTemplate: '%s · Nuxt Examples' 3 | icon: i-lucide-app-window-mac 4 | -------------------------------------------------------------------------------- /.docs/0.hello-world.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: Hello World 4 | description: 'A minimal Nuxt application only requires the `app.vue` and `nuxt.config.js` files.' 5 | --- 6 | 7 | :read-more{to="/docs/getting-started/introduction"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/hello-world" file="app.vue"} 10 | -------------------------------------------------------------------------------- /.docs/1.features/1.auto-imports.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: Auto Imports 4 | description: 'This example demonstrates the auto-imports feature in Nuxt.' 5 | --- 6 | 7 | Example of the auto-imports feature in Nuxt with: 8 | - Vue components in the `components/` directory are auto-imported and can be used directly in your templates. 9 | - Vue composables in the `composables/` directory are auto-imported and can be used directly in your templates and JS/TS files. 10 | - JS/TS variables and functions in the `utils/` directory are auto-imported and can be used directly in your templates and JS/TS files. 11 | 12 | :read-more{to="/docs/guide/directory-structure/components"} 13 | :read-more{to="/docs/guide/directory-structure/composables"} 14 | :read-more{to="/docs/guide/directory-structure/utils"} 15 | 16 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/features/auto-imports" file="app.vue"} 17 | -------------------------------------------------------------------------------- /.docs/1.features/2.data-fetching.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: Data Fetching 4 | description: 'This example demonstrates data fetching with Nuxt using built-in composables and API routes.' 5 | --- 6 | 7 | :read-more{to="/docs/getting-started/data-fetching"} 8 | :read-more{to="/docs/guide/directory-structure/server"} 9 | 10 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/features/data-fetching" file="app.vue"} 11 | -------------------------------------------------------------------------------- /.docs/1.features/3.state-management.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: State Management 4 | description: 'This example shows how to use the `useState` composable to create a reactive and SSR-friendly shared state across components.' 5 | --- 6 | 7 | :read-more{to="/docs/getting-started/state-management"} 8 | :read-more{to="/docs/api/composables/use-state"} 9 | 10 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/features/state-management" file="app.vue"} 11 | -------------------------------------------------------------------------------- /.docs/1.features/4.meta-tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: Meta Tags 4 | description: 'This example shows how to use the Nuxt helpers and composables for SEO and meta management.' 5 | --- 6 | 7 | :read-more{to="/docs/getting-started/seo-meta"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/features/meta-tags/" file="app.vue"} 10 | -------------------------------------------------------------------------------- /.docs/1.features/5.layouts.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: Layouts 4 | description: 'This example shows how to define default and custom layouts.' 5 | --- 6 | 7 | :read-more{to="/docs/getting-started/views#layouts"} 8 | :read-more{to="/docs/guide/directory-structure/layouts"} 9 | 10 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/features/layouts" file="pages/index.vue"} 11 | -------------------------------------------------------------------------------- /.docs/2.routing/middleware.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'Middleware' 4 | description: 'This example shows how to add route middleware with the middleware/ directory or with a plugin, and how to use them globally or per page.' 5 | --- 6 | 7 | :read-more{to="/docs/guide/directory-structure/middleware"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/routing/middleware" file="app.vue"} 10 | -------------------------------------------------------------------------------- /.docs/2.routing/pages.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'Pages' 4 | description: 'This example shows how to use the pages/ directory to create application routes.' 5 | --- 6 | 7 | :read-more{to="/docs/guide/directory-structure/pages"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/routing/pages" file="app.vue"} 10 | -------------------------------------------------------------------------------- /.docs/2.routing/universal-router.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'Universal Router' 4 | description: 'This example demonstrates Nuxt universal routing utilities without depending on `pages/` and `vue-router`.' 5 | --- 6 | 7 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/routing/universal-router" file="app.vue"} 8 | -------------------------------------------------------------------------------- /.docs/4.advanced/config-extends.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'Layers' 4 | description: 'This example shows how to use the extends key in `nuxt.config.ts`.' 5 | --- 6 | 7 | This example shows how to use the `extends` key in `nuxt.config.ts` to use the `base/` directory as a base Nuxt application, and use its components, composables or config and override them if necessary. 8 | 9 | :read-more{to="/docs/getting-started/layers"} 10 | 11 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/config-extends" file="nuxt.config.ts"} 12 | -------------------------------------------------------------------------------- /.docs/4.advanced/error-handling.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'Error Handling' 4 | description: 'This example shows how to handle errors in different contexts: pages, plugins, components and middleware.' 5 | --- 6 | 7 | :read-more{to="/docs/getting-started/error-handling"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/error-handling" file="app.vue"} 10 | -------------------------------------------------------------------------------- /.docs/4.advanced/jsx.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'JSX / TSX' 4 | description: 'This example shows how to use JSX syntax with typescript in Nuxt pages and components.' 5 | --- 6 | 7 | :read-more{icon="i-simple-icons-vuedotjs" to="https://vuejs.org/guide/extras/render-function.html#jsx-tsx" target="_blank"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/jsx" file="app.vue"} 10 | -------------------------------------------------------------------------------- /.docs/4.advanced/locale.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'Locale' 4 | description: "This example shows how to define a locale composable to handle the application's locale, both server and client side." 5 | --- 6 | 7 | ::callout{icon="i-ph-info-duotone"} 8 | You can right-click to "View Page Source" and see that Nuxt renders the correct date in SSR based on the visitor's locale. 9 | :: 10 | 11 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/locale" file="app.vue"} 12 | -------------------------------------------------------------------------------- /.docs/4.advanced/module-extend-pages.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'Module Extend Pages' 4 | description: 'This example defines a new `test` page using `extendPages` within a module.' 5 | --- 6 | 7 | :read-more{to="/docs/guide/going-further/modules"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/module-extend-pages" file="pages/index.vue"} 10 | -------------------------------------------------------------------------------- /.docs/4.advanced/teleport.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: Teleport 4 | description: 'This example shows how to use the with client-side and server-side rendering.' 5 | --- 6 | 7 | Vue 3 provides the [`` component](https://vuejs.org/guide/built-ins/teleport.html) which allows content to be rendered elsewhere in the DOM, outside of the Vue application. 8 | 9 | This example shows how to use the `` with client-side and server-side rendering. 10 | 11 | :read-more{to="/docs/api/components/teleports"} 12 | 13 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/teleport" file="app.vue"} 14 | -------------------------------------------------------------------------------- /.docs/4.advanced/testing.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: Testing 4 | description: 'This example shows how to test your Nuxt application.' 5 | --- 6 | 7 | :read-more{to="/docs/getting-started/testing"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/testing" file="app.vue"} 10 | -------------------------------------------------------------------------------- /.docs/4.advanced/use-cookie.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'useCookie' 4 | description: 'This example shows how to use the useCookie API to persist small amounts of data that both client and server can use.' 5 | --- 6 | 7 | :read-more{to="/docs/api/composables/use-cookie"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/use-cookie" file="app.vue"} 10 | -------------------------------------------------------------------------------- /.docs/4.advanced/use-custom-fetch-composable.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'Use Custom Fetch Composable' 4 | description: 'This example shows a convenient wrapper for the useFetch composable from nuxt. It allows you to customize the fetch request with default values and user authentication token.' 5 | --- 6 | 7 | :read-more{to="/docs/guide/recipes/custom-usefetch"} 8 | 9 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/advanced/use-custom-fetch-composable" file="composables/useCustomFetch.ts"} 10 | -------------------------------------------------------------------------------- /.docs/7.experimental/wasm.md: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: 'WASM' 4 | description: 'This example demonstrates the server-side support of WebAssembly in Nuxt.' 5 | --- 6 | 7 | :sandbox{repo="nuxt/examples" branch="main" dir="examples/experimental/wasm" file="app.vue"} 8 | -------------------------------------------------------------------------------- /.e2e/README.md: -------------------------------------------------------------------------------- 1 | # Nuxt Example's E2E Tests 2 | 3 | This project contains the end-to-end tests for the examples in the repository. 4 | 5 | ## Getting Started 6 | 7 | Install the dependencies if you haven't already in the project root: 8 | 9 | ```sh 10 | pnpm install 11 | ``` 12 | 13 | ## Commands 14 | 15 | Running non-visual tests (recommended during development): 16 | 17 | ```sh 18 | pnpm -F e2e test 19 | ``` 20 | 21 | Running [visual regression tests](https://playwright.dev/docs/test-snapshots): 22 | 23 | ```sh 24 | pnpm -F e2e test:visual 25 | ``` 26 | 27 | Updating snapshots for visual regression tests: 28 | 29 | ```sh 30 | pnpm -F e2e test:visual:update-snapshots 31 | ``` 32 | 33 | Running every test: 34 | 35 | ```sh 36 | pnpm -F e2e test:all 37 | ``` 38 | 39 | Opening the [code generator](https://playwright.dev/docs/codegen-intro#running-codegen): 40 | 41 | ```sh 42 | pnpm -F e2e codegen 43 | ``` 44 | 45 | Starting in [UI mode](https://playwright.dev/docs/test-ui-mode): 46 | 47 | ```sh 48 | pnpm -F e2e ui 49 | ``` 50 | 51 | ## Note for Windows Users 52 | 53 | Windows users shouldn't run visual regression tests directly, because the CI uses ubuntu and different operating systems has different font loading behavior. 54 | 55 | In case you want to run these tests, you should use a docker image: 56 | 57 | ```ps 58 | docker run --rm --network host -v $(pwd):/work/ -w /work/ -it node:20-bookworm /bin/bash 59 | cd .e2e 60 | npm install 61 | 62 | # just running the tests 63 | npx run test:visual 64 | 65 | # updating snapshots 66 | npx run test:visual:update-snapshots 67 | ``` 68 | 69 | See: [official docs for visual testing](https://playwright.dev/docs/test-snapshots) 70 | -------------------------------------------------------------------------------- /.e2e/__snapshots__/ui/daisyui.spec.ts/Matches-snapshot-visual-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/.e2e/__snapshots__/ui/daisyui.spec.ts/Matches-snapshot-visual-1.png -------------------------------------------------------------------------------- /.e2e/__snapshots__/ui/sass.spec.ts/Matches-snapshot-visual-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/.e2e/__snapshots__/ui/sass.spec.ts/Matches-snapshot-visual-1.png -------------------------------------------------------------------------------- /.e2e/__snapshots__/ui/tailwindcss.spec.ts/Matches-snapshot-visual-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/.e2e/__snapshots__/ui/tailwindcss.spec.ts/Matches-snapshot-visual-1.png -------------------------------------------------------------------------------- /.e2e/__snapshots__/ui/vuetify.spec.ts/Matches-snapshot-visual-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/.e2e/__snapshots__/ui/vuetify.spec.ts/Matches-snapshot-visual-1.png -------------------------------------------------------------------------------- /.e2e/augments.d.ts: -------------------------------------------------------------------------------- 1 | import type { useNuxtApp } from 'nuxt/app' 2 | 3 | declare global { 4 | interface Window { 5 | useNuxtApp?: typeof useNuxtApp 6 | } 7 | } 8 | 9 | export {} 10 | -------------------------------------------------------------------------------- /.e2e/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2e", 3 | "scripts": { 4 | "test": "playwright test --grep-invert @visual", 5 | "test:all": "playwright test", 6 | "test:visual": "playwright test --grep @visual", 7 | "test:visual:update-snapshots": "playwright test --grep @visual --update-snapshots", 8 | "codegen": "playwright codegen", 9 | "ui": "playwright test --ui" 10 | }, 11 | "devDependencies": { 12 | "@playwright/test": "1.52.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.e2e/playwright.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, devices } from '@playwright/test' 2 | 3 | /** 4 | * See https://playwright.dev/docs/test-configuration. 5 | */ 6 | export default defineConfig({ 7 | testDir: './tests', 8 | fullyParallel: true, 9 | forbidOnly: !!process.env.CI, 10 | retries: process.env.CI ? 3 : 1, 11 | workers: process.env.CI ? 1 : undefined, 12 | reporter: [['html', { open: 'never' }]], 13 | snapshotPathTemplate: '{testDir}/../__snapshots__/{testFilePath}/{arg}{ext}', 14 | use: { 15 | trace: 'on-first-retry', 16 | screenshot: 'only-on-failure', 17 | }, 18 | expect: { 19 | toHaveScreenshot: { 20 | maxDiffPixelRatio: 0.05, 21 | }, 22 | }, 23 | projects: [ 24 | { 25 | name: 'chromium', 26 | use: { ...devices['Desktop Chrome'] }, 27 | }, 28 | ], 29 | }) 30 | -------------------------------------------------------------------------------- /.e2e/tests/advanced/config-extends.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('config-extends')) 5 | 6 | test('App config merged', async ({ page }) => { 7 | // TODO need a unique locator 8 | await page.goto('/') 9 | await expect( 10 | page.getByText( 11 | '"bar": "user", "baz": "base", "array": [ "user", "user", "user" ], "arrayNested": { "nested": { "array": [ "base", "base", "base" ] } }, "foo": "user" }', 12 | ), 13 | ).toBeVisible() 14 | }) 15 | 16 | test.fixme('Runtime config is shown', async () => { 17 | // TODO it is not shown 18 | }) 19 | 20 | test('Base button is shown', async ({ page }) => { 21 | await page.goto('/') 22 | await expect( 23 | page.getByRole('button', { name: 'Base Button' }), 24 | ).toHaveAttribute('role', 'button') 25 | }) 26 | 27 | test('Fancy button from base layer is overridden', async ({ page }) => { 28 | await page.goto('/') 29 | await expect(page.getByRole('button', { name: 'Fancy Button' })).toHaveClass( 30 | 'border p-2 fancy-button', 31 | ) 32 | }) 33 | 34 | test('UI button is shown', async ({ page }) => { 35 | await page.goto('/') 36 | await expect(page.getByRole('button', { name: 'UI Button' })).toBeVisible() 37 | }) 38 | 39 | test('"useFoo()" composable and "getBar()" util is usable from base layer', async ({ 40 | page, 41 | }) => { 42 | await page.goto('/') 43 | await expect(page.getByText('foo bar')).toBeVisible() 44 | }) 45 | 46 | test('Plugin from base layer is registered', async ({ page }) => { 47 | await page.goto('/') 48 | await expect( 49 | page.getByText('String generated from my auto-imported plugin!'), 50 | ).toBeVisible() 51 | }) 52 | 53 | test('"api/hello" endpoint works', async ({ page }) => { 54 | await page.goto('/api/hello') 55 | await expect(page.getByText('hello')).toBeVisible() 56 | }) 57 | 58 | test('"api/base" endpoint works', async ({ page }) => { 59 | await page.goto('/api/base') 60 | await expect(page.getByText('base')).toBeVisible() 61 | }) 62 | 63 | test('page inherited from base layer loads', async ({ page }) => { 64 | await page.goto('/foo') 65 | await expect(page.getByText('Hello from extended page !')).toBeVisible() 66 | }) 67 | 68 | test('Middleware for inherited page loads', async ({ page }) => { 69 | const inheritedMiddlewareLoggedPromise = page.waitForEvent('console', { 70 | predicate: message => 71 | message.text() === 'Hello from extended middleware !', 72 | }) 73 | 74 | await page.goto('/foo') 75 | await inheritedMiddlewareLoggedPromise 76 | }) 77 | -------------------------------------------------------------------------------- /.e2e/tests/advanced/error-handling.spec.ts: -------------------------------------------------------------------------------- 1 | import type { Page } from '@playwright/test' 2 | import { test, expect } from '@playwright/test' 3 | import { getSettingsForDeployment } from '@/utils' 4 | 5 | test.use(getSettingsForDeployment('error-handling')) 6 | 7 | test('Home page loads without any errors', async ({ page }) => { 8 | await page.goto('/') 9 | await expect(page.getByText('Current route: /')).toBeVisible() 10 | }) 11 | 12 | test('Error in setup() runs the global error handler and vue:error hook', async ({ 13 | page, 14 | }) => { 15 | const globalErrorHandlerPromise = waitForGlobalErrorHandlerToRan(page) 16 | const vueErrorHookPromise = waitForVueErrorHookToRan(page) 17 | 18 | await page.goto('?setup') 19 | 20 | await globalErrorHandlerPromise 21 | await vueErrorHookPromise 22 | }) 23 | 24 | test('Error in mounted() runs the global error handler and vue:error hook', async ({ 25 | page, 26 | }) => { 27 | const globalErrorHandlerPromise = waitForGlobalErrorHandlerToRan(page) 28 | const vueErrorHookPromise = waitForVueErrorHookToRan(page) 29 | 30 | await page.goto('?mounted') 31 | 32 | await globalErrorHandlerPromise 33 | await vueErrorHookPromise 34 | }) 35 | 36 | test('404 error triggers app:error hook and navigates to the error page', async ({ 37 | page, 38 | }) => { 39 | await page.goto('/') 40 | 41 | const appErrorHookPromise = waitForAppErrorHookToRan(page) 42 | await page.getByRole('link', { name: '404' }).click() 43 | await appErrorHookPromise 44 | 45 | await expect( 46 | page.getByRole('heading', { name: 'Page not found: /404' }), 47 | ).toBeVisible() 48 | await expect(page.getByText('There was an error')).toBeVisible() 49 | }) 50 | 51 | test('Clearing the error on the 404 page navigates home', async ({ page }) => { 52 | await page.goto('/404') 53 | 54 | await page.getByRole('button', { name: 'Clear error' }).click() 55 | 56 | await expect(page.getByRole('link', { name: 'Home' })).toBeVisible() 57 | }) 58 | 59 | test('Clicking on "Navigate home" on the 404 page navigates home', async ({ 60 | page, 61 | }) => { 62 | await page.goto('/404') 63 | 64 | await page.getByRole('link', { name: 'Navigate home' }).click() 65 | 66 | await expect(page.getByRole('link', { name: 'Home' })).toBeVisible() 67 | }) 68 | 69 | test('Error in middleware navigates to the error page and triggers the app:error hook', async ({ 70 | page, 71 | }) => { 72 | await page.goto('/') 73 | 74 | const appErrorHookPromise = waitForAppErrorHookToRan(page) 75 | await page.getByRole('link', { name: 'Middleware' }).click() 76 | await appErrorHookPromise 77 | 78 | await expect( 79 | page.getByRole('heading', { name: 'error in middleware' }), 80 | ).toBeVisible() 81 | await expect(page.getByText('There was an error')).toBeVisible() 82 | }) 83 | 84 | test('Clicking on the "Trigger fatal error" button navigates to the error page and triggers the app:error hook', async ({ 85 | page, 86 | }) => { 87 | await page.goto('/') 88 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 89 | 90 | const appErrorHookPromise = waitForAppErrorHookToRan(page) 91 | await page.getByRole('button', { name: 'Trigger fatal error' }).click() 92 | await appErrorHookPromise 93 | 94 | await expect(page.getByText('There was an error')).toBeVisible() 95 | }) 96 | 97 | test('Triggering non-fatal error with button runs the global error handler and vue:error hook', async ({ 98 | page, 99 | }) => { 100 | await page.goto('/') 101 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 102 | 103 | const globalErrorHandlerPromise = waitForGlobalErrorHandlerToRan(page) 104 | const vueErrorHookPromise = waitForVueErrorHookToRan(page) 105 | 106 | await page.getByRole('button', { name: 'Trigger non-fatal error' }).click() 107 | await globalErrorHandlerPromise 108 | await vueErrorHookPromise 109 | }) 110 | 111 | function waitForGlobalErrorHandlerToRan(page: Page) { 112 | return page.waitForEvent('console', { 113 | predicate: message => message.text() === 'global error handler', 114 | }) 115 | } 116 | 117 | function waitForVueErrorHookToRan(page: Page) { 118 | return page.waitForEvent('console', { 119 | predicate: message => message.text() === 'vue:error', 120 | }) 121 | } 122 | 123 | function waitForAppErrorHookToRan(page: Page) { 124 | return page.waitForEvent('console', { 125 | predicate: message => message.text() === 'app:error', 126 | }) 127 | } 128 | -------------------------------------------------------------------------------- /.e2e/tests/advanced/jsx.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('jsx')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | }) 8 | 9 | test('Inline components load', async ({ page }) => { 10 | await expect(page.getByText('Nuxt 3')).toBeVisible() 11 | }) 12 | 13 | test('JSX component from "component" folder loads', async ({ page }) => { 14 | await expect( 15 | page.getByText('This is an external JSX component'), 16 | ).toBeVisible() 17 | }) 18 | -------------------------------------------------------------------------------- /.e2e/tests/advanced/locale.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('locale')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 8 | }) 9 | 10 | test.describe('British Locale', () => { 11 | test.use({ 12 | locale: 'en-GB', 13 | }) 14 | 15 | test('Date is in british format', async ({ page }) => { 16 | await expect(page.getByText('Wednesday 26 October 2016')).toBeVisible() 17 | }) 18 | 19 | test('British locale has been selected', async ({ page }) => { 20 | await expect(page.getByRole('combobox')).toHaveText('en-GB') 21 | }) 22 | 23 | test('Changing locales works', async ({ page }) => { 24 | await page.getByRole('combobox').click() 25 | await page.getByRole('option', { name: 'ko-KR' }).click() 26 | await expect(page.getByText('2016년 10월 26일 수요일')).toBeVisible() 27 | 28 | await page.getByRole('combobox').click() 29 | await page.getByRole('option', { name: 'fa-IR' }).click() 30 | await expect(page.getByText('۱۳۹۵ آبان ۵, چهارشنبه')).toBeVisible() 31 | }) 32 | }) 33 | 34 | test.describe('US Locale', () => { 35 | test.use({ 36 | locale: 'en-US', 37 | }) 38 | 39 | test('Date is in US format', async ({ page }) => { 40 | await expect(page.getByText('Wednesday, October 26, 2016')).toBeVisible() 41 | }) 42 | 43 | test('US locale has been selected', async ({ page }) => { 44 | await expect(page.getByRole('combobox')).toHaveText('en-US') 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /.e2e/tests/advanced/module-extend-pages.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('module-extend-pages')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 8 | }) 9 | 10 | test('Page that has been added by a module works', async ({ page }) => { 11 | await page.getByRole('link', { name: 'Test Page' }).click() 12 | await expect(page.getByText('Test page added by module')).toBeVisible() 13 | 14 | await page.getByRole('link', { name: 'Homepage' }).click() 15 | await expect(page.getByText('Go to Test Page')).toBeVisible() 16 | }) 17 | -------------------------------------------------------------------------------- /.e2e/tests/advanced/use-cookie.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { addCookies, addForcedCookie, getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('use-cookie')) 5 | 6 | test('Login screen shows by default', async ({ page }) => { 7 | await page.goto('/') 8 | await expect(page.getByRole('heading', { name: 'Login' })).toBeVisible() 9 | }) 10 | 11 | test('Logging in multiple times increases counter', async ({ page }) => { 12 | await page.goto('/') 13 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 14 | 15 | await page.getByPlaceholder('Enter your name...').fill('Nuxt') 16 | await page.getByRole('button', { name: 'Log in' }).click() 17 | 18 | await expect(page.getByText('You have logged in 1 times!')).toBeVisible() 19 | await page.getByRole('button', { name: 'Log out' }).click() 20 | 21 | await page.getByPlaceholder('Enter your name...').press('Control+a') 22 | await page.getByPlaceholder('Enter your name...').fill('Nuxt') 23 | await page.getByRole('button', { name: 'Log in' }).click() 24 | 25 | await expect(page.getByText('You have logged in 2 times!')).toBeVisible() 26 | await page.getByRole('button', { name: 'Log out' }).click() 27 | 28 | await page.getByPlaceholder('Enter your name...').press('Control+a') 29 | await page.getByPlaceholder('Enter your name...').fill('Nuxt') 30 | await page.getByRole('button', { name: 'Log in' }).click() 31 | 32 | await expect(page.getByText('You have logged in 3 times!')).toBeVisible() 33 | }) 34 | 35 | test('Automatic login with existing cookies', async ({ context, page }) => { 36 | await addCookies(context, 'use-cookie', [ 37 | { 38 | name: 'user', 39 | value: '{"name":"Nuxt"}', 40 | }, 41 | { 42 | name: 'logins', 43 | value: '1', 44 | }, 45 | ]) 46 | 47 | await page.goto('/') 48 | 49 | await expect(page.getByRole('heading', { name: 'Welcome, Nuxt! 👋' })).toBeVisible() 50 | await expect(page.getByText('You have logged in 1 times!')).toBeVisible() 51 | }) 52 | 53 | test('Clearing cookies resets the timer', async ({ context, page }) => { 54 | await page.goto('/') 55 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 56 | 57 | await page.getByPlaceholder('Enter your name...').fill('Nuxt') 58 | await page.getByRole('button', { name: 'Log in' }).click() 59 | await expect(page.getByText('You have logged in 1 times!')).toBeVisible() 60 | await page.getByRole('button', { name: 'Log out' }).click() 61 | 62 | await context.clearCookies() 63 | await addForcedCookie(context, 'use-cookie') 64 | await page.reload({ waitUntil: 'load' }) 65 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 66 | 67 | await page.getByPlaceholder('Enter your name...').fill('Nuxt') 68 | await page.getByRole('button', { name: 'Log in' }).click() 69 | await expect(page.getByText('You have logged in 1 times!')).toBeVisible() 70 | }) 71 | -------------------------------------------------------------------------------- /.e2e/tests/experimental/wasm.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('wasm')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | }) 8 | 9 | test('Sum is correctly calculated', async ({ page }) => { 10 | await expect(page.getByText('a = 100')).toBeVisible() 11 | await expect(page.getByText('b = 250')).toBeVisible() 12 | await expect(page.getByText('100 + 250 = 350')).toBeVisible() 13 | }) 14 | -------------------------------------------------------------------------------- /.e2e/tests/features/auto-imports.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('auto-imports')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 8 | }) 9 | 10 | test('Heading is visible', async ({ page }) => { 11 | await expect( 12 | page.getByRole('heading', { name: 'Demo with auto imports' }), 13 | ).toBeVisible() 14 | }) 15 | 16 | test('Alert shows "Hello NUXT!" without editing the input', async ({ 17 | page, 18 | }) => { 19 | page.once('dialog', (dialog) => { 20 | expect(dialog.message()).toBe('Hello NUXT!') 21 | dialog.dismiss() 22 | }) 23 | await page.getByRole('button', { name: 'Hello' }).click() 24 | }) 25 | 26 | test('Alert shows the right message when the input has been edited', async ({ 27 | page, 28 | }) => { 29 | await page.getByRole('textbox').fill('Test') 30 | page.once('dialog', (dialog) => { 31 | expect(dialog.message()).toBe('Hello TEST!') 32 | dialog.dismiss() 33 | }) 34 | await page.getByRole('button', { name: 'Hello' }).click() 35 | }) 36 | -------------------------------------------------------------------------------- /.e2e/tests/features/data-fetching.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('data-fetching')) 5 | 6 | test.describe('Index page', () => { 7 | test('Hello world is shown on the index page', async ({ page }) => { 8 | await page.goto('/') 9 | await expect(page.getByText('Result of /api/hello:')).toBeVisible() 10 | await expect(page.getByText('{ "hello": "world" }')).toBeVisible() 11 | }) 12 | }) 13 | 14 | test.describe('External page', () => { 15 | test('Visiting "External Page" from index shows item with ID: 1', async ({ 16 | page, 17 | }) => { 18 | await page.goto('/') 19 | await page.getByRole('link', { name: 'External' }).click() 20 | 21 | await expect(page.getByRole('spinbutton')).toHaveValue('1') 22 | await expect(page.getByText('"id": 1')).toBeVisible() 23 | }) 24 | 25 | test('Visiting "External Page" directly shows item with ID: 1', async ({ 26 | page, 27 | }) => { 28 | await page.goto('/external') 29 | 30 | await expect(page.getByRole('spinbutton')).toHaveValue('1') 31 | await expect(page.getByText('"id": 1')).toBeVisible() 32 | }) 33 | }) 34 | 35 | test.describe('Component page', () => { 36 | test('Visiting "Component Page" from index shows the first quote', async ({ 37 | page, 38 | }) => { 39 | await page.goto('/') 40 | await page.getByRole('link', { name: 'Component' }).click() 41 | 42 | await expect( 43 | page.getByText( 44 | 'Your heart is the size of an ocean. Go find yourself in its hidden depths.', 45 | ), 46 | ).toBeVisible() 47 | await expect(page.getByText('Rumi')).toBeVisible() 48 | }) 49 | 50 | test('Visiting "Component Page" directly shows the first quote', async ({ 51 | page, 52 | }) => { 53 | await page.goto('/component') 54 | 55 | await expect( 56 | page.getByText( 57 | 'Your heart is the size of an ocean. Go find yourself in its hidden depths.', 58 | ), 59 | ).toBeVisible() 60 | await expect(page.getByText('Rumi')).toBeVisible() 61 | }) 62 | }) 63 | -------------------------------------------------------------------------------- /.e2e/tests/features/meta-tags.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('meta-tags')) 5 | 6 | const INDEX_LANG = 'en' 7 | const INDEX_DEFAULT_TITLE = 'Lucky number: 1 - Meta Tags Example' 8 | const INDEX_DEFAULT_DESCRIPTION = 'My page\'s 1 description' 9 | const ABOUT_PAGE_TITLE = 'About page - Meta Tags Example' 10 | const ABOUT_PAGE_DESCRIPTION = 'This is the about page' 11 | 12 | test.describe('Index page', () => { 13 | test.beforeEach(async ({ page }) => { 14 | await page.goto('/') 15 | }) 16 | 17 | test('HTML lang on index page is \'en\'', async ({ page }) => { 18 | await expect(page.locator('html')).toHaveAttribute('lang', INDEX_LANG) 19 | }) 20 | 21 | test('Index page has \'my-body-class\' CSS class', async ({ page }) => { 22 | await expect(page.locator('body.my-body-class')).toBeVisible() 23 | }) 24 | 25 | test('Lucky number is initially 1 in the title and description', async ({ 26 | page, 27 | }) => { 28 | await expect(page.locator('meta[name="description"]')).toHaveAttribute( 29 | 'content', 30 | INDEX_DEFAULT_DESCRIPTION, 31 | ) 32 | await expect(page).toHaveTitle(INDEX_DEFAULT_TITLE) 33 | }) 34 | }) 35 | 36 | test.describe('About page', () => { 37 | test.beforeEach(async ({ page }) => { 38 | await page.goto('/about') 39 | }) 40 | 41 | test('\'my-body-class\' CSS class is not present on the body', async ({ 42 | page, 43 | }) => { 44 | await expect(page.locator('body.my-body-class')).not.toBeVisible() 45 | await expect(page.locator('body')).toBeVisible() 46 | }) 47 | 48 | test('Title and description is set', async ({ page }) => { 49 | await expect(page.locator('meta[name="description"]')).toHaveAttribute( 50 | 'content', 51 | ABOUT_PAGE_DESCRIPTION, 52 | ) 53 | await expect(page).toHaveTitle(ABOUT_PAGE_TITLE) 54 | }) 55 | }) 56 | 57 | test.describe('Moving from index to about, and back to the index page', () => { 58 | test('HTML lang attribute changes', async ({ page }) => { 59 | await page.goto('/') 60 | await expect(page.locator('html')).toHaveAttribute('lang', INDEX_LANG) 61 | 62 | await page.getByRole('link', { name: 'About page' }).click() 63 | await expect(page.locator('html')).not.toHaveAttribute('lang', INDEX_LANG) 64 | 65 | await page.getByRole('link', { name: 'Back home' }).click() 66 | await expect(page.locator('html')).toHaveAttribute('lang', INDEX_LANG) 67 | }) 68 | 69 | test('\'my-body-class\' CSS class removed then added back', async ({ 70 | page, 71 | }) => { 72 | await page.goto('/') 73 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 74 | await expect(page.locator('body.my-body-class')).toBeVisible() 75 | 76 | await page.getByRole('link', { name: 'About page' }).click() 77 | await expect(page.locator('body.my-body-class')).not.toBeVisible() 78 | await expect(page.locator('body')).toBeVisible() 79 | 80 | await page.getByRole('link', { name: 'Back home' }).click() 81 | await expect(page.locator('body.my-body-class')).toBeVisible() 82 | }) 83 | 84 | test('Title and description changes', async ({ page }) => { 85 | await page.goto('/') 86 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 87 | await expect(page.locator('meta[name="description"]')).toHaveAttribute( 88 | 'content', 89 | INDEX_DEFAULT_DESCRIPTION, 90 | ) 91 | await expect(page).toHaveTitle(INDEX_DEFAULT_TITLE) 92 | 93 | await page.getByRole('link', { name: 'About page' }).click() 94 | await expect(page.locator('meta[name="description"]')).toHaveAttribute( 95 | 'content', 96 | ABOUT_PAGE_DESCRIPTION, 97 | ) 98 | await expect(page).toHaveTitle(ABOUT_PAGE_TITLE) 99 | 100 | await page.getByRole('link', { name: 'Back home' }).click() 101 | await expect(page.locator('meta[name="description"]')).toHaveAttribute( 102 | 'content', 103 | INDEX_DEFAULT_DESCRIPTION, 104 | ) 105 | await expect(page).toHaveTitle(INDEX_DEFAULT_TITLE) 106 | }) 107 | }) 108 | -------------------------------------------------------------------------------- /.e2e/tests/features/state-management.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, type Page } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('state-management')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 8 | }) 9 | 10 | test('Same value is displayed on load for both counters', async ({ page }) => { 11 | const counterValue = await getCounterValue(page) 12 | await expect(page.getByText(`Counter: ${counterValue}`)).toHaveCount(2) 13 | }) 14 | 15 | test('Clicking on "-" decrements both counters', async ({ page }) => { 16 | const counterValue = await getCounterValue(page) 17 | await page.getByRole('button', { name: '-' }).click() 18 | await page.getByText(`Counter: ${counterValue - 1}`).first().isVisible() 19 | await expect(page.getByText(`Counter: ${counterValue - 1}`)).toHaveCount(2) 20 | }) 21 | 22 | test('Clicking on "+" increments both counters', async ({ page }) => { 23 | const counterValue = await getCounterValue(page) 24 | await page.getByRole('button', { name: '+' }).click() 25 | await page.getByText(`Counter: ${counterValue + 1}`).first().isVisible() 26 | await expect(page.getByText(`Counter: ${counterValue + 1}`)).toHaveCount(2) 27 | }) 28 | 29 | async function getCounterValue(page: Page) { 30 | const sameCounterText = await page.getByText('Same Counter:').textContent() 31 | return Number(sameCounterText.split(':').at(-1).trim()) 32 | } 33 | -------------------------------------------------------------------------------- /.e2e/tests/hello-world.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('hello-world')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | }) 8 | 9 | test('"Hello Nuxt 3!" is visible', async ({ page }) => { 10 | await expect(page.getByText('Hello Nuxt 3!')).toBeVisible() 11 | }) 12 | -------------------------------------------------------------------------------- /.e2e/tests/routing/middleware.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { addForcedCookie, getSettingsForDeployment, wait } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('middleware')) 5 | 6 | test('Global middleware is being registered', async ({ page }) => { 7 | const globalMiddlewareMessageLoggedPromise = page.waitForEvent('console', { 8 | predicate: message => message.text() === 'running global middleware', 9 | }) 10 | 11 | await page.goto('/') 12 | await globalMiddlewareMessageLoggedPromise 13 | await expect(page.getByText('Current route: /', { exact: true })).toBeVisible() 14 | }) 15 | 16 | test('Global middleware from plugin is being registered', async ({ page }) => { 17 | const globalMiddlewareMessageLoggedPromise = page.waitForEvent('console', { 18 | predicate: message => 19 | message.text() === 'this global middleware was added in a plugin', 20 | }) 21 | 22 | await page.goto('/') 23 | await globalMiddlewareMessageLoggedPromise 24 | await expect(page.getByText('Current route: /', { exact: true })).toBeVisible() 25 | }) 26 | 27 | test('Inline middleware on the "forbidden" page cancels navigation', async ({ 28 | page, 29 | }) => { 30 | await page.goto('/') 31 | 32 | const strictlyForbiddenLoggedPromise = page.waitForEvent('console', { 33 | predicate: message => message.text() === 'Strictly forbidden.', 34 | }) 35 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 36 | await page.getByRole('link', { name: 'Forbidden' }).click() 37 | await strictlyForbiddenLoggedPromise 38 | await wait(500) 39 | 40 | await expect(page.getByText('Current route: /', { exact: true })).toBeVisible() 41 | }) 42 | 43 | test('Middleware redirects from the "/redirect" page to the "/secret" page', async ({ page, context }) => { 44 | await addForcedCookie(context, 'middleware') 45 | await page.goto('/redirect') 46 | await expect(page.getByText('You should never see this page')).toBeHidden() 47 | await expect(page).toHaveURL('/secret') 48 | }) 49 | 50 | test('Named middleware is registered on the secret page', async ({ page }) => { 51 | const namedMiddlewareLoggedPromise = page.waitForEvent('console', { 52 | predicate: message => 53 | message.text() === 'this named middleware was added in a plugin', 54 | }) 55 | 56 | await page.goto('/secret') 57 | await namedMiddlewareLoggedPromise 58 | await expect(page.getByText('You\'ve landed on a page that wasn\'t in the menu!')).toBeVisible() 59 | }) 60 | -------------------------------------------------------------------------------- /.e2e/tests/routing/pages.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('pages')) 5 | 6 | test.describe('Linked pages', () => { 7 | test.beforeEach(async ({ page }) => { 8 | await page.goto('/') 9 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 10 | }) 11 | 12 | test('Home page is shown', async ({ page }) => { 13 | await expect(page.getByText('Home').nth(1)).toBeVisible() 14 | await expect(page.getByText('Current route: /')).toBeVisible() 15 | }) 16 | 17 | test('Navigating to "About" page', async ({ page }) => { 18 | await page.getByRole('link', { name: 'About' }).click() 19 | await expect(page.getByText('About').nth(1)).toBeVisible() 20 | await expect(page.getByText('Current route: /about')).toBeVisible() 21 | }) 22 | 23 | test('Navigating to "Parent/index" page', async ({ page }) => { 24 | await page.getByRole('link', { name: 'Parent (index)' }).click() 25 | await expect(page.getByText('Parent Parent/index')).toBeVisible() 26 | await expect(page.getByText('Current route: /parent')).toBeVisible() 27 | }) 28 | 29 | test('Navigating to "Parent/b" page', async ({ page }) => { 30 | await page.getByRole('link', { name: 'Parent (b)' }).click() 31 | await expect(page.getByText('Parent Parent/b')).toBeVisible() 32 | await expect(page.getByText('Current route: /parent/b')).toBeVisible() 33 | }) 34 | 35 | test('Navigating to keyed child page', async ({ page }) => { 36 | await page.getByRole('button', { name: 'Keyed child', exact: true }).click() 37 | await expect(page.getByText('Child reloaded: 1')).toBeVisible() 38 | await expect(page.getByText('Current route: /parent/reload-')).toBeVisible() 39 | }) 40 | 41 | test('Navigating to keyed child with different path param increases counter', async ({ 42 | page, 43 | }) => { 44 | await page.getByRole('button', { name: 'Keyed child', exact: true }).click() 45 | await expect(page.getByText('Child reloaded: 1')).toBeVisible() 46 | 47 | await page.getByRole('button', { name: 'Keyed child', exact: true }).click() 48 | await expect(page.getByText('Child reloaded: 2')).toBeVisible() 49 | }) 50 | 51 | test('Navigating to non-keyed child child page', async ({ page }) => { 52 | await page.getByRole('button', { name: 'Non-Keyed child' }).click() 53 | await expect(page.getByText('Child reloaded: 1')).toBeVisible() 54 | await expect(page.getByText('Current route: /parent/static-')).toBeVisible() 55 | }) 56 | 57 | test('Navigating to non-keyed child child with different path param does not increases counter', async ({ 58 | page, 59 | }) => { 60 | await page.getByRole('button', { name: 'Non-Keyed child' }).click() 61 | await expect(page.getByText('Child reloaded: 1')).toBeVisible() 62 | 63 | await page.getByRole('button', { name: 'Non-Keyed child' }).click() 64 | await expect(page.getByText('Child reloaded: 1')).toBeVisible() 65 | }) 66 | }) 67 | 68 | test('Navigating to catchall route', async ({ page }) => { 69 | await page.goto('/catchall/1') 70 | await expect(page.getByText('test-[ "1" ]')).toBeVisible() 71 | await expect(page.getByText('Current route: /catchall/1')).toBeVisible() 72 | }) 73 | -------------------------------------------------------------------------------- /.e2e/tests/routing/universal-router.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { addForcedCookie, getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('universal-router')) 5 | 6 | test('Global middleware is being registered', async ({ page }) => { 7 | const globalMiddlewareMessageLoggedPromise = page.waitForEvent('console', { 8 | predicate: message => message.text() === 'running global middleware', 9 | }) 10 | 11 | await page.goto('/') 12 | await globalMiddlewareMessageLoggedPromise 13 | await expect(page.getByText('Current route: /', { exact: true })).toBeVisible() 14 | }) 15 | 16 | test('Timer is shows during client-side navigation', async ({ page }) => { 17 | await page.goto('/') 18 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 19 | await page.getByRole('link', { name: 'Home' }).click() 20 | await expect(page.getByText('A page... Processing navigation')).toBeVisible() 21 | await expect(page.getByText('A page... Processing navigation')).toBeHidden() 22 | }) 23 | 24 | test('Middleware redirects from the "/redirect" page to the "/secret" page', async ({ page, context }) => { 25 | await addForcedCookie(context, 'middleware') 26 | await page.goto('/redirect') 27 | await expect(page.getByText('You should never see this page')).toBeHidden() 28 | await expect(page).toHaveURL('/secret') 29 | }) 30 | 31 | test('Middleware redirects from the "/redirect" page to the "/secret" page using custom NuxtLink', async ({ 32 | page, 33 | }) => { 34 | await page.goto('/') 35 | await page.waitForFunction(() => window.useNuxtApp?.().isHydrating === false) 36 | await page.getByRole('button', { name: 'Custom: /redirect' }).click() 37 | await expect(page).toHaveURL('/secret') 38 | }) 39 | -------------------------------------------------------------------------------- /.e2e/tests/ui/daisyui.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('daisyui')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | }) 8 | 9 | test('Matches snapshot @visual', async ({ page }) => { 10 | await expect(page).toHaveScreenshot() 11 | }) 12 | -------------------------------------------------------------------------------- /.e2e/tests/ui/sass.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('sass')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | }) 8 | 9 | test('Matches snapshot @visual', async ({ page }) => { 10 | await expect(page).toHaveScreenshot() 11 | }) 12 | -------------------------------------------------------------------------------- /.e2e/tests/ui/tailwindcss.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('tailwindcss')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | }) 8 | 9 | test('Matches snapshot @visual', async ({ page }) => { 10 | await expect(page).toHaveScreenshot() 11 | }) 12 | -------------------------------------------------------------------------------- /.e2e/tests/ui/vuetify.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { getSettingsForDeployment } from '@/utils' 3 | 4 | test.use(getSettingsForDeployment('vuetify')) 5 | test.beforeEach(async ({ page }) => { 6 | await page.goto('/') 7 | }) 8 | 9 | test('Matches snapshot @visual', async ({ page }) => { 10 | await expect(page).toHaveScreenshot() 11 | }) 12 | -------------------------------------------------------------------------------- /.e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/*": ["./*"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.e2e/utils/index.ts: -------------------------------------------------------------------------------- 1 | import type { BrowserContext, Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs } from '@playwright/test' 2 | import { withoutProtocol } from 'ufo' 3 | 4 | export const wait = (ms: number) => 5 | new Promise(resolve => setTimeout(resolve, ms)) 6 | 7 | // eslint-disable-next-line @typescript-eslint/no-empty-object-type 8 | export const getSettingsForDeployment = (slug: string): Fixtures<{}, {}, PlaywrightTestArgs & PlaywrightTestOptions, PlaywrightWorkerArgs> => ({ 9 | baseURL: process.env.DEPLOY_URL || `https://${slug}.example.nuxt.space/`, 10 | extraHTTPHeaders: { cookie: `forced=${slug}` }, 11 | }) 12 | 13 | export async function addForcedCookie(context: BrowserContext, slug: string) { 14 | return addCookies(context, slug, [{ name: 'forced', value: slug }]) 15 | } 16 | 17 | export async function addCookies(context: BrowserContext, slug: string, cookies: Array<{ name: string, value: string }>) { 18 | const domain = withoutProtocol(process.env.DEPLOY_URL || `https://${slug}.example.nuxt.space`) 19 | await context.addCookies(cookies.map(c => ({ 20 | name: c.name, 21 | value: c.value, 22 | domain, 23 | path: '/', 24 | })).concat([{ name: 'forced', value: slug, domain, path: '/' }])) 25 | } 26 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 2 5 | indent_style = space 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | # https://github.com/vitejs/vite/blob/main/.github/workflows/ci.yml 12 | env: 13 | # 7 GiB by default on GitHub, setting to 6 GiB 14 | # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources 15 | NODE_OPTIONS: --max-old-space-size=6144 16 | 17 | # Remove default permissions of GITHUB_TOKEN for security 18 | # https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs 19 | permissions: {} 20 | 21 | jobs: 22 | lint: 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 27 | - run: npm i -g --force corepack && corepack enable 28 | - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 29 | with: 30 | node-version: lts/* 31 | cache: "pnpm" 32 | 33 | - name: Install dependencies 34 | run: pnpm install 35 | 36 | - name: Lint 37 | run: pnpm lint 38 | 39 | typecheck: 40 | runs-on: ubuntu-latest 41 | 42 | steps: 43 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 44 | - run: npm i -g --force corepack && corepack enable 45 | - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 46 | with: 47 | node-version: lts/* 48 | cache: "pnpm" 49 | 50 | - name: Install dependencies 51 | run: pnpm install 52 | 53 | - name: Typecheck 54 | run: pnpm typecheck 55 | -------------------------------------------------------------------------------- /.github/workflows/playwright.yml: -------------------------------------------------------------------------------- 1 | name: e2e 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | url: 7 | required: false 8 | description: The URL to run the test suite against. If omitted, it runs against all. 9 | type: string 10 | deployment_status: 11 | 12 | jobs: 13 | test: 14 | timeout-minutes: 60 15 | runs-on: ubuntu-latest 16 | container: 17 | image: mcr.microsoft.com/playwright:v1.52.0-noble 18 | steps: 19 | - uses: actions/checkout@v4 20 | - run: npm i -g --force corepack && corepack enable 21 | - uses: actions/setup-node@v4 22 | with: 23 | node-version: lts/* 24 | cache: "pnpm" 25 | 26 | - name: Install dependencies 27 | run: pnpm install 28 | 29 | - name: Install playwright 30 | run: pnpm playwright install 31 | working-directory: .e2e 32 | 33 | - name: Run Playwright tests 34 | run: pnpm --filter e2e test:all 35 | env: 36 | DEPLOY_URL: ${{ github.event.inputs.url || github.event.deployment.payload.web_url || github.event.deployment_status.target_url }} 37 | 38 | - uses: actions/upload-artifact@v4 39 | if: always() 40 | with: 41 | name: playwright-report 42 | path: .e2e/playwright-report/ 43 | retention-days: 30 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules 3 | jspm_packages 4 | .pnpm-store 5 | 6 | package-lock.json 7 | */**/yarn.lock 8 | 9 | # Logs 10 | *.log 11 | 12 | # Temp directories 13 | .temp 14 | .tmp 15 | .cache 16 | 17 | # Generated dirs 18 | dist 19 | .nuxt 20 | .nuxt-* 21 | .output 22 | .gen 23 | 24 | # Junit reports 25 | reports 26 | 27 | # Coverage reports 28 | coverage 29 | *.lcov 30 | .nyc_output 31 | 32 | # VSCode 33 | .vscode 34 | 35 | # Intellij idea 36 | *.iml 37 | .idea 38 | 39 | # OSX 40 | .DS_Store 41 | .AppleDouble 42 | .LSOverride 43 | 44 | # Files that might appear in the root of a volume 45 | .DocumentRevisions-V100 46 | .fseventsd 47 | .Spotlight-V100 48 | .TemporaryItems 49 | .Trashes 50 | .VolumeIcon.icns 51 | .com.apple.timemachine.donotpresent 52 | 53 | # Directories potentially created on remote AFP share 54 | .AppleDB 55 | .AppleDesktop 56 | Network Trash Folder 57 | Temporary Items 58 | .apdisk 59 | 60 | .vercel_build_output 61 | .build-* 62 | .env 63 | .netlify 64 | .turbo 65 | .vercel 66 | 67 | # Playwright 68 | **/test-results/ 69 | **/playwright-report/ 70 | **/playwright/.cache/ 71 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shell-emulator=true 2 | -------------------------------------------------------------------------------- /.nuxtrc: -------------------------------------------------------------------------------- 1 | nitro.preset=vercel 2 | sourcemap=false 3 | -------------------------------------------------------------------------------- /.scripts/build.mjs: -------------------------------------------------------------------------------- 1 | import fsp from 'node:fs/promises' 2 | import { glob } from 'tinyglobby' 3 | import { readPackageJSON } from 'pkg-types' 4 | import { join, resolve } from 'pathe' 5 | 6 | const stringify = contents => JSON.stringify(contents, null, 2) 7 | 8 | const packages = await glob([ 9 | 'examples/**/package.json', 10 | '!**/node_modules', 11 | '!**/.nitro', 12 | '!**/.vercel', 13 | '!**/.output', 14 | ]).then(r => r.sort()) 15 | const names = new Set() 16 | 17 | await fsp.rm('.vercel/output', { recursive: true, force: true }) 18 | 19 | // Create public files 20 | await fsp.mkdir('.vercel/output/static', { recursive: true }) 21 | await fsp.mkdir('.vercel/output/functions', { recursive: true }) 22 | for (const config of packages) { 23 | const { name } = await readPackageJSON(resolve(config)) 24 | const output = resolve(config, '../.vercel/output') 25 | try { 26 | const stats = await fsp.stat(output) 27 | if (!stats.isDirectory()) continue 28 | } 29 | catch { 30 | continue 31 | } 32 | 33 | await fsp.cp(join(output, 'static'), `.vercel/output/static/${name}`, { 34 | recursive: true, 35 | }) 36 | await fsp.cp( 37 | join(output, 'functions/__nitro.func'), 38 | `.vercel/output/functions/${name}.func`, 39 | { 40 | recursive: true, 41 | }, 42 | ) 43 | names.add(name) 44 | } 45 | 46 | // Create middleware 47 | await fsp.mkdir('.vercel/output/functions/_middleware.func', { 48 | recursive: true, 49 | }) 50 | await fsp.writeFile( 51 | '.vercel/output/functions/_middleware.func/index.js', 52 | ` 53 | const names = ${stringify([...names])} 54 | 55 | export default function middleware(req) { 56 | const forced = req.url.match(/\\?force=(.*)$/)?.[1] 57 | const hostname = req.headers.get('host') 58 | const subdomain = forced || req.headers.get('cookie')?.match(/forced=([^;]*)(;|$)/)?.[1] || hostname.split('.').shift() 59 | 60 | if (names.includes(subdomain)) { 61 | const response = new Response() 62 | const url = new URL(req.url) 63 | response.headers.set('x-middleware-rewrite', '/' + subdomain + url.pathname) 64 | if (forced) { 65 | response.headers.set('set-cookie', \`forced=$\{forced}\`) 66 | } 67 | return response 68 | } 69 | 70 | return new Response(null, { 71 | status: 307, 72 | headers: { 73 | Location: 'https://nuxt.com/docs/examples/essentials/hello-world/' 74 | } 75 | }) 76 | 77 | }`, 78 | ) 79 | await fsp.writeFile( 80 | '.vercel/output/functions/_middleware.func/.vc-config.json', 81 | stringify({ 82 | runtime: 'edge', 83 | entrypoint: 'index.js', 84 | }), 85 | ) 86 | await fsp.writeFile( 87 | '.vercel/output/config.json', 88 | stringify({ 89 | version: 3, 90 | routes: [ 91 | { 92 | src: '/(.*)', 93 | middlewarePath: '_middleware', 94 | continue: true, 95 | }, 96 | { 97 | handle: 'filesystem', 98 | }, 99 | ...[...names].map(name => ({ 100 | src: `/${name}/(.*)`, 101 | dest: `/${name}`, 102 | })), 103 | ], 104 | }), 105 | ) 106 | 107 | console.log('Successfully built nuxt/examples:') 108 | let index = 0 109 | const README = await fsp.readFile('README.md', 'utf-8') 110 | const missingPackages = [] 111 | for (const name of names) { 112 | const treeChar = index++ === names.size - 1 ? '└─' : '├─' 113 | process.stdout.write(` ${treeChar} ${name}\n`) 114 | if (!README.includes(`https://${name}.example.nuxt.space`)) { 115 | missingPackages.push(name) 116 | } 117 | } 118 | 119 | if (missingPackages.length) { 120 | throw new Error(`Packages not found in README: ${missingPackages.join(', ')}`) 121 | } 122 | -------------------------------------------------------------------------------- /.scripts/typecheck.mjs: -------------------------------------------------------------------------------- 1 | import { basename } from 'node:path' 2 | import { glob } from 'tinyglobby' 3 | import { exec } from 'tinyexec' 4 | import { consola } from 'consola' 5 | 6 | const packages = await glob([ 7 | 'shared/**/package.json', 8 | 'examples/**/package.json', 9 | '!**/node_modules', 10 | '!**/.nitro', 11 | '!**/.vercel', 12 | '!**/.output', 13 | ], { absolute: true }) 14 | 15 | for (const pkg of packages) { 16 | const cwd = pkg.replace('/package.json', '') 17 | 18 | await exec('nuxi', ['prepare'], { nodeOptions: { cwd }, throwOnError: true }) 19 | const res = await exec('vue-tsc', ['--noEmit'], { nodeOptions: { cwd } }) 20 | if (res.exitCode !== 0) { 21 | consola.withTag(basename(cwd)).error(res.stdout.trim()) 22 | process.exit(1) 23 | } 24 | else { 25 | consola.success('type checked', basename(cwd)) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.vercelignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/.nuxt 3 | **/.output 4 | **/.turbo 5 | **/dist 6 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @danielroe 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 - Nuxt Project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nuxt Examples 2 | 3 | 👉 https://nuxt.com/docs/examples 4 | 5 | --- 6 | 7 | ## Sites 8 | 9 | - [hello-world](https://hello-world.example.nuxt.space/) - ([source](./examples/hello-world/)) 10 | 11 | ### Features 12 | 13 | Inside [features/](./examples/features). 14 | 15 | - [auto-imports](https://auto-imports.example.nuxt.space/) 16 | - [data-fetching](https://data-fetching.example.nuxt.space/) 17 | - [state-management](https://state-management.example.nuxt.space/) 18 | - [meta-tags](https://meta-tags.example.nuxt.space/) 19 | - [layouts](https://layouts.example.nuxt.space/) 20 | 21 | ### Routing 22 | 23 | Inside [routing/](./examples/routing). 24 | 25 | - [middleware](https://middleware.example.nuxt.space/) 26 | - [pages](https://pages.example.nuxt.space/) 27 | - [universal-router](https://universal-router.example.nuxt.space/) 28 | 29 | ### UI Frameworks 30 | 31 | Inside [ui/](./examples/ui). 32 | 33 | - [daisyui](https://daisyui.example.nuxt.space/) 34 | - [tailwindcss](https://tailwindcss.example.nuxt.space/) 35 | - [sass](https://sass.example.nuxt.space/) 36 | - [vuetify](https://vuetify.example.nuxt.space/) 37 | 38 | ### Authentication 39 | 40 | Inside [auth/](./examples/auth). 41 | 42 | - [local](https://local-auth.example.nuxt.space/) 43 | 44 | ## Advanced 45 | 46 | Inside [advanced/](./examples/advanced). 47 | 48 | - [config-extends](https://config-extends.example.nuxt.space/) 49 | - [error-handling](https://error-handling.example.nuxt.space/) 50 | - [jsx](https://jsx.example.nuxt.space/) 51 | - [locale](https://locale.example.nuxt.space/) 52 | - [module-extend-pages](https://module-extend-pages.example.nuxt.space/) 53 | - [teleport](https://teleport.example.nuxt.space/) 54 | - [testing](https://testing.example.nuxt.space/) 55 | - [use-cookie](https://use-cookie.example.nuxt.space/) 56 | - [use-custom-fetch-composable](https://use-custom-fetch-composable.example.nuxt.space/) 57 | 58 | ## Experimental 59 | 60 | Inside [experimental/](./examples/experimental). 61 | 62 | - [wasm](https://wasm.example.nuxt.space/) 63 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { createConfigForNuxt } from '@nuxt/eslint-config/flat' 2 | 3 | export default createConfigForNuxt({ 4 | features: { 5 | tooling: true, 6 | stylistic: true, 7 | }, 8 | }, { 9 | rules: { 10 | 'vue/multi-word-component-names': 'off', 11 | '@typescript-eslint/ban-types': 'off', 12 | '@typescript-eslint/no-unused-vars': 'warn', 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/app.config.ts: -------------------------------------------------------------------------------- 1 | export default defineAppConfig({ 2 | foo: 'user', 3 | bar: 'user', 4 | baz: 'base', 5 | array: [ 6 | 'user', 7 | 'user', 8 | 'user', 9 | ], 10 | }) 11 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/app.config.ts: -------------------------------------------------------------------------------- 1 | export default defineAppConfig({ 2 | bar: 'base', 3 | baz: 'base', 4 | array: () => [ 5 | 'base', 6 | 'base', 7 | 'base', 8 | ], 9 | arrayNested: { 10 | nested: { 11 | array: [ 12 | 'base', 13 | 'base', 14 | 'base', 15 | ], 16 | }, 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/components/BaseButton.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/components/FancyButton.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/composables/foo.ts: -------------------------------------------------------------------------------- 1 | import { useState } from '#imports' 2 | 3 | export const useFoo = () => useState('foo', () => 'foo') 4 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/middleware/foo.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware(() => { 2 | console.log('Hello from extended middleware !') 3 | }) 4 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | imports: { 3 | dirs: ['utils'], 4 | }, 5 | runtimeConfig: { 6 | public: { 7 | theme: { 8 | primaryColor: 'base_primary', 9 | secondaryColor: 'base_secondary', 10 | }, 11 | }, 12 | }, 13 | 14 | compatibilityDate: '2024-04-03', 15 | }) 16 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/pages/foo.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/plugins/my-plugin.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtPlugin((/* nuxtApp */) => { 2 | return { 3 | provide: { 4 | myPlugin: () => 'String generated from my auto-imported plugin!', 5 | }, 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/server/api/base.ts: -------------------------------------------------------------------------------- 1 | export default () => 'base' 2 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/base/utils/bar.ts: -------------------------------------------------------------------------------- 1 | export const getBar = () => 'bar' 2 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/components/FancyButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | './ui', 5 | './base', 6 | ], 7 | runtimeConfig: { 8 | public: { 9 | theme: { 10 | primaryColor: 'user_primary', 11 | }, 12 | }, 13 | }, 14 | 15 | compatibilityDate: '2024-04-03', 16 | }) 17 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "config-extends", 3 | "private": true, 4 | "scripts": { 5 | "dev": "nuxi dev", 6 | "build": "nuxi build", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/pages/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 28 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/server/api/hello.ts: -------------------------------------------------------------------------------- 1 | export default () => 'hello' 2 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/ui/components/Button.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /examples/advanced/config-extends/ui/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | components: [ 3 | { path: './components', prefix: 'UI' }, 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/app.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 64 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/components/FaultyComponent.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/components/ThrowError.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/error.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 37 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/middleware/error.global.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware((to) => { 2 | if ('middleware' in to.query) { 3 | return showError('error in middleware') 4 | } 5 | }) 6 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "error-handling", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/pages/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/pages/other.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/plugins/error.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtPlugin((nuxtApp) => { 2 | nuxtApp.hook('vue:error', (..._args) => { 3 | console.log('vue:error') 4 | // if (process.client) { 5 | // console.log(..._args) 6 | // } 7 | }) 8 | nuxtApp.hook('app:error', (..._args) => { 9 | console.log('app:error') 10 | // if (process.client) { 11 | // console.log(..._args) 12 | // } 13 | }) 14 | nuxtApp.vueApp.config.errorHandler = (..._args) => { 15 | console.log('global error handler') 16 | // if (process.client) { 17 | // console.log(..._args) 18 | // } 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/server/middleware/error.ts: -------------------------------------------------------------------------------- 1 | export default defineEventHandler((event) => { 2 | if ('api' in getQuery(event)) { 3 | throw new Error('Server middleware error') 4 | } 5 | }) 6 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/error-handling/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/jsx/app.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 30 | -------------------------------------------------------------------------------- /examples/advanced/jsx/components/MyComponent.tsx: -------------------------------------------------------------------------------- 1 | export default defineComponent({ 2 | props: { 3 | message: String, 4 | }, 5 | // @ts-expect-error investigate why `props` is not typed 6 | render(props) { 7 | return ( 8 |
9 | { props.message } 10 |
11 | ) 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /examples/advanced/jsx/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/advanced/jsx/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsx", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced/jsx/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/locale/app.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 22 | -------------------------------------------------------------------------------- /examples/advanced/locale/composables/locale.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue' 2 | 3 | export const useNuxtLocale = () => useState('locale', () => useDefaultLocale().value) 4 | 5 | export const useDefaultLocale = (fallback = 'en-US') => { 6 | const locale = ref(fallback) 7 | if (import.meta.server) { 8 | // Learn more about the nuxtApp interface on https://nuxt.com/docs/guide/going-further/internals#the-nuxtapp-interface 9 | const reqLocale = useRequestHeaders()['accept-language']?.split(',')[0] 10 | if (reqLocale) { 11 | locale.value = reqLocale 12 | } 13 | } 14 | else if (import.meta.client) { 15 | const navLang = navigator.language 16 | if (navLang) { 17 | locale.value = navLang 18 | } 19 | } 20 | return locale 21 | } 22 | 23 | export const useNuxtLocales = () => { 24 | const locale = useNuxtLocale() 25 | const locales = ref([ 26 | 'en-US', 27 | 'en-GB', 28 | 'ko-KR', 29 | 'zh-CN', 30 | 'ar-EG', 31 | 'fa-IR', 32 | 'ja-JP-u-ca-japanese', 33 | ]) 34 | if (!locales.value.includes(locale.value)) { 35 | locales.value.unshift(locale.value) 36 | } 37 | return locales 38 | } 39 | 40 | // Using Intl.DateTimeFormat for language-sensitive date and time formatting 41 | // Learn more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat 42 | export const useNuxtLocaleDate = (date: Ref | Date, locale = useNuxtLocale()) => { 43 | return computed(() => new Intl.DateTimeFormat(locale.value, { dateStyle: 'full' }).format(unref(date))) 44 | } 45 | -------------------------------------------------------------------------------- /examples/advanced/locale/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/advanced/locale/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "locale", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced/locale/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/module-extend-pages/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /examples/advanced/module-extend-pages/modules/pages/index.ts: -------------------------------------------------------------------------------- 1 | import { createResolver, defineNuxtModule, extendPages } from 'nuxt/kit' 2 | 3 | export default defineNuxtModule({ 4 | setup() { 5 | const resolver = createResolver(import.meta.url) 6 | extendPages((pages) => { 7 | // Add /test page 8 | pages.push({ 9 | name: 'Test', 10 | path: '/test', 11 | file: resolver.resolve('./pages/test.vue'), 12 | }) 13 | }) 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /examples/advanced/module-extend-pages/modules/pages/pages/test.vue: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /examples/advanced/module-extend-pages/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | modules: [ 6 | '~/modules/pages/index', 7 | ], 8 | 9 | compatibilityDate: '2024-04-03', 10 | }) 11 | -------------------------------------------------------------------------------- /examples/advanced/module-extend-pages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "module-extend-pages", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced/module-extend-pages/pages/index.vue: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /examples/advanced/module-extend-pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/teleport/app.vue: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /examples/advanced/teleport/components/MyModal.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | 35 | 45 | -------------------------------------------------------------------------------- /examples/advanced/teleport/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/advanced/teleport/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "teleport", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced/teleport/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/testing/app.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /examples/advanced/testing/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/advanced/testing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "testing", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview", 8 | "test": "vitest run" 9 | }, 10 | "devDependencies": { 11 | "@nuxt/examples-ui": "latest", 12 | "@nuxt/test-utils": "^3.17.2", 13 | "nuxt": "^3.16.2", 14 | "vitest": "3.1.2", 15 | "vue": "3.5.13" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/advanced/testing/tests/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { describe, expect, it } from 'vitest' 3 | import { setup, $fetch, isDev } from '@nuxt/test-utils' 4 | 5 | describe('example', async () => { 6 | await setup({ 7 | rootDir: fileURLToPath(new URL('..', import.meta.url)), 8 | server: true, 9 | }) 10 | 11 | it('Renders Hello Nuxt', async () => { 12 | expect(await $fetch('/')).toMatch('Hello Nuxt!') 13 | }) 14 | 15 | if (isDev()) { 16 | it('[dev] ensure vite client script is added', async () => { 17 | expect(await $fetch('/')).toMatch('/_nuxt/@vite/client"') 18 | }) 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /examples/advanced/testing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/use-cookie/app.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 70 | -------------------------------------------------------------------------------- /examples/advanced/use-cookie/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/advanced/use-cookie/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-cookie", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced/use-cookie/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced/use-custom-fetch-composable/app.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | -------------------------------------------------------------------------------- /examples/advanced/use-custom-fetch-composable/composables/useCustomFetch.ts: -------------------------------------------------------------------------------- 1 | import type { UseFetchOptions } from 'nuxt/app' 2 | 3 | export function useCustomFetch( 4 | url: string | (() => string), 5 | options: UseFetchOptions = {}, 6 | ) { 7 | return useFetch(url, { 8 | ...options, 9 | $fetch: useNuxtApp().$customFetch, 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /examples/advanced/use-custom-fetch-composable/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | runtimeConfig: { 7 | baseURL: '', 8 | }, 9 | 10 | compatibilityDate: '2024-04-03', 11 | }) 12 | -------------------------------------------------------------------------------- /examples/advanced/use-custom-fetch-composable/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-custom-fetch-composable", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced/use-custom-fetch-composable/plugins/customFetch.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtPlugin((nuxtApp) => { 2 | const userAuth = useCookie('token') 3 | const config = useRuntimeConfig() 4 | 5 | const $customFetch = $fetch.create({ 6 | baseURL: config.baseUrl as string ?? 'https://api.nuxt.com', 7 | onRequest({ request, options, error }) { 8 | if (userAuth.value) { 9 | // Add Authorization header 10 | options.headers.set('Authorization', `Bearer ${userAuth.value}`) 11 | } 12 | }, 13 | onResponse({ response }) { 14 | // response._data = new myBusinessResponse(response._data) 15 | }, 16 | async onResponseError({ response }) { 17 | if (response.status === 401) { 18 | await nuxtApp.runWithContext(() => navigateTo('/login')) 19 | } 20 | }, 21 | }) 22 | // Expose to useNuxtApp().$customFetch 23 | return { 24 | provide: { 25 | customFetch: $customFetch, 26 | }, 27 | } 28 | }) 29 | -------------------------------------------------------------------------------- /examples/advanced/use-custom-fetch-composable/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /examples/auth/local/.env.example: -------------------------------------------------------------------------------- 1 | NUXT_AUTH_PASSWORD=secretsecretsecretsecretsecretsecretsecret 2 | -------------------------------------------------------------------------------- /examples/auth/local/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .env 8 | dist 9 | .data 10 | -------------------------------------------------------------------------------- /examples/auth/local/.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /examples/auth/local/README.md: -------------------------------------------------------------------------------- 1 | # Nuxt with Local Auth 2 | 3 | Simple password based starter made with Nuxt goodies, built-in session, storage layer and composables. 4 | 5 | This project uses [Nuxt Extend Layers](https://nuxt.com/docs/getting-started/layers) feature to implement local auth in [`auth`](./auth) directory with a modular approach. This way you can share and reuse your authentication implementation across projects and keep the code clean. 6 | 7 | Default database is using built-in key-value storage. You can rewrite it with a custom database by updating [`./auth/server/utils/db.ts`](./auth/server/utils/db.ts) 8 | 9 | Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more about Nuxt. 10 | 11 | ## Setup 12 | 13 | Make sure to install the dependencies: 14 | 15 | ```bash 16 | # yarn 17 | yarn install 18 | 19 | # npm 20 | npm install 21 | 22 | # pnpm 23 | pnpm install 24 | ``` 25 | 26 | Copy `.env.example` to `.env` and provide a secure string for session password. 27 | 28 | ## Development Server 29 | 30 | Start the development server on http://localhost:3000 31 | 32 | ```bash 33 | npm run dev 34 | ``` 35 | 36 | ## Production 37 | 38 | Build the application for production: 39 | 40 | ```bash 41 | npm run build 42 | ``` 43 | 44 | Locally preview production build: 45 | 46 | ```bash 47 | npm run preview 48 | ``` 49 | 50 | Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. 51 | -------------------------------------------------------------------------------- /examples/auth/local/app.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 35 | -------------------------------------------------------------------------------- /examples/auth/local/auth/composables/auth.ts: -------------------------------------------------------------------------------- 1 | export const useAuth = () => useNuxtApp().$auth 2 | 3 | export const authLogin = async (email: string, password: string) => { 4 | await $fetch('/api/auth/login', { 5 | method: 'POST', 6 | body: { 7 | email: email, 8 | password: password, 9 | }, 10 | }) 11 | useAuth().redirectTo.value = null 12 | await useAuth().updateSession() 13 | await navigateTo(useAuth().redirectTo.value || '/') 14 | } 15 | 16 | export const authRegister = async (email: string, password: string) => { 17 | await $fetch('/api/auth/register', { 18 | method: 'POST', 19 | body: { 20 | email: email, 21 | password: password, 22 | }, 23 | }) 24 | return await authLogin(email, password) 25 | } 26 | 27 | export const authLogout = async () => { 28 | await $fetch('/api/auth/logout', { 29 | method: 'POST', 30 | }) 31 | await useAuth().updateSession() 32 | } 33 | -------------------------------------------------------------------------------- /examples/auth/local/auth/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | 3 | // This code is demo only. 4 | if (!process.env.NUXT_AUTH_PASSWORD) { 5 | console.warn('Security warning: NUXT_AUTH_PASSWORD is not set. Using an example value. Please set it otherwise your session is unsecure!') 6 | process.env.NUXT_AUTH_PASSWORD = 'secretsecretsecretsecretsecretsecretsecret' 7 | } 8 | 9 | export default defineNuxtConfig({ 10 | runtimeConfig: { 11 | auth: { 12 | name: 'nuxt-session', 13 | password: process.env.NUXT_AUTH_PASSWORD || '', 14 | }, 15 | }, 16 | 17 | compatibilityDate: '2024-04-03', 18 | nitro: { 19 | storage: { 20 | '.data:auth': { driver: 'fs', base: './.data/auth' }, 21 | }, 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /examples/auth/local/auth/plugins/0.auth.ts: -------------------------------------------------------------------------------- 1 | import type { AuthSession } from '~~/auth/server/utils/session' 2 | 3 | export default defineNuxtPlugin(async (nuxtApp) => { 4 | // Skip plugin when rendering error page 5 | if (nuxtApp.payload.error) { 6 | return {} 7 | } 8 | 9 | const { data: session, refresh: updateSession } 10 | = await useFetch('/api/auth/session') 11 | 12 | const loggedIn = computed(() => !!session.value?.email) 13 | 14 | // Create a ref to know where to redirect the user when logged in 15 | const redirectTo = useState('authRedirect') 16 | 17 | /** 18 | * Add global route middleware to protect pages using: 19 | * 20 | * definePageMeta({ 21 | * auth: true 22 | * }) 23 | */ 24 | // 25 | 26 | addRouteMiddleware( 27 | 'auth', 28 | (to) => { 29 | if (to.meta.auth && !loggedIn.value) { 30 | redirectTo.value = to.path 31 | return '/login' 32 | } 33 | }, 34 | { global: true }, 35 | ) 36 | 37 | const currentRoute = useRoute() 38 | 39 | if (import.meta.client) { 40 | watch(loggedIn, async (loggedIn) => { 41 | if (!loggedIn && currentRoute.meta.auth) { 42 | redirectTo.value = currentRoute.path 43 | await navigateTo('/login') 44 | } 45 | }) 46 | } 47 | 48 | if (loggedIn.value && currentRoute.path === '/login') { 49 | await navigateTo(redirectTo.value || '/') 50 | } 51 | 52 | return { 53 | provide: { 54 | auth: { 55 | loggedIn, 56 | session, 57 | redirectTo, 58 | updateSession, 59 | }, 60 | }, 61 | } 62 | }) 63 | -------------------------------------------------------------------------------- /examples/auth/local/auth/server/api/auth/login.post.ts: -------------------------------------------------------------------------------- 1 | export default eventHandler(async (event) => { 2 | const session = await useAuthSession(event) 3 | const { email, password } = await readBody(event) 4 | const user = await findUserByEmail(email) 5 | if (!user) { 6 | throw createError({ 7 | message: 'Email not found! Please register.', 8 | statusCode: 401, 9 | }) 10 | } 11 | if (!user.password || user.password !== (await hash(password))) { 12 | throw createError({ 13 | message: 'Incorrect password!', 14 | statusCode: 401, 15 | }) 16 | } 17 | await session.update({ 18 | id: user.id, 19 | name: user.name, 20 | email: user.email, 21 | }) 22 | return session 23 | }) 24 | -------------------------------------------------------------------------------- /examples/auth/local/auth/server/api/auth/logout.post.ts: -------------------------------------------------------------------------------- 1 | export default eventHandler(async (event) => { 2 | const session = await useAuthSession(event) 3 | await session.clear() 4 | return { 5 | message: 'Successfully logged out!', 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /examples/auth/local/auth/server/api/auth/register.post.ts: -------------------------------------------------------------------------------- 1 | export default eventHandler(async (event) => { 2 | const { email, password } = await readBody(event) 3 | await createUser({ 4 | email, 5 | name: email.split('@')[0], 6 | password: await hash(password), 7 | }) 8 | return { 9 | message: 'Successfully registered!', 10 | } 11 | }) 12 | -------------------------------------------------------------------------------- /examples/auth/local/auth/server/api/auth/session.get.ts: -------------------------------------------------------------------------------- 1 | export default eventHandler(async (event) => { 2 | const session = await useAuthSession(event) 3 | return session.data 4 | }) 5 | -------------------------------------------------------------------------------- /examples/auth/local/auth/server/utils/db.ts: -------------------------------------------------------------------------------- 1 | import { randomUUID } from 'uncrypto' 2 | 3 | export interface User { 4 | id: string 5 | createdAt: string 6 | name: string 7 | email: string 8 | password: string 9 | } 10 | 11 | export async function findUserByEmail(email: string): Promise { 12 | const storage = useStorage() 13 | const key = getUserKey(email!) 14 | return await storage.getItem(key) as User 15 | } 16 | 17 | export async function createUser(user: Partial) { 18 | const storage = useStorage() 19 | const key = getUserKey(user.email!) 20 | if (await storage.hasItem(key)) { 21 | throw createError({ message: 'Email already exists!', statusCode: 409 }) 22 | } 23 | return await storage.setItem(key, { 24 | id: randomUUID(), 25 | ...user, 26 | }) 27 | } 28 | 29 | export async function updateUserByEmail(email: string, updates: Partial) { 30 | const storage = useStorage() 31 | const user = await findUserByEmail(email) 32 | const key = getUserKey(user.email!) 33 | return await storage.setItem(key, { 34 | ...user, 35 | ...updates, 36 | }) 37 | } 38 | 39 | function getUserKey(email: string) { 40 | return `db:auth:users:${encodeURIComponent(email)}` 41 | } 42 | -------------------------------------------------------------------------------- /examples/auth/local/auth/server/utils/session.ts: -------------------------------------------------------------------------------- 1 | import type { H3Event, SessionConfig } from 'h3' 2 | import crypto from 'uncrypto' 3 | 4 | const sessionConfig: SessionConfig = useRuntimeConfig().auth || {} 5 | 6 | export type AuthSession = { 7 | id: string 8 | name: string 9 | email: string 10 | } 11 | 12 | export const useAuthSession = async (event: H3Event) => { 13 | const session = await useSession(event, sessionConfig) 14 | return session 15 | } 16 | 17 | export const requireAuthSession = async (event: H3Event) => { 18 | const session = await useAuthSession(event) 19 | if (!session.data.email) { 20 | throw createError({ 21 | message: 'Not Authorized', 22 | statusCode: 401, 23 | }) 24 | } 25 | return session 26 | } 27 | 28 | export async function hash(str: string) { 29 | const msgUint8 = new TextEncoder().encode(str) 30 | const hashBuffer = await crypto.subtle.digest('SHA-512', msgUint8) 31 | const hashArray = Array.from(new Uint8Array(hashBuffer)) 32 | const hashHex = hashArray 33 | .map(b => b.toString(16).padStart(2, '0')) 34 | .join('') 35 | return hashHex 36 | } 37 | -------------------------------------------------------------------------------- /examples/auth/local/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | 3 | // This code is demo only. 4 | if (!process.env.NUXT_AUTH_PASSWORD) { 5 | console.warn('Security warning: NUXT_AUTH_PASSWORD is not set. Using an example value. Please set it otherwise your session is unsecure!') 6 | process.env.NUXT_AUTH_PASSWORD = 'secretsecretsecretsecretsecretsecretsecret' 7 | } 8 | 9 | export default defineNuxtConfig({ 10 | // Learn more: https://nuxt.com/docs/getting-started/layers 11 | extends: [ 12 | '@nuxt/examples-ui', 13 | './auth', 14 | ], 15 | 16 | compatibilityDate: '2024-04-03', 17 | }) 18 | -------------------------------------------------------------------------------- /examples/auth/local/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "local-auth", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "uncrypto": "^0.1.3", 13 | "vue": "3.5.13" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/auth/local/pages/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /examples/auth/local/pages/login.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 188 | -------------------------------------------------------------------------------- /examples/auth/local/pages/profile.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 39 | -------------------------------------------------------------------------------- /examples/auth/local/pages/secret.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /examples/auth/local/server/api/secret.ts: -------------------------------------------------------------------------------- 1 | export default eventHandler(async (event) => { 2 | const auth = await requireAuthSession(event) 3 | return { 4 | message: `You are accessing secret api with email: ${auth.data.email}`, 5 | } 6 | }) 7 | -------------------------------------------------------------------------------- /examples/auth/local/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/auth/local/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /examples/experimental/wasm/app.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /examples/experimental/wasm/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | nitro: { 8 | experimental: { 9 | wasm: true, 10 | }, 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /examples/experimental/wasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wasm", 3 | "private": true, 4 | "devDependencies": { 5 | "@nuxt/examples-ui": "latest", 6 | "nuxt": "^3.16.2", 7 | "vue": "3.5.13" 8 | }, 9 | "scripts": { 10 | "dev": "nuxi dev", 11 | "build": "nuxi build", 12 | "start": "nuxi preview" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/experimental/wasm/server/api/sum.ts: -------------------------------------------------------------------------------- 1 | import { defineEventHandler, defineLazyEventHandler } from 'h3' 2 | 3 | export default defineLazyEventHandler(async () => { 4 | // @ts-expect-error TODO: https://github.com/nuxt/nuxt/issues/14131 5 | const { sum } = await import('~/server/wasm/sum.wasm') 6 | 7 | return defineEventHandler((event) => { 8 | const { a = 0, b = 0 } = getQuery(event) 9 | return { sum: sum(a, b) } 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /examples/experimental/wasm/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/experimental/wasm/server/wasm/sum.wasm: -------------------------------------------------------------------------------- 1 | asm`sum 2 |  j name -------------------------------------------------------------------------------- /examples/experimental/wasm/server/wasm/sum.wat: -------------------------------------------------------------------------------- 1 | ;; https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format 2 | ;; https://webassembly.github.io/wabt/demo/wat2wasm/ 3 | (module 4 | (func (export "sum") (param i32 i32) (result i32) 5 | local.get 0 6 | local.get 1 7 | i32.add)) 8 | -------------------------------------------------------------------------------- /examples/experimental/wasm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/features/README.md: -------------------------------------------------------------------------------- 1 | # Nuxt Examples 2 | 3 | 👉 https://nuxt.com/docs/examples 4 | -------------------------------------------------------------------------------- /examples/features/auto-imports/app.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 23 | -------------------------------------------------------------------------------- /examples/features/auto-imports/components/CustomInput.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | -------------------------------------------------------------------------------- /examples/features/auto-imports/composables/hello.ts: -------------------------------------------------------------------------------- 1 | export function sayHello(message = 'World') { 2 | alert(`Hello ${upperCase(message)}!`) 3 | } 4 | -------------------------------------------------------------------------------- /examples/features/auto-imports/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/features/auto-imports/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto-imports", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/features/auto-imports/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/features/auto-imports/utils/string.ts: -------------------------------------------------------------------------------- 1 | export const upperCase = (str: string) => str.toUpperCase() 2 | -------------------------------------------------------------------------------- /examples/features/data-fetching/app.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 28 | -------------------------------------------------------------------------------- /examples/features/data-fetching/components/TheQuote.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | -------------------------------------------------------------------------------- /examples/features/data-fetching/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/features/data-fetching/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "data-fetching", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/features/data-fetching/pages/component.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 24 | -------------------------------------------------------------------------------- /examples/features/data-fetching/pages/external.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 50 | -------------------------------------------------------------------------------- /examples/features/data-fetching/pages/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /examples/features/data-fetching/server/api/hello.ts: -------------------------------------------------------------------------------- 1 | export default defineEventHandler(() => { 2 | return { 3 | hello: 'world', 4 | } 5 | }) 6 | -------------------------------------------------------------------------------- /examples/features/data-fetching/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/features/data-fetching/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/features/layouts/app.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 50 | 51 | 56 | -------------------------------------------------------------------------------- /examples/features/layouts/layouts/custom.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 26 | -------------------------------------------------------------------------------- /examples/features/layouts/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | -------------------------------------------------------------------------------- /examples/features/layouts/layouts/other.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | -------------------------------------------------------------------------------- /examples/features/layouts/middleware/other.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware(() => { 2 | setPageLayout('other') 3 | }) 4 | -------------------------------------------------------------------------------- /examples/features/layouts/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/features/layouts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "layouts", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/features/layouts/pages/custom.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /examples/features/layouts/pages/dynamic.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 26 | 27 | 43 | -------------------------------------------------------------------------------- /examples/features/layouts/pages/index.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /examples/features/layouts/pages/other.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /examples/features/layouts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/features/meta-tags/app.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | -------------------------------------------------------------------------------- /examples/features/meta-tags/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/features/meta-tags/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meta-tags", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "node .output/server" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/features/meta-tags/pages/about.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 17 | -------------------------------------------------------------------------------- /examples/features/meta-tags/pages/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 41 | 42 | 47 | -------------------------------------------------------------------------------- /examples/features/meta-tags/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/features/state-management/app.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 20 | -------------------------------------------------------------------------------- /examples/features/state-management/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/features/state-management/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "state-management", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/features/state-management/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json", 3 | } 4 | -------------------------------------------------------------------------------- /examples/hello-world/app.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /examples/hello-world/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-world", 3 | "private": true, 4 | "scripts": { 5 | "dev": "nuxi dev", 6 | "build": "nuxi build", 7 | "generate": "nuxi generate", 8 | "start": "nuxi preview" 9 | }, 10 | "devDependencies": { 11 | "@nuxt/examples-ui": "latest", 12 | "nuxt": "^3.16.2", 13 | "vue": "3.5.13" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/hello-world/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/examples/hello-world/public/favicon.ico -------------------------------------------------------------------------------- /examples/hello-world/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/routing/middleware/app.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 24 | -------------------------------------------------------------------------------- /examples/routing/middleware/middleware/always-run.global.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware(() => { 2 | console.log('running global middleware') 3 | }) 4 | -------------------------------------------------------------------------------- /examples/routing/middleware/middleware/redirect-me.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware((to) => { 2 | const { $config } = useNuxtApp() 3 | if ($config) { 4 | console.log('Accessed runtime config within middleware.') 5 | } 6 | console.log('Heading to', to.path, 'but I think we should go somewhere else...') 7 | return '/secret' 8 | }) 9 | -------------------------------------------------------------------------------- /examples/routing/middleware/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/routing/middleware/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/routing/middleware/pages/forbidden.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /examples/routing/middleware/pages/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/routing/middleware/pages/redirect.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /examples/routing/middleware/pages/secret.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /examples/routing/middleware/plugins/add.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtPlugin(() => { 2 | addRouteMiddleware('global-test', () => { 3 | console.log('this global middleware was added in a plugin') 4 | }, { global: true }) 5 | 6 | addRouteMiddleware('named-test', () => { 7 | console.log('this named middleware was added in a plugin') 8 | }) 9 | }) 10 | -------------------------------------------------------------------------------- /examples/routing/middleware/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/routing/pages/app.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 24 | -------------------------------------------------------------------------------- /examples/routing/pages/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/routing/pages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pages", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/routing/pages/pages/about.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/routing/pages/pages/catchall/[...id].vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/routing/pages/pages/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/routing/pages/pages/parent.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /examples/routing/pages/pages/parent/b.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/routing/pages/pages/parent/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/routing/pages/pages/parent/reload-[id].vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /examples/routing/pages/pages/parent/static-[id].vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /examples/routing/pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/routing/universal-router/app.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 49 | -------------------------------------------------------------------------------- /examples/routing/universal-router/middleware/always-run.global.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware(() => { 2 | console.log('running global middleware') 3 | }) 4 | -------------------------------------------------------------------------------- /examples/routing/universal-router/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | }) 8 | -------------------------------------------------------------------------------- /examples/routing/universal-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "universal-router", 3 | "private": true, 4 | "scripts": { 5 | "build": "nuxi build", 6 | "dev": "nuxi dev", 7 | "start": "nuxi preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/examples-ui": "latest", 11 | "nuxt": "^3.16.2", 12 | "vue": "3.5.13" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/routing/universal-router/plugins/add.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtPlugin(() => { 2 | const timer = useState('timer', () => 0) 3 | 4 | if (import.meta.client) { 5 | let timerRunning = false 6 | addRouteMiddleware(async () => { 7 | if (timerRunning) return 8 | 9 | console.log('Starting timer...') 10 | timerRunning = true 11 | timer.value = 5 12 | 13 | do { 14 | await new Promise(resolve => setTimeout(resolve, 100)) 15 | console.log('Timer:', timer.value) 16 | timer.value-- 17 | } while (timer.value > 0) 18 | 19 | console.log('...and navigating') 20 | timerRunning = false 21 | }) 22 | } 23 | 24 | addRouteMiddleware((to) => { 25 | if (to.path === '/forbidden') { 26 | return false 27 | } 28 | }) 29 | 30 | addRouteMiddleware((to) => { 31 | const { $config } = useNuxtApp() 32 | if ($config) { 33 | console.log('Accessed runtime config within middleware.') 34 | } 35 | 36 | if (to.path !== '/redirect') { 37 | return 38 | } 39 | 40 | console.log('Heading to', to.path, 'but I think we should go somewhere else...') 41 | return '/secret' 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /examples/routing/universal-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/ui/daisyui/app.vue: -------------------------------------------------------------------------------- 1 | 61 | 62 | 97 | -------------------------------------------------------------------------------- /examples/ui/daisyui/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | modules: [ 3 | '@nuxtjs/tailwindcss', 4 | '@nuxtjs/color-mode', 5 | ], 6 | 7 | colorMode: { 8 | preference: 'system', // default theme 9 | dataValue: 'theme', // activate data-theme in tag 10 | classSuffix: '', 11 | }, 12 | 13 | compatibilityDate: '2024-04-03', 14 | }) 15 | -------------------------------------------------------------------------------- /examples/ui/daisyui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "daisyui", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "nuxt dev", 7 | "build": "nuxt build", 8 | "start": "nuxt start", 9 | "generate": "nuxt generate" 10 | }, 11 | "devDependencies": { 12 | "@nuxtjs/color-mode": "^3.5.2", 13 | "@nuxtjs/tailwindcss": "^6.13.2", 14 | "daisyui": "^4.12.24", 15 | "nuxt": "^3.16.2", 16 | "tailwindcss": "3.4.17", 17 | "vue": "3.5.13" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/ui/daisyui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/examples/ui/daisyui/public/favicon.ico -------------------------------------------------------------------------------- /examples/ui/daisyui/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [require('daisyui')], 3 | } 4 | -------------------------------------------------------------------------------- /examples/ui/daisyui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/ui/sass/app.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 16 | -------------------------------------------------------------------------------- /examples/ui/sass/assets/styles/_colors.sass: -------------------------------------------------------------------------------- 1 | $primary: #00DC82 2 | $secondary: #16A79E -------------------------------------------------------------------------------- /examples/ui/sass/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | extends: [ 3 | '@nuxt/examples-ui', 4 | ], 5 | 6 | compatibilityDate: '2024-04-03', 7 | vite: { 8 | css: { 9 | preprocessorOptions: { 10 | sass: { 11 | additionalData: '@use "@/assets/styles/_colors.sass" as *\n', 12 | }, 13 | }, 14 | }, 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /examples/ui/sass/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sass", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "nuxt dev", 7 | "build": "nuxt build", 8 | "start": "nuxt start", 9 | "generate": "nuxt generate" 10 | }, 11 | "devDependencies": { 12 | "@nuxt/examples-ui": "latest", 13 | "nuxt": "^3.16.2", 14 | "sass": "^1.69.5", 15 | "vue": "3.5.13" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/ui/sass/pages/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /examples/ui/sass/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/examples/ui/sass/public/favicon.ico -------------------------------------------------------------------------------- /examples/ui/sass/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/ui/tailwindcss/app.vue: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /examples/ui/tailwindcss/components/TButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /examples/ui/tailwindcss/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | modules: [ 3 | '@nuxtjs/tailwindcss', 4 | '@nuxtjs/color-mode', 5 | ], 6 | colorMode: { 7 | classSuffix: '', 8 | }, 9 | 10 | compatibilityDate: '2024-04-03', 11 | // https://tailwindcss.nuxtjs.org 12 | tailwindcss: { 13 | // Expose tailwind config with #tailwind-config 14 | exposeConfig: true, 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /examples/ui/tailwindcss/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwindcss", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "nuxt dev", 7 | "build": "nuxt build", 8 | "start": "nuxt start", 9 | "generate": "nuxt generate" 10 | }, 11 | "devDependencies": { 12 | "@nuxtjs/color-mode": "^3.5.2", 13 | "@nuxtjs/tailwindcss": "^6.13.2", 14 | "nuxt": "^3.16.2", 15 | "tailwindcss": "3.4.17", 16 | "vue": "3.5.13" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/ui/tailwindcss/pages/about.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 21 | -------------------------------------------------------------------------------- /examples/ui/tailwindcss/pages/index.vue: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /examples/ui/tailwindcss/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/examples/ui/tailwindcss/public/favicon.ico -------------------------------------------------------------------------------- /examples/ui/tailwindcss/public/mountains.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/examples/ui/tailwindcss/public/mountains.jpg -------------------------------------------------------------------------------- /examples/ui/tailwindcss/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | darkMode: 'class', 3 | } 4 | -------------------------------------------------------------------------------- /examples/ui/tailwindcss/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/ui/vuetify/app.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 19 | -------------------------------------------------------------------------------- /examples/ui/vuetify/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | css: [ 3 | 'vuetify/lib/styles/main.sass', 4 | '@mdi/font/css/materialdesignicons.min.css', 5 | ], 6 | build: { 7 | transpile: ['vuetify'], 8 | }, 9 | 10 | compatibilityDate: '2024-04-03', 11 | }) 12 | -------------------------------------------------------------------------------- /examples/ui/vuetify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuetify", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "nuxt dev", 7 | "build": "nuxt build", 8 | "start": "nuxt start", 9 | "generate": "nuxt generate" 10 | }, 11 | "devDependencies": { 12 | "@mdi/font": "^7.4.47", 13 | "nuxt": "^3.16.2", 14 | "sass": "^1.69.5", 15 | "vue": "3.5.13", 16 | "vuetify": "^3.3.23" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/ui/vuetify/plugins/vuetify.ts: -------------------------------------------------------------------------------- 1 | import { createVuetify } from 'vuetify' 2 | import * as components from 'vuetify/components' 3 | import * as directives from 'vuetify/directives' 4 | 5 | export default defineNuxtPlugin((nuxtApp) => { 6 | const vuetify = createVuetify({ 7 | ssr: true, 8 | components, 9 | directives, 10 | }) 11 | 12 | nuxtApp.vueApp.use(vuetify) 13 | }) 14 | -------------------------------------------------------------------------------- /examples/ui/vuetify/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt/examples/67d8e1aa1e3b1ff8ff890cad6ab6d7828eebd539/examples/ui/vuetify/public/favicon.ico -------------------------------------------------------------------------------- /examples/ui/vuetify/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-examples", 3 | "private": true, 4 | "version": "1.0.0", 5 | "license": "MIT", 6 | "scripts": { 7 | "build": "turbo run build --concurrency 80% && node .scripts/build.mjs", 8 | "lint": "eslint", 9 | "lint:fix": "eslint --fix", 10 | "typecheck": "node .scripts/typecheck.mjs" 11 | }, 12 | "devDependencies": { 13 | "@nuxt/cli": "^3.25.1", 14 | "@nuxt/eslint": "^1.3.1", 15 | "@nuxt/eslint-config": "^1.3.1", 16 | "@types/node": "^22.15.17", 17 | "consola": "^3.4.2", 18 | "eslint": "^9.26.0", 19 | "pathe": "^2.0.3", 20 | "pkg-types": "^2.1.0", 21 | "tinyexec": "^1.0.1", 22 | "tinyglobby": "^0.2.13", 23 | "turbo": "2.5.3", 24 | "typescript": "5.8.3", 25 | "vue-tsc": "2.2.10" 26 | }, 27 | "resolutions": { 28 | "@nuxt/examples-ui": "workspace:*", 29 | "@nuxt/kit": "3.17.3", 30 | "nuxt": "3.17.3", 31 | "vue": "3.5.13" 32 | }, 33 | "packageManager": "pnpm@10.10.0" 34 | } 35 | -------------------------------------------------------------------------------- /patches/@nuxtjs__tailwindcss.patch: -------------------------------------------------------------------------------- 1 | diff --git a/dist/module.mjs b/dist/module.mjs 2 | index 5f10c126846f6dafef05339f9097ee1c1bc0b2b2..4da27fdd488c12b382921bed8004ca74341f9e46 100644 3 | --- a/dist/module.mjs 4 | +++ b/dist/module.mjs 5 | @@ -21,7 +21,7 @@ const compatibility = { 6 | async function resolveCSSPath(cssPath, nuxt = useNuxt()) { 7 | if (typeof cssPath === "string") { 8 | const _cssPath = await resolvePath(cssPath, { extensions: [".css", ".sass", ".scss", ".less", ".styl"] }); 9 | - return existsSync(_cssPath) ? [_cssPath, `Using Tailwind CSS from ~/${relative(nuxt.options.srcDir, _cssPath)}`] : await tryResolveModule("tailwindcss/package.json").then((twLocation) => twLocation ? [join(twLocation, "../tailwind.css"), "Using default Tailwind CSS file"] : Promise.reject("Unable to resolve tailwindcss. Is it installed?")); 10 | + return existsSync(_cssPath) ? [_cssPath, `Using Tailwind CSS from ~/${relative(nuxt.options.srcDir, _cssPath)}`] : await tryResolveModule("tailwindcss/package.json", import.meta.url).then((twLocation) => twLocation ? [join(twLocation, "../tailwind.css"), "Using default Tailwind CSS file"] : Promise.reject("Unable to resolve tailwindcss. Is it installed?")); 11 | } else { 12 | return [ 13 | false, 14 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - shared 3 | - examples/** 4 | - .e2e 5 | - '!**/.vercel/**' 6 | ignoredBuiltDependencies: 7 | - esbuild 8 | - vue-demi 9 | patchedDependencies: 10 | '@nuxtjs/tailwindcss': patches/@nuxtjs__tailwindcss.patch 11 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>nuxt/renovate-config-nuxt" 5 | ], 6 | "rebaseStalePrs": true, 7 | "prCreation": "not-pending", 8 | "packageRules": [ 9 | { 10 | "groupName": "nuxt core", 11 | "groupSlug": "nuxt", 12 | "matchPackageNames": [ 13 | "nuxt", 14 | "@nuxt/kit", 15 | "@nuxt/schema", 16 | "@nuxt/vite-builder", 17 | "@nuxt/webpack-builder", 18 | "@nuxt/rspack-builder" 19 | ] 20 | }, 21 | { 22 | "groupName": "nuxt ui", 23 | "groupSlug": "nuxt-ui", 24 | "matchPackageNames": [ 25 | "@nuxt/ui" 26 | ] 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /shared/README.md: -------------------------------------------------------------------------------- 1 | # @nuxt/examples-ui 2 | 3 | Shared UI for Nuxt examples on https://nuxt.com/docs/examples 4 | -------------------------------------------------------------------------------- /shared/assets/main.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | @import "@nuxt/ui"; 3 | @source "../components/Logo.vue"; 4 | @source "../components/NuxtExample.vue"; 5 | -------------------------------------------------------------------------------- /shared/components/Logo.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 47 | -------------------------------------------------------------------------------- /shared/components/NuxtExample.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 138 | 139 | 150 | -------------------------------------------------------------------------------- /shared/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import { createResolver } from 'nuxt/kit' 2 | 3 | const resolver = createResolver(import.meta.url) 4 | 5 | export default defineNuxtConfig({ 6 | modules: [ 7 | '@nuxt/ui', 8 | ], 9 | 10 | css: [ 11 | resolver.resolve('./assets/main.css'), 12 | ], 13 | 14 | compatibilityDate: '2024-04-03', 15 | }) 16 | -------------------------------------------------------------------------------- /shared/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nuxt/examples-ui", 3 | "version": "0.0.2", 4 | "private": false, 5 | "scripts": { 6 | "dev": "nuxi dev", 7 | "build": "nuxi build", 8 | "start": "nuxi preview", 9 | "prepare": "nuxi prepare" 10 | }, 11 | "main": "./nuxt.config.ts", 12 | "files": [ 13 | "assets", 14 | "components", 15 | "nuxt.config.ts" 16 | ], 17 | "devDependencies": { 18 | "nuxt": "^3.17.3", 19 | "vue": "3.5.13" 20 | }, 21 | "dependencies": { 22 | "@iconify-json/lucide": "^1.2.42", 23 | "@nuxt/ui": "3.1.3", 24 | "tailwindcss": "4.1.6" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.org/schema.json", 3 | "globalDependencies": [ 4 | ".nuxtrc", 5 | "modules/**", 6 | "shared" 7 | ], 8 | "tasks": { 9 | "build": { 10 | "dependsOn": [ 11 | "^build" 12 | ], 13 | "outputs": [ 14 | ".output/**", 15 | ".output/server/node_modules/**", 16 | ".vercel/**" 17 | ] 18 | }, 19 | "generate": { 20 | "dependsOn": [ 21 | "^build" 22 | ], 23 | "outputs": [ 24 | ".output/public/**", 25 | ".vercel/**" 26 | ] 27 | } 28 | } 29 | } 30 | --------------------------------------------------------------------------------