[build] publish = "dist" command = "pnpm run build" [build.environment] NODE_VERSION = "22" PNPM_VERSION = "8" # Enable compression for all text-based files # Note: Netlify automatically handles gzip/brotli compression based on client support [[headers]] for = "/*.html" [headers.values] Cache-Control = "public, max-age=3600, s-maxage=86400" [[headers]] for = "/*.css" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "/*.js" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "/*.json" [headers.values] Cache-Control = "public, max-age=3600" [[headers]] for = "/*.xml" [headers.values] Cache-Control = "public, max-age=3600" [[headers]] for = "/*.txt" [headers.values] Cache-Control = "public, max-age=3600" # Handle pre-compressed files [[headers]] for = "/*.gz" [headers.values] Content-Encoding = "gzip" Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "/*.br" [headers.values] Content-Encoding = "br" Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "/*" [headers.values] X-Frame-Options = "DENY" X-XSS-Protection = "1; mode=block" X-Content-Type-Options = "nosniff" Referrer-Policy = "strict-origin-when-cross-origin" Permissions-Policy = "camera=(), microphone=(), geolocation=()" Cross-Origin-Embedder-Policy = "unsafe-none" Cross-Origin-Opener-Policy = "same-origin" Content-Security-Policy = "default-src 'self'; script-src 'self' 'unsafe-inline' https://unpkg.com https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://giscus.app https://platform.twitter.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com; font-src 'self' data: https://fonts.gstatic.com https://cdnjs.cloudflare.com; img-src 'self' data: https:; connect-src 'self' https://giscus.app; frame-src 'self' https://www.youtube.com https://giscus.app https://platform.twitter.com; object-src 'none'; base-uri 'self';" # Static assets with long-term caching [[headers]] for = "/_assets/*" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.webp" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.woff2" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.woff" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.ttf" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.eot" [headers.values] Cache-Control = "public, max-age=31536000, immutable" # Images with long-term caching [[headers]] for = "*.jpg" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.jpeg" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.png" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.gif" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.svg" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [[headers]] for = "*.ico" [headers.values] Cache-Control = "public, max-age=31536000, immutable" # PDF files - allow iframe embedding [[headers]] for = "*.pdf" [headers.values] Cache-Control = "public, max-age=3600" X-Frame-Options = "SAMEORIGIN" # Favicon files [[headers]] for = "/favicon*" [headers.values] Cache-Control = "public, max-age=31536000, immutable" [dev] command = "pnpm run dev" port = 5000 publish = "dist" # Generated redirects from content aliases [[redirects]] from = "/about-me" to = "/about" status = 301 force = true [[redirects]] from = "/about-us" to = "/about" status = 301 force = true [[redirects]] from = "/contact" to = "/contact-me" status = 301 force = true [[redirects]] from = "/contact-us" to = "/contact-me" status = 301 force = true [[redirects]] from = "/privacy-policy" to = "/privacy" status = 301 force = true [[redirects]] from = "/posts/chao-tia-to" to = "/posts/chao-tia-to-gung-trung-ga" status = 301 force = true [[redirects]] from = "/posts/le-chung-tac-duong-phen" to = "/posts/l-chng-tc-ng-phn-tr-ho-khan" status = 301 force = true [[redirects]] from = "/posts/nâng-cấp-kỹ-năng-và-mindset-sử-dụng-ai-làm-gì-để-hạn-chế-fomo-trong-thời-đại-ai-nhiễu-loạn" to = "/posts/nang-cap-ky-nang-su-dung-ai" status = 301 force = true [[redirects]] from = "/posts/obsidian-embeds-demo" to = "/posts/mermaid-test" status = 301 force = true [[redirects]] from = "/posts/mermaid-diagram-test" to = "/posts/mermaid-test" status = 301 force = true [[redirects]] from = "/posts/mermaid-diagrams" to = "/posts/mermaid-test" status = 301 force = true [[redirects]] from = "/posts/phan-biet-cam-xuc-va-tam-thuc" to = "/posts/phan-biet-cam-xuc-tam-thuc" status = 301 force = true [[redirects]] from = "/posts/vault-cms-guide" to = "/posts/astro-suite-vault-modular-guide" status = 301 force = true [[redirects]] from = "/posts/astro-suite-obsidian-vault-guide-astro-modular" to = "/posts/astro-suite-vault-modular-guide" status = 301 force = true [[redirects]] from = "/posts/obsidian-vault-guide" to = "/posts/astro-suite-vault-modular-guide" status = 301 force = true [[redirects]] from = "/posts/xây-dựng-thư-viện-tri-thức-cá-nhân-với-notebook-lm-và-obsidian" to = "/posts/xay-dung-thu-vien-tri-thuc-ca-nhan-notebooklm-obsidian" status = 301 force = true [[redirects]] from = "/projects/astro-composer" to = "/projects/obsidian-astro-composer" status = 301 force = true [[redirects]] from = "/projects/vault-cms" to = "/projects/obsidian-astro-suite" status = 301 force = true [[redirects]] from = "/docs/api" to = "/docs/api-reference" status = 301 force = true [[redirects]] from = "/docs/configuration" to = "/docs/astro-modular-configuration" status = 301 force = true [[redirects]] from = "/docs/sourcetree-and-git-setup" to = "/docs/sourcetree-and-git" status = 301 force = true [[redirects]] from = "/*" to = "/404" status = 404