1/* eslint-disable import/order */ 2const { copySync, removeSync } = require('fs-extra'); 3const { join } = require('path'); 4const semver = require('semver'); 5const { info: logInfo } = require('next/dist/build/output/log'); 6 7const navigation = require('./constants/navigation'); 8const { VERSIONS } = require('./constants/versions'); 9const { version, betaVersion } = require('./package.json'); 10 11// To generate a sitemap, we need context about the supported versions and navigational data 12const createSitemap = require('./scripts/create-sitemap'); 13 14// Prepare the latest version by copying the actual exact latest version 15const vLatest = join('pages', 'versions', `v${version}/`); 16const latest = join('pages', 'versions', 'latest/'); 17removeSync(latest); 18copySync(vLatest, latest); 19logInfo(`Copied latest Expo SDK version from v${version}`); 20 21/** @type {import('next').NextConfig} */ 22module.exports = { 23 trailingSlash: true, 24 pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'], 25 compiler: { emotion: true }, 26 swcMinify: true, 27 webpack: (config, options) => { 28 // Add preval support for `constants/*` only and move it to the `.next/preval` cache. 29 // It's to prevent over-usage and separate the cache to allow manually invalidation. 30 // See: https://github.com/kentcdodds/babel-plugin-preval/issues/19 31 config.module.rules.push({ 32 test: /.js$/, 33 include: [join(__dirname, 'constants')], 34 use: { 35 loader: 'babel-loader', 36 options: { 37 // Keep this path in sync with package.json and other scripts that clear the cache 38 cacheDirectory: '.next/preval', 39 plugins: ['preval'], 40 presets: ['next/babel'], 41 }, 42 }, 43 }); 44 45 // Add support for MDX with our custom loader and esbuild 46 config.module.rules.push({ 47 test: /.mdx?$/, 48 use: [ 49 options.defaultLoaders.babel, 50 { 51 loader: '@mdx-js/loader', 52 options: { 53 remarkPlugins: [ 54 [require('remark-frontmatter'), ['yaml']], 55 require('./mdx-plugins/remark-export-yaml'), 56 require('./mdx-plugins/remark-export-headings'), 57 require('./mdx-plugins/remark-link-rewrite'), 58 ], 59 rehypePlugins: [require('rehype-slug')], 60 }, 61 }, 62 ], 63 }); 64 65 // Fix inline or browser MDX usage: https://mdxjs.com/getting-started/webpack#running-mdx-in-the-browser 66 config.resolve.fallback = { fs: false, path: require.resolve('path-browserify') }; 67 68 return config; 69 }, 70 // Create a map of all pages to export 71 async exportPathMap(defaultPathMap, { dev, outDir }) { 72 if (dev) { 73 return defaultPathMap; 74 } 75 const pathMap = Object.assign( 76 ...Object.entries(defaultPathMap).map(([pathname, page]) => { 77 if (pathname.match(/unversioned/)) { 78 // Remove unversioned pages from the exported site 79 return {}; 80 } else { 81 // Remove newer unreleased versions from the exported side 82 const versionMatch = pathname.match(/\/v(\d\d\.\d\.\d)\//); 83 if (versionMatch?.[1] && semver.gt(versionMatch[1], betaVersion || version)) { 84 return {}; 85 } 86 } 87 88 return { [pathname]: page }; 89 }) 90 ); 91 92 const sitemapEntries = createSitemap({ 93 pathMap, 94 domain: `https://docs.expo.dev`, 95 output: join(outDir, `sitemap.xml`), 96 // Some of the search engines only track the first N items from the sitemap, 97 // this makes sure our starting and general guides are first, and API index last (in order from new to old) 98 pathsPriority: [ 99 ...navigation.startingDirectories, 100 ...navigation.generalDirectories, 101 ...navigation.easDirectories, 102 ...VERSIONS.map(version => `versions/${version}`), 103 ], 104 // Some of our pages are "hidden" and should not be added to the sitemap 105 pathsHidden: navigation.previewDirectories, 106 }); 107 logInfo(` Generated sitemap with ${sitemapEntries.length} entries`); 108 109 return pathMap; 110 }, 111 async headers() { 112 const cacheHeaders = [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }]; 113 return [{ source: '/_next/static/:static*', headers: cacheHeaders }]; 114 }, 115}; 116