1import fsExtra from 'fs-extra'; 2import { info as logInfo } from 'next/dist/build/output/log.js'; 3import { join } from 'path'; 4import rehypeSlug from 'rehype-slug'; 5import remarkFrontmatter from 'remark-frontmatter'; 6import remarkGFM from 'remark-gfm'; 7import remarkMDX from 'remark-mdx'; 8import remarkMdxDisableExplicitJsx from 'remark-mdx-disable-explicit-jsx'; 9import remarkMDXFrontmatter from 'remark-mdx-frontmatter'; 10import semver from 'semver'; 11 12import remarkCreateStaticProps from './mdx-plugins/remark-create-static-props.js'; 13import remarkExportHeadings from './mdx-plugins/remark-export-headings.js'; 14import remarkLinkRewrite from './mdx-plugins/remark-link-rewrite.js'; 15import createSitemap from './scripts/create-sitemap.js'; 16 17const { copySync, removeSync, readJsonSync } = fsExtra; 18 19// note(simek): We cannot use direct JSON import because ESLint do not support `assert { type: 'json' }` syntax yet: 20// * https://github.com/eslint/eslint/discussions/15305 21const { version, betaVersion } = readJsonSync('./package.json'); 22const { VERSIONS } = readJsonSync('./public/static/constants/versions.json'); 23const navigation = readJsonSync('./public/static/constants/navigation.json'); 24 25// Prepare the latest version by copying the actual exact latest version 26const vLatest = join('pages', 'versions', `v${version}/`); 27const latest = join('pages', 'versions', 'latest/'); 28removeSync(latest); 29copySync(vLatest, latest); 30logInfo(`Copied latest Expo SDK version from v${version}`); 31 32/** @type {import('next').NextConfig} */ 33export default { 34 trailingSlash: true, 35 experimental: { esmExternals: true }, 36 pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'], 37 compiler: { emotion: true }, 38 swcMinify: true, 39 webpack: (config, options) => { 40 // Add support for MDX with our custom loader 41 config.module.rules.push({ 42 test: /.mdx?$/, 43 use: [ 44 options.defaultLoaders.babel, 45 { 46 loader: '@mdx-js/loader', 47 /** @type {import('@mdx-js/loader').Options} */ 48 options: { 49 providerImportSource: '@mdx-js/react', 50 remarkPlugins: [ 51 remarkMDX, 52 remarkGFM, 53 [remarkMdxDisableExplicitJsx, { whiteList: ['kbd'] }], 54 remarkFrontmatter, 55 [remarkMDXFrontmatter, { name: 'meta' }], 56 remarkExportHeadings, 57 remarkLinkRewrite, 58 [remarkCreateStaticProps, `{ meta: meta || {}, headings: headings || [] }`], 59 ], 60 rehypePlugins: [rehypeSlug], 61 }, 62 }, 63 ], 64 }); 65 66 // Fix inline or browser MDX usage 67 config.resolve.fallback = { fs: false, path: 'path-browserify' }; 68 69 return config; 70 }, 71 72 // Create a map of all pages to export 73 async exportPathMap(defaultPathMap, { dev, outDir }) { 74 if (dev) { 75 return defaultPathMap; 76 } 77 const pathMap = Object.assign( 78 ...Object.entries(defaultPathMap).map(([pathname, page]) => { 79 if (pathname.match(/unversioned/)) { 80 // Remove unversioned pages from the exported site 81 return {}; 82 } else { 83 // Remove newer unreleased versions from the exported side 84 const versionMatch = pathname.match(/\/v(\d\d\.\d\.\d)\//); 85 if (versionMatch?.[1] && semver.gt(versionMatch[1], betaVersion || version, false)) { 86 return {}; 87 } 88 } 89 90 return { [pathname]: page }; 91 }) 92 ); 93 94 const sitemapEntries = createSitemap({ 95 pathMap, 96 domain: `https://docs.expo.dev`, 97 output: join(outDir, `sitemap.xml`), 98 // Some of the search engines only track the first N items from the sitemap, 99 // this makes sure our starting and general guides are first, and API index last (in order from new to old) 100 pathsPriority: [ 101 ...navigation.generalDirectories, 102 ...navigation.easDirectories, 103 ...VERSIONS.map(version => `versions/${version}`), 104 ], 105 // Some of our pages are "hidden" and should not be added to the sitemap 106 pathsHidden: [...navigation.previewDirectories, ...navigation.archiveDirectories], 107 }); 108 logInfo(` Generated sitemap with ${sitemapEntries.length} entries`); 109 110 return pathMap; 111 }, 112 async headers() { 113 const cacheHeaders = [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }]; 114 return [{ source: '/_next/static/:static*', headers: cacheHeaders }]; 115 }, 116}; 117