Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/pull-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: pull-preview

on:
# zizmor: ignore[dangerous-triggers] - DO NOT add actions/checkout: the called workflow only reads PR metadata
pull_request_target:
branches:
- main
paths:
- 'docs/**'
types:
- opened
- reopened
- synchronize
- labeled
- unlabeled
- closed

permissions: {}

concurrency:
group: pull-preview-${{ github.event.pull_request.number }}
cancel-in-progress: false
queue: max

jobs:
comment:
if: github.repository == 'nuxt/hints'
permissions:
pull-requests: write
uses: nuxt/nuxt.com/.github/workflows/pull-preview-comment.yml@main # zizmor: ignore[unpinned-uses] - nuxt.com owns the preview comment
170 changes: 17 additions & 153 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,171 +9,35 @@

Nuxt Hints integrates directly into the Nuxt DevTools, giving you actionable insights to improve your web vitals, fix hydration mismatches, and audit third-party scripts without ever leaving your development environment.

- [✨Release Notes](/CHANGELOG.md)
- [📖  Read Documentation](https://nuxt.com/modules/hints)
- [✨  Release Notes](https://github.com/nuxt/hints/releases)

## Getting Started

To install and add the module, you can run the following command:

```bash
npx nuxt module add hints
```

The module is now automatically installed and added to your `nuxt.config.ts`.
Now you can open your Nuxt app, go to the DevTools, and click the Nuxt Hints icon to get started.
![Nuxt Hints homepage in the Nuxt DevTools](./docs/images/devtools-homepage.png)

## Features

- **🚀 Rich DevTools UI**: A dedicated tab in Nuxt DevTools to visualize issues, inspect elements, and get recommendations.
- **💧 Hydration Mismatch Debugging**: Side-by-side diffing of server-rendered and client-hydrated HTML to pinpoint the exact cause of mismatches.
- **⚡️ Web Vitals Analysis**: Real-time metrics for LCP, INP, and CLS with detailed attribution and element-specific optimization tips.
- **📦 Third-Party Script Auditing**: Dashboard to monitor performance, identify render-blocking scripts, and get security recommendations.
- **🧩 Unused Component Detection**: Detects statically imported components that aren't rendered during SSR or hydration and suggests lazy-loading them to reduce bundle size.
- **🔍 Interactive Diagnostics**:
- **Hover to Highlight**: Hover over an issue in the DevTools to highlight the corresponding element on your page.
- **Click to Inspect**: Click to open the component source file directly in your code editor.
- **💡 Actionable Console Warnings**: Clear, concise console messages that guide you to best practices and performance improvements.

## Visual Interface within Devtools

Nuxt Hints provides a rich, interactive UI inside the Nuxt DevTools panel.

### Homepage

A central hub to see a summary of all detected issues at a glance.

![hints devtools homepage screenshot](./.github/assets/devtools-homepage.png)

### Web Vitals

Drill down into Core Web Vitals metrics. See detailed attribution for LCP, INP, and CLS, inspect the problematic elements, and get context-aware advice.

![hints devtools web vitals screenshot](./.github/assets/devtools-webvitals.png)

### Hydration Inspector

Debug hydration mismatches with a powerful side-by-side diff viewer. See the exact differences between the server-rendered HTML and the client-side result.

![hints devtools hydration screenshot](./.github/assets/devtools-hydration.png)

### Third-Party Scripts

Analyze all third-party scripts on your page. The dashboard shows loading times, render-blocking status, and security attributes, helping you identify and mitigate performance bottlenecks.

![hints devtools third-party screenshot](./.github/assets/devtools-thirdparties.png)

### Unused Imported Component Detection (Lazy Load)

Identify statically imported components that were never rendered during SSR or initial hydration. The module suggests converting them to lazy-loaded components to reduce end-users initial bundle size.

![hints devtools lazy-load screenshot](./.github/assets/devtools-lazy-load.png)

## How It Works

### Performance Monitoring

Nuxt Hints uses `web-vitals` to gather Core Web Vitals metrics and automatically logs any msetrics that need improvement. It listens for INP, LCP, and CLS and provides detailed attribution for each.

### Hydration Mismatch Detection

The module hooks into Vue's hydration process to compare the server-rendered DOM with the client-side DOM. When a mismatch is detected, it captures the pre- and post-hydration HTML for inspection.

### Third-Party Script Analysis

Using a combination of a Nitro plugin and client-side observers, Nuxt Hints tracks every script loaded on the page, measuring its performance and analyzing its attributes.
- 🚀 Rich DevTools UI to visualize issues, inspect elements, and get recommendations
- ⚡️ [Web Vitals](https://nuxt.com/modules/hints/web-vitals) analysis for LCP, INP, and CLS
- 💧 [Hydration mismatch](https://nuxt.com/modules/hints/hydration) debugging with a side-by-side diff
- 📦 [Third-party script](https://nuxt.com/modules/hints/third-party-scripts) auditing
- 🧩 [Unused component detection](https://nuxt.com/modules/hints/lazy-load) to suggest lazy-loading
- ✅ [HTML validation](https://nuxt.com/modules/hints/html-validate) of server-rendered pages

### Unused Component Detection (Lazy Load)

At build time, a Vite plugin analyzes your component imports to identify statically imported `.vue` components. At runtime, the module tracks which of those components actually render during SSR and initial hydration. After the page finishes loading, any imported component that was never rendered is flagged as a candidate for lazy loading.

Suggestions are reported to the console and sent to the DevTools UI via Server-Sent Events, where you can review them per route and dismiss entries you've already addressed. The recommended fix is to either prefix the component with `Lazy` (e.g., `<LazyHeavyComponent>`) or use `defineAsyncComponent` so it is only downloaded when needed.

### HTML Validate integration

Nuxt Hints includes a built-in HTML validation feature powered by [`html-validate`](https://html-validate.org/). On every server-rendered response, the module intercepts the HTML output and runs it through `html-validate`.

![hints html-validate screenshot](./.github/assets/devtools-html-validate.png)

### Example Console Output

When Nuxt Hints detects issues, you'll see clear warnings in your browser console:

```
[@nuxt/hints:performance] LCP Element should not have `loading="lazy"`
Learn more: https://web.dev/optimize-lcp/#optimize-the-priority-the-resource-is-given
```

```
[@nuxt/hints] Third-party script "https://cdn.example.com/script.js" is missing crossorigin attribute.
Consider adding crossorigin="anonymous" for better security and error reporting.
```

## Module Options

Configure the module in your `nuxt.config.ts` under the `hints` key:

```typescript
export default defineNuxtConfig({
hints: {
devtools: true,

// Enable or configure individual features
// if you feel overwhelmed by logs, you can disable some features and fix things step by step.
features: {
// Defaults to true for each feature
hydration: true,
},
},
})
```

### Feature toggles

Each feature accepts either a **boolean** or an **object** for finer control:

| Key | Description |
|-----|-------------|
| `hydration` | Detect and inspect hydration mismatches |
| `lazyLoad` | Flag unused imported components that could be lazy-loaded |
| `webVitals` | Track LCP, INP, and CLS metrics |
| `thirdPartyScripts` | Audit third-party scripts for performance and security |
| `htmlValidate` | Validate server-rendered HTML with [html-validate](https://html-validate.org/) |

When using the object syntax, the following flags are available:

```typescript
{
logs: true, // Print warnings to the browser console
devtools: true, // Show this feature in the DevTools panel
options: { ... }, // Feature-specific options
}
```

## Development
## Quick Setup

```bash
# Install dependencies
pnpm install

# Generate type stubs
pnpm run dev:prepare
npx nuxt add hints
```

# Develop with the playground
pnpm run dev
Then open your Nuxt app, go to the DevTools, and click the Hints icon to get started.

# Build the playground
pnpm run dev:build
## Contributing

# Run ESLint
pnpm run lint
See the [contributing guide](https://nuxt.com/modules/hints/contributing).

# Run Vitest
pnpm run test
pnpm run test:watch
## License

# Release new version
pnpm run release
```
[MIT License](./LICENSE)

<!-- Badges -->

Expand Down
1 change: 1 addition & 0 deletions docs/.navigation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
title: Nuxt Hints
65 changes: 65 additions & 0 deletions docs/1.configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
title: Configuration
description: Configure Nuxt Hints and enable or disable each feature.
---

Configure the module in your `nuxt.config.ts` under the `hints` key:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
modules: ['@nuxt/hints'],
hints: {
devtools: true,

// Enable or configure individual features
// if you feel overwhelmed by logs, you can disable some features and fix things step by step.
features: {
// Defaults to true for each feature
hydration: true,
},
},
})
```

## `devtools`

- Type: `boolean`
- Default: `true`

Adds the **Hints** tab to the Nuxt DevTools.

## `features`

Each feature is enabled by default and accepts either a **boolean** or an **object** for finer control:

| Key | Description |
|-----|-------------|
| [`hydration`](/modules/hints/hydration) | Detect and inspect hydration mismatches |
| [`lazyLoad`](/modules/hints/lazy-load) | Flag unused imported components that could be lazy-loaded |
| [`webVitals`](/modules/hints/web-vitals) | Track LCP, INP, and CLS metrics |
| [`thirdPartyScripts`](/modules/hints/third-party-scripts) | Audit third-party scripts for performance and security |
| [`htmlValidate`](/modules/hints/html-validate) | Validate server-rendered HTML with [html-validate](https://html-validate.org/) |

When using the object syntax, the following flags are available:

```ts
{
logs: true, // Print warnings to the browser console
devtools: true, // Show this feature in the DevTools panel
options: { ... }, // Feature-specific options
}
```

`logs` and `devtools` default to `true` when omitted. For example, to keep the hydration panel in the DevTools without the console warnings:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
hints: {
features: {
hydration: { logs: false },
},
},
})
```

The `options` accepted by each feature are described on its own page: [Web Vitals](/modules/hints/web-vitals#options), [Third-Party Scripts](/modules/hints/third-party-scripts#options) and [HTML Validation](/modules/hints/html-validate#options).
45 changes: 45 additions & 0 deletions docs/2.web-vitals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
title: Web Vitals
description: Drill down into Core Web Vitals metrics with detailed attribution for LCP, INP, and CLS.
---

Drill down into Core Web Vitals metrics. See detailed attribution for LCP, INP, and CLS, inspect the problematic elements, and get context-aware advice.

![Web Vitals panel in the Nuxt DevTools](./images/devtools-webvitals.png)

## How it works

Nuxt Hints uses [`web-vitals`](https://github.com/GoogleChrome/web-vitals) to gather Core Web Vitals metrics and automatically logs any metrics that need improvement. It listens for INP, LCP, and CLS and provides detailed attribution for each.

When the LCP element is an image, Nuxt Hints also checks it and warns when it is lazy-loaded or not served in a modern format like `webp` or `avif`.

## Options

```ts [nuxt.config.ts]
export default defineNuxtConfig({
hints: {
features: {
webVitals: {
options: {
trackedMetrics: ['LCP', 'CLS'],
ignoreDomains: ['images.example.com'],
},
},
},
},
})
```

### `trackedMetrics`

- Type: `Array<'LCP' | 'INP' | 'CLS'>`
- Default: `['LCP', 'INP', 'CLS']`

The metrics to track.

### `ignoreDomains`

- Type: `string[]`
- Default: `[]`

Skip the LCP image checks for images served from these domains and their subdomains.
12 changes: 12 additions & 0 deletions docs/3.hydration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: Hydration
description: Debug hydration mismatches with a side-by-side diff of the server-rendered and client-side HTML.
---

Debug hydration mismatches with a powerful side-by-side diff viewer. See the exact differences between the server-rendered HTML and the client-side result.

![Hydration panel in the Nuxt DevTools](./images/devtools-hydration.png)

## How it works

The module hooks into Vue's hydration process to compare the server-rendered DOM with the client-side DOM. When a mismatch is detected, it captures the pre- and post-hydration HTML for inspection.
44 changes: 44 additions & 0 deletions docs/4.third-party-scripts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: Third-Party Scripts
description: Audit the loading time, render-blocking status, and security attributes of every third-party script.
---

Analyze all third-party scripts on your page. The dashboard shows loading times, render-blocking status, and security attributes, helping you identify and mitigate performance bottlenecks.

![Third-party scripts panel in the Nuxt DevTools](./images/devtools-thirdparties.png)

## How it works

Using a combination of a Nitro plugin and client-side observers, Nuxt Hints tracks every script loaded on the page, measuring its performance and analyzing its attributes.

Scripts served from your own origin and scripts injected by browser extensions are ignored.

## Options

```ts [nuxt.config.ts]
export default defineNuxtConfig({
hints: {
features: {
thirdPartyScripts: {
options: {
ignoredDomains: ['cdn.example.com'],
},
},
},
},
})
```

### `ignoredDomains`

- Type: `string[]`
- Default: `[]`

Additional domains, and their subdomains, to ignore when detecting third-party scripts.

### `ignoredSchemes`

- Type: `string[]`
- Default: `[]`

Additional URL schemes to ignore. Browser extension schemes (`chrome-extension`, `moz-extension`, `safari-extension` and `ms-browser-extension`) are always ignored.
Loading
Loading