chore: load assets with assetPrefix

This commit is contained in:
Rahul Jain
2025-10-15 21:50:49 +05:30
parent 2dbe4c1d94
commit 4ee906e1ce
5 changed files with 122 additions and 91 deletions
+100 -86
View File
@@ -1,101 +1,115 @@
import type { NextConfig } from 'next';
import { PHASE_PRODUCTION_BUILD } from 'next/constants';
const nextConfig: NextConfig = {
// Output as static site for GitHub Pages
output: 'export',
const nextConfig = (phase: string): NextConfig => {
// Determine if we should use basePath (production build, not Surge preview)
const isProductionBuild = phase === PHASE_PRODUCTION_BUILD;
const isSurgePreview = process.env.SURGE_PREVIEW === 'true';
const shouldUseBasePath = isProductionBuild && !isSurgePreview;
const basePath = shouldUseBasePath ? '/github-profile-readme-generator' : '';
// Base path for GitHub Pages (only in production AND not for Surge previews)
basePath:
process.env.NODE_ENV === 'production' && !process.env.SURGE_PREVIEW
? '/github-profile-readme-generator'
: '',
return {
// Output as static site for GitHub Pages
output: 'export',
// Image optimization for static export
images: {
unoptimized: true, // Required for static export
},
// Base path for GitHub Pages (only for production builds, not Surge previews)
basePath,
// Trailing slashes for better compatibility
trailingSlash: true,
// Asset prefix to ensure all assets use the correct path
assetPrefix: shouldUseBasePath ? '/github-profile-readme-generator/' : '',
// Enable strict mode for better error catching
reactStrictMode: true,
// Enable experimental features for better performance
experimental: {
// Optimize CSS
optimizeCss: true,
// Enable optimized package imports for heavy libraries
optimizePackageImports: [
'framer-motion',
'@hookform/resolvers',
'react-markdown',
'remark-gfm',
'rehype-raw',
'rehype-sanitize',
'zod',
'zustand',
'lucide-react',
'@headlessui/react',
],
},
// Compiler options for better performance
compiler: {
// Remove console.log in production
removeConsole: process.env.NODE_ENV === 'production' ? { exclude: ['error', 'warn'] } : false,
// Enable React compiler optimizations
reactRemoveProperties: process.env.NODE_ENV === 'production',
},
// Optimize transpilation
transpilePackages: ['react-markdown', 'remark-gfm', 'rehype-raw', 'rehype-sanitize'],
// Turbopack configuration (replaces webpack config)
turbopack: {
// Enable faster module resolution
resolveAlias: {
// Optimize common imports
'@': './src',
// Environment variables
env: {
NEXT_PUBLIC_BASE_PATH: basePath,
},
},
// Webpack optimizations for development (only when not using Turbopack)
webpack: (config, { dev, isServer }) => {
if (dev && !isServer && !process.env.TURBOPACK) {
// Optimize development builds
config.optimization = {
...config.optimization,
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
priority: 10,
},
markdown: {
test: /[\\/]node_modules[\\/](react-markdown|remark-|rehype-)/,
name: 'markdown',
chunks: 'all',
priority: 20,
// Image optimization for static export
images: {
unoptimized: true, // Required for static export
},
// Trailing slashes for better compatibility
trailingSlash: true,
// Enable strict mode for better error catching
reactStrictMode: true,
// Enable experimental features for better performance
experimental: {
// Optimize CSS
optimizeCss: true,
// Enable optimized package imports for heavy libraries
optimizePackageImports: [
'framer-motion',
'@hookform/resolvers',
'react-markdown',
'remark-gfm',
'rehype-raw',
'rehype-sanitize',
'zod',
'zustand',
'lucide-react',
'@headlessui/react',
],
},
// Compiler options for better performance
compiler: {
// Remove console.log in production
removeConsole: isProductionBuild ? { exclude: ['error', 'warn'] } : false,
// Enable React compiler optimizations
reactRemoveProperties: isProductionBuild,
},
// Optimize transpilation
transpilePackages: ['react-markdown', 'remark-gfm', 'rehype-raw', 'rehype-sanitize'],
// Turbopack configuration (replaces webpack config)
turbopack: {
// Enable faster module resolution
resolveAlias: {
// Optimize common imports
'@': './src',
},
},
// Webpack optimizations for development (only when not using Turbopack)
webpack: (config, { dev, isServer }) => {
if (dev && !isServer && !process.env.TURBOPACK) {
// Optimize development builds
config.optimization = {
...config.optimization,
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
priority: 10,
},
markdown: {
test: /[\\/]node_modules[\\/](react-markdown|remark-|rehype-)/,
name: 'markdown',
chunks: 'all',
priority: 20,
},
},
},
},
};
};
// Enable faster rebuilds
config.cache = {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
};
}
// Enable faster rebuilds
config.cache = {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
};
}
return config;
},
return config;
},
};
};
export default nextConfig;
+4 -3
View File
@@ -7,6 +7,7 @@ import { ToastProvider } from '@/components/ui/toast';
import { BuyMeACoffeeWidget } from '@/components/ui/buy-me-coffee';
import { ConditionalAnalytics } from '@/components/analytics/conditional-analytics';
import { CookieConsent } from '@/components/ui/cookie-consent';
import { getAssetPath } from '@/lib/asset-path';
const robotoMono = Roboto_Mono({
variable: '--font-mono',
@@ -83,11 +84,11 @@ export const metadata: Metadata = {
icons: {
icon: [
{ url: '/favicon.ico', sizes: 'any' },
{ url: '/mdg.png', type: 'image/png' },
{ url: getAssetPath('/mdg.png'), type: 'image/png' },
],
apple: '/mdg.png',
apple: getAssetPath('/mdg.png'),
},
manifest: '/manifest.json',
manifest: getAssetPath('/manifest.json'),
robots: {
index: true,
follow: true,
+2 -1
View File
@@ -1,5 +1,6 @@
import Link from 'next/link';
import Image from 'next/image';
import { getAssetPath } from '@/lib/asset-path';
export function Footer() {
return (
@@ -8,7 +9,7 @@ export function Footer() {
{/* Logo Section */}
<div className="mb-8 flex items-center justify-center gap-3">
<Image
src="/mdg.png"
src={getAssetPath('/mdg.png')}
alt="GitHub Profile README Generator Logo"
width={48}
height={48}
+2 -1
View File
@@ -6,6 +6,7 @@ import { usePathname } from 'next/navigation';
import { ThemeToggle } from '@/components/ui/theme-toggle';
import { AccessibilityMenu } from '@/components/ui/accessibility-menu';
import { GitHubStats } from '@/components/ui/github-stats';
import { getAssetPath } from '@/lib/asset-path';
const navigation = [
{ name: 'Generator', href: '/' },
@@ -30,7 +31,7 @@ export function Header({}: HeaderProps = {}) {
<div className="flex items-center gap-4">
<Link href="/" prefetch={true} className="flex items-center gap-3 hover:opacity-80">
<Image
src="/mdg.png"
src={getAssetPath('/mdg.png')}
alt="GitHub Profile README Generator Logo"
width={40}
height={40}
+14
View File
@@ -0,0 +1,14 @@
/**
* Get the correct asset path with basePath for GitHub Pages
* Uses NEXT_PUBLIC_BASE_PATH environment variable if set
*/
export function getAssetPath(path: string): string {
// Ensure path starts with /
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
// Use NEXT_PUBLIC_BASE_PATH if set, otherwise detect based on build
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '';
return `${basePath}${normalizedPath}`;
}