Skip to content

Commit c77485e

Browse files
author
Dimitri POSTOLOV
authoredSep 7, 2023
[v3] set default head option as null in nextra-theme-docs and improve bundle size (#2270)

File tree

11 files changed

+105
-100
lines changed

11 files changed

+105
-100
lines changed
 

‎.changeset/fair-balloons-talk.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'nextra-theme-docs': minor
3+
---
4+
5+
set default `head` option as `null`

‎packages/nextra-theme-docs/src/constants.tsx

+1-12
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,7 @@ export const DEFAULT_THEME: DocsThemeConfig = {
9797
</>
9898
)
9999
},
100-
head: (
101-
<>
102-
<meta name="msapplication-TileColor" content="#fff" />
103-
<meta httpEquiv="Content-Language" content="en" />
104-
<meta name="description" content="Nextra: the next docs builder" />
105-
<meta name="twitter:card" content="summary_large_image" />
106-
<meta name="twitter:site" content="@shuding_" />
107-
<meta property="og:title" content="Nextra: the next docs builder" />
108-
<meta property="og:description" content="Nextra: the next docs builder" />
109-
<meta name="apple-mobile-web-app-title" content="Nextra" />
110-
</>
111-
),
100+
head: null,
112101
i18n: [],
113102
logo: (
114103
<>

‎packages/nextra/__test__/loader.test.ts

+18-9
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,26 @@ describe('tree shaking', async () => {
1616
)
1717
const pageChunkFileNames = await fs.readdir(pageChunksDirPath)
1818

19-
describe('_app', () => {
20-
it('ensure zod is removed from production build with /* @__PURE__ */ comments', async () => {
21-
const appFile = await fs.readFile(
22-
path.join(
23-
pageChunksDirPath,
24-
pageChunkFileNames.find(name => name.startsWith('_app-'))!
25-
),
26-
'utf8'
27-
)
19+
describe('_app', async () => {
20+
const appFile = await fs.readFile(
21+
path.join(
22+
pageChunksDirPath,
23+
pageChunkFileNames.find(name => name.startsWith('_app-'))!
24+
),
25+
'utf8'
26+
)
27+
it('ensure `zod` is removed from production build with /* @__PURE__ */ comments', async () => {
2828
expect(appFile.includes('Zod')).toBe(false)
2929
})
30+
it('ensure `title` is removed', () => {
31+
expect(appFile.includes('ZEIT Inc.')).toBe(false)
32+
})
33+
it('ensure nextra logger is removed', () => {
34+
expect(appFile.includes('[nextra]')).toBe(false)
35+
})
36+
it('ensure `slash` is removed', () => {
37+
expect(appFile.includes('\\\\?\\')).toBe(false)
38+
})
3039
})
3140

3241
describe('index page', async () => {

‎packages/nextra/src/context.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,18 @@ function filter(
2929
} {
3030
let activeLevelPages: Page[] = []
3131
const items: Page[] = []
32-
const meta = pageMap.find(/* @__PURE__ */ isMeta)
32+
const meta = pageMap.find(isMeta)
3333
const metaData = meta?.data || {}
3434

3535
for (const item of pageMap) {
36-
if (/* @__PURE__ */ isMeta(item)) continue
37-
const meta = /* @__PURE__ */ normalizeMeta(metaData[item.name])
36+
if (isMeta(item)) continue
37+
const meta = normalizeMeta(metaData[item.name])
3838
const page = {
3939
...item,
4040
...(Object.keys(meta || {}).length > 0 && { meta })
4141
} as Page
4242

43-
if (/* @__PURE__ */ isFolder(page)) {
43+
if (isFolder(page)) {
4444
const filtered = filter(page.children, activeLevel)
4545
page.children = filtered.items
4646
if (filtered.activeLevelPages.length) {

‎packages/nextra/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import {
1111
MARKDOWN_EXTENSIONS
1212
} from './constants'
1313
import { nextraConfigSchema } from './schemas'
14+
import { logger } from './server/utils'
1415
import type { Nextra } from './types'
15-
import { logger } from './utils'
1616
import { NextraPlugin, NextraSearchPlugin } from './webpack-plugins'
1717

1818
const DEFAULT_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx']

‎packages/nextra/src/loader.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import {
1111
} from './constants'
1212
import { PAGES_DIR } from './file-system'
1313
import { collectMdx } from './plugin'
14+
import { logger, pageTitleFromFilename } from './server/utils'
1415
import type { FileMap, LoaderOptions, MdxPath, PageOpts } from './types'
15-
import { isMeta, logger, pageTitleFromFilename } from './utils'
16+
import { isMeta } from './utils'
1617

1718
const initGitRepo = (async () => {
1819
const IS_WEB_CONTAINER = !!process.versions.webcontainer
@@ -266,7 +267,7 @@ ${themeConfigImport && '__nextra_internal__.themeConfig = __themeConfig'}`
266267
finalResult.slice(lastIndexOfFooter + FOOTER_TO_REMOVE.length)
267268
const pageMapPath = path.join(CHUNKS_DIR, `nextra-page-map-${locale}.mjs`)
268269

269-
const rawJs = `import { setupNextraPage } from 'nextra/setup-page'
270+
const rawJs = `import { setupNextraPage, resolvePageMap } from 'nextra/setup-page'
270271
import { pageMap as __nextraPageMap, dynamicMetaModules } from '${pageMapPath}'
271272
${isAppFileFromNodeModules ? cssImports : ''}
272273
${mdxContent}
@@ -277,7 +278,7 @@ const __nextraPageOptions = {
277278
pageOpts: ${stringifiedPageOpts}
278279
}
279280
if (typeof window === 'undefined') {
280-
__nextraPageOptions.dynamicMetaModules = dynamicMetaModules
281+
globalThis.__nextra_resolvePageMap = resolvePageMap(dynamicMetaModules)
281282
}
282283
283284
export default setupNextraPage(__nextraPageOptions)`

‎packages/nextra/src/normalize-pages.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export function normalizePages({
9696
}) {
9797
let _meta: Record<string, any> | undefined
9898
for (const item of list) {
99-
if (/* @__PURE__ */ isMeta(item)) {
99+
if (isMeta(item)) {
100100
_meta = item.data
101101
break
102102
}
@@ -140,7 +140,7 @@ export function normalizePages({
140140
const items = list
141141
.filter(
142142
(a): a is MdxFile | Folder =>
143-
!(/* @__PURE__ */ isMeta(a)) &&
143+
!isMeta(a) &&
144144
// not hidden routes
145145
!a.name.startsWith('_')
146146
)
@@ -259,7 +259,7 @@ export function normalizePages({
259259
}
260260
}
261261
if (
262-
(display === 'hidden' && !(/* @__PURE__ */ isFolder(item))) ||
262+
(display === 'hidden' && !isFolder(item)) ||
263263
ERROR_ROUTES.has(a.route)
264264
) {
265265
continue

‎packages/nextra/src/plugin.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
MARKDOWN_EXTENSION_REGEX,
1010
META_FILENAME
1111
} from './constants'
12+
import { logger, sortPages } from './server/utils'
1213
import type {
1314
FileMap,
1415
Folder,
@@ -22,9 +23,7 @@ import {
2223
isMdxFile,
2324
isMeta,
2425
isSerializable,
25-
logger,
2626
normalizePageRoute,
27-
sortPages,
2827
truthy
2928
} from './utils'
3029

‎packages/nextra/src/server/utils.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import title from 'title'
2+
import type { Folder, MdxFile } from '../types'
3+
4+
export const logger = {
5+
info: console.log.bind(null, '-', '\x1b[36minfo\x1b[0m', '[nextra]'),
6+
warn: console.log.bind(null, '-', '\x1b[33mwarn\x1b[0m', '[nextra]'),
7+
error: console.log.bind(null, '-', '\x1b[31merror\x1b[0m', '[nextra]')
8+
}
9+
10+
export function pageTitleFromFilename(fileName: string) {
11+
return title(fileName.replaceAll(/[-_]/g, ' '))
12+
}
13+
14+
export function sortPages(
15+
pages: (Omit<MdxFile, 'route'> | Omit<Folder, 'route' | 'children'>)[],
16+
locale?: string
17+
): [string, string][] {
18+
return pages
19+
.map(item => ({
20+
name: item.name,
21+
date: 'frontMatter' in item && item.frontMatter?.date,
22+
title:
23+
('frontMatter' in item && item.frontMatter?.title) ||
24+
pageTitleFromFilename(item.name)
25+
}))
26+
.sort((a, b) => {
27+
if (a.date && b.date) {
28+
return new Date(b.date).getTime() - new Date(a.date).getTime()
29+
}
30+
if (a.date) {
31+
return -1 // sort a before b
32+
}
33+
if (b.date) {
34+
return 1 // sort a after b
35+
}
36+
return a.title.localeCompare(b.title, locale || undefined, {
37+
numeric: true
38+
})
39+
})
40+
.map(item => [item.name, item.title])
41+
}

‎packages/nextra/src/setup-page.tsx

+27-26
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useRouter } from 'next/router'
88
import type { FC, ReactElement } from 'react'
99
import { NEXTRA_INTERNAL } from './constants'
1010
import { SSGContext } from './data'
11+
import { pageTitleFromFilename } from './server/utils'
1112
import type {
1213
DynamicFolder,
1314
DynamicMeta,
@@ -19,7 +20,7 @@ import type {
1920
PageMapItem,
2021
PageOpts
2122
} from './types'
22-
import { normalizePageRoute, pageTitleFromFilename } from './utils'
23+
import { normalizePageRoute } from './utils'
2324

2425
function isFolder(value: DynamicMetaItem): value is DynamicFolder {
2526
return !!value && typeof value === 'object' && value.type === 'folder'
@@ -32,10 +33,10 @@ function normalizeMetaData(obj: DynamicMeta): DynamicMeta {
3233
const keyWithoutSlash = key.replace('/', '')
3334
return [
3435
keyWithoutSlash,
35-
value.title || /* @__PURE__ */ pageTitleFromFilename(keyWithoutSlash)
36+
value.title || pageTitleFromFilename(keyWithoutSlash)
3637
]
3738
}
38-
return [key, value || /* @__PURE__ */ pageTitleFromFilename(key)]
39+
return [key, value || pageTitleFromFilename(key)]
3940
})
4041
)
4142
}
@@ -57,7 +58,7 @@ export function collectCatchAllRoutes(
5758
}
5859
parent.children.push({
5960
name: key,
60-
route: /* @__PURE__ */ normalizePageRoute(parent.route, key)
61+
route: normalizePageRoute(parent.route, key)
6162
})
6263
continue
6364
}
@@ -75,37 +76,37 @@ export function collectCatchAllRoutes(
7576

7677
let cachedResolvedPageMap: PageMapItem[]
7778

79+
export const resolvePageMap =
80+
(dynamicMetaModules: [() => any, DynamicMetaDescriptor][]) => async () => {
81+
const __nextra_internal__ = (globalThis as NextraInternalGlobal)[
82+
NEXTRA_INTERNAL
83+
]
84+
if (process.env.NODE_ENV === 'production' && cachedResolvedPageMap) {
85+
return cachedResolvedPageMap
86+
}
87+
const clonedPageMap = structuredClone(__nextra_internal__.pageMap)
88+
for (const [
89+
metaFunction,
90+
{ metaObjectKeyPath, metaParentKeyPath }
91+
] of dynamicMetaModules) {
92+
const metaData = await metaFunction()
93+
const meta: DynamicMetaJsonFile = get(clonedPageMap, metaObjectKeyPath)
94+
meta.data = metaData
95+
const parent: Folder = get(clonedPageMap, metaParentKeyPath)
96+
collectCatchAllRoutes(parent, meta)
97+
}
98+
return (cachedResolvedPageMap = clonedPageMap)
99+
}
100+
78101
export function setupNextraPage({
79102
pageOpts,
80103
MDXContent,
81-
dynamicMetaModules = [],
82104
route
83105
}: {
84106
pageOpts: PageOpts
85107
MDXContent: FC
86-
dynamicMetaModules?: [() => any, DynamicMetaDescriptor][]
87108
route: string
88109
}) {
89-
if (typeof window === 'undefined') {
90-
globalThis.__nextra_resolvePageMap = async () => {
91-
if (process.env.NODE_ENV === 'production' && cachedResolvedPageMap) {
92-
return cachedResolvedPageMap
93-
}
94-
const clonedPageMap = structuredClone(__nextra_internal__.pageMap)
95-
for (const [
96-
metaFunction,
97-
{ metaObjectKeyPath, metaParentKeyPath }
98-
] of dynamicMetaModules) {
99-
const metaData = await metaFunction()
100-
const meta: DynamicMetaJsonFile = get(clonedPageMap, metaObjectKeyPath)
101-
meta.data = metaData
102-
const parent: Folder = get(clonedPageMap, metaParentKeyPath)
103-
collectCatchAllRoutes(parent, meta)
104-
}
105-
return (cachedResolvedPageMap = clonedPageMap)
106-
}
107-
}
108-
109110
// Make sure the same component is always returned so Next.js will render the
110111
// stable layout. We then put the actual content into a global store and use
111112
// the route to identify it.

‎packages/nextra/src/utils.ts

-40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import path from 'node:path'
22
import slash from 'slash'
3-
import title from 'title'
43
import type { Folder, MdxFile, Meta, MetaJsonFile, PageMapItem } from './types'
54

65
type Truthy<T> = T extends false | '' | 0 | null | undefined ? never : T // from lodash
@@ -17,39 +16,6 @@ export function normalizePageRoute(parentRoute: string, route: string): string {
1716
return slash(path.join(parentRoute, route.replace(/^index$/, '')))
1817
}
1918

20-
export function pageTitleFromFilename(fileName: string) {
21-
return title(fileName.replaceAll(/[-_]/g, ' '))
22-
}
23-
24-
export function sortPages(
25-
pages: (Omit<MdxFile, 'route'> | Omit<Folder, 'route' | 'children'>)[],
26-
locale?: string
27-
): [string, string][] {
28-
return pages
29-
.map(item => ({
30-
name: item.name,
31-
date: 'frontMatter' in item && item.frontMatter?.date,
32-
title:
33-
('frontMatter' in item && item.frontMatter?.title) ||
34-
pageTitleFromFilename(item.name)
35-
}))
36-
.sort((a, b) => {
37-
if (a.date && b.date) {
38-
return new Date(b.date).getTime() - new Date(a.date).getTime()
39-
}
40-
if (a.date) {
41-
return -1 // sort a before b
42-
}
43-
if (b.date) {
44-
return 1 // sort a after b
45-
}
46-
return a.title.localeCompare(b.title, locale || undefined, {
47-
numeric: true
48-
})
49-
})
50-
.map(item => [item.name, item.title])
51-
}
52-
5319
export function isSerializable(o: any): boolean {
5420
try {
5521
JSON.stringify(o)
@@ -63,12 +29,6 @@ export function getDefault<T>(module: T & { default?: T }): T {
6329
return module.default || module
6430
}
6531

66-
export const logger = {
67-
info: console.log.bind(null, '-', '\x1b[36minfo\x1b[0m', '[nextra]'),
68-
warn: console.log.bind(null, '-', '\x1b[33mwarn\x1b[0m', '[nextra]'),
69-
error: console.log.bind(null, '-', '\x1b[31merror\x1b[0m', '[nextra]')
70-
}
71-
7232
export function isMeta(item: PageMapItem): item is MetaJsonFile {
7333
return 'data' in item
7434
}

0 commit comments

Comments
 (0)
Please sign in to comment.