Skip to content

Commit e1724bc

Browse files
committedFeb 18, 2025
fix(devtools): rework path debugging
Fixes #189
1 parent a74cb62 commit e1724bc

File tree

13 files changed

+85
-18
lines changed

13 files changed

+85
-18
lines changed
 

Diff for: ‎.playground/components/DisableIndexing.vue

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script lang="ts" setup>
2+
import { disableIndexing } from '../composables/robots'
3+
4+
disableIndexing()
5+
</script>
6+
7+
<template>
8+
<div>disable</div>
9+
</template>

Diff for: ‎.playground/composables/robots.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { useRobotsRule } from '#robots/app/composables/useRobotsRule'
2+
3+
export function disableIndexing() {
4+
return useRobotsRule(false)
5+
}

Diff for: ‎.playground/pages/composable-false.vue

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script lang="ts" setup>
2+
import { useRobotsRule } from '#imports'
3+
4+
const rule = useRobotsRule(false)
5+
</script>
6+
7+
<template>
8+
<div>rule: {{ rule }}</div>
9+
</template>

Diff for: ‎.playground/pages/composable-nested.vue

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script lang="ts" setup>
2+
</script>
3+
4+
<template>
5+
<div>
6+
<DisableIndexing />
7+
</div>
8+
</template>

Diff for: ‎client/app.vue

+10-4
Original file line numberDiff line numberDiff line change
@@ -216,17 +216,23 @@ const tab = useLocalStorage('nuxt-robots:tab', 'overview')
216216
<div v-else>
217217
<div class="inline-flex gap-3 mb-5 items-center">
218218
<div>
219-
<NIcon v-if="pathDebugData?.indexable" icon="carbon:checkmark-filled" class="text-green-300" />
219+
<NIcon v-if="pathDebugData?.indexable && pathDebugData.crawlable" icon="carbon:checkmark-filled" class="text-green-300" />
220220
<NIcon v-else icon="carbon:warning-filled" class="text-red-300" />
221221
</div>
222-
<div v-if="pathDebugData.indexable">
223-
Robots can crawl <code class="opacity-60 text-sm">{{ path }}</code>.
222+
<div v-if="!pathDebugData.crawlable">
223+
Robots are not allowed to access <code class="opacity-60 text-sm">{{ path }}</code>.
224+
</div>
225+
<div v-else-if="!pathDebugData.indexable">
226+
Robots are not allowed to index <code class="opacity-60 text-sm">{{ path }}</code>, however, they can access it.
224227
</div>
225228
<div v-else>
226-
Robots are blocked from crawling <code class="opacity-60 text-sm">{{ path }}</code>.
229+
Robots can access and crawl <code class="opacity-60 text-sm">{{ path }}</code>.
227230
</div>
228231
</div>
229232
<OCodeBlock :code="metaTag" lang="html" />
233+
<div v-if="pathDebugData.robotsHeader" class="mt-3">
234+
<OCodeBlock :code="`X-Robots-Tag: ${pathDebugData.robotsHeader}`" lang="bash" />
235+
</div>
230236
<div v-if="pathDebugData?.debug" class="mt-3 flex gap-2">
231237
<div v-if="pathDebugData?.debug?.source" class="text-xs text-gray-300 mt-3 border-gray-600 rounded-xl border-1 px-2 py-1 inline-flex">
232238
Source: {{ pathDebugData?.debug?.source }}

Diff for: ‎client/composables/shiki.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function loadShiki() {
1616
langs: [
1717
'html',
1818
'json',
19+
'bash',
1920
Object.freeze({
2021
displayName: 'robots.txt',
2122
name: 'robots-txt',

Diff for: ‎src/module.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -489,11 +489,9 @@ declare module 'nitropack' {
489489
}
490490
}
491491
declare module 'h3' {
492+
import type { RobotsContext } from '#robots/types'
492493
interface H3EventContext {
493-
robots: {
494-
rule: string
495-
indexable: boolean
496-
}
494+
robots: RobotsContext
497495
}
498496
}
499497
`

Diff for: ‎src/runtime/app/composables/useRobotsRule.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import type { MaybeRef } from 'vue'
2+
// @ts-expect-error untyped
3+
import { devRootDir } from '#build/nuxt.config.mjs'
24
import { injectHead, useHead } from '@unhead/vue'
35
import { setHeader } from 'h3'
46
import {
57
useRequestEvent,
68
useRuntimeConfig,
79
} from 'nuxt/app'
8-
import { computed, onBeforeUnmount, ref, toValue } from 'vue'
10+
import { computed, getCurrentInstance, onBeforeUnmount, ref, toValue } from 'vue'
911

1012
/**
1113
* Get and set the current robots rule.
1214
*/
1315
export function useRobotsRule(rule?: MaybeRef<boolean | string>) {
1416
const head = injectHead()
17+
const vm = getCurrentInstance()
1518
if (import.meta.client) {
1619
// bit hacky but should work fine
1720
const robotsRef = ref(document.querySelector('meta[name="robots"]')?.getAttribute('content') || '')
@@ -39,8 +42,9 @@ export function useRobotsRule(rule?: MaybeRef<boolean | string>) {
3942
useHead({
4043
meta: [
4144
{
42-
name: 'robots',
43-
content: _rule,
45+
'name': 'robots',
46+
'content': _rule,
47+
'data-hint': import.meta.dev ? `useRobotsRule,.${vm ? vm.type?.__file?.split(devRootDir)[1] : ''}` : undefined,
4448
},
4549
],
4650
}, {

Diff for: ‎src/runtime/app/plugins/robot-meta.server.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default defineNuxtPlugin({
1515
{
1616
'name': 'robots',
1717
'content': () => ctx.rule || '',
18-
'data-hint': () => config['nuxt-robots']?.debug ? ctx.debug?.source : undefined,
18+
'data-hint': () => config['nuxt-robots']?.debug && ctx.debug?.source ? `${ctx.debug?.source},${ctx.debug?.line}` : undefined,
1919
},
2020
],
2121
})

Diff for: ‎src/runtime/server/composables/getPathRobotConfig.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { H3Event } from 'h3'
2+
import type { RobotsContext } from '../../types'
23
import { getRequestHeader } from 'h3'
34
import { useNitroApp, useRuntimeConfig } from 'nitropack/runtime'
45
import { withoutTrailingSlash } from 'ufo'
56
import { matchPathToRule, normaliseRobotsRouteRule } from '../../util'
67
import { createNitroRouteRuleMatcher } from '../kit'
78
import { getSiteRobotConfig } from './getSiteRobotConfig'
89

9-
export function getPathRobotConfig(e: H3Event, options?: { userAgent?: string, skipSiteIndexable?: boolean, path?: string }): { rule: string, indexable: boolean, debug?: { source: string, line: string } } {
10+
export function getPathRobotConfig(e: H3Event, options?: { userAgent?: string, skipSiteIndexable?: boolean, path?: string }): RobotsContext {
1011
// has already been resolved
1112
const { robotsDisabledValue, robotsEnabledValue, isNuxtContentV2 } = useRuntimeConfig()['nuxt-robots']
1213
if (!options?.skipSiteIndexable) {

Diff for: ‎src/runtime/server/middleware/injectContext.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { getPathRobotConfig } from '../composables/getPathRobotConfig'
55
export default defineEventHandler(async (e) => {
66
if (e.path === '/robots.txt' || e.path.startsWith('/__') || e.path.startsWith('/api') || e.path.startsWith('/_nuxt'))
77
return
8-
const robotConfig = getPathRobotConfig(e)
98
const nuxtRobotsConfig = useRuntimeConfig(e)['nuxt-robots']
109
if (nuxtRobotsConfig) {
1110
const { header } = nuxtRobotsConfig
11+
const robotConfig = getPathRobotConfig(e)
1212
if (header) {
1313
setHeader(e, 'X-Robots-Tag', robotConfig.rule)
1414
}

Diff for: ‎src/runtime/server/routes/__robots__/debug-path.ts

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
11
import { defineEventHandler, getQuery } from 'h3'
2-
import { getPathRobotConfig } from '../../composables/getPathRobotConfig'
2+
import { withQuery } from 'ufo'
33

44
export default defineEventHandler(async (e) => {
5-
const path = getQuery(e).path as string
6-
return getPathRobotConfig(e, {
5+
const query = getQuery(e)
6+
const path = query.path as string
7+
delete query.path
8+
// we have to fetch the path to know for sure
9+
const res = await $fetch.raw(withQuery(path, query))
10+
const html = res._data
11+
const robotsHeader = String(res.headers.get('x-robots-tag'))
12+
// get robots meta tag <meta name="robots" content="noindex, nofollow" data-hint="useRobotsRule">
13+
// <meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
14+
const robotsMeta = html.match(/<meta[^>]+name=["']robots["'][^>]+content=["']([^"']+)["'](?:[^>]+data-hint=["']([^"']+)["'])?[^>]*>/i)
15+
const [, robotsContent = null, robotsHint = null] = robotsMeta || []
16+
const [source, line] = robotsHint ? robotsHint.split(',') : [null, null]
17+
return {
18+
rule: robotsContent,
19+
indexable: !(robotsContent?.includes('noindex') && robotsHeader?.includes('noindex')),
20+
crawlable: !(source === '/robots.txt'),
721
path,
8-
})
22+
debug: {
23+
source,
24+
line,
25+
},
26+
robotsHeader,
27+
robotsContent,
28+
}
929
})

Diff for: ‎src/runtime/types.ts

+6
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,9 @@ export interface AutoI18nConfig {
5656
defaultLocale: string
5757
strategy: 'prefix' | 'prefix_except_default' | 'prefix_and_default' | 'no_prefix'
5858
}
59+
60+
export interface RobotsContext {
61+
rule: string
62+
indexable: boolean
63+
debug?: { source: string, line?: string }
64+
}

0 commit comments

Comments
 (0)
Please sign in to comment.