Refactor code structure for improved readability and maintainability
This commit is contained in:
+10
-4
@@ -1,9 +1,12 @@
|
|||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
|
|
||||||
// استراتژی چند-دامنهای: هر دامنهی شهری یک property مستقل و first-class است.
|
// استراتژی canonical: محتوای همهی دامنههای شهری از nobat724.com تغذیه میشود —
|
||||||
// هر صفحه self-canonical روی هاست جاری میگیرد؛ هرگز به دامنهی اصلی canonical نمیدهیم.
|
// پس canonical هر صفحه (روی هر دامنهای) به همان مسیر روی دامنهی اصلی اشاره میکند.
|
||||||
|
// دامنهی اصلی هم self-canonical میگیرد.
|
||||||
|
// توجه: buildCanonicalUrl per-host است و برای JSON-LD/sitemap/robots استفاده میشود — به آن دست نزن.
|
||||||
|
|
||||||
const DEFAULT_HOST = "nobat724.com";
|
const DEFAULT_HOST = "nobat724.com";
|
||||||
|
const MAIN_ORIGIN = "https://nobat724.com";
|
||||||
|
|
||||||
export function normalizeHost(rawHost) {
|
export function normalizeHost(rawHost) {
|
||||||
return (rawHost || DEFAULT_HOST).toLowerCase().replace(/^www\./, "");
|
return (rawHost || DEFAULT_HOST).toLowerCase().replace(/^www\./, "");
|
||||||
@@ -34,15 +37,18 @@ export async function getRequestOrigin() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildMainCanonicalUrl(pathname) {
|
||||||
|
return `${MAIN_ORIGIN}${buildCanonicalPath(pathname)}`;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getCanonicalUrl() {
|
export async function getCanonicalUrl() {
|
||||||
try {
|
try {
|
||||||
const headersList = await headers();
|
const headersList = await headers();
|
||||||
const host = headersList.get("host");
|
|
||||||
const pathname = headersList.get("x-pathname");
|
const pathname = headersList.get("x-pathname");
|
||||||
// مسیرهای خارج از matcher میدلور (panel/dashboard/login) این هدر را ندارند —
|
// مسیرهای خارج از matcher میدلور (panel/dashboard/login) این هدر را ندارند —
|
||||||
// آنها noindex هستند و نباید canonical جعلی به ریشه بگیرند.
|
// آنها noindex هستند و نباید canonical جعلی به ریشه بگیرند.
|
||||||
if (!pathname) return null;
|
if (!pathname) return null;
|
||||||
return buildCanonicalUrl(host, pathname);
|
return buildMainCanonicalUrl(pathname);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error generating canonical URL:", error);
|
console.error("Error generating canonical URL:", error);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { getStateInfoClient } from '@/lib/getStateInfoClient';
|
import { getStateInfoClient } from '@/lib/getStateInfoClient';
|
||||||
import { buildCanonicalUrl, buildCanonicalPath, normalizeHost } from '@/lib/getCanonicalUrl';
|
import {
|
||||||
|
buildCanonicalUrl,
|
||||||
|
buildCanonicalPath,
|
||||||
|
buildMainCanonicalUrl,
|
||||||
|
normalizeHost,
|
||||||
|
} from '@/lib/getCanonicalUrl';
|
||||||
|
|
||||||
function setLocation(loc) {
|
function setLocation(loc) {
|
||||||
Object.defineProperty(window, 'location', { value: loc, writable: true, configurable: true });
|
Object.defineProperty(window, 'location', { value: loc, writable: true, configurable: true });
|
||||||
@@ -56,3 +61,18 @@ describe('buildCanonicalUrl (self-canonical per-host)', () => {
|
|||||||
expect(buildCanonicalUrl(null, '/x')).toBe('https://nobat724.com/x');
|
expect(buildCanonicalUrl(null, '/x')).toBe('https://nobat724.com/x');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('buildMainCanonicalUrl (canonical متادیتا → دامنهی اصلی)', () => {
|
||||||
|
it('هر مسیری → همان مسیر روی nobat724.com', () => {
|
||||||
|
expect(buildMainCanonicalUrl('/doctors')).toBe('https://nobat724.com/doctors');
|
||||||
|
expect(buildMainCanonicalUrl('/doctor/abc-123')).toBe('https://nobat724.com/doctor/abc-123');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ریشه → با trailing slash', () => {
|
||||||
|
expect(buildMainCanonicalUrl('/')).toBe('https://nobat724.com/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('query و trailing slash حذف میشوند', () => {
|
||||||
|
expect(buildMainCanonicalUrl('/doctors/?specialty=قلب')).toBe('https://nobat724.com/doctors');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
+3
-20
@@ -2,34 +2,17 @@
|
|||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
// Add other configurations below
|
// Add other configurations below
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
// متادیتا (canonical/OG/keywords) باید داخل <head> رندر شود نه استریم در <body>.
|
||||||
|
// از Next 15.2 استریم متادیتا پیشفرض است؛ این regex همهی UAها را blocking میکند.
|
||||||
|
htmlLimitedBots: /.*/,
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'api.clinic-pro.ir',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'https',
|
|
||||||
hostname: 'clinicpro.liara.run',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'http',
|
|
||||||
hostname: 'clinic-pro.ir',
|
hostname: 'clinic-pro.ir',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'back-dev.clinic-pro.ir',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'https',
|
|
||||||
hostname: 'clinic-pro-back.ddev.site',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'https',
|
|
||||||
hostname: 'clinic-pro.ddev.site',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'http',
|
|
||||||
hostname: 'clinic-pro.ddev.site',
|
hostname: 'clinic-pro.ddev.site',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user