From 488f7377da02c0f0533762cde3a9a9d5b985ad5a Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 23 Jul 2022 14:42:29 +0200 Subject: [PATCH] fix client console error on React 17 / crash on React 18 - Text content does not match server-rendered HTML (#568) fix client console error - Text content does not match server-rendered HTML --- .changeset/dry-windows-play.md | 5 +++ packages/nextra/scripts/build.js | 2 +- packages/nextra/scripts/dev.js | 2 +- packages/nextra/src/index.js | 58 --------------------------- packages/nextra/src/index.ts | 69 ++++++++++++++++++++++++++++++++ packages/nextra/src/types.ts | 7 ++-- 6 files changed, 79 insertions(+), 64 deletions(-) create mode 100644 .changeset/dry-windows-play.md delete mode 100644 packages/nextra/src/index.js create mode 100644 packages/nextra/src/index.ts diff --git a/.changeset/dry-windows-play.md b/.changeset/dry-windows-play.md new file mode 100644 index 0000000000..e6b24b736c --- /dev/null +++ b/.changeset/dry-windows-play.md @@ -0,0 +1,5 @@ +--- +'nextra': patch +--- + +fix client console error - Text content does not match server-rendered HTML diff --git a/packages/nextra/scripts/build.js b/packages/nextra/scripts/build.js index 44294f6ee6..8c5a11010d 100644 --- a/packages/nextra/scripts/build.js +++ b/packages/nextra/scripts/build.js @@ -17,7 +17,7 @@ const externalDeps = [ esbuild.buildSync({ ...BUILD_OPTIONS, entryPoints: [ - 'src/index.js', + 'src/index.ts', 'src/ssg.ts', 'src/locales.ts', 'src/context.ts' diff --git a/packages/nextra/scripts/dev.js b/packages/nextra/scripts/dev.js index 4f630ea96d..1c0a00d480 100644 --- a/packages/nextra/scripts/dev.js +++ b/packages/nextra/scripts/dev.js @@ -28,7 +28,7 @@ const externalDeps = [ esbuild.build({ ...BUILD_OPTIONS, entryPoints: [ - 'src/index.js', + 'src/index.ts', 'src/ssg.ts', 'src/locales.ts', 'src/context.ts' diff --git a/packages/nextra/src/index.js b/packages/nextra/src/index.js deleted file mode 100644 index 6275159ee2..0000000000 --- a/packages/nextra/src/index.js +++ /dev/null @@ -1,58 +0,0 @@ -import { NextraPlugin, pageMapCache } from './plugin' -import { MARKDOWN_EXTENSION_REGEX } from './constants' - -const defaultExtensions = ['js', 'jsx', 'ts', 'tsx'] -const markdownExtensions = ['md', 'mdx'] - -module.exports = - (...args) => - (nextConfig = {}) => { - const nextraConfig = - typeof args[0] === 'string' - ? { - theme: args[0], - themeConfig: args[1] - } - : args[0] - - const locales = nextConfig.i18n?.locales || null - const defaultLocale = nextConfig.i18n?.defaultLocale || null - - let pageExtensions = nextConfig.pageExtensions || [...defaultExtensions] - pageExtensions = pageExtensions.concat(markdownExtensions) - - if (locales) { - console.log( - '[nextra] You have Next.js i18n enabled, read here (TODO: link) for the docs.' - ) - } - - return Object.assign({}, nextConfig, { - pageExtensions, - webpack(config, options) { - const nextra = new NextraPlugin(nextraConfig) - if (!config.plugins) { - config.plugins = [nextra] - } else { - config.plugins.push(nextra) - } - - config.module.rules.push({ - test: MARKDOWN_EXTENSION_REGEX, - use: [ - options.defaultLoaders.babel, - { - loader: 'nextra/loader', - options: { ...nextraConfig, locales, defaultLocale, pageMapCache } - } - ] - }) - - if (typeof nextConfig.webpack === 'function') { - return nextConfig.webpack(config, options) - } - - return config - } - }) - } diff --git a/packages/nextra/src/index.ts b/packages/nextra/src/index.ts new file mode 100644 index 0000000000..931671a5d9 --- /dev/null +++ b/packages/nextra/src/index.ts @@ -0,0 +1,69 @@ +import { NextraPlugin, pageMapCache } from './plugin' +import { MARKDOWN_EXTENSION_REGEX } from './constants' +import { LoaderOptions, Nextra } from './types' + +const DEFAULT_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx'] as const +const MARKDOWN_EXTENSIONS = ['md', 'mdx'] as const + +const nextra: Nextra = (...args) => + function withNextra(nextConfig = {}) { + const nextraConfig = + typeof args[0] === 'string' + ? { + theme: args[0], + themeConfig: args[1] as string + } + : args[0] + + const nextraPlugin = new NextraPlugin(nextraConfig) + const { i18n, pageExtensions = DEFAULT_EXTENSIONS } = nextConfig + + if (i18n?.locales) { + console.log( + '[nextra] You have Next.js i18n enabled, read here https://nextjs.org/docs/advanced-features/i18n-routing for the docs.' + ) + } else if (!i18n?.defaultLocale) { + // If `i18n.locales` and `i18n.defaultLocale` were not specified, + // client will receive error - Text content does not match server-rendered HTML. + // Due to `const { locales } = useRouter()` where `locales` will be `undefined` + // To fix it we need to explicitly specify `i18n.locales` and `i18n.defaultLocale` + nextConfig.i18n = { + ...i18n, + locales: ['en-US'], + defaultLocale: 'en-US' + } + } + + return { + ...nextConfig, + pageExtensions: [...pageExtensions, ...MARKDOWN_EXTENSIONS], + webpack(config, options) { + config.plugins ||= [] + config.plugins.push(nextraPlugin) + + config.module.rules.push({ + test: MARKDOWN_EXTENSION_REGEX, + use: [ + options.defaultLoaders.babel, + { + loader: 'nextra/loader', + options: { + ...nextraConfig, + locales: nextConfig.i18n?.locales, + defaultLocale: nextConfig.i18n?.defaultLocale, + pageMapCache + } + } + ] + }) + + if (typeof nextConfig.webpack === 'function') { + return nextConfig.webpack(config, options) + } + + return config + } + } + } + +module.exports = nextra diff --git a/packages/nextra/src/types.ts b/packages/nextra/src/types.ts index 799fd6c8bb..53c458af64 100644 --- a/packages/nextra/src/types.ts +++ b/packages/nextra/src/types.ts @@ -1,3 +1,4 @@ +import { NextConfig } from 'next' import { Heading as MDASTHeading } from 'mdast' import { ProcessorOptions } from '@mdx-js/mdx' import { Options as RehypePrettyCodeOptions } from 'rehype-pretty-code' @@ -57,8 +58,6 @@ export type NextraConfig = { } } -export type withNextra = ( +export type Nextra = ( ...args: [NextraConfig] | [theme: Theme, themeConfig: string] -) => (nextConfig: Record) => {} - -export default withNextra +) => (nextConfig: NextConfig) => NextConfig