properly shared seo fiels between containers
This commit is contained in:
parent
ce926cee4b
commit
77df5d6cd8
5 changed files with 5 additions and 149 deletions
|
|
@ -85,7 +85,7 @@ const siteMapService = {
|
|||
sitemap += `</urlset>`;
|
||||
|
||||
// Write sitemap to file
|
||||
const publicDir = path.join(__dirname, '../../public');
|
||||
const publicDir = path.join(__dirname, '../../public/seo-files');
|
||||
if (!fs.existsSync(publicDir)) {
|
||||
fs.mkdirSync(publicDir, { recursive: true });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ services:
|
|||
volumes:
|
||||
- ./frontend:/app
|
||||
- /app/node_modules
|
||||
- seo-volume:/app/public
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
|
|
@ -28,7 +29,8 @@ services:
|
|||
volumes:
|
||||
- ./backend:/app
|
||||
- /app/node_modules
|
||||
- ./backend/public/uploads:/app/public/uploads # Persist uploads
|
||||
- ./backend/public/uploads:/app/public/uploads
|
||||
- seo-volume:/app/public/seo-files
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
|
@ -102,6 +104,7 @@ services:
|
|||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
seo-volume:
|
||||
|
||||
networks:
|
||||
app-network:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import useBrandingSettings from '@hooks/brandingHooks';
|
|||
import imageUtils from '@utils/imageUtils';
|
||||
import Clarity from '@microsoft/clarity';
|
||||
import CookieConsentPopup from '@components/CookieConsentPopup';
|
||||
import SeoProxyRoutes from '@components/SeoProxyRoutes';
|
||||
|
||||
// Import layouts
|
||||
import MainLayout from './layouts/MainLayout';
|
||||
|
|
@ -133,9 +132,6 @@ function App() {
|
|||
<Notifications />
|
||||
<CookieConsentPopup />
|
||||
|
||||
{/* SEO Routes for sitemap.xml and robots.txt */}
|
||||
<SeoProxyRoutes />
|
||||
|
||||
<Routes>
|
||||
{/* Main routes with MainLayout */}
|
||||
<Route path="/" element={<MainLayout />}>
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
import axiosClient from '@services/seoapi';
|
||||
|
||||
/**
|
||||
* Component to serve SEO files (sitemap.xml, robots.txt) directly from API
|
||||
*/
|
||||
const SeoFile = ({ filePath }) => {
|
||||
const [content, setContent] = useState('');
|
||||
const [contentType, setContentType] = useState('');
|
||||
const [error, setError] = useState(null);
|
||||
console.log(filePath)
|
||||
useEffect(() => {
|
||||
// Determine the content type based on the file extension
|
||||
const fileExtension = filePath.split('.').pop();
|
||||
const type = fileExtension === 'xml' ? 'application/xml' : 'text/plain';
|
||||
setContentType(type);
|
||||
|
||||
// Fetch the file from the API
|
||||
axiosClient.get(filePath, {
|
||||
responseType: 'text',
|
||||
headers: {
|
||||
'Accept': type
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
setContent(response.data);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(`Error fetching ${filePath}:`, err);
|
||||
setError(`Error loading ${filePath}. ${err.message}`);
|
||||
});
|
||||
}, [filePath]);
|
||||
|
||||
// Set the content type and return the raw content
|
||||
useEffect(() => {
|
||||
if (content && contentType) {
|
||||
// Clear existing document
|
||||
document.open();
|
||||
|
||||
if (contentType.includes('xml')) {
|
||||
// For XML sitemaps, just write the raw content directly
|
||||
// This is critical - no HTML tags or wrappers for XML files
|
||||
document.write(content);
|
||||
} else {
|
||||
// For robots.txt, use the pre tag to preserve formatting
|
||||
document.write(`<pre>${content}</pre>`);
|
||||
}
|
||||
|
||||
document.close();
|
||||
|
||||
// Set the correct content type meta tag
|
||||
const meta = document.createElement('meta');
|
||||
meta.httpEquiv = 'Content-Type';
|
||||
meta.content = `${contentType}; charset=utf-8`;
|
||||
document.head.appendChild(meta);
|
||||
|
||||
// Add minimal styling for robots.txt only
|
||||
if (!contentType.includes('xml')) {
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
pre {
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
padding: 15px;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}
|
||||
}, [content, contentType]);
|
||||
|
||||
// If there was an error, show a simple error message
|
||||
if (error) {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
// During loading, return nothing (blank page)
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Routes component that handles SEO file requests
|
||||
*/
|
||||
const SeoProxyRoutes = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/sitemap.xml" element={<SeoFile filePath="/sitemap.xml" />} />
|
||||
<Route path="/robots.txt" element={<SeoFile filePath="/robots.txt" />} />
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
|
||||
export default SeoProxyRoutes;
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
import axios from 'axios';
|
||||
import { store } from '../store';
|
||||
|
||||
let url = "";
|
||||
if(import.meta.env.VITE_ENVIRONMENT === "beta"){
|
||||
url = import.meta.env.VITE_API_URL.split('/api')[0]
|
||||
}else {
|
||||
url = `https://${import.meta.env.VITE_API_PROD_URL}`
|
||||
}
|
||||
|
||||
const axiosClient = axios.create({
|
||||
baseURL: url,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
// console.log(url, `https://${import.meta.env.VITE_API_PROD_URL}`)
|
||||
axiosClient.interceptors.request.use(
|
||||
(config) => {
|
||||
const state = store.getState();
|
||||
const apiKey = state.auth.apiKey;
|
||||
|
||||
if (apiKey) {
|
||||
config.headers['X-API-Key'] = apiKey;
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Add response interceptor to handle common errors
|
||||
axiosClient.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
// Handle 401 unauthorized errors
|
||||
if (error.response && error.response.status === 401) {
|
||||
console.log("Missing Seo Files")
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default axiosClient;
|
||||
Loading…
Reference in a new issue