From d7f2249fb1d1e530cedc46c72560b5b55de6e600 Mon Sep 17 00:00:00 2001 From: MananTank Date: Tue, 14 Jan 2025 09:46:30 +0000 Subject: [PATCH] [TOOL-3032] Next.js build memory optimizations (#5938) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Disable eslint as part of next.js build - We are already running eslint in separate pipeline * Enable Next.js memory optimization flags --- ## PR-Codex overview This PR primarily focuses on enhancing the configuration of multiple `Next.js` applications by adding ESLint settings, production source maps, and experimental features. It also modifies security headers and refines the handling of IPFS gateways. ### Detailed summary - Added `eslint` configuration with `ignoreDuringBuilds: true` to multiple `next.config` files. - Set `productionBrowserSourceMaps` to `false`. - Enabled experimental features: `webpackBuildWorker`, `webpackMemoryOptimizations`, and `serverSourceMaps`. - Updated security headers in `apps/dashboard/next.config.ts` for consistent formatting. - Refined `determineIpfsGateways` function for IPFS gateway handling. - Maintained existing configurations for redirects, rewrites, images, and compiler settings. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- apps/dashboard/next.config.ts | 365 ++++++++++++++-------------- apps/playground-web/next.config.mjs | 9 + apps/portal/next.config.mjs | 9 + apps/wallet-ui/next.config.mjs | 9 + 4 files changed, 212 insertions(+), 180 deletions(-) diff --git a/apps/dashboard/next.config.ts b/apps/dashboard/next.config.ts index dec847c159f..f8230298abd 100644 --- a/apps/dashboard/next.config.ts +++ b/apps/dashboard/next.config.ts @@ -19,204 +19,209 @@ const ContentSecurityPolicy = ` `; const securityHeaders = [ - { - key: "X-DNS-Prefetch-Control", - value: "on", - }, - { - key: "X-XSS-Protection", - value: "1; mode=block", - }, - { - key: "X-Frame-Options", - value: "SAMEORIGIN", - }, - { - key: "Referrer-Policy", - value: "origin-when-cross-origin", - }, - { - key: "Content-Security-Policy", - value: ContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(), - }, + { + key: "X-DNS-Prefetch-Control", + value: "on", + }, + { + key: "X-XSS-Protection", + value: "1; mode=block", + }, + { + key: "X-Frame-Options", + value: "SAMEORIGIN", + }, + { + key: "Referrer-Policy", + value: "origin-when-cross-origin", + }, + { + key: "Content-Security-Policy", + value: ContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(), + }, ]; function determineIpfsGateways() { - // add the clientId ipfs gateways - const remotePatterns: RemotePattern[] = []; - if (process.env.API_ROUTES_CLIENT_ID) { - remotePatterns.push({ - protocol: "https", - hostname: `${process.env.API_ROUTES_CLIENT_ID}.ipfscdn.io`, - }); - remotePatterns.push({ - protocol: "https", - hostname: `${process.env.API_ROUTES_CLIENT_ID}.thirdwebstorage-staging.com`, - }); - remotePatterns.push({ - protocol: "https", - hostname: `${process.env.API_ROUTES_CLIENT_ID}.thirdwebstorage-dev.com`, - }); - } else { - // this should only happen in development - remotePatterns.push({ - protocol: "https", - hostname: "ipfs.io", - }); - } - // also add the dashboard clientId ipfs gateway if it is set - if (process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID) { - remotePatterns.push({ - protocol: "https", - hostname: `${process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID}.ipfscdn.io`, - }); - remotePatterns.push({ - protocol: "https", - hostname: `${process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID}.thirdwebstorage-staging.com`, - }); - remotePatterns.push({ - protocol: "https", - hostname: `${process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID}.thirdwebstorage-dev.com`, - }); - } - return remotePatterns; + // add the clientId ipfs gateways + const remotePatterns: RemotePattern[] = []; + if (process.env.API_ROUTES_CLIENT_ID) { + remotePatterns.push({ + protocol: "https", + hostname: `${process.env.API_ROUTES_CLIENT_ID}.ipfscdn.io`, + }); + remotePatterns.push({ + protocol: "https", + hostname: `${process.env.API_ROUTES_CLIENT_ID}.thirdwebstorage-staging.com`, + }); + remotePatterns.push({ + protocol: "https", + hostname: `${process.env.API_ROUTES_CLIENT_ID}.thirdwebstorage-dev.com`, + }); + } else { + // this should only happen in development + remotePatterns.push({ + protocol: "https", + hostname: "ipfs.io", + }); + } + // also add the dashboard clientId ipfs gateway if it is set + if (process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID) { + remotePatterns.push({ + protocol: "https", + hostname: `${process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID}.ipfscdn.io`, + }); + remotePatterns.push({ + protocol: "https", + hostname: `${process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID}.thirdwebstorage-staging.com`, + }); + remotePatterns.push({ + protocol: "https", + hostname: `${process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID}.thirdwebstorage-dev.com`, + }); + } + return remotePatterns; } const SENTRY_OPTIONS: SentryBuildOptions = { - // For all available options, see: - // https://github.com/getsentry/sentry-webpack-plugin#options + // For all available options, see: + // https://github.com/getsentry/sentry-webpack-plugin#options - org: "thirdweb-dev", - project: "dashboard", - // An auth token is required for uploading source maps. - authToken: process.env.SENTRY_AUTH_TOKEN, - // Suppresses source map uploading logs during build - silent: true, - // For all available options, see: - // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ + org: "thirdweb-dev", + project: "dashboard", + // An auth token is required for uploading source maps. + authToken: process.env.SENTRY_AUTH_TOKEN, + // Suppresses source map uploading logs during build + silent: true, + // For all available options, see: + // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ - // Upload a larger set of source maps for prettier stack traces (increases build time) - widenClientFileUpload: true, + // Upload a larger set of source maps for prettier stack traces (increases build time) + widenClientFileUpload: true, - // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load) - tunnelRoute: "/err", + // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load) + tunnelRoute: "/err", - // Hides source maps from generated client bundles - hideSourceMaps: true, + // Hides source maps from generated client bundles + hideSourceMaps: true, - // Automatically tree-shake Sentry logger statements to reduce bundle size - disableLogger: true, + // Automatically tree-shake Sentry logger statements to reduce bundle size + disableLogger: true, - // Enables automatic instrumentation of Vercel Cron Monitors. - // See the following for more information: - // https://docs.sentry.io/product/crons/ - // https://vercel.com/docs/cron-jobs - automaticVercelMonitors: false, + // Enables automatic instrumentation of Vercel Cron Monitors. + // See the following for more information: + // https://docs.sentry.io/product/crons/ + // https://vercel.com/docs/cron-jobs + automaticVercelMonitors: false, }; const baseNextConfig: NextConfig = { - serverExternalPackages: ["pino-pretty"], - async headers() { - return [ - { - // Apply these headers to all routes in your application. - source: "/(.*)", - headers: [ - ...securityHeaders, - { - key: "accept-ch", - value: "sec-ch-viewport-width", - }, - ], - }, - ]; - }, - async redirects() { - return getRedirects(); - }, - async rewrites() { - return [ - { - source: "/thirdweb.eth", - destination: "/deployer.thirdweb.eth", - }, - { - source: "/thirdweb.eth/:path*", - destination: "/deployer.thirdweb.eth/:path*", - }, - // re-write /home to / (this is so that logged in users will be able to go to /home and NOT be redirected to the logged in app) - { - source: "/home", - destination: "/", - }, - ...FRAMER_PATHS.map((path) => ({ - source: path, - destination: `https://landing.thirdweb.com${path}`, - })), - ]; - }, - images: { - dangerouslyAllowSVG: true, - contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;", - remotePatterns: [ - { - protocol: "https", - hostname: "**.thirdweb.com", - }, - ...determineIpfsGateways(), - ], - }, - compiler: { - emotion: true, - }, - reactStrictMode: true, + eslint: { + ignoreDuringBuilds: true, + }, + productionBrowserSourceMaps: false, + experimental: { + webpackBuildWorker: true, + webpackMemoryOptimizations: true, + serverSourceMaps: false, + }, + serverExternalPackages: ["pino-pretty"], + async headers() { + return [ + { + // Apply these headers to all routes in your application. + source: "/(.*)", + headers: [ + ...securityHeaders, + { + key: "accept-ch", + value: "sec-ch-viewport-width", + }, + ], + }, + ]; + }, + async redirects() { + return getRedirects(); + }, + async rewrites() { + return [ + { + source: "/thirdweb.eth", + destination: "/deployer.thirdweb.eth", + }, + { + source: "/thirdweb.eth/:path*", + destination: "/deployer.thirdweb.eth/:path*", + }, + // re-write /home to / (this is so that logged in users will be able to go to /home and NOT be redirected to the logged in app) + { + source: "/home", + destination: "/", + }, + ...FRAMER_PATHS.map((path) => ({ + source: path, + destination: `https://landing.thirdweb.com${path}`, + })), + ]; + }, + images: { + dangerouslyAllowSVG: true, + contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;", + remotePatterns: [ + { + protocol: "https", + hostname: "**.thirdweb.com", + }, + ...determineIpfsGateways(), + ], + }, + compiler: { + emotion: true, + }, + reactStrictMode: true, }; function getConfig(): NextConfig { - if (process.env.NODE_ENV === "production") { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const withBundleAnalyzer = require("@next/bundle-analyzer")({ - enabled: process.env.ANALYZE === "true", - }); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const { withPlausibleProxy } = require("next-plausible"); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const { withSentryConfig } = require("@sentry/nextjs"); - return withBundleAnalyzer( - withPlausibleProxy({ - customDomain: "https://pl.thirdweb.com", - scriptName: "pl", - })( - withSentryConfig( - { - ...baseNextConfig, - experimental: { - webpackBuildWorker: true, - webpackMemoryOptimizations: true, - }, - // @ts-expect-error - this is a valid option - webpack: (config) => { - if (config.cache) { - config.cache = Object.freeze({ - type: "memory", - }); - } - config.externals.push("pino-pretty"); - config.module = { - ...config.module, - exprContextCritical: false, - }; - // Important: return the modified config - return config; - }, - }, - SENTRY_OPTIONS, - ), - ), - ); - } - // otherwise return the base - return baseNextConfig; + if (process.env.NODE_ENV === "production") { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const withBundleAnalyzer = require("@next/bundle-analyzer")({ + enabled: process.env.ANALYZE === "true", + }); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { withPlausibleProxy } = require("next-plausible"); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { withSentryConfig } = require("@sentry/nextjs"); + return withBundleAnalyzer( + withPlausibleProxy({ + customDomain: "https://pl.thirdweb.com", + scriptName: "pl", + })( + withSentryConfig( + { + ...baseNextConfig, + // @ts-expect-error - this is a valid option + webpack: (config) => { + if (config.cache) { + config.cache = Object.freeze({ + type: "memory", + }); + } + config.externals.push("pino-pretty"); + config.module = { + ...config.module, + exprContextCritical: false, + }; + // Important: return the modified config + return config; + }, + }, + SENTRY_OPTIONS, + ), + ), + ); + } + // otherwise return the base + return baseNextConfig; } export default getConfig(); diff --git a/apps/playground-web/next.config.mjs b/apps/playground-web/next.config.mjs index 29d885c2196..da70718cd7b 100644 --- a/apps/playground-web/next.config.mjs +++ b/apps/playground-web/next.config.mjs @@ -37,6 +37,15 @@ const securityHeaders = [ /** @type {import('next').NextConfig} */ const nextConfig = { + eslint: { + ignoreDuringBuilds: true, + }, + productionBrowserSourceMaps: false, + experimental: { + webpackBuildWorker: true, + webpackMemoryOptimizations: true, + serverSourceMaps: false, + }, async headers() { return [ { diff --git a/apps/portal/next.config.mjs b/apps/portal/next.config.mjs index 40542e1f5a3..53ec36300a6 100644 --- a/apps/portal/next.config.mjs +++ b/apps/portal/next.config.mjs @@ -47,6 +47,15 @@ const withMDX = createMDX({ /** @type {import('next').NextConfig} */ const nextConfig = { + eslint: { + ignoreDuringBuilds: true, + }, + productionBrowserSourceMaps: false, + experimental: { + webpackBuildWorker: true, + webpackMemoryOptimizations: true, + serverSourceMaps: false, + }, pageExtensions: ["mdx", "tsx", "ts"], redirects, webpack: (config) => { diff --git a/apps/wallet-ui/next.config.mjs b/apps/wallet-ui/next.config.mjs index a039161897d..cff1d19527f 100644 --- a/apps/wallet-ui/next.config.mjs +++ b/apps/wallet-ui/next.config.mjs @@ -46,6 +46,15 @@ export async function headers() { /** @type {import('next').NextConfig} */ const nextConfig = { + eslint: { + ignoreDuringBuilds: true, + }, + productionBrowserSourceMaps: false, + experimental: { + webpackBuildWorker: true, + webpackMemoryOptimizations: true, + serverSourceMaps: false, + }, webpack: (config) => { config.externals.push("pino-pretty", "lokijs", "encoding"); return config;