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