Initial commit
This commit is contained in:
265
src/vite.config.js
Normal file
265
src/vite.config.js
Normal file
@@ -0,0 +1,265 @@
|
||||
import path from 'node:path';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { createLogger, defineConfig } from 'vite';
|
||||
import inlineEditPlugin from './plugins/visual-editor/vite-plugin-react-inline-editor.js';
|
||||
import editModeDevPlugin from './plugins/visual-editor/vite-plugin-edit-mode.js';
|
||||
import iframeRouteRestorationPlugin from './plugins/vite-plugin-iframe-route-restoration.js';
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const configHorizonsViteErrorHandler = `
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
for (const addedNode of mutation.addedNodes) {
|
||||
if (
|
||||
addedNode.nodeType === Node.ELEMENT_NODE &&
|
||||
(
|
||||
addedNode.tagName?.toLowerCase() === 'vite-error-overlay' ||
|
||||
addedNode.classList?.contains('backdrop')
|
||||
)
|
||||
) {
|
||||
handleViteOverlay(addedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.documentElement, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
function handleViteOverlay(node) {
|
||||
if (!node.shadowRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
const backdrop = node.shadowRoot.querySelector('.backdrop');
|
||||
|
||||
if (backdrop) {
|
||||
const overlayHtml = backdrop.outerHTML;
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(overlayHtml, 'text/html');
|
||||
const messageBodyElement = doc.querySelector('.message-body');
|
||||
const fileElement = doc.querySelector('.file');
|
||||
const messageText = messageBodyElement ? messageBodyElement.textContent.trim() : '';
|
||||
const fileText = fileElement ? fileElement.textContent.trim() : '';
|
||||
const error = messageText + (fileText ? ' File:' + fileText : '');
|
||||
|
||||
window.parent.postMessage({
|
||||
type: 'horizons-vite-error',
|
||||
error,
|
||||
}, '*');
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const configHorizonsRuntimeErrorHandler = `
|
||||
window.onerror = (message, source, lineno, colno, errorObj) => {
|
||||
const errorDetails = errorObj ? JSON.stringify({
|
||||
name: errorObj.name,
|
||||
message: errorObj.message,
|
||||
stack: errorObj.stack,
|
||||
source,
|
||||
lineno,
|
||||
colno,
|
||||
}) : null;
|
||||
|
||||
window.parent.postMessage({
|
||||
type: 'horizons-runtime-error',
|
||||
message,
|
||||
error: errorDetails
|
||||
}, '*');
|
||||
};
|
||||
`;
|
||||
|
||||
const configHorizonsConsoleErrroHandler = `
|
||||
const originalConsoleError = console.error;
|
||||
console.error = function(...args) {
|
||||
originalConsoleError.apply(console, args);
|
||||
|
||||
let errorString = '';
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
if (arg instanceof Error) {
|
||||
errorString = arg.stack || \`\${arg.name}: \${arg.message}\`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorString) {
|
||||
errorString = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
|
||||
}
|
||||
|
||||
window.parent.postMessage({
|
||||
type: 'horizons-console-error',
|
||||
error: errorString
|
||||
}, '*');
|
||||
};
|
||||
`;
|
||||
|
||||
const configWindowFetchMonkeyPatch = `
|
||||
const originalFetch = window.fetch;
|
||||
|
||||
window.fetch = function(...args) {
|
||||
const url = args[0] instanceof Request ? args[0].url : args[0];
|
||||
|
||||
// Skip WebSocket URLs
|
||||
if (url.startsWith('ws:') || url.startsWith('wss:')) {
|
||||
return originalFetch.apply(this, args);
|
||||
}
|
||||
|
||||
return originalFetch.apply(this, args)
|
||||
.then(async response => {
|
||||
const contentType = response.headers.get('Content-Type') || '';
|
||||
|
||||
// Exclude HTML document responses
|
||||
const isDocumentResponse =
|
||||
contentType.includes('text/html') ||
|
||||
contentType.includes('application/xhtml+xml');
|
||||
|
||||
if (!response.ok && !isDocumentResponse) {
|
||||
const responseClone = response.clone();
|
||||
const errorFromRes = await responseClone.text();
|
||||
const requestUrl = response.url;
|
||||
console.error(\`Fetch error from \${requestUrl}: \${errorFromRes}\`);
|
||||
}
|
||||
|
||||
return response;
|
||||
})
|
||||
.catch(error => {
|
||||
if (!url.match(/\.html?$/i)) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
`;
|
||||
|
||||
const configNavigationHandler = `
|
||||
if (window.navigation && window.self !== window.top) {
|
||||
window.navigation.addEventListener('navigate', (event) => {
|
||||
const url = event.destination.url;
|
||||
|
||||
try {
|
||||
const destinationUrl = new URL(url);
|
||||
const destinationOrigin = destinationUrl.origin;
|
||||
const currentOrigin = window.location.origin;
|
||||
|
||||
if (destinationOrigin === currentOrigin) {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.parent.postMessage({
|
||||
type: 'horizons-navigation-error',
|
||||
url,
|
||||
}, '*');
|
||||
});
|
||||
}
|
||||
`;
|
||||
|
||||
const addTransformIndexHtml = {
|
||||
name: 'add-transform-index-html',
|
||||
transformIndexHtml(html) {
|
||||
const tags = [
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: { type: 'module' },
|
||||
children: configHorizonsRuntimeErrorHandler,
|
||||
injectTo: 'head',
|
||||
},
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: { type: 'module' },
|
||||
children: configHorizonsViteErrorHandler,
|
||||
injectTo: 'head',
|
||||
},
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {type: 'module'},
|
||||
children: configHorizonsConsoleErrroHandler,
|
||||
injectTo: 'head',
|
||||
},
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: { type: 'module' },
|
||||
children: configWindowFetchMonkeyPatch,
|
||||
injectTo: 'head',
|
||||
},
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: { type: 'module' },
|
||||
children: configNavigationHandler,
|
||||
injectTo: 'head',
|
||||
},
|
||||
];
|
||||
|
||||
if (!isDev && process.env.TEMPLATE_BANNER_SCRIPT_URL && process.env.TEMPLATE_REDIRECT_URL) {
|
||||
tags.push(
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
src: process.env.TEMPLATE_BANNER_SCRIPT_URL,
|
||||
'template-redirect-url': process.env.TEMPLATE_REDIRECT_URL,
|
||||
},
|
||||
injectTo: 'head',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
html,
|
||||
tags,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
console.warn = () => {};
|
||||
|
||||
const logger = createLogger()
|
||||
const loggerError = logger.error
|
||||
|
||||
logger.error = (msg, options) => {
|
||||
if (options?.error?.toString().includes('CssSyntaxError: [postcss]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
loggerError(msg, options);
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
customLogger: logger,
|
||||
plugins: [
|
||||
...(isDev ? [inlineEditPlugin(), editModeDevPlugin(), iframeRouteRestorationPlugin()] : []),
|
||||
react(),
|
||||
addTransformIndexHtml
|
||||
],
|
||||
server: {
|
||||
cors: true,
|
||||
headers: {
|
||||
'Cross-Origin-Embedder-Policy': 'credentialless',
|
||||
},
|
||||
allowedHosts: true,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.jsx', '.js', '.tsx', '.ts', '.json', ],
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: [
|
||||
'@babel/parser',
|
||||
'@babel/traverse',
|
||||
'@babel/generator',
|
||||
'@babel/types'
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user