You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.3 KiB
207 lines
5.3 KiB
/**
|
|
* Vite Plugin for TimeSafari Daily Notification Plugin
|
|
*
|
|
* Provides Vite-specific optimizations and integrations for the TimeSafari PWA.
|
|
* Handles tree-shaking, SSR safety, and platform-specific builds.
|
|
*
|
|
* @author Matthew Raymer
|
|
* @version 1.0.0
|
|
*/
|
|
|
|
import type { Plugin } from 'vite';
|
|
|
|
export interface TimeSafariPluginOptions {
|
|
/**
|
|
* Enable SSR safety checks
|
|
*/
|
|
ssrSafe?: boolean;
|
|
|
|
/**
|
|
* Enable tree-shaking optimizations
|
|
*/
|
|
treeShaking?: boolean;
|
|
|
|
/**
|
|
* Platform-specific builds
|
|
*/
|
|
platforms?: ('android' | 'ios' | 'electron')[];
|
|
|
|
/**
|
|
* Bundle size budget in KB
|
|
*/
|
|
bundleSizeBudget?: number;
|
|
|
|
/**
|
|
* Enable development mode optimizations
|
|
*/
|
|
devMode?: boolean;
|
|
}
|
|
|
|
/**
|
|
* TimeSafari Vite Plugin
|
|
*
|
|
* Provides optimizations and integrations for TimeSafari PWA compatibility.
|
|
*/
|
|
export function timeSafariPlugin(options: TimeSafariPluginOptions = {}): Plugin {
|
|
const {
|
|
ssrSafe = true,
|
|
treeShaking = true,
|
|
platforms = ['android', 'ios'],
|
|
bundleSizeBudget = 35,
|
|
devMode = false
|
|
} = options;
|
|
|
|
return {
|
|
name: 'timesafari-daily-notification',
|
|
|
|
// Plugin configuration
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
config(config, { command }): any {
|
|
const isDev = command === 'serve';
|
|
|
|
return {
|
|
// Build optimizations
|
|
build: {
|
|
...config.build,
|
|
// Enable tree-shaking
|
|
rollupOptions: {
|
|
...config.build?.rollupOptions,
|
|
treeshake: treeShaking ? {
|
|
moduleSideEffects: false,
|
|
propertyReadSideEffects: false,
|
|
unknownGlobalSideEffects: false
|
|
} : false
|
|
}
|
|
},
|
|
|
|
// Define constants
|
|
define: {
|
|
...config.define,
|
|
__TIMESAFARI_SSR_SAFE__: ssrSafe,
|
|
__TIMESAFARI_PLATFORMS__: JSON.stringify(platforms),
|
|
__TIMESAFARI_BUNDLE_BUDGET__: bundleSizeBudget,
|
|
__TIMESAFARI_DEV_MODE__: devMode || isDev
|
|
}
|
|
};
|
|
},
|
|
|
|
// Transform code for SSR safety
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
transform(code, _id): any {
|
|
if (!ssrSafe) return null;
|
|
|
|
// Check for SSR-unsafe code patterns
|
|
const ssrUnsafePatterns = [
|
|
/window\./g,
|
|
/document\./g,
|
|
/navigator\./g,
|
|
/localStorage\./g,
|
|
/sessionStorage\./g,
|
|
];
|
|
|
|
let hasUnsafeCode = false;
|
|
for (const pattern of ssrUnsafePatterns) {
|
|
if (pattern.test(code)) {
|
|
hasUnsafeCode = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (hasUnsafeCode) {
|
|
// Wrap unsafe code in platform checks
|
|
const wrappedCode = `
|
|
// SSR-safe wrapper for TimeSafari Daily Notification Plugin
|
|
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
${code}
|
|
} else {
|
|
// SSR fallback - return mock implementation
|
|
// Running in SSR environment, using fallback implementation
|
|
}
|
|
`;
|
|
|
|
return {
|
|
code: wrappedCode,
|
|
map: null
|
|
};
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
// Generate platform-specific builds
|
|
generateBundle(_options, bundle): void {
|
|
// Remove any web-specific code (not applicable in native-first architecture)
|
|
Object.keys(bundle).forEach(fileName => {
|
|
if (fileName.includes('web') || fileName.includes('browser')) {
|
|
delete bundle[fileName];
|
|
}
|
|
});
|
|
|
|
if (!platforms.includes('android')) {
|
|
// Remove Android-specific code
|
|
Object.keys(bundle).forEach(fileName => {
|
|
if (fileName.includes('android')) {
|
|
delete bundle[fileName];
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!platforms.includes('ios')) {
|
|
// Remove iOS-specific code
|
|
Object.keys(bundle).forEach(fileName => {
|
|
if (fileName.includes('ios')) {
|
|
delete bundle[fileName];
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
// Bundle size analysis
|
|
writeBundle(_options, bundle): void {
|
|
if (devMode) return;
|
|
|
|
let totalSize = 0;
|
|
const fileSizes: Record<string, number> = {};
|
|
|
|
Object.entries(bundle).forEach(([fileName, chunk]) => {
|
|
if (chunk.type === 'chunk') {
|
|
const size = Buffer.byteLength(chunk.code, 'utf8');
|
|
fileSizes[fileName] = size;
|
|
totalSize += size;
|
|
}
|
|
});
|
|
|
|
const totalSizeKB = totalSize / 1024;
|
|
|
|
if (totalSizeKB > bundleSizeBudget) {
|
|
// Bundle size exceeds budget
|
|
|
|
// Log largest files for debugging (available in fileSizes)
|
|
} else {
|
|
// Bundle size within budget
|
|
}
|
|
},
|
|
|
|
// Development server middleware
|
|
configureServer(server): void {
|
|
if (!devMode) return;
|
|
|
|
// Add development-specific middleware
|
|
server.middlewares.use('/timesafari-plugin', (_req, res, _next) => {
|
|
res.setHeader('Content-Type', 'application/json');
|
|
res.end(JSON.stringify({
|
|
name: 'TimeSafari Daily Notification Plugin',
|
|
version: process.env.npm_package_version || '1.0.0',
|
|
platforms: platforms,
|
|
ssrSafe: ssrSafe,
|
|
treeShaking: treeShaking
|
|
}));
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Default export for easy usage
|
|
*/
|
|
export default timeSafariPlugin;
|
|
|