xref: /expo/docs/next.config.js (revision 2f344939)
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