Compare commits

...

22 Commits

Author SHA1 Message Date
Andrey Yolkin 6db6f6c565
fix(docs): add missing utils 2023-09-03 20:25:47 +03:00
Andrey Yolkin da0fbb5d49
feat(docs): define `useLogger` 2023-09-03 20:03:07 +03:00
Andrey Yolkin 1bc2e22552
refactor(docs): add heading to each utility 2023-09-03 19:42:57 +03:00
Andrey Yolkin f38e51daf4
Merge remote-tracking branch 'refs/remotes/origin/docs/kit' into docs/kit 2023-09-03 19:37:02 +03:00
Andrey Yolkin c0f701d41a
feat(docs): describe `updateTemplates` 2023-09-03 19:36:59 +03:00
Andrey Yolkin daf3a8ae2d
fix(docs): add return type to template functions 2023-09-03 19:31:10 +03:00
Andrey Yolkin 9e64b26cac
fix(docs): remove arguments from `addTypeTemplate` heading 2023-09-03 19:25:40 +03:00
autofix-ci[bot] 2d6416fd8a
[autofix.ci] apply automated fixes 2023-09-03 13:50:01 +00:00
Andrey Yolkin b4030afa75
feat(docs): describe `addTypeTemplate` 2023-09-03 16:49:19 +03:00
Andrey Yolkin ff48d797c6
fix(docs): close code-group 2023-09-03 16:36:09 +03:00
Andrey Yolkin 5fda425e86
Merge branch 'main' into docs/kit 2023-09-03 16:30:10 +03:00
Harlan Wilton 4e05650cde
fix(nuxt): unpause dom updates on error (#22945) 2023-09-01 15:00:20 +01:00
Daniel Roe 559a72370b
docs: update examples of dynamic `pageKey` (#22920) 2023-08-31 11:27:23 +01:00
Alex Liu 2d46971162
fix(nuxt): ensure middleware is processed when returning `true` (#22905) 2023-08-31 10:19:26 +01:00
Jonas Thelemann 1f98f34c8e
docs: clarify that 'it' is `<NuxtPage>` (#22912)
Co-authored-by: Damian Głowala <damian.glowala.rebkow@gmail.com>
2023-08-31 09:42:05 +01:00
Daniel Roe 9610cf03db chore: track `nuxi-edge` rather than `nuxi-ng` 2023-08-30 15:37:57 +01:00
Andrey Yolkin aa0ea8bf2d
fix(kit): allow passing a string to `addLayout` (#22902) 2023-08-30 11:45:16 +01:00
Sébastien Chopin ea51421768
docs: text center on banner 2023-08-30 11:09:45 +02:00
Sébastien Chopin 681f929158
docs: simplify readme 2023-08-30 11:06:45 +02:00
Sébastien Chopin e92d99db34
docs: add banner for readme 2023-08-30 11:05:19 +02:00
Sébastien Chopin 9991da6340
docs: rename nuxt-community to nuxt-modules 2023-08-30 10:49:55 +02:00
Daniel Roe 6036e9d6a2
fix(kit): respect `priority` when registering components dirs (#22882) 2023-08-29 23:06:41 +01:00
17 changed files with 286 additions and 133 deletions

1
.github/assets/banner.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

145
README.md
View File

@ -1,113 +1,52 @@
[![Nuxt banner](./.github/assets/banner.svg)](https://nuxt.com)
[![Nuxt banner](./.github/assets/banner.png)](https://nuxt.com)
# Nuxt
# 👋 Welcome to Nuxt
Nuxt's goal is to make web development intuitive and performant, with a great developer experience.<br>Learn more in the ['What is Nuxt?'](https://nuxt.com/docs/getting-started/introduction) section of our documentation.
<p>
<p>
<a href="https://www.npmjs.com/package/nuxt"><img src="https://img.shields.io/npm/v/nuxt.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="Version"></a>
<a href="https://www.npmjs.com/package/nuxt"><img src="https://img.shields.io/npm/dm/nuxt.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="Downloads"></a>
<a href="./LICENSE"><img src="https://img.shields.io/github/license/nuxt/nuxt.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="License"></a>
<a href="https://nuxt.com"><img src="https://img.shields.io/badge/Open%20Documentation-18181B?logo=nuxt.js" alt="Website"></a>
<a href="https://volta.net/nuxt/nuxt?utm_source=nuxt_readme"><img src="https://user-images.githubusercontent.com/904724/209143798-32345f6c-3cf8-4e06-9659-f4ace4a6acde.svg" alt="Volta board"></a>
</p>
<a href="https://nuxt.com"><img src="https://img.shields.io/badge/Nuxt%20Docs-18181B?logo=nuxt.js" alt="Website"></a>
<a href="https://chat.nuxt.dev"><img src="https://img.shields.io/badge/Nuxt%20Discord-18181B?logo=discord" alt="Discord"></a>
</p>
<table>
<thead>
<tr>
<th width="2000" colspan="2">
</th>
</tr>
</thead>
<tbody>
<tr>
<td width="80" align="center" valign="top">
<br>
<a href="https://nuxt.com/docs"><img src="./.github/assets/documentation.png"></a>
</td>
<td valign="top">
<h3>Documentation</h3>
<p>
We highly recommend you take a look at <a href="https://nuxt.com">the Nuxt documentation</a> to level up.
</p>
</td>
</tr>
<tr>
<td width="80" align="center" valign="top">
<br>
<a href="https://nuxt.com/modules"><img src="./.github/assets/modules.png"></a>
</td>
<td valign="top">
<h3>Modules</h3>
<p>
Discover our <a href="https://nuxt.com/modules">list of modules</a> to supercharge your Nuxt project. Created by the Nuxt team and community.
</p>
</td>
</tr>
<tr>
<td width="80" align="center" valign="top">
<br>
<a href="https://nuxt.com/docs/examples/hello-world"><img src="./.github/assets/examples.png"></a>
</td>
<td>
<h3>Examples</h3>
<p>
Explore different ways of using Nuxt features and get inspired with <a href="https://nuxt.com/docs/examples/hello-world">our list of examples</a>.
</p>
</td>
</tr>
</tbody>
</table>
Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.
<table>
<thead>
<tr>
<th width="2000" colspan="2">
</th>
</tr>
</thead>
<tbody>
<tr>
<td width="80" align="center" valign="top">
<br>
<a href="https://nuxt.com/docs/community/reporting-bugs"><img src="./.github/assets/reporting-bugs.png"></a>
</td>
<td valign="top">
<h3>Reporting bugs</h3>
<p>
Check out the <a href="https://nuxt.com/docs/community/reporting-bugs">Reporting Bugs</a> page.</p>
</p>
</td>
</tr>
<tr>
<td width="80" align="center" valign="top">
<br>
<a href="https://nuxt.com/docs/community/contribution"><img src="./.github/assets/suggestions.png"></a>
</td>
<td valign="top">
<h3>Suggestions</h3>
<p>
Check out the <a href="https://nuxt.com/docs/community/contribution">Contribution</a> page.
</p>
</td>
</tr>
<tr>
<td width="80" align="center" valign="top">
<br>
<a href="https://nuxt.com/docs/community/getting-help"><img src="./.github/assets/questions.png"></a>
</td>
<td valign="top">
<h3>Questions</h3>
<p>
Check out the <a href="https://nuxt.com/docs/community/getting-help">Getting Help</a> page.
</p>
</td>
</tr>
</tbody>
</table>
It provides a number of features that make it easy to build fast, SEO-friendly, and scalable web applications, including:
- Server-side rendering, Static Site Generation or Hybrid Rendering
- Automatic routing with code-splitting
- State management
- SEO Optimization
- Extandable with [100+ modules](https://nuxt.com/modules)
- Deployment to a variety of hosting platforms
- ...[and much more](https://nuxt.com) 🚀
## Getting Started
Use the following command to create a new starter project. This will create a starter project with all the necessary files and dependencies:
```bash
npx nuxi@latest nuxi init <my-project>
```
Discover also [nuxt.new](https://nuxt.new): Open a Nuxt starter on CodeSandbox, StackBlitz or locally to get up and running in a few seconds.
## Documentation
We highly recommend you take a look at the [Nuxt documentation](https://nuxt.com/docs) to level up. Its a great resource for learning more about the framework. It covers everything from getting started to advanced topics.
## Modules
Discover our [list of modules](https://nuxt.com/modules) to supercharge your Nuxt project, created by the Nuxt team and community.
## Contribute
We invite you to contribute and help improve Nuxt 💚
Here are a few ways you can get involved:
- **Reporting Bugs:** If you come across any bugs or issues, please check out the [reporting bugs guide](https://nuxt.com/docs/community/reporting-bugs) to learn how to submit a bug report.
- **Suggestions:** Have ideas to enhance Nuxt? We'd love to hear them! Check out the [contribution guide](https://nuxt.com/docs/community/contribution#creating-an-issue) to share your suggestions.
- **Questions:** If you have questions or need assistance, the [getting help guide](https://nuxt.com/docs/community/getting-help) provides resources to help you out.
## Local Development

View File

@ -205,7 +205,7 @@ If you want more control over when the `<NuxtPage>` component is re-rendered (fo
<template>
<div>
<h1>I am the parent view</h1>
<NuxtPage :page-key="someKey" />
<NuxtPage :page-key="route => route.fullPath" />
</div>
</template>
```

View File

@ -34,7 +34,7 @@ If you have a [`pages/`](/docs/guide/directory-structure/pages) directory, to di
```
::alert{type=danger}
Since Nuxt 3 uses [`<Suspense>`](https://vuejs.org/guide/built-ins/suspense.html#suspense) inside `<NuxtPage>`, it cannot be set as a root element.
Since `<NuxtPage>` internally uses the [`<Suspense>`](https://vuejs.org/guide/built-ins/suspense.html#suspense) component, `<NuxtPage>` cannot be set as a root element.
::
::alert{type=warning}

View File

@ -34,6 +34,12 @@ For example, passing `static` key, `NuxtPage` component is rendered only once wh
<NuxtPage page-key="static" />
```
You can also use a dynamic key based on the current route. (Don't use `$route` object here as it can cause problems with how `<NuxtPage>` renders pages with `<Suspense>`.)
```html
<NuxtPage :page-key="route => route.fullPath" />
```
Alternatively, `pageKey` can be passed as a `key` value via `definePageMeta` from the `<script>` section of your Vue component in the `/pages` directory.
```js

View File

@ -1808,18 +1808,20 @@ export default defineNuxtPlugin((nuxtApp) => {
})
```
::
## Templates
[source code](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/template.ts)
### `addTemplate`
Renders given template using lodash template during build into the project buildDir.
Renders given template using [lodash template](https://lodash.com/docs/4.17.15#template) during build into the project buildDir.
#### Type
```ts
function addTemplate (template: NuxtTemplate | string): NuxtTemplate
function addTemplate (template: NuxtTemplate | string): ResolvedNuxtTemplate
interface NuxtTemplate {
src?: string
@ -1829,6 +1831,17 @@ interface NuxtTemplate {
getContents?: (data: Record<string, any>) => string | Promise<string>
write?: boolean
}
interface ResolvedNuxtTemplate {
src: string
filename: string
dst: string
options: Record<string, any>
getContents: (data: Record<string, any>) => string | Promise<string>
write: boolean
filename: string
dst: string
}
```
#### Parameters
@ -1877,43 +1890,218 @@ A template object or a string with the path to the template. If a string is prov
If set to `true`, the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem.
### `addTypeTemplate(templateOptions)`
### `addTypeTemplate`
### `updateTemplates({ filter?: ResolvedNuxtTemplate => boolean })`
Renders given template using [lodash template](https://lodash.com/docs/4.17.15#template) during build into the project buildDir, then registers it as types.
#### Type
```ts
function addTypeTemplate (template: NuxtTypeTemplate | string): ResolvedNuxtTemplate
interface NuxtTemplate {
src?: string
filename?: string
dst?: string
options?: Record<string, any>
getContents?: (data: Record<string, any>) => string | Promise<string>
}
interface ResolvedNuxtTemplate {
src: string
filename: string
dst: string
options: Record<string, any>
getContents: (data: Record<string, any>) => string | Promise<string>
write: boolean
filename: string
dst: string
}
```
#### Parameters
##### `template`
**Type**: `NuxtTypeTemplate | string`
**Required**: `true`
A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties:
- `src` (optional)
**Type**: `string`
Path to the template. If `src` is not provided, `getContents` must be provided instead.
- `filename` (optional)
**Type**: `string`
Filename of the template. If `filename` is not provided, it will be generated from the `src` path. In this case, the `src` option is required.
- `dst` (optional)
**Type**: `string`
Path to the destination file. If `dst` is not provided, it will be generated from the `filename` path and nuxt `buildDir` option.
- `options` (optional)
**Type**: `Options`
Options to pass to the template.
- `getContents` (optional)
**Type**: `(data: Options) => string | Promise<string>`
A function that will be called with the `options` object. It should return a string or a promise that resolves to a string. If `src` is provided, this function will be ignored.
### `updateTemplates`
Regenerate templates that match the filter. If no filter is provided, all templates will be regenerated.
#### Type
```ts
async function updateTemplates (options: UpdateTemplatesOptions): void
interface UpdateTemplatesOptions {
filter?: (template: ResolvedNuxtTemplate) => boolean
}
interface ResolvedNuxtTemplate {
src: string
filename: string
dst: string
options: Record<string, any>
getContents: (data: Record<string, any>) => string | Promise<string>
write: boolean
filename: string
dst: string
}
```
#### Parameters
##### `options`
**Type**: `UpdateTemplatesOptions`
**Default**: `{}`
Options to pass to the template. This object can have the following property:
- `filter` (optional)
**Type**: `(template: ResolvedNuxtTemplate) => boolean`
A function that will be called with the `template` object. It should return a boolean indicating whether the template should be regenerated. If `filter` is not provided, all templates will be regenerated.
#### Example
```ts
// https://github.com/nuxt/nuxt
import { defineNuxtModule, updateTemplates } from '@nuxt/kit'
export default defineNuxtModule({
setup(options, nuxt) {
// watch and rebuild routes template list when one of the pages changes
nuxt.hook('builder:watch', async (event, relativePath) => {
if (event === 'change') { return }
const path = resolve(nuxt.options.srcDir, relativePath)
if (updateTemplatePaths.some(dir => path.startsWith(dir))) {
await updateTemplates({
filter: template => template.filename === 'routes.mjs'
})
}
})
}
})
```
### `writeTypes`
## Nitro
[source code](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/nitro.ts)
- `addServerHandler (handler)`
- `addDevServerHandler (handler)`
- `useNitro()` (only usable after `ready` hook)
- `addServerPlugin`
- `addPrerenderRoutes`
### `addServerHandler (handler)`
### `addDevServerHandler (handler)`
### `useNitro()` (only usable after `ready` hook)
### `addServerPlugin`
### `addPrerenderRoutes`
## Resolving
[source code](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/resolve.ts)
- `resolvePath (path, resolveOptions?)`
- `resolveAlias (path, aliases?)`
- `findPath (paths, resolveOptions?)`
- `createResolver (base)`
### `resolvePath (path, resolveOptions?)`
### `resolveAlias (path, aliases?)`
### `findPath (paths, resolveOptions?)`
### `createResolver (base)`
## Logging
[source code](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/logger.ts)
- `useLogger(scope?)`
### `useLogger`
Returns a logger instance. It uses [consola](https://github.com/unjs/consola) under the hood.
#### Type
```ts
function useLogger (tag?: string): ConsolaInstance
```
#### Parameters
##### `tag`
**Type**: `string`
***Optional**: `true`
A tag to prefix all log messages with.
#### Examples
```ts
import { defineNuxtModule, useLogger } from '@nuxt/kit'
export default defineNuxtModule({
setup(options, nuxt) {
const logger = useLogger('my-module')
logger.info('Hello from my module!')
}
})
```
## Builder
[source code](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/build.ts)
- `extendWebpackConfig(callback, options?)`
- `extendViteConfig(callback, options?)`
- `addWebpackPlugin(webpackPlugin, options?)`
- `addVitePlugin(vitePlugin, options?)`
### `extendWebpackConfig(callback, options?)`
### `extendViteConfig(callback, options?)`
### `addWebpackPlugin(webpackPlugin, options?)`
### `addVitePlugin(vitePlugin, options?)`
### `addBuildPlugin`
## Examples

View File

@ -13,8 +13,7 @@ There is a range of different ways you might be able to contribute to the Nuxt e
The Nuxt ecosystem includes many different projects and organizations. For example:
* [nuxt/](https://github.com/nuxt) - core repositories for the Nuxt framework itself. [**nuxt/nuxt**](https://github.com/nuxt/nuxt) contains the Nuxt framework (both versions 2 and 3).
* [nuxt-community/](https://github.com/nuxt-community) - community-contributed and maintained modules and libraries. There is a [process to migrate a module](/docs/guide/going-further/modules/#joining-nuxt-community) to `nuxt-community`. While these modules have individual maintainers, they are not dependent on a single person.
* [nuxt-contrib/](https://github.com/nuxt-contrib) - the previous home for libraries that are not specific to Nuxt but produced and used by the Nuxt team.
* [nuxt-modules/](https://github.com/nuxt-modules) - community-contributed and maintained modules and libraries. There is a [process to migrate a module](/docs/guide/going-further/modules/#joining-nuxt-modules-and-nuxtjs) to `nuxt-modules`. While these modules have individual maintainers, they are not dependent on a single person.
* [unjs/](https://github.com/unjs) - many of these libraries are used throughout the Nuxt ecosystem. They are designed to be universal libraries that are framework- and environment-agnostic. We welcome contributions and usage by other frameworks and projects.
## How To Contribute

View File

@ -12,6 +12,7 @@ export async function addComponentsDir (dir: ComponentsDir) {
const nuxt = useNuxt()
await assertNuxtCompatibility({ nuxt: '>=2.13' }, nuxt)
nuxt.options.components = nuxt.options.components || []
dir.priority ||= 0
nuxt.hook('components:dirs', (dirs) => { dirs.push(dir) })
}

View File

@ -6,7 +6,7 @@ import { useNuxt } from './context'
import { logger } from './logger'
import { addTemplate } from './template'
export function addLayout (this: any, template: NuxtTemplate, name?: string) {
export function addLayout (this: any, template: NuxtTemplate | string, name?: string) {
const nuxt = useNuxt()
const { filename, src } = addTemplate(template)
const layoutName = kebabCase(name || parse(filename).name).replace(/["']/g, '')

View File

@ -58,7 +58,7 @@ function getRouteFromPath (fullPath: string | Partial<Route>) {
}
}
type RouteGuardReturn = void | Error | string | false
type RouteGuardReturn = void | Error | string | boolean
interface RouteGuard {
(to: Route, from: Route): RouteGuardReturn | Promise<RouteGuardReturn>
@ -130,7 +130,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
// Cancel navigation
if (result === false || result instanceof Error) { return }
// Redirect
if (result) { return handleNavigation(result, true) }
if (typeof result === 'string' && result.length) { return handleNavigation(result, true) }
}
for (const handler of hooks['resolve:before']) {
@ -250,6 +250,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
return nuxtApp.runWithContext(() => showError(error))
}
}
if (result === true) { continue }
if (result || result === false) { return result }
}
}

View File

@ -121,7 +121,7 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
shortPath,
export: 'default',
// by default, give priority to scanned components
priority: 1
priority: dir.priority ?? 1
}
if (typeof dir.extendComponent === 'function') {
@ -135,9 +135,15 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
}
const existingComponent = components.find(c => c.pascalName === component.pascalName && ['all', component.mode].includes(c.mode))
// Ignore component if component is already defined (with same mode)
if (existingComponent) {
// Ignore component if component is already defined (with same mode)
warnAboutDuplicateComponent(componentName, filePath, existingComponent.filePath)
const existingPriority = existingComponent.priority ?? 0
const newPriority = component.priority ?? 0
if (newPriority >= existingPriority) {
warnAboutDuplicateComponent(componentName, filePath, existingComponent.filePath)
}
continue
}

View File

@ -27,6 +27,8 @@ export default defineNuxtPlugin({
nuxtApp.hooks.hook('page:start', () => { pauseDOMUpdates = true })
// wait for new page before unpausing dom updates (triggered after suspense resolved)
nuxtApp.hooks.hook('page:finish', syncHead)
// unpause on error
nuxtApp.hooks.hook('app:error', syncHead)
// unpause the DOM once the mount suspense is resolved
nuxtApp.hooks.hook('app:suspense:resolve', syncHead)
}

View File

@ -179,6 +179,7 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
}
}
if (result === true) { continue }
if (result || result === false) {
return result
}

View File

@ -85,6 +85,14 @@ export interface ComponentsDir extends ScanDir {
* By default ('auto') it will set transpile: true if node_modules/ is in path.
*/
transpile?: 'auto' | boolean
/**
* This number allows configuring the behavior of overriding Nuxt components.
* It will be inherited by any components within the directory.
*
* If multiple components are provided with the same name, then higher priority
* components will be used instead of lower priority components.
*/
priority?: number
}
export interface ComponentsOptions {

View File

@ -5,7 +5,7 @@ import { determineBumpType, loadWorkspace } from './_utils'
const nightlyPackages = {
nitropack: 'nitropack-edge',
h3: 'h3-nightly',
nuxi: 'nuxi-ng'
nuxi: 'nuxi-edge'
}
async function main () {

View File

@ -19,7 +19,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
for (const outputDir of ['.output', '.output-inline']) {
it('default client bundle size', async () => {
const clientStats = await analyzeSizes('**/*.js', join(rootDir, outputDir, 'public'))
expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot('"96.9k"')
expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot('"97.0k"')
expect(clientStats.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
[
"_nuxt/entry.js",

View File

@ -4,4 +4,5 @@ export default defineNuxtRouteMiddleware((to) => {
statusCode: 401
})
}
return true
})