diff --git a/.github/workflows/pull-preview.yml b/.github/workflows/pull-preview.yml new file mode 100644 index 00000000..fa1555bd --- /dev/null +++ b/.github/workflows/pull-preview.yml @@ -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 diff --git a/README.md b/README.md index 45ef0347..732fdc3b 100644 --- a/README.md +++ b/README.md @@ -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., ``) 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) diff --git a/docs/.navigation.yml b/docs/.navigation.yml new file mode 100644 index 00000000..03e30b2a --- /dev/null +++ b/docs/.navigation.yml @@ -0,0 +1 @@ +title: Nuxt Hints diff --git a/docs/1.configuration.md b/docs/1.configuration.md new file mode 100644 index 00000000..04558e4c --- /dev/null +++ b/docs/1.configuration.md @@ -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). diff --git a/docs/2.web-vitals.md b/docs/2.web-vitals.md new file mode 100644 index 00000000..2e93ed10 --- /dev/null +++ b/docs/2.web-vitals.md @@ -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. diff --git a/docs/3.hydration.md b/docs/3.hydration.md new file mode 100644 index 00000000..779ebff6 --- /dev/null +++ b/docs/3.hydration.md @@ -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. diff --git a/docs/4.third-party-scripts.md b/docs/4.third-party-scripts.md new file mode 100644 index 00000000..46e3b391 --- /dev/null +++ b/docs/4.third-party-scripts.md @@ -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. diff --git a/docs/5.lazy-load.md b/docs/5.lazy-load.md new file mode 100644 index 00000000..52470bd0 --- /dev/null +++ b/docs/5.lazy-load.md @@ -0,0 +1,28 @@ +--- +title: Lazy Load +description: Find statically imported components that never render during SSR or hydration, and lazy-load them. +--- + +Identify statically imported components that were never rendered during SSR or initial hydration. The module suggests converting them to lazy-loaded components to reduce your users' initial bundle size. + +![Lazy load panel in the Nuxt DevTools](./images/devtools-lazy-load.png) + +## How it works + +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. + +## Fixing a suggestion + +Either prefix the component with `Lazy`, or use `defineAsyncComponent`, so it is only downloaded when needed: + +```vue + +``` + +::note{to="/docs/4.x/directory-structure/app/components#dynamic-imports"} +Read more about lazy-loading components in the Nuxt documentation. +:: diff --git a/docs/6.html-validate.md b/docs/6.html-validate.md new file mode 100644 index 00000000..b9ae3468 --- /dev/null +++ b/docs/6.html-validate.md @@ -0,0 +1,28 @@ +--- +title: HTML Validation +description: Validate every server-rendered page with html-validate. +--- + +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`. + +![HTML validation panel in the Nuxt DevTools](./images/devtools-html-validate.png) + +## Options + +The `options` are an [`html-validate` configuration](https://html-validate.org/usage/index.html#configuration), merged with the defaults of Nuxt Hints. By default, the `html-validate:standard`, `html-validate:document` and `html-validate:browser` presets are enabled, with a few rules turned off because they conflict with Nuxt defaults. + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + hints: { + features: { + htmlValidate: { + options: { + rules: { + 'no-redundant-role': 'off', + }, + }, + }, + }, + }, +}) +``` diff --git a/docs/7.contributing.md b/docs/7.contributing.md new file mode 100644 index 00000000..49ac444d --- /dev/null +++ b/docs/7.contributing.md @@ -0,0 +1,41 @@ +--- +title: Contributing +description: We can never thank you enough for your contributions. +--- + +::warning +It is highly recommended to read [the Nuxt contribution guide](/docs/community/contribution) before making any contributions. +:: + +## Development + +- Clone the [nuxt/hints](https://github.com/nuxt/hints) repository +- Enable Corepack using `corepack enable` +- Apply your changes, then check them with the commands below + +```bash +# Install dependencies +pnpm install + +# Generate type stubs +pnpm run dev:prepare + +# Develop with the playground +pnpm run dev + +# Build the playground +pnpm run dev:build + +# Run ESLint +pnpm run lint + +# Run Vitest +pnpm run test +pnpm run test:watch +``` + +## Documentation + +The documentation lives in the [`docs/`](https://github.com/nuxt/hints/tree/main/docs) directory and is published on [nuxt.com/modules/hints](/modules/hints). Keep images next to the pages in `docs/images/` and link them with a relative path, such as `![Hints tab](./images/devtools-homepage.png)`. + +To preview your changes, run the [nuxt.com](https://github.com/nuxt/nuxt.com) dev server with `NUXT_HINTS_PATH` set to your local clone of this repo. Pull requests changing `docs/` can also be previewed on nuxt.com once a maintainer adds the `preview:enabled` label. diff --git a/.github/assets/devtools-homepage.png b/docs/images/devtools-homepage.png similarity index 100% rename from .github/assets/devtools-homepage.png rename to docs/images/devtools-homepage.png diff --git a/.github/assets/devtools-html-validate.png b/docs/images/devtools-html-validate.png similarity index 100% rename from .github/assets/devtools-html-validate.png rename to docs/images/devtools-html-validate.png diff --git a/.github/assets/devtools-hydration.png b/docs/images/devtools-hydration.png similarity index 100% rename from .github/assets/devtools-hydration.png rename to docs/images/devtools-hydration.png diff --git a/.github/assets/devtools-lazy-load.png b/docs/images/devtools-lazy-load.png similarity index 100% rename from .github/assets/devtools-lazy-load.png rename to docs/images/devtools-lazy-load.png diff --git a/.github/assets/devtools-thirdparties.png b/docs/images/devtools-thirdparties.png similarity index 100% rename from .github/assets/devtools-thirdparties.png rename to docs/images/devtools-thirdparties.png diff --git a/.github/assets/devtools-webvitals.png b/docs/images/devtools-webvitals.png similarity index 100% rename from .github/assets/devtools-webvitals.png rename to docs/images/devtools-webvitals.png diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..5786d848 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,86 @@ +--- +title: Nuxt Hints +description: 'Real-time feedback on your Nuxt app performance, accessibility, and security, right in your browser.' +navigation: + title: Quick Start +--- + +## Introduction + +Nuxt Hints integrates directly into the [Nuxt DevTools](/modules/devtools), giving you actionable insights to improve your web vitals, fix hydration mismatches, and audit third-party scripts without ever leaving your development environment. + +![Nuxt Hints homepage in the Nuxt DevTools](./images/devtools-homepage.png) + +- **Rich DevTools UI**: a dedicated tab in Nuxt DevTools to visualize issues, inspect elements, and get recommendations. +- **[Web Vitals](/modules/hints/web-vitals)**: real-time metrics for LCP, INP, and CLS with detailed attribution and element-specific optimization tips. +- **[Hydration mismatch debugging](/modules/hints/hydration)**: side-by-side diffing of server-rendered and client-hydrated HTML to pinpoint the exact cause of mismatches. +- **[Third-party script auditing](/modules/hints/third-party-scripts)**: a dashboard to monitor performance, identify render-blocking scripts, and get security recommendations. +- **[Unused component detection](/modules/hints/lazy-load)**: detects statically imported components that aren't rendered during SSR or hydration and suggests lazy-loading them to reduce bundle size. +- **[HTML validation](/modules/hints/html-validate)**: every server-rendered page is checked with [`html-validate`](https://html-validate.org/). + +## Automatic Installation + +To get started, add `@nuxt/hints` to your project: + +```bash +npx nuxt add hints +``` + +The module is now installed and added to your `nuxt.config.ts`. + +## Manual Installation + +Or you can install it manually. + +::code-group + ```bash [pnpm] + pnpm i @nuxt/hints + ``` + ```bash [yarn] + yarn add @nuxt/hints + ``` + ```bash [npm] + npm i @nuxt/hints + ``` +:: + +Then, add it to the `modules` in your `nuxt.config`: + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + modules: [ + '@nuxt/hints', + ], +}) +``` + +::note +Nuxt Hints only runs during development (`nuxt dev`). It adds nothing to your production build. +:: + +## Usage + +Start your Nuxt app, open the Nuxt DevTools and click the **Hints** icon to get started. + +The homepage is a central hub to see a summary of all detected issues at a glance. From there, every feature has its own panel: + +- **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. + +## Console Warnings + +Nuxt Hints also prints clear, concise messages in your browser console that guide you to best practices and performance improvements: + +``` +[@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. +``` + +::tip{to="/modules/hints/configuration"} +If you feel overwhelmed by logs, you can disable some features or only their console output, and fix things step by step. +::