-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
index.ts
160 lines (136 loc) · 5.92 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import webpack from 'webpack'
import { NextConfig } from 'next'
import { PHASE_DEVELOPMENT_SERVER } from 'next/constants'
import { resolve } from 'node:path'
import createMdxPlugin from '@next/mdx'
import type { bundledThemes } from 'shiki/bundle/web'
import { getMdxPlugins } from '../mdx-plugins'
import { renumberFilenames } from '../utils/renumber'
import { createRefreshServer } from './create-refresh-server'
type PluginOptions = {
/** Path to the VS Code compatible theme used for syntax highlighting the `CodeBlock`, `CodeInline`, and `Tokens` components. */
theme: keyof typeof bundledThemes | (string & {})
/** The URL of the production site. This is used for generating sitemap and RSS feed URLs. If using Vercel, the `VERCEL_PROJECT_PRODUCTION_URL` [environment variable](https://vercel.com/docs/projects/environment-variables/system-environment-variables) will be used by default. */
siteUrl?: string
/** The git source to use for linking to the repository and source files. This is automatically inferred from the git remote URL or [Vercel environment variables](https://vercel.com/docs/projects/environment-variables/system-environment-variables) if not provided. */
gitSource?: string
/** The branch to use for linking to the repository and source files. */
gitBranch?: string
/** Whether or not to renumber ordered filenames (e.g. 01.getting-started) when adding/removing/modifying MDX files. This only occurs while the development server is running. */
renumberFilenames?: boolean
/** Whether or not to add rich highlighted errors in the console when type-checking source code in `CodeBlock`. Note, this may affect framework error boundaries that don't understand color encoding. */
highlightErrors?: boolean
}
/** A Next.js plugin to configure MDXTS theming, `rehype` and `remark` markdown plugins, and the [Webpack loader](mdxts.dev/packages/loader). */
export function createMdxtsPlugin(pluginOptions: PluginOptions) {
let refreshServerPort: string | null = null
let {
gitSource = getVercelGitSource() ?? '',
gitBranch = 'main',
siteUrl = process.env.VERCEL_PROJECT_PRODUCTION_URL,
theme,
renumberFilenames: renumberFilenamesOption = true,
highlightErrors,
} = pluginOptions
const themePath = theme.endsWith('.json')
? resolve(process.cwd(), theme)
: theme
return function withMdxts(nextConfig: NextConfig = {}) {
const getWebpackConfig = nextConfig.webpack
let startedRenumberFilenameWatcher = false
return async (phase: typeof PHASE_DEVELOPMENT_SERVER) => {
const plugins = await getMdxPlugins({ gitSource, gitBranch })
const withMdx = createMdxPlugin({
options: plugins,
extension: /\.(md|mdx)$/,
})
nextConfig.webpack = (config, options) => {
// add default mdx components before @mdx-js/react
config.resolve.alias['next-mdx-import-source-file'].splice(
-1,
0,
resolve(__dirname, '../../src/components/MDXComponents.js')
)
config.plugins.push(
// silence ts-morph and jju warnings
new webpack.ContextReplacementPlugin(
/\/(@ts-morph\/common|jju)\//,
(data: { dependencies: Array<{ critical?: boolean }> }) => {
for (const dependency of data.dependencies) {
delete dependency.critical
}
return data
}
),
new webpack.IgnorePlugin({
resourceRegExp: /^perf_hooks$/,
})
)
if (
!startedRenumberFilenameWatcher &&
renumberFilenamesOption &&
options.isServer &&
options.dev
) {
renumberFilenames()
startedRenumberFilenameWatcher = true
}
config.module.rules.push({
test: /\.(?:jsx?|tsx?)$/,
exclude: /node_modules/,
use: [{ loader: 'mdxts/loader', options: { gitSource, gitBranch } }],
})
if (typeof getWebpackConfig === 'function') {
return getWebpackConfig(config, options)
}
return config
}
if (nextConfig.env === undefined) {
nextConfig.env = {}
}
nextConfig.env.MDXTS_GIT_SOURCE = gitSource ?? ''
nextConfig.env.MDXTS_GIT_BRANCH = gitBranch
nextConfig.env.MDXTS_SITE_URL = siteUrl
nextConfig.env.MDXTS_THEME_PATH = themePath
nextConfig.env.MDXTS_HIGHLIGHT_ERRORS = String(highlightErrors)
if (phase === PHASE_DEVELOPMENT_SERVER) {
if (refreshServerPort === null) {
const server = await createRefreshServer()
const address = server.address()
if (address === null || typeof address === 'string') {
throw new Error('Expected server to be listening')
}
refreshServerPort = String(address.port)
}
nextConfig.env.MDXTS_REFRESH_PORT = refreshServerPort
}
if (nextConfig.pageExtensions === undefined) {
nextConfig.pageExtensions = ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx']
}
nextConfig.experimental = {
...nextConfig.experimental,
serverComponentsExternalPackages: [
...(nextConfig.experimental?.serverComponentsExternalPackages ?? []),
'ts-morph',
],
}
return withMdx(nextConfig)
}
}
}
const VERCEL_GIT_PROVIDER = process.env.VERCEL_GIT_PROVIDER
const VERCEL_GIT_REPO_SLUG = process.env.VERCEL_GIT_REPO_SLUG
const VERCEL_GIT_REPO_OWNER = process.env.VERCEL_GIT_REPO_OWNER
/** Constructs a URL for a repository based on the provider. */
function getVercelGitSource(): string | null {
switch (VERCEL_GIT_PROVIDER?.toLowerCase()) {
case 'github':
return `https://github.com/${VERCEL_GIT_REPO_OWNER}/${VERCEL_GIT_REPO_SLUG}`
case 'gitlab':
return `https://gitlab.com/${VERCEL_GIT_REPO_OWNER}/${VERCEL_GIT_REPO_SLUG}`
case 'bitbucket':
return `https://bitbucket.org/${VERCEL_GIT_REPO_OWNER}/${VERCEL_GIT_REPO_SLUG}`
default:
return null
}
}