← Files Willy SEOARCHIVED FILE
dist/src/rules/technical.js
8.13 KB · Oct 3, 2026 · 06:36 UTC
export function auditTechnical(data) {
const checks = [];
// 1. HTTP Status Code
if (data.statusCode >= 200 && data.statusCode < 300) {
checks.push({
id: 'tech-status-200',
category: 'technical',
name: 'Código de Estado HTTP',
status: 'good',
score: 100,
weight: 30,
message: `La página responde con código de estado HTTP ${data.statusCode} OK.`,
});
}
else if (data.statusCode >= 300 && data.statusCode < 400) {
checks.push({
id: 'tech-status-redirect',
category: 'technical',
name: 'Código de Estado HTTP',
status: 'warning',
score: 70,
weight: 30,
message: `La URL genera una redirección (HTTP ${data.statusCode}).`,
recommendation: 'Asegúrate de que la redirección sea 301 (permanente) y no cree bucles ni cadenas de redirección.',
});
}
else {
checks.push({
id: 'tech-status-error',
category: 'technical',
name: 'Código de Estado HTTP',
status: 'critical',
score: 0,
weight: 35,
message: `La página devuelve un error HTTP ${data.statusCode}.`,
recommendation: 'Revisa la disponibilidad del servidor o la ruta del recurso solicitado.',
});
}
// 2. Meta Robots (Index / Noindex)
if (data.metaRobots) {
if (data.metaRobots.includes('noindex')) {
checks.push({
id: 'tech-robots-noindex',
category: 'technical',
name: 'Directiva de Indexación (Meta Robots)',
status: 'critical',
score: 0,
weight: 30,
message: `Detectada directiva "noindex" (${data.metaRobots}). Esta página está bloqueada para los buscadores y NO aparecerá en Google.`,
recommendation: 'Si deseas posicionar esta página, elimina la etiqueta "noindex".',
snippet: `<meta name="robots" content="${data.metaRobots}">`,
});
}
else {
checks.push({
id: 'tech-robots-index',
category: 'technical',
name: 'Directiva de Indexación (Meta Robots)',
status: 'good',
score: 100,
weight: 20,
message: `Página indexable. Directiva: "${data.metaRobots}".`,
});
}
}
else {
checks.push({
id: 'tech-robots-default',
category: 'technical',
name: 'Directiva de Indexación (Meta Robots)',
status: 'good',
score: 100,
weight: 20,
message: 'No hay restricción de indexación (por defecto Google indexará la página: index, follow).',
});
}
// 3. Etiqueta Canonical
if (!data.canonical) {
checks.push({
id: 'tech-canonical-missing',
category: 'technical',
name: 'Etiqueta Canonical',
status: 'warning',
score: 50,
weight: 15,
message: 'No se ha especificado etiqueta <link rel="canonical">.',
recommendation: 'Añade una etiqueta canonical autorreferencial para prevenir problemas de contenido duplicado (con parámetros URL, www vs non-www, etc.).',
});
}
else {
try {
const pageUrl = new URL(data.url);
const canUrl = new URL(data.canonical, data.url);
const isSelfCanonical = pageUrl.origin + pageUrl.pathname === canUrl.origin + canUrl.pathname;
if (isSelfCanonical) {
checks.push({
id: 'tech-canonical-self',
category: 'technical',
name: 'Etiqueta Canonical',
status: 'good',
score: 100,
weight: 15,
message: 'Etiqueta canonical autorreferencial correctamente configurada.',
snippet: `<link rel="canonical" href="${data.canonical}" />`,
});
}
else {
checks.push({
id: 'tech-canonical-cross',
category: 'technical',
name: 'Etiqueta Canonical',
status: 'info',
score: 85,
weight: 15,
message: `La etiqueta canonical apunta a otra URL: "${data.canonical}".`,
recommendation: 'Verifica si esta página transfiere intencionadamente su autoridad a la URL canónica indicada.',
snippet: `<link rel="canonical" href="${data.canonical}" />`,
});
}
}
catch {
checks.push({
id: 'tech-canonical-invalid',
category: 'technical',
name: 'Etiqueta Canonical',
status: 'warning',
score: 40,
weight: 15,
message: `La URL de la etiqueta canonical es inválida: "${data.canonical}".`,
});
}
}
// 4. Tiempo de respuesta (TTFB/Server Response)
if (data.responseTimeMs > 2500) {
checks.push({
id: 'tech-response-time-slow',
category: 'technical',
name: 'Tiempo de Respuesta del Servidor (TTFB)',
status: 'critical',
score: 40,
weight: 15,
message: `Tiempo de respuesta elevado: ${data.responseTimeMs} ms.`,
recommendation: 'Optimiza la caché de servidor, consulta a base de datos o utiliza una CDN (Cloudflare) para reducir el tiempo por debajo de 600ms.',
});
}
else if (data.responseTimeMs > 1000) {
checks.push({
id: 'tech-response-time-medium',
category: 'technical',
name: 'Tiempo de Respuesta del Servidor (TTFB)',
status: 'warning',
score: 75,
weight: 15,
message: `Tiempo de respuesta moderado: ${data.responseTimeMs} ms.`,
recommendation: 'Recomendable optimizar para servir la respuesta en menos de 600 ms.',
});
}
else {
checks.push({
id: 'tech-response-time-fast',
category: 'technical',
name: 'Tiempo de Respuesta del Servidor (TTFB)',
status: 'good',
score: 100,
weight: 15,
message: `Excelente tiempo de respuesta: ${data.responseTimeMs} ms.`,
});
}
// 5. Viewport Móvil
if (!data.viewport) {
checks.push({
id: 'tech-viewport-missing',
category: 'technical',
name: 'Optimización Mobile-Friendly (Viewport)',
status: 'critical',
score: 0,
weight: 15,
message: 'Falta la metaetiqueta viewport. El sitio no se adaptará correctamente a dispositivos móviles.',
recommendation: 'Añade `<meta name="viewport" content="width=device-width, initial-scale=1.0">`.',
});
}
else {
checks.push({
id: 'tech-viewport-ok',
category: 'technical',
name: 'Optimización Mobile-Friendly (Viewport)',
status: 'good',
score: 100,
weight: 15,
message: 'Meta viewport configurado correctamente.',
});
}
// 6. Protocolo HTTPS
if (data.url.startsWith('http://')) {
checks.push({
id: 'tech-https-missing',
category: 'technical',
name: 'Seguridad HTTPS',
status: 'critical',
score: 0,
weight: 15,
message: 'La página se sirve mediante protocolo HTTP no seguro.',
recommendation: 'Instala un certificado SSL/TLS y fuerza la redirección a HTTPS (HSTS).',
});
}
else {
checks.push({
id: 'tech-https-ok',
category: 'technical',
name: 'Seguridad HTTPS',
status: 'good',
score: 100,
weight: 10,
message: 'Protocolo HTTPS seguro y verificado.',
});
}
return checks;
}
SHA-256: 18aa739a036f65761f591386d3b266fd078d416323b10456e0afafaf338d239d