Skip to content

Commit

Permalink
[v3] set default head option as null in nextra-theme-docs and i…
Browse files Browse the repository at this point in the history
…mprove bundle size (#2270)
  • Loading branch information
Dimitri POSTOLOV authored Sep 7, 2023
1 parent b9f88e3 commit c77485e
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 100 deletions.
5 changes: 5 additions & 0 deletions .changeset/fair-balloons-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'nextra-theme-docs': minor
---

set default `head` option as `null`
13 changes: 1 addition & 12 deletions packages/nextra-theme-docs/src/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,7 @@ export const DEFAULT_THEME: DocsThemeConfig = {
</>
)
},
head: (
<>
<meta name="msapplication-TileColor" content="#fff" />
<meta httpEquiv="Content-Language" content="en" />
<meta name="description" content="Nextra: the next docs builder" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@shuding_" />
<meta property="og:title" content="Nextra: the next docs builder" />
<meta property="og:description" content="Nextra: the next docs builder" />
<meta name="apple-mobile-web-app-title" content="Nextra" />
</>
),
head: null,
i18n: [],
logo: (
<>
Expand Down
27 changes: 18 additions & 9 deletions packages/nextra/__test__/loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,26 @@ describe('tree shaking', async () => {
)
const pageChunkFileNames = await fs.readdir(pageChunksDirPath)

describe('_app', () => {
it('ensure zod is removed from production build with /* @__PURE__ */ comments', async () => {
const appFile = await fs.readFile(
path.join(
pageChunksDirPath,
pageChunkFileNames.find(name => name.startsWith('_app-'))!
),
'utf8'
)
describe('_app', async () => {
const appFile = await fs.readFile(
path.join(
pageChunksDirPath,
pageChunkFileNames.find(name => name.startsWith('_app-'))!
),
'utf8'
)
it('ensure `zod` is removed from production build with /* @__PURE__ */ comments', async () => {
expect(appFile.includes('Zod')).toBe(false)
})
it('ensure `title` is removed', () => {
expect(appFile.includes('ZEIT Inc.')).toBe(false)
})
it('ensure nextra logger is removed', () => {
expect(appFile.includes('[nextra]')).toBe(false)
})
it('ensure `slash` is removed', () => {
expect(appFile.includes('\\\\?\\')).toBe(false)
})
})

describe('index page', async () => {
Expand Down
8 changes: 4 additions & 4 deletions packages/nextra/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ function filter(
} {
let activeLevelPages: Page[] = []
const items: Page[] = []
const meta = pageMap.find(/* @__PURE__ */ isMeta)
const meta = pageMap.find(isMeta)
const metaData = meta?.data || {}

for (const item of pageMap) {
if (/* @__PURE__ */ isMeta(item)) continue
const meta = /* @__PURE__ */ normalizeMeta(metaData[item.name])
if (isMeta(item)) continue
const meta = normalizeMeta(metaData[item.name])
const page = {
...item,
...(Object.keys(meta || {}).length > 0 && { meta })
} as Page

if (/* @__PURE__ */ isFolder(page)) {
if (isFolder(page)) {
const filtered = filter(page.children, activeLevel)
page.children = filtered.items
if (filtered.activeLevelPages.length) {
Expand Down
2 changes: 1 addition & 1 deletion packages/nextra/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
MARKDOWN_EXTENSIONS
} from './constants'
import { nextraConfigSchema } from './schemas'
import { logger } from './server/utils'
import type { Nextra } from './types'
import { logger } from './utils'
import { NextraPlugin, NextraSearchPlugin } from './webpack-plugins'

const DEFAULT_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx']
Expand Down
7 changes: 4 additions & 3 deletions packages/nextra/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import {
} from './constants'
import { PAGES_DIR } from './file-system'
import { collectMdx } from './plugin'
import { logger, pageTitleFromFilename } from './server/utils'
import type { FileMap, LoaderOptions, MdxPath, PageOpts } from './types'
import { isMeta, logger, pageTitleFromFilename } from './utils'
import { isMeta } from './utils'

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

const rawJs = `import { setupNextraPage } from 'nextra/setup-page'
const rawJs = `import { setupNextraPage, resolvePageMap } from 'nextra/setup-page'
import { pageMap as __nextraPageMap, dynamicMetaModules } from '${pageMapPath}'
${isAppFileFromNodeModules ? cssImports : ''}
${mdxContent}
Expand All @@ -277,7 +278,7 @@ const __nextraPageOptions = {
pageOpts: ${stringifiedPageOpts}
}
if (typeof window === 'undefined') {
__nextraPageOptions.dynamicMetaModules = dynamicMetaModules
globalThis.__nextra_resolvePageMap = resolvePageMap(dynamicMetaModules)
}
export default setupNextraPage(__nextraPageOptions)`
Expand Down
6 changes: 3 additions & 3 deletions packages/nextra/src/normalize-pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export function normalizePages({
}) {
let _meta: Record<string, any> | undefined
for (const item of list) {
if (/* @__PURE__ */ isMeta(item)) {
if (isMeta(item)) {
_meta = item.data
break
}
Expand Down Expand Up @@ -140,7 +140,7 @@ export function normalizePages({
const items = list
.filter(
(a): a is MdxFile | Folder =>
!(/* @__PURE__ */ isMeta(a)) &&
!isMeta(a) &&
// not hidden routes
!a.name.startsWith('_')
)
Expand Down Expand Up @@ -259,7 +259,7 @@ export function normalizePages({
}
}
if (
(display === 'hidden' && !(/* @__PURE__ */ isFolder(item))) ||
(display === 'hidden' && !isFolder(item)) ||
ERROR_ROUTES.has(a.route)
) {
continue
Expand Down
3 changes: 1 addition & 2 deletions packages/nextra/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
MARKDOWN_EXTENSION_REGEX,
META_FILENAME
} from './constants'
import { logger, sortPages } from './server/utils'
import type {
FileMap,
Folder,
Expand All @@ -22,9 +23,7 @@ import {
isMdxFile,
isMeta,
isSerializable,
logger,
normalizePageRoute,
sortPages,
truthy
} from './utils'

Expand Down
41 changes: 41 additions & 0 deletions packages/nextra/src/server/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import title from 'title'
import type { Folder, MdxFile } from '../types'

export const logger = {
info: console.log.bind(null, '-', '\x1b[36minfo\x1b[0m', '[nextra]'),
warn: console.log.bind(null, '-', '\x1b[33mwarn\x1b[0m', '[nextra]'),
error: console.log.bind(null, '-', '\x1b[31merror\x1b[0m', '[nextra]')
}

export function pageTitleFromFilename(fileName: string) {
return title(fileName.replaceAll(/[-_]/g, ' '))
}

export function sortPages(
pages: (Omit<MdxFile, 'route'> | Omit<Folder, 'route' | 'children'>)[],
locale?: string
): [string, string][] {
return pages
.map(item => ({
name: item.name,
date: 'frontMatter' in item && item.frontMatter?.date,
title:
('frontMatter' in item && item.frontMatter?.title) ||
pageTitleFromFilename(item.name)
}))
.sort((a, b) => {
if (a.date && b.date) {
return new Date(b.date).getTime() - new Date(a.date).getTime()
}
if (a.date) {
return -1 // sort a before b
}
if (b.date) {
return 1 // sort a after b
}
return a.title.localeCompare(b.title, locale || undefined, {
numeric: true
})
})
.map(item => [item.name, item.title])
}
53 changes: 27 additions & 26 deletions packages/nextra/src/setup-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useRouter } from 'next/router'
import type { FC, ReactElement } from 'react'
import { NEXTRA_INTERNAL } from './constants'
import { SSGContext } from './data'
import { pageTitleFromFilename } from './server/utils'
import type {
DynamicFolder,
DynamicMeta,
Expand All @@ -19,7 +20,7 @@ import type {
PageMapItem,
PageOpts
} from './types'
import { normalizePageRoute, pageTitleFromFilename } from './utils'
import { normalizePageRoute } from './utils'

function isFolder(value: DynamicMetaItem): value is DynamicFolder {
return !!value && typeof value === 'object' && value.type === 'folder'
Expand All @@ -32,10 +33,10 @@ function normalizeMetaData(obj: DynamicMeta): DynamicMeta {
const keyWithoutSlash = key.replace('/', '')
return [
keyWithoutSlash,
value.title || /* @__PURE__ */ pageTitleFromFilename(keyWithoutSlash)
value.title || pageTitleFromFilename(keyWithoutSlash)
]
}
return [key, value || /* @__PURE__ */ pageTitleFromFilename(key)]
return [key, value || pageTitleFromFilename(key)]
})
)
}
Expand All @@ -57,7 +58,7 @@ export function collectCatchAllRoutes(
}
parent.children.push({
name: key,
route: /* @__PURE__ */ normalizePageRoute(parent.route, key)
route: normalizePageRoute(parent.route, key)
})
continue
}
Expand All @@ -75,37 +76,37 @@ export function collectCatchAllRoutes(

let cachedResolvedPageMap: PageMapItem[]

export const resolvePageMap =
(dynamicMetaModules: [() => any, DynamicMetaDescriptor][]) => async () => {
const __nextra_internal__ = (globalThis as NextraInternalGlobal)[
NEXTRA_INTERNAL
]
if (process.env.NODE_ENV === 'production' && cachedResolvedPageMap) {
return cachedResolvedPageMap
}
const clonedPageMap = structuredClone(__nextra_internal__.pageMap)
for (const [
metaFunction,
{ metaObjectKeyPath, metaParentKeyPath }
] of dynamicMetaModules) {
const metaData = await metaFunction()
const meta: DynamicMetaJsonFile = get(clonedPageMap, metaObjectKeyPath)
meta.data = metaData
const parent: Folder = get(clonedPageMap, metaParentKeyPath)
collectCatchAllRoutes(parent, meta)
}
return (cachedResolvedPageMap = clonedPageMap)
}

export function setupNextraPage({
pageOpts,
MDXContent,
dynamicMetaModules = [],
route
}: {
pageOpts: PageOpts
MDXContent: FC
dynamicMetaModules?: [() => any, DynamicMetaDescriptor][]
route: string
}) {
if (typeof window === 'undefined') {
globalThis.__nextra_resolvePageMap = async () => {
if (process.env.NODE_ENV === 'production' && cachedResolvedPageMap) {
return cachedResolvedPageMap
}
const clonedPageMap = structuredClone(__nextra_internal__.pageMap)
for (const [
metaFunction,
{ metaObjectKeyPath, metaParentKeyPath }
] of dynamicMetaModules) {
const metaData = await metaFunction()
const meta: DynamicMetaJsonFile = get(clonedPageMap, metaObjectKeyPath)
meta.data = metaData
const parent: Folder = get(clonedPageMap, metaParentKeyPath)
collectCatchAllRoutes(parent, meta)
}
return (cachedResolvedPageMap = clonedPageMap)
}
}

// Make sure the same component is always returned so Next.js will render the
// stable layout. We then put the actual content into a global store and use
// the route to identify it.
Expand Down
40 changes: 0 additions & 40 deletions packages/nextra/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import path from 'node:path'
import slash from 'slash'
import title from 'title'
import type { Folder, MdxFile, Meta, MetaJsonFile, PageMapItem } from './types'

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

export function pageTitleFromFilename(fileName: string) {
return title(fileName.replaceAll(/[-_]/g, ' '))
}

export function sortPages(
pages: (Omit<MdxFile, 'route'> | Omit<Folder, 'route' | 'children'>)[],
locale?: string
): [string, string][] {
return pages
.map(item => ({
name: item.name,
date: 'frontMatter' in item && item.frontMatter?.date,
title:
('frontMatter' in item && item.frontMatter?.title) ||
pageTitleFromFilename(item.name)
}))
.sort((a, b) => {
if (a.date && b.date) {
return new Date(b.date).getTime() - new Date(a.date).getTime()
}
if (a.date) {
return -1 // sort a before b
}
if (b.date) {
return 1 // sort a after b
}
return a.title.localeCompare(b.title, locale || undefined, {
numeric: true
})
})
.map(item => [item.name, item.title])
}

export function isSerializable(o: any): boolean {
try {
JSON.stringify(o)
Expand All @@ -63,12 +29,6 @@ export function getDefault<T>(module: T & { default?: T }): T {
return module.default || module
}

export const logger = {
info: console.log.bind(null, '-', '\x1b[36minfo\x1b[0m', '[nextra]'),
warn: console.log.bind(null, '-', '\x1b[33mwarn\x1b[0m', '[nextra]'),
error: console.log.bind(null, '-', '\x1b[31merror\x1b[0m', '[nextra]')
}

export function isMeta(item: PageMapItem): item is MetaJsonFile {
return 'data' in item
}
Expand Down

0 comments on commit c77485e

Please sign in to comment.