next.config.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* eslint-disable react-func/max-lines-per-function */
  2. /* eslint-disable no-param-reassign */
  3. const path = require('path');
  4. const withBundleAnalyzer = require('@next/bundle-analyzer')({
  5. enabled: process.env.ANALYZE_BUNDLE === 'true',
  6. });
  7. const { withSentryConfig } = require('@sentry/nextjs');
  8. const withPlugins = require('next-compose-plugins');
  9. const withFonts = require('next-fonts');
  10. const withPWA = require('next-pwa');
  11. const nextTranslate = require('next-translate');
  12. const securityHeaders = require('./configs/SecurityHeaders.js');
  13. const runtimeCaching = require('./pwa-runtime-config.js');
  14. const isDev = process.env.NEXT_PUBLIC_VERCEL_ENV === 'development';
  15. const isProduction = process.env.NEXT_PUBLIC_VERCEL_ENV === 'production';
  16. const config = {
  17. productionBrowserSourceMaps: true, // {@see https://nextjs.org/docs/advanced-features/source-maps}
  18. images: {
  19. formats: ['image/avif', 'image/webp'],
  20. domains: [
  21. 'cdn.qurancdn.com',
  22. 'static.qurancdn.com',
  23. 'vercel.com',
  24. 'now.sh',
  25. 'quran.com',
  26. 'images.quran.com',
  27. ],
  28. },
  29. pwa: {
  30. disable: !isProduction,
  31. dest: 'public',
  32. mode: isProduction ? 'production' : 'development',
  33. runtimeCaching,
  34. publicExcludes: [
  35. '!fonts/**/!(sura_names|ProximaVara)*', // exclude pre-caching all fonts that are not sura_names or ProximaVara
  36. '!icons/**', // exclude all icons
  37. '!images/**/!(background|homepage)*', // don't pre-cache except background.jpg and homepage.png
  38. ],
  39. },
  40. // this is needed to support importing audioWorklet nodes. {@see https://github.com/webpack/webpack/issues/11543#issuecomment-826897590}
  41. webpack: (webpackConfig) => {
  42. webpackConfig.resolve = {
  43. ...webpackConfig.resolve,
  44. alias: {
  45. ...webpackConfig.resolve.alias,
  46. 'audio-worklet': path.resolve(__dirname, 'src/audioInput/audio-worklet.ts'),
  47. },
  48. };
  49. webpackConfig.module.parser = {
  50. ...webpackConfig.module.parser,
  51. javascript: {
  52. worker: ['AudioWorklet from audio-worklet'],
  53. },
  54. };
  55. webpackConfig.module.rules.push({
  56. test: /\.svg$/i,
  57. issuer: {
  58. and: [/\.(js|ts)x?$/],
  59. },
  60. use: [
  61. {
  62. loader: '@svgr/webpack',
  63. options: {
  64. prettier: false,
  65. svgo: true,
  66. svgoConfig: {
  67. plugins: [
  68. {
  69. name: 'preset-default',
  70. params: {
  71. overrides: {
  72. removeViewBox: false,
  73. },
  74. },
  75. },
  76. ],
  77. },
  78. },
  79. },
  80. ],
  81. });
  82. return webpackConfig;
  83. },
  84. SentryWebpackPluginOptions: {
  85. // Additional config options for the Sentry Webpack plugin. Keep in mind that
  86. // the following options are set automatically, and overriding them is not
  87. // recommended:
  88. // release, url, org, project, authToken, configFile, stripPrefix,
  89. // urlPrefix, include, ignore
  90. silent: true, // Suppresses all logs
  91. // For all available options, see:
  92. // https://github.com/getsentry/sentry-webpack-plugin#options.
  93. },
  94. async headers() {
  95. return isDev
  96. ? []
  97. : [
  98. {
  99. source: '/:route*', // apply security rules to all routes.
  100. headers: securityHeaders,
  101. },
  102. {
  103. source: '/fonts/:font*', // match wildcard fonts' path which will match any font file on any level under /fonts.
  104. headers: [
  105. {
  106. key: 'cache-control',
  107. value: 'public, max-age=31536000, immutable', // Max-age is 1 year. immutable indicates that the font will not change over the expiry time.
  108. },
  109. ],
  110. },
  111. {
  112. source: '/images/:image*', // match wildcard images' path which will match any image file on any level under /images.
  113. headers: [
  114. {
  115. key: 'cache-control',
  116. value: 'public, max-age=604800, immutable', // Max-age is 1 week. immutable indicates that the image will not change over the expiry time.
  117. },
  118. ],
  119. },
  120. {
  121. source: '/icons/:icon*', // match wildcard icons' path which will match any icon file on any level under /icons.
  122. headers: [
  123. {
  124. key: 'cache-control',
  125. value: 'public, max-age=604800, immutable', // Max-age is 1 week. immutable indicates that the icon will not change over the expiry time.
  126. },
  127. ],
  128. },
  129. ];
  130. },
  131. async redirects() {
  132. return [
  133. {
  134. source: '/:surah/:from(\\d{1,})\\::to(\\d{1,})', // 1/2:3 => 1/2-3
  135. destination: '/:surah/:from-:to',
  136. permanent: true,
  137. },
  138. {
  139. source: '/:surah\\::from(\\d{1,})\\::to(\\d{1,})', // 1:2:3 => 1/2-3
  140. destination: '/:surah/:from-:to',
  141. permanent: true,
  142. },
  143. {
  144. source: '/:surah(\\d{1,})-:from\\::to', // 1-2:3 => 1/2-3
  145. destination: '/:surah/:from-:to',
  146. permanent: true,
  147. },
  148. {
  149. source: '/:surah(\\d{1,})-:from(\\d{1,})-:to(\\d{1,})', // 1-2-3 => 1/2-3
  150. destination: '/:surah/:from-:to',
  151. permanent: true,
  152. },
  153. {
  154. source: '/:surah(\\d{1,})\\::from(\\d{1,})-:to(\\d{1,})', // 1:2-3 => 1/2-3
  155. destination: '/:surah/:from-:to',
  156. permanent: true,
  157. },
  158. ];
  159. },
  160. };
  161. // eslint-disable-next-line max-lines
  162. module.exports = withPlugins(
  163. [withBundleAnalyzer, withPWA, withFonts, nextTranslate, withSentryConfig],
  164. config,
  165. );