From 256154ad92b079254126c61609cbf7d0c5968f20 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Wed, 7 Sep 2022 22:12:01 +0300 Subject: [PATCH] use "next/future/image" if `"experimental.images.allowFutureImage": true` is set in next config (#817) * use "next/future/image" if `"experimental.images.allowFutureImage": true` is set in next config * Update packages/nextra/src/mdx-plugins/remark.ts * replace images with `` even when url not relative but that starts from `/` (public directory) (#819) * replace images with `` even when url not relative but that starts from `/` (public directory) * fix build --- .changeset/shiny-apples-speak.md | 7 + .changeset/spotty-swans-explain.md | 7 + examples/swr-site/next.config.js | 3 + .../pages/docs/advanced/_meta.en-US.json | 7 +- .../docs/advanced/future-image.en-US.mdx | 3 + examples/swr-site/theme.config.tsx | 9 - packages/nextra-theme-docs/src/constants.tsx | 2 - .../__snapshots__/context.test.ts.snap | 593 +++++++++--------- .../__snapshots__/page-map.test.ts.snap | 19 +- packages/nextra/package.json | 4 +- packages/nextra/src/compile.ts | 37 +- packages/nextra/src/constants.ts | 10 + packages/nextra/src/content-dump.ts | 55 +- packages/nextra/src/file-system.ts | 10 + packages/nextra/src/index.js | 3 +- packages/nextra/src/loader.ts | 23 +- packages/nextra/src/mdx-plugins/index.ts | 4 + .../{rehype-handler.js => rehype.js} | 0 packages/nextra/src/mdx-plugins/remark.ts | 45 +- .../nextra/src/mdx-plugins/static-image.js | 107 ---- .../nextra/src/mdx-plugins/static-image.ts | 128 ++++ .../nextra/src/mdx-plugins/structurize.js | 32 +- packages/nextra/src/page-map.ts | 2 +- packages/nextra/src/plugin.ts | 9 +- packages/nextra/src/types.ts | 1 + packages/nextra/src/utils.ts | 3 +- pnpm-lock.yaml | 36 +- 27 files changed, 630 insertions(+), 529 deletions(-) create mode 100644 .changeset/shiny-apples-speak.md create mode 100644 .changeset/spotty-swans-explain.md create mode 100644 examples/swr-site/pages/docs/advanced/future-image.en-US.mdx create mode 100644 packages/nextra/src/file-system.ts create mode 100644 packages/nextra/src/mdx-plugins/index.ts rename packages/nextra/src/mdx-plugins/{rehype-handler.js => rehype.js} (100%) delete mode 100644 packages/nextra/src/mdx-plugins/static-image.js create mode 100644 packages/nextra/src/mdx-plugins/static-image.ts diff --git a/.changeset/shiny-apples-speak.md b/.changeset/shiny-apples-speak.md new file mode 100644 index 0000000000..3b8dc6807e --- /dev/null +++ b/.changeset/shiny-apples-speak.md @@ -0,0 +1,7 @@ +--- +'nextra': patch +'nextra-theme-blog': patch +'nextra-theme-docs': patch +--- + +use "next/future/image" if `"experimental.images.allowFutureImage": true` is set in next config diff --git a/.changeset/spotty-swans-explain.md b/.changeset/spotty-swans-explain.md new file mode 100644 index 0000000000..f876495c7a --- /dev/null +++ b/.changeset/spotty-swans-explain.md @@ -0,0 +1,7 @@ +--- +'nextra': patch +'nextra-theme-docs': patch +'nextra-theme-blog': patch +--- + +replace images with `` even when url not relative but that starts from `/` (public directory) diff --git a/examples/swr-site/next.config.js b/examples/swr-site/next.config.js index e08be49a31..07b879629f 100644 --- a/examples/swr-site/next.config.js +++ b/examples/swr-site/next.config.js @@ -65,5 +65,8 @@ module.exports = withNextra({ reactStrictMode: true, experimental: { newNextLinkBehavior: true, + images: { + allowFutureImage: true, + }, }, }); diff --git a/examples/swr-site/pages/docs/advanced/_meta.en-US.json b/examples/swr-site/pages/docs/advanced/_meta.en-US.json index f5b48da062..ef68c50f1b 100644 --- a/examples/swr-site/pages/docs/advanced/_meta.en-US.json +++ b/examples/swr-site/pages/docs/advanced/_meta.en-US.json @@ -8,11 +8,6 @@ "title": "Do Not Use", "type": "separator" }, - "cache": "Cache", - "performance": "Performance", - "react-native": "React Native", - "markdown-import": "Markdown import", "more": "More: A Super Super Super Super Long Directory", - "file-name.with.DOTS": "Filenames with dots", - "code-highlighting": "Code highlighting" + "file-name.with.DOTS": "Filenames with Dots" } diff --git a/examples/swr-site/pages/docs/advanced/future-image.en-US.mdx b/examples/swr-site/pages/docs/advanced/future-image.en-US.mdx new file mode 100644 index 0000000000..0b209de411 --- /dev/null +++ b/examples/swr-site/pages/docs/advanced/future-image.en-US.mdx @@ -0,0 +1,3 @@ +![](../../../public/favicon/android-chrome-512x512.png) + +![](/favicon/android-chrome-512x512.png) diff --git a/examples/swr-site/theme.config.tsx b/examples/swr-site/theme.config.tsx index 9ea2a05d36..56caf047b1 100644 --- a/examples/swr-site/theme.config.tsx +++ b/examples/swr-site/theme.config.tsx @@ -92,14 +92,6 @@ const config: DocsThemeConfig = { key: "swr-2", text: "SWR 2.0 is out! Read more →", }, - bodyExtraContent() { - const router = useRouter(); - return ( - router.route.startsWith("/docs") && ( - <>💪 content from `config.bodyExtraContent` - ) - ); - }, darkMode: true, docsRepositoryBase: "https://github.com/shuding/nextra/blob/core/examples/swr-site", @@ -128,7 +120,6 @@ const config: DocsThemeConfig = { ); }, }, - gitTimestamp: "Last updated on", github: "https://github.com/vercel/swr", head() { const config = useConfig(); diff --git a/packages/nextra-theme-docs/src/constants.tsx b/packages/nextra-theme-docs/src/constants.tsx index 7e16d7bbb1..c8e94ef1c6 100644 --- a/packages/nextra-theme-docs/src/constants.tsx +++ b/packages/nextra-theme-docs/src/constants.tsx @@ -12,8 +12,6 @@ export const DEFAULT_LOCALE = 'en-US' export const IS_BROWSER = typeof window !== 'undefined' -export const META_FILENAME = '_meta.json' - export const DEFAULT_THEME: DocsThemeConfig = { banner: { key: 'nextra-banner', diff --git a/packages/nextra/__test__/__snapshots__/context.test.ts.snap b/packages/nextra/__test__/__snapshots__/context.test.ts.snap index 0ea1d54181..2d8444937d 100644 --- a/packages/nextra/__test__/__snapshots__/context.test.ts.snap +++ b/packages/nextra/__test__/__snapshots__/context.test.ts.snap @@ -876,6 +876,79 @@ exports[`context > getAllPages() > should work 1`] = ` }, { "children": [ + { + "children": [ + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Loooooooooooooooooooong Title", + }, + "name": "loooooooooooooooooooong-title", + "route": "/docs/advanced/more/loooooooooooooooooooong-title", + }, + ], + "kind": "Folder", + "meta": { + "title": "More: A Super Super Super Super Long Directory", + }, + "name": "more", + "route": "/docs/advanced/more", + }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "es-ES", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ja", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ko", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ru", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "zh-CN", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, { "kind": "MdxPage", "locale": "en-US", @@ -921,6 +994,33 @@ exports[`context > getAllPages() > should work 1`] = ` "name": "cache", "route": "/docs/advanced/cache", }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Code Highlighting", + }, + "name": "code-highlighting", + "route": "/docs/advanced/code-highlighting", + }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Future Image", + }, + "name": "future-image", + "route": "/docs/advanced/future-image", + }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Markdown Import", + }, + "name": "markdown-import", + "route": "/docs/advanced/markdown-import", + }, { "kind": "MdxPage", "locale": "en-US", @@ -1020,97 +1120,6 @@ exports[`context > getAllPages() > should work 1`] = ` "name": "react-native", "route": "/docs/advanced/react-native", }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Markdown import", - }, - "name": "markdown-import", - "route": "/docs/advanced/markdown-import", - }, - { - "children": [ - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Loooooooooooooooooooong Title", - }, - "name": "loooooooooooooooooooong-title", - "route": "/docs/advanced/more/loooooooooooooooooooong-title", - }, - ], - "kind": "Folder", - "meta": { - "title": "More: A Super Super Super Super Long Directory", - }, - "name": "more", - "route": "/docs/advanced/more", - }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "es-ES", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "ja", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "ko", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "ru", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "zh-CN", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Code highlighting", - }, - "name": "code-highlighting", - "route": "/docs/advanced/code-highlighting", - }, ], "kind": "Folder", "meta": { @@ -2590,6 +2599,79 @@ exports[`context > getCurrentLevelPages() > should work 1`] = ` }, { "children": [ + { + "children": [ + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Loooooooooooooooooooong Title", + }, + "name": "loooooooooooooooooooong-title", + "route": "/docs/advanced/more/loooooooooooooooooooong-title", + }, + ], + "kind": "Folder", + "meta": { + "title": "More: A Super Super Super Super Long Directory", + }, + "name": "more", + "route": "/docs/advanced/more", + }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "es-ES", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ja", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ko", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ru", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "zh-CN", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, { "kind": "MdxPage", "locale": "en-US", @@ -2639,32 +2721,32 @@ exports[`context > getCurrentLevelPages() > should work 1`] = ` "kind": "MdxPage", "locale": "en-US", "meta": { - "title": "Performance", + "title": "Code Highlighting", }, - "name": "performance", - "route": "/docs/advanced/performance", + "name": "code-highlighting", + "route": "/docs/advanced/code-highlighting", }, { "kind": "MdxPage", - "locale": "es-ES", + "locale": "en-US", "meta": { - "title": "Performance", + "title": "Future Image", }, - "name": "performance", - "route": "/docs/advanced/performance", + "name": "future-image", + "route": "/docs/advanced/future-image", }, { "kind": "MdxPage", - "locale": "ja", + "locale": "en-US", "meta": { - "title": "Performance", + "title": "Markdown Import", }, - "name": "performance", - "route": "/docs/advanced/performance", + "name": "markdown-import", + "route": "/docs/advanced/markdown-import", }, { "kind": "MdxPage", - "locale": "ko", + "locale": "en-US", "meta": { "title": "Performance", }, @@ -2673,7 +2755,7 @@ exports[`context > getCurrentLevelPages() > should work 1`] = ` }, { "kind": "MdxPage", - "locale": "ru", + "locale": "es-ES", "meta": { "title": "Performance", }, @@ -2682,7 +2764,7 @@ exports[`context > getCurrentLevelPages() > should work 1`] = ` }, { "kind": "MdxPage", - "locale": "zh-CN", + "locale": "ja", "meta": { "title": "Performance", }, @@ -2691,34 +2773,34 @@ exports[`context > getCurrentLevelPages() > should work 1`] = ` }, { "kind": "MdxPage", - "locale": "en-US", + "locale": "ko", "meta": { - "title": "React Native", + "title": "Performance", }, - "name": "react-native", - "route": "/docs/advanced/react-native", + "name": "performance", + "route": "/docs/advanced/performance", }, { "kind": "MdxPage", - "locale": "ja", + "locale": "ru", "meta": { - "title": "React Native", + "title": "Performance", }, - "name": "react-native", - "route": "/docs/advanced/react-native", + "name": "performance", + "route": "/docs/advanced/performance", }, { "kind": "MdxPage", - "locale": "ko", + "locale": "zh-CN", "meta": { - "title": "React Native", + "title": "Performance", }, - "name": "react-native", - "route": "/docs/advanced/react-native", + "name": "performance", + "route": "/docs/advanced/performance", }, { "kind": "MdxPage", - "locale": "ru", + "locale": "en-US", "meta": { "title": "React Native", }, @@ -2727,103 +2809,39 @@ exports[`context > getCurrentLevelPages() > should work 1`] = ` }, { "kind": "MdxPage", - "locale": "zh-CN", + "locale": "ja", "meta": { "title": "React Native", }, "name": "react-native", "route": "/docs/advanced/react-native", }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Markdown import", - }, - "name": "markdown-import", - "route": "/docs/advanced/markdown-import", - }, - { - "children": [ - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Loooooooooooooooooooong Title", - }, - "name": "loooooooooooooooooooong-title", - "route": "/docs/advanced/more/loooooooooooooooooooong-title", - }, - ], - "kind": "Folder", - "meta": { - "title": "More: A Super Super Super Super Long Directory", - }, - "name": "more", - "route": "/docs/advanced/more", - }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "es-ES", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "ja", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, { "kind": "MdxPage", "locale": "ko", "meta": { - "title": "Filenames with dots", + "title": "React Native", }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", + "name": "react-native", + "route": "/docs/advanced/react-native", }, { "kind": "MdxPage", "locale": "ru", "meta": { - "title": "Filenames with dots", + "title": "React Native", }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", + "name": "react-native", + "route": "/docs/advanced/react-native", }, { "kind": "MdxPage", "locale": "zh-CN", "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Code highlighting", + "title": "React Native", }, - "name": "code-highlighting", - "route": "/docs/advanced/code-highlighting", + "name": "react-native", + "route": "/docs/advanced/react-native", }, ], "kind": "Folder", @@ -3003,6 +3021,79 @@ exports[`context > getCurrentLevelPages() > should work 1`] = ` exports[`context > getPagesUnderRoute() > should work 1`] = ` [ + { + "children": [ + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Loooooooooooooooooooong Title", + }, + "name": "loooooooooooooooooooong-title", + "route": "/docs/advanced/more/loooooooooooooooooooong-title", + }, + ], + "kind": "Folder", + "meta": { + "title": "More: A Super Super Super Super Long Directory", + }, + "name": "more", + "route": "/docs/advanced/more", + }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "es-ES", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ja", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ko", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "ru", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, + { + "kind": "MdxPage", + "locale": "zh-CN", + "meta": { + "title": "Filenames with Dots", + }, + "name": "file-name.with.DOTS", + "route": "/docs/advanced/file-name.with.DOTS", + }, { "kind": "MdxPage", "locale": "en-US", @@ -3048,6 +3139,33 @@ exports[`context > getPagesUnderRoute() > should work 1`] = ` "name": "cache", "route": "/docs/advanced/cache", }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Code Highlighting", + }, + "name": "code-highlighting", + "route": "/docs/advanced/code-highlighting", + }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Future Image", + }, + "name": "future-image", + "route": "/docs/advanced/future-image", + }, + { + "kind": "MdxPage", + "locale": "en-US", + "meta": { + "title": "Markdown Import", + }, + "name": "markdown-import", + "route": "/docs/advanced/markdown-import", + }, { "kind": "MdxPage", "locale": "en-US", @@ -3147,96 +3265,5 @@ exports[`context > getPagesUnderRoute() > should work 1`] = ` "name": "react-native", "route": "/docs/advanced/react-native", }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Markdown import", - }, - "name": "markdown-import", - "route": "/docs/advanced/markdown-import", - }, - { - "children": [ - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Loooooooooooooooooooong Title", - }, - "name": "loooooooooooooooooooong-title", - "route": "/docs/advanced/more/loooooooooooooooooooong-title", - }, - ], - "kind": "Folder", - "meta": { - "title": "More: A Super Super Super Super Long Directory", - }, - "name": "more", - "route": "/docs/advanced/more", - }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "es-ES", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "ja", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "ko", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "ru", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "zh-CN", - "meta": { - "title": "Filenames with dots", - }, - "name": "file-name.with.DOTS", - "route": "/docs/advanced/file-name.with.DOTS", - }, - { - "kind": "MdxPage", - "locale": "en-US", - "meta": { - "title": "Code highlighting", - }, - "name": "code-highlighting", - "route": "/docs/advanced/code-highlighting", - }, ] `; diff --git a/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap b/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap index c6f9f23fc9..e1cfed40c9 100644 --- a/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap +++ b/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap @@ -245,9 +245,10 @@ exports[`Page Process > pageMap en-US 1`] = ` "type": "separator", }, "cache": "Cache", - "code-highlighting": "Code highlighting", - "file-name.with.DOTS": "Filenames with dots", - "markdown-import": "Markdown import", + "code-highlighting": "Code Highlighting", + "file-name.with.DOTS": "Filenames with Dots", + "future-image": "Future Image", + "markdown-import": "Markdown Import", "more": "More: A Super Super Super Super Long Directory", "performance": "Performance", "react-native": "React Native", @@ -273,6 +274,12 @@ exports[`Page Process > pageMap en-US 1`] = ` "name": "file-name.with.DOTS", "route": "/docs/advanced/file-name.with.DOTS", }, + { + "kind": "MdxPage", + "locale": "en-US", + "name": "future-image", + "route": "/docs/advanced/future-image", + }, { "kind": "MdxPage", "locale": "en-US", @@ -723,6 +730,12 @@ exports[`Page Process > pageMap zh-CN 1`] = ` "name": "code-highlighting", "route": "/docs/advanced/code-highlighting", }, + { + "kind": "MdxPage", + "locale": "en-US", + "name": "future-image", + "route": "/docs/advanced/future-image", + }, { "kind": "MdxPage", "locale": "en-US", diff --git a/packages/nextra/package.json b/packages/nextra/package.json index 52ecef668a..c19fcf2ffd 100644 --- a/packages/nextra/package.json +++ b/packages/nextra/package.json @@ -87,7 +87,8 @@ "remark-reading-time": "^2.0.1", "shiki": "0.10.1", "slash": "^3.0.0", - "title": "^3.5.3" + "title": "^3.5.3", + "unist-util-visit": "^4.1.1" }, "peerDependencies": { "next": ">=9.5.3", @@ -110,6 +111,7 @@ "next": "^12.2.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "unified": "^10.1.2", "vitest": "^0.21.0" } } diff --git a/packages/nextra/src/compile.ts b/packages/nextra/src/compile.ts index 30de46a0ec..0fcdf39592 100644 --- a/packages/nextra/src/compile.ts +++ b/packages/nextra/src/compile.ts @@ -4,11 +4,14 @@ import remarkGfm from 'remark-gfm' import rehypePrettyCode from 'rehype-pretty-code' import { rehypeMdxTitle } from 'rehype-mdx-title' import readingTime from 'remark-reading-time' -import { remarkStaticImage } from './mdx-plugins/static-image' -import { remarkHeadings } from './mdx-plugins/remark' +import { + remarkStaticImage, + remarkHeadings, + structurize, + parseMeta, + attachMeta +} from './mdx-plugins' import { LoaderOptions, PageOpts, ReadingTime } from './types' -import structurize from './mdx-plugins/structurize' -import { parseMeta, attachMeta } from './mdx-plugins/rehype-handler' import theme from './theme.json' import { truthy } from './utils' @@ -39,18 +42,23 @@ const rehypePrettyCodeOptions = { export async function compileMdx( source: string, - mdxOptions: LoaderOptions['mdxOptions'] & - Pick = {}, - nextraOptions: Pick< + loaderOptions: Pick< LoaderOptions, | 'unstable_staticImage' | 'unstable_flexsearch' | 'unstable_defaultShowCopyCode' | 'unstable_readingTime' - > = {}, + | 'allowFutureImage' + > & { + mdxOptions?: LoaderOptions['mdxOptions'] & + Pick + } = {}, filePath = '' ) { const structurizedData = Object.create(null) + + const mdxOptions = loaderOptions.mdxOptions || {} + const compiler = createCompiler({ jsx: mdxOptions.jsx ?? true, outputFormat: mdxOptions.outputFormat, @@ -59,10 +67,13 @@ export async function compileMdx( ...(mdxOptions.remarkPlugins || []), remarkGfm, remarkHeadings, - nextraOptions.unstable_staticImage && remarkStaticImage, - nextraOptions.unstable_flexsearch && - structurize(structurizedData, nextraOptions.unstable_flexsearch), - nextraOptions.unstable_readingTime && readingTime + loaderOptions.unstable_staticImage && [ + remarkStaticImage, + { allowFutureImage: loaderOptions.allowFutureImage, filePath } + ] as any, + loaderOptions.unstable_flexsearch && + structurize(structurizedData, loaderOptions.unstable_flexsearch), + loaderOptions.unstable_readingTime && readingTime ].filter(truthy), rehypePlugins: [ ...(mdxOptions.rehypePlugins || []), @@ -74,7 +85,7 @@ export async function compileMdx( [rehypeMdxTitle, { name: '__nextra_title__' }], [ attachMeta, - { defaultShowCopyCode: nextraOptions.unstable_defaultShowCopyCode } + { defaultShowCopyCode: loaderOptions.unstable_defaultShowCopyCode } ] ] }) diff --git a/packages/nextra/src/constants.ts b/packages/nextra/src/constants.ts index e60f898f1b..fffd624052 100644 --- a/packages/nextra/src/constants.ts +++ b/packages/nextra/src/constants.ts @@ -1,3 +1,5 @@ +import path from 'node:path' + export const MARKDOWN_EXTENSION_REGEX = /\.mdx?$/ export const IS_PRODUCTION = process.env.NODE_ENV === 'production' @@ -16,3 +18,11 @@ export const META_FILENAME = '_meta.json' export const CWD = process.cwd() export const MARKDOWN_EXTENSIONS = ['md', 'mdx'] as const + +export const PUBLIC_DIR = path.join(CWD, 'public') + +export const CACHE_DIR = path.join(CWD, '.next/cache') + +export const ASSET_DIR = path.join(CWD, '.next/static/chunks') + +export const EXTERNAL_URL_REGEX = /^https?:\/\// diff --git a/packages/nextra/src/content-dump.ts b/packages/nextra/src/content-dump.ts index cd0a9cf40c..253ff1147e 100644 --- a/packages/nextra/src/content-dump.ts +++ b/packages/nextra/src/content-dump.ts @@ -1,34 +1,24 @@ +import path from 'node:path' import fs from 'graceful-fs' -import path from 'path' -import { FrontMatter } from './types' -import { CWD } from './constants' - -const { statSync, mkdirSync } = fs - -const cacheDir = path.join(CWD, '.next', 'cache') -const assetDir = path.join(CWD, '.next', 'static', 'chunks') +import { existsSync } from './file-system' +import { ASSET_DIR, CACHE_DIR } from './constants' const asset: { [locale: string]: any } = Object.create(null) const cached = new Map() -try { - statSync(assetDir) -} catch { - mkdirSync(assetDir, { recursive: true }) +if (!existsSync(ASSET_DIR)) { + fs.mkdirSync(ASSET_DIR, { recursive: true }) } -let cacheDirExist = false -try { - statSync(cacheDir) - cacheDirExist = true -} catch { - mkdirSync(cacheDir, { recursive: true }) +const cacheDirExist = existsSync(CACHE_DIR) +if (!cacheDirExist) { + fs.mkdirSync(CACHE_DIR, { recursive: true }) } function initFromCache(filename: string) { if (!cached.has(filename)) { try { - const content = fs.readFileSync(path.join(assetDir, filename), 'utf8') + const content = fs.readFileSync(path.join(ASSET_DIR, filename), 'utf8') cached.set(filename, true) return JSON.parse(content) } catch { @@ -61,24 +51,23 @@ export function addPage({ // @TODO: introduce mutex lock, or only generate the asset when finishing the // entire build. const content = JSON.stringify(asset[locale]) - fs.writeFileSync(path.join(assetDir, dataFilename), content) - fs.writeFileSync(path.join(cacheDir, dataFilename), content) + fs.writeFileSync(path.join(ASSET_DIR, dataFilename), content) + fs.writeFileSync(path.join(CACHE_DIR, dataFilename), content) } // Copy cached data to the asset directory. -export async function restoreCache() { - if (cacheDirExist) { - try { - statSync(assetDir) - } catch { - mkdirSync(assetDir, { recursive: true }) - } +export function restoreCache(): void { + if (!cacheDirExist) { + return + } + if (!existsSync(ASSET_DIR)) { + fs.mkdirSync(ASSET_DIR, { recursive: true }) + } - const files = fs.readdirSync(cacheDir) - for (const file of files) { - if (file.startsWith('nextra-data-')) { - fs.copyFileSync(path.join(cacheDir, file), path.join(assetDir, file)) - } + const files = fs.readdirSync(CACHE_DIR) + for (const file of files) { + if (file.startsWith('nextra-data-')) { + fs.copyFileSync(path.join(CACHE_DIR, file), path.join(ASSET_DIR, file)) } } } diff --git a/packages/nextra/src/file-system.ts b/packages/nextra/src/file-system.ts new file mode 100644 index 0000000000..d1dd1a6985 --- /dev/null +++ b/packages/nextra/src/file-system.ts @@ -0,0 +1,10 @@ +import fs from 'graceful-fs' + +export const existsSync = (filePath: string): boolean => { + try { + fs.statSync(filePath) + return true + } catch { + return false + } +} diff --git a/packages/nextra/src/index.js b/packages/nextra/src/index.js index ba05cb9c92..03994fe624 100644 --- a/packages/nextra/src/index.js +++ b/packages/nextra/src/index.js @@ -40,7 +40,8 @@ const nextra = (...config) => locales: nextConfig.i18n?.locales || [DEFAULT_LOCALE], defaultLocale: nextConfig.i18n?.defaultLocale || DEFAULT_LOCALE, pageMapCache, - newNextLinkBehavior: nextConfig.experimental?.newNextLinkBehavior + newNextLinkBehavior: nextConfig.experimental?.newNextLinkBehavior, + allowFutureImage: nextConfig.experimental?.images?.allowFutureImage } config.module.rules.push( diff --git a/packages/nextra/src/loader.ts b/packages/nextra/src/loader.ts index 55110726c9..b711ea6eec 100644 --- a/packages/nextra/src/loader.ts +++ b/packages/nextra/src/loader.ts @@ -1,6 +1,6 @@ import type { LoaderOptions, MdxPath, PageOpts } from './types' -import path from 'path' +import path from 'node:path' import grayMatter from 'gray-matter' import slash from 'slash' import { LoaderContext } from 'webpack' @@ -17,14 +17,13 @@ import { DEFAULT_LOCALE, OFFICIAL_THEMES, MARKDOWN_EXTENSION_REGEX, - CWD + CWD, } from './constants' +const PAGES_DIR = findPagesDir(CWD).pages // TODO: create this as a webpack plugin. const indexContentEmitted = new Set() -const pagesDir = findPagesDir(CWD).pages - const [repository, gitRoot] = (function () { try { const repo = Repository.discover(CWD) @@ -68,7 +67,8 @@ async function loader( unstable_readingTime, mdxOptions, pageMapCache, - newNextLinkBehavior + newNextLinkBehavior, + allowFutureImage } = context.getOptions() context.cacheable(true) @@ -89,7 +89,7 @@ async function loader( const { items, fileMap } = IS_PRODUCTION ? pageMapCache.get()! - : await collectFiles(pagesDir) + : await collectFiles(PAGES_DIR) // mdx is imported but is outside the `pages` directory if (!fileMap[mdxPath]) { @@ -106,7 +106,7 @@ async function loader( } // Add the entire directory `pages` as the dependency, // so we can generate the correct page map. - context.addContextDependency(pagesDir) + context.addContextDependency(PAGES_DIR) // Extract frontMatter information if it exists const { data: frontMatter, content } = grayMatter(source) @@ -114,12 +114,13 @@ async function loader( const { result, headings, structurizedData, hasJsxInH1, readingTime } = await compileMdx( content, - mdxOptions, { + mdxOptions, unstable_readingTime, unstable_defaultShowCopyCode, unstable_staticImage, - unstable_flexsearch + unstable_flexsearch, + allowFutureImage }, mdxPath ) @@ -191,7 +192,7 @@ export default MDXContent`.trimStart() const pageNextRoute = '/' + - slash(path.relative(pagesDir, mdxPath)) + slash(path.relative(PAGES_DIR, mdxPath)) // Remove the `mdx?` extension .replace(MARKDOWN_EXTENSION_REGEX, '') // Remove the `*/index` suffix @@ -216,7 +217,7 @@ ${result} __nextra_pageOpts__.title = ${JSON.stringify(frontMatter.title)} || (typeof __nextra_title__ === 'string' && __nextra_title__) || - 'Untitled' + ${JSON.stringify(title /* Fallback as sidebar link name */)} const Content = props => ( <__nextra_SSGContext__.Provider value={props}> diff --git a/packages/nextra/src/mdx-plugins/index.ts b/packages/nextra/src/mdx-plugins/index.ts new file mode 100644 index 0000000000..7b0a636ce8 --- /dev/null +++ b/packages/nextra/src/mdx-plugins/index.ts @@ -0,0 +1,4 @@ +export { parseMeta, attachMeta } from './rehype' +export { remarkHeadings } from './remark' +export { remarkStaticImage } from './static-image' +export { structurize } from './structurize' diff --git a/packages/nextra/src/mdx-plugins/rehype-handler.js b/packages/nextra/src/mdx-plugins/rehype.js similarity index 100% rename from packages/nextra/src/mdx-plugins/rehype-handler.js rename to packages/nextra/src/mdx-plugins/rehype.js diff --git a/packages/nextra/src/mdx-plugins/remark.ts b/packages/nextra/src/mdx-plugins/remark.ts index a62daf9b92..20e5e8db44 100644 --- a/packages/nextra/src/mdx-plugins/remark.ts +++ b/packages/nextra/src/mdx-plugins/remark.ts @@ -1,20 +1,11 @@ import { Processor } from '@mdx-js/mdx/lib/core' +import { visit } from 'unist-util-visit' +import { Plugin } from 'unified' import { Root, Heading, Parent } from 'mdast' import { PageOpts } from '../types' -function visit( - node: any, - tester: (node: any) => boolean, - handler: (node: any) => any -) { - if (tester(node)) { - handler(node) - } - node.children?.forEach((n: any) => visit(n, tester, handler)) -} - -export function getFlattenedValue(node: Parent): string { - return node.children +export const getFlattenedValue = (node: Parent): string => + node.children .map(child => 'children' in child ? getFlattenedValue(child) @@ -23,23 +14,20 @@ export function getFlattenedValue(node: Parent): string { : '' ) .join('') -} -export function remarkHeadings(this: Processor) { +export const remarkHeadings: Plugin<[], Root> = function (this: Processor) { const data = this.data() as { headingMeta: Pick } - return (tree: Root, _file: any, done: () => void) => { + return (tree, _file, done) => { visit( tree, - node => { + [ // Match headings and
- return ( - node.type === 'heading' || - node.name === 'summary' || - node.name === 'details' - ) - }, + { type: 'heading' }, + { name: 'summary' }, + { name: 'details' } + ], node => { if (node.type === 'heading') { const hasJsxInH1 = @@ -56,11 +44,12 @@ export function remarkHeadings(this: Processor) { if (hasJsxInH1) { data.headingMeta.hasJsxInH1 = true } - } else if (node.name === 'summary' || node.name === 'details') { - // Replace the and
with customized components. - if (node.data) { - delete node.data._mdxExplicitJsx - } + return + } + + // Replace the and
with customized components. + if (node.data) { + delete node.data._mdxExplicitJsx } } ) diff --git a/packages/nextra/src/mdx-plugins/static-image.js b/packages/nextra/src/mdx-plugins/static-image.js deleted file mode 100644 index 2f2f381504..0000000000 --- a/packages/nextra/src/mdx-plugins/static-image.js +++ /dev/null @@ -1,107 +0,0 @@ -// Based on the remark-embed-images project -// https://github.com/remarkjs/remark-embed-images - -const relative = /^\.{1,2}\// - -function visit(node, type, handler) { - if (node.type === type) { - handler(node) - } - if (node.children) { - node.children.forEach(n => visit(n, type, handler)) - } -} - -function ASTNodeImport(name, from) { - return { - type: 'mdxjsEsm', - value: `import ${name} from "${from}"`, - data: { - estree: { - type: 'Program', - body: [ - { - type: 'ImportDeclaration', - specifiers: [ - { - type: 'ImportDefaultSpecifier', - local: { type: 'Identifier', name } - } - ], - source: { - type: 'Literal', - value: from, - raw: `"${from}"` - } - } - ], - sourceType: 'module' - } - } - } -} - -export function remarkStaticImage() { - return (tree, _file, done) => { - const importsToInject = [] - - visit(tree, 'image', visitor) - tree.children.unshift(...importsToInject) - tree.children.unshift(ASTNodeImport('$NextImageNextra', 'next/image')) - done() - - function visitor(node) { - const url = node.url - - if (url && relative.test(url)) { - // Unique variable name for the given static image URL. - const tempVariableName = `$nextraImage${importsToInject.length}` - - // Replace the image node with a MDX component node (Next.js Image). - Object.assign(node, { - type: 'mdxJsxFlowElement', - name: '$NextImageNextra', - attributes: [ - { - type: 'mdxJsxAttribute', - name: 'alt', - value: node.alt || '' - }, - { - type: 'mdxJsxAttribute', - name: 'placeholder', - value: 'blur' - }, - { - type: 'mdxJsxAttribute', - name: 'src', - value: { - type: 'mdxJsxAttributeValueExpression', - value: tempVariableName, - data: { - estree: { - type: 'Program', - body: [ - { - type: 'ExpressionStatement', - expression: { - type: 'Identifier', - name: tempVariableName - } - } - ], - sourceType: 'module' - } - } - } - } - ], - children: [] - }) - - // Inject the static image import into the root node. - importsToInject.push(ASTNodeImport(tempVariableName, url)) - } - } - } -} diff --git a/packages/nextra/src/mdx-plugins/static-image.ts b/packages/nextra/src/mdx-plugins/static-image.ts new file mode 100644 index 0000000000..8bd0a4463a --- /dev/null +++ b/packages/nextra/src/mdx-plugins/static-image.ts @@ -0,0 +1,128 @@ +import { visit } from 'unist-util-visit' +import { Plugin } from 'unified' +import { Root } from 'mdast' +import path from 'node:path' +import { truthy } from '../utils' +import { existsSync } from '../file-system' +import { EXTERNAL_URL_REGEX, PUBLIC_DIR } from '../constants' + +const getASTNodeImport = (name: string, from: string) => ({ + type: 'mdxjsEsm', + value: `import ${name} from "${from}"`, + data: { + estree: { + type: 'Program', + body: [ + { + type: 'ImportDeclaration', + specifiers: [ + { + type: 'ImportDefaultSpecifier', + local: { type: 'Identifier', name } + } + ], + source: { + type: 'Literal', + value: from, + raw: `"${from}"` + } + } + ], + sourceType: 'module' + } + } +}) + +// Based on the remark-embed-images project +// https://github.com/remarkjs/remark-embed-images +export const remarkStaticImage: Plugin< + [{ allowFutureImage?: boolean; filePath: string }], + Root +> = + ({ allowFutureImage, filePath }) => + (tree, _file, done) => { + const importsToInject: any[] = [] + + visit(tree, 'image', node => { + let { url } = node + if (!url) { + console.warn( + `[nextra] File "${filePath}" contain image with empty "src" property, skipping…` + ) + return + } + + if (EXTERNAL_URL_REGEX.test(url)) { + // do nothing with images with external url + return + } + + if (url.startsWith('/')) { + const urlPath = path.join(PUBLIC_DIR, url) + if (!existsSync(urlPath)) { + console.error( + `[nextra] File "${filePath}" contain image with url "${url}" that not found in "/public" directory, skipping…` + ) + return + } + url = urlPath + } + // Unique variable name for the given static image URL. + const tempVariableName = `$nextraImage${importsToInject.length}` + + // Replace the image node with a MDX component node (Next.js Image). + Object.assign(node, { + type: 'mdxJsxFlowElement', + name: '$NextImageNextra', + children: [], + attributes: [ + // do not render empty alt in html markup + node.alt && { + type: 'mdxJsxAttribute', + name: 'alt', + value: node.alt + }, + { + type: 'mdxJsxAttribute', + name: 'placeholder', + value: 'blur' + }, + { + type: 'mdxJsxAttribute', + name: 'src', + value: { + type: 'mdxJsxAttributeValueExpression', + value: tempVariableName, + data: { + estree: { + type: 'Program', + sourceType: 'module', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'Identifier', + name: tempVariableName + } + } + ] + } + } + } + } + ].filter(truthy) + }) + + // Inject the static image import into the root node. + importsToInject.push(getASTNodeImport(tempVariableName, url)) + }) + + tree.children.unshift( + getASTNodeImport( + '$NextImageNextra', + allowFutureImage ? 'next/future/image' : 'next/image' + ) as any, + ...importsToInject + ) + done() + } diff --git a/packages/nextra/src/mdx-plugins/structurize.js b/packages/nextra/src/mdx-plugins/structurize.js index 168f378fa7..66ef912af7 100644 --- a/packages/nextra/src/mdx-plugins/structurize.js +++ b/packages/nextra/src/mdx-plugins/structurize.js @@ -8,8 +8,10 @@ function cleanup(content) { .join('\n') } -export default (structurizedData, options) => { - if (typeof options === 'boolean') options = {} +export const structurize = (structurizedData, options) => { + if (typeof options === 'boolean') { + options = {} + } options = Object.assign({ codeblocks: true }, options) const slugger = new Slugger() @@ -35,7 +37,9 @@ export default (structurizedData, options) => { /** @type {Type} */ const type = node.type - if (type === 'heading') skip = true + if (type === 'heading') { + skip = true + } if ( ['code', 'table', 'blockquote', 'list', 'mdxJsxFlowElement'].includes( @@ -43,7 +47,9 @@ export default (structurizedData, options) => { ) ) { result += '\n' - if (!skip) content += '\n' + if (!skip) { + content += '\n' + } } if ('children' in node) { @@ -59,7 +65,9 @@ export default (structurizedData, options) => { ].includes(type) ) { result += node.value - if (!skip) content += node.value + if (!skip) { + content += node.value + } } if ( @@ -74,14 +82,20 @@ export default (structurizedData, options) => { ].includes(type) ) { result += '\n' - if (!skip) content += '\n' + if (!skip) { + content += '\n' + } } - if (['tableCell'].includes(type)) { + if (type === 'tableCell') { result += '\t' - if (!skip) content += '\t' + if (!skip) { + content += '\t' + } } - if (type === 'heading') skip = false + if (type === 'heading') { + skip = false + } if (type === 'heading' && node.depth > 1) { structurizedData[activeSlug] = cleanup(content) diff --git a/packages/nextra/src/page-map.ts b/packages/nextra/src/page-map.ts index 7ec51251bf..99bdedfd4d 100644 --- a/packages/nextra/src/page-map.ts +++ b/packages/nextra/src/page-map.ts @@ -1,5 +1,5 @@ +import path from 'node:path' import { FileMap, MdxPath, MetaJsonPath, PageMapItem } from './types' -import path from 'path' import { META_FILENAME } from './constants' import { normalizeMeta, parseFileName } from './utils' import filterRouteLocale from './filter-route-locale' diff --git a/packages/nextra/src/plugin.ts b/packages/nextra/src/plugin.ts index 7b7b14bf8f..31fdd7441d 100644 --- a/packages/nextra/src/plugin.ts +++ b/packages/nextra/src/plugin.ts @@ -9,14 +9,14 @@ import { MetaJsonFile } from './types' import fs from 'graceful-fs' -import { promisify } from 'util' +import { promisify } from 'node:util' import { parseFileName, parseJsonFile, truthy } from './utils' -import path from 'path' +import path from 'node:path' import slash from 'slash' import grayMatter from 'gray-matter' -import { findPagesDir } from 'next/dist/lib/find-pages-dir.js' import { Compiler } from 'webpack' import title from 'title' +import { findPagesDir } from 'next/dist/lib/find-pages-dir.js' import { restoreCache } from './content-dump' import { CWD, MARKDOWN_EXTENSION_REGEX, META_FILENAME } from './constants' @@ -169,7 +169,8 @@ export class NextraPlugin { // Restore the search data from the cache. restoreCache() } - const result = await collectFiles(findPagesDir(CWD).pages, '/') + const PAGES_DIR = findPagesDir(CWD).pages + const result = await collectFiles(PAGES_DIR) pageMapCache.set(result) callback() } diff --git a/packages/nextra/src/types.ts b/packages/nextra/src/types.ts index e930d20373..3e1c5c140e 100644 --- a/packages/nextra/src/types.ts +++ b/packages/nextra/src/types.ts @@ -15,6 +15,7 @@ export interface LoaderOptions extends NextraConfig { defaultLocale: string pageMapCache: PageMapCache newNextLinkBehavior?: boolean + allowFutureImage?: boolean } export interface Folder { diff --git a/packages/nextra/src/utils.ts b/packages/nextra/src/utils.ts index 8be92f3272..48f825a2b0 100644 --- a/packages/nextra/src/utils.ts +++ b/packages/nextra/src/utils.ts @@ -1,4 +1,5 @@ -import path from 'path' +import path from 'node:path' +import fs from 'graceful-fs' import { LOCALE_REGEX } from './constants' import { Meta } from './types' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c1e5fb924..2b1ea46e3a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,6 +146,8 @@ importers: shiki: 0.10.1 slash: ^3.0.0 title: ^3.5.3 + unified: ^10.1.2 + unist-util-visit: ^4.1.1 vitest: ^0.21.0 dependencies: '@mdx-js/mdx': 2.1.3 @@ -160,6 +162,7 @@ importers: shiki: 0.10.1 slash: 3.0.0 title: 3.5.3 + unist-util-visit: 4.1.1 devDependencies: '@types/github-slugger': 1.3.0 '@types/graceful-fs': 4.1.5 @@ -170,6 +173,7 @@ importers: next: 12.2.4_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 + unified: 10.1.2 vitest: 0.21.0 packages/nextra-theme-blog: @@ -632,7 +636,7 @@ packages: unified: 10.1.2 unist-util-position-from-estree: 1.1.1 unist-util-stringify-position: 3.0.2 - unist-util-visit: 4.1.0 + unist-util-visit: 4.1.1 vfile: 5.3.4 transitivePeerDependencies: - supports-color @@ -1541,7 +1545,6 @@ packages: /bail/2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - dev: false /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2723,7 +2726,6 @@ packages: /extend/3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: false /extendable-error/0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -3192,7 +3194,6 @@ packages: /is-buffer/2.0.5: resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} engines: {node: '>=4'} - dev: false /is-callable/1.2.4: resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==} @@ -3279,7 +3280,6 @@ packages: /is-plain-obj/4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - dev: false /is-reference/3.0.0: resolution: {integrity: sha512-Eo1W3wUoHWoCoVM4GVl/a+K0IgiqE5aIo4kJABFyMum1ZORlPkC+UC357sSQUL5w5QCE5kCC9upl75b7+7CY/Q==} @@ -3578,7 +3578,7 @@ packages: dependencies: '@types/mdast': 3.0.10 '@types/unist': 2.0.6 - unist-util-visit: 4.1.0 + unist-util-visit: 4.1.1 dev: false /mdast-util-find-and-replace/2.2.1: @@ -3725,7 +3725,7 @@ packages: unist-builder: 3.0.0 unist-util-generated: 2.0.0 unist-util-position: 4.0.3 - unist-util-visit: 4.1.0 + unist-util-visit: 4.1.1 dev: false /mdast-util-to-markdown/1.3.0: @@ -3736,7 +3736,7 @@ packages: longest-streak: 3.0.1 mdast-util-to-string: 3.1.0 micromark-util-decode-string: 1.0.2 - unist-util-visit: 4.1.0 + unist-util-visit: 4.1.1 zwitch: 2.0.2 dev: false @@ -5835,7 +5835,6 @@ packages: /trough/2.1.0: resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} - dev: false /ts-interface-checker/0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -6098,7 +6097,6 @@ packages: is-plain-obj: 4.1.0 trough: 2.1.0 vfile: 5.3.4 - dev: false /unist-builder/3.0.0: resolution: {integrity: sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==} @@ -6134,14 +6132,13 @@ packages: resolution: {integrity: sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ==} dependencies: '@types/unist': 2.0.6 - unist-util-visit: 4.1.0 + unist-util-visit: 4.1.1 dev: false /unist-util-stringify-position/3.0.2: resolution: {integrity: sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==} dependencies: '@types/unist': 2.0.6 - dev: false /unist-util-visit-parents/3.1.1: resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} @@ -6164,6 +6161,13 @@ packages: unist-util-is: 5.1.1 dev: false + /unist-util-visit-parents/5.1.1: + resolution: {integrity: sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 5.1.1 + dev: false + /unist-util-visit/2.0.3: resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} dependencies: @@ -6180,12 +6184,12 @@ packages: unist-util-visit-parents: 4.1.1 dev: false - /unist-util-visit/4.1.0: - resolution: {integrity: sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ==} + /unist-util-visit/4.1.1: + resolution: {integrity: sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==} dependencies: '@types/unist': 2.0.6 unist-util-is: 5.1.1 - unist-util-visit-parents: 5.1.0 + unist-util-visit-parents: 5.1.1 dev: false /universalify/0.1.2: @@ -6275,7 +6279,6 @@ packages: dependencies: '@types/unist': 2.0.6 unist-util-stringify-position: 3.0.2 - dev: false /vfile/5.3.4: resolution: {integrity: sha512-KI+7cnst03KbEyN1+JE504zF5bJBZa+J+CrevLeyIMq0aPU681I2rQ5p4PlnQ6exFtWiUrg26QUdFMnAKR6PIw==} @@ -6284,7 +6287,6 @@ packages: is-buffer: 2.0.5 unist-util-stringify-position: 3.0.2 vfile-message: 3.1.2 - dev: false /vite/2.9.14: resolution: {integrity: sha512-P/UCjSpSMcE54r4mPak55hWAZPlyfS369svib/gpmz8/01L822lMPOJ/RYW6tLCe1RPvMvOsJ17erf55bKp4Hw==}