Schema.org
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Injectable, inject, PLATFORM_ID } from '@angular/core';
|
||||
import { isPlatformBrowser } from '@angular/common';
|
||||
import { Injectable, inject, PLATFORM_ID, Renderer2, RendererFactory2 } from '@angular/core';
|
||||
import { isPlatformBrowser, DOCUMENT } from '@angular/common';
|
||||
import { Meta, Title } from '@angular/platform-browser';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@@ -22,11 +22,17 @@ export class SeoService {
|
||||
private router = inject(Router);
|
||||
private platformId = inject(PLATFORM_ID);
|
||||
private isBrowser = isPlatformBrowser(this.platformId);
|
||||
private document = inject(DOCUMENT);
|
||||
private renderer: Renderer2;
|
||||
|
||||
private readonly defaultImage = 'https://www.bizmatch.net/assets/images/bizmatch-og-image.jpg';
|
||||
private readonly siteName = 'BizMatch';
|
||||
private readonly baseUrl = 'https://www.bizmatch.net';
|
||||
|
||||
constructor(rendererFactory: RendererFactory2) {
|
||||
this.renderer = rendererFactory.createRenderer(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URL for SEO purposes
|
||||
*/
|
||||
@@ -109,20 +115,18 @@ export class SeoService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update canonical URL
|
||||
* Update canonical URL (SSR-compatible using Renderer2)
|
||||
*/
|
||||
private updateCanonicalUrl(url: string): void {
|
||||
if (!this.isBrowser) return;
|
||||
|
||||
let link: HTMLLinkElement | null = document.querySelector('link[rel="canonical"]');
|
||||
let link: HTMLLinkElement | null = this.document.querySelector('link[rel="canonical"]');
|
||||
|
||||
if (link) {
|
||||
link.setAttribute('href', url);
|
||||
this.renderer.setAttribute(link, 'href', url);
|
||||
} else {
|
||||
link = document.createElement('link');
|
||||
link.setAttribute('rel', 'canonical');
|
||||
link.setAttribute('href', url);
|
||||
document.head.appendChild(link);
|
||||
link = this.renderer.createElement('link');
|
||||
this.renderer.setAttribute(link, 'rel', 'canonical');
|
||||
this.renderer.setAttribute(link, 'href', url);
|
||||
this.renderer.appendChild(this.document.head, link);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,32 +273,40 @@ export class SeoService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject JSON-LD structured data into page
|
||||
* Inject JSON-LD structured data into page (SSR-compatible using Renderer2)
|
||||
*/
|
||||
injectStructuredData(schema: object): void {
|
||||
if (!this.isBrowser) return;
|
||||
// Clear existing schema scripts with the same type
|
||||
this.removeAllSchemas();
|
||||
|
||||
// Remove existing schema script
|
||||
const existingScript = document.querySelector('script[type="application/ld+json"]');
|
||||
if (existingScript) {
|
||||
existingScript.remove();
|
||||
}
|
||||
// Create new script element using Renderer2 (works in both SSR and browser)
|
||||
const script = this.renderer.createElement('script');
|
||||
this.renderer.setAttribute(script, 'type', 'application/ld+json');
|
||||
this.renderer.setAttribute(script, 'data-schema', 'true');
|
||||
|
||||
// Add new schema script
|
||||
const script = document.createElement('script');
|
||||
script.type = 'application/ld+json';
|
||||
script.text = JSON.stringify(schema);
|
||||
document.head.appendChild(script);
|
||||
// Create text node with schema JSON
|
||||
const schemaText = this.renderer.createText(JSON.stringify(schema));
|
||||
this.renderer.appendChild(script, schemaText);
|
||||
|
||||
// Append to document head
|
||||
this.renderer.appendChild(this.document.head, script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all structured data
|
||||
* Remove all schema scripts (internal helper, SSR-compatible)
|
||||
*/
|
||||
private removeAllSchemas(): void {
|
||||
const existingScripts = this.document.querySelectorAll('script[data-schema="true"]');
|
||||
existingScripts.forEach(script => {
|
||||
this.renderer.removeChild(this.document.head, script);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all structured data (SSR-compatible)
|
||||
*/
|
||||
clearStructuredData(): void {
|
||||
if (!this.isBrowser) return;
|
||||
|
||||
const scripts = document.querySelectorAll('script[type="application/ld+json"]');
|
||||
scripts.forEach(script => script.remove());
|
||||
this.removeAllSchemas();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -516,20 +528,21 @@ export class SeoService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject multiple structured data schemas
|
||||
* Inject multiple structured data schemas (SSR-compatible using Renderer2)
|
||||
*/
|
||||
injectMultipleSchemas(schemas: object[]): void {
|
||||
if (!this.isBrowser) return;
|
||||
// Clear existing schema scripts
|
||||
this.removeAllSchemas();
|
||||
|
||||
// Remove existing schema scripts
|
||||
this.clearStructuredData();
|
||||
|
||||
// Add new schema scripts
|
||||
// Add new schema scripts using Renderer2
|
||||
schemas.forEach(schema => {
|
||||
const script = document.createElement('script');
|
||||
script.type = 'application/ld+json';
|
||||
script.text = JSON.stringify(schema);
|
||||
document.head.appendChild(script);
|
||||
const script = this.renderer.createElement('script');
|
||||
this.renderer.setAttribute(script, 'type', 'application/ld+json');
|
||||
this.renderer.setAttribute(script, 'data-schema', 'true');
|
||||
|
||||
const schemaText = this.renderer.createText(JSON.stringify(schema));
|
||||
this.renderer.appendChild(script, schemaText);
|
||||
this.renderer.appendChild(this.document.head, script);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
// Development: use browser-bunyan for rich logging
|
||||
// Production: use lightweight console wrapper to avoid loading 50KB+ library
|
||||
export const createLogger = environment.production
|
||||
? (name: string) => ({
|
||||
info: (...args: any[]) => console.log(`[${name}]`, ...args),
|
||||
warn: (...args: any[]) => console.warn(`[${name}]`, ...args),
|
||||
error: (...args: any[]) => console.error(`[${name}]`, ...args),
|
||||
debug: () => {}, // no-op in production
|
||||
})
|
||||
: require('browser-bunyan').createLogger;
|
||||
// Lightweight logger implementation for both dev and production
|
||||
// Avoids dynamic require() which causes build issues
|
||||
const createLoggerImpl = (name: string) => ({
|
||||
info: (...args: any[]) => {
|
||||
if (!environment.production) {
|
||||
console.log(`[${name}]`, ...args);
|
||||
}
|
||||
},
|
||||
warn: (...args: any[]) => console.warn(`[${name}]`, ...args),
|
||||
error: (...args: any[]) => console.error(`[${name}]`, ...args),
|
||||
debug: (...args: any[]) => {
|
||||
if (!environment.production) {
|
||||
console.debug(`[${name}]`, ...args);
|
||||
}
|
||||
},
|
||||
trace: (...args: any[]) => {
|
||||
if (!environment.production) {
|
||||
console.trace(`[${name}]`, ...args);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const createLogger = createLoggerImpl;
|
||||
|
||||
Reference in New Issue
Block a user