From de30ad9162b74f23bb416d252e63c9ada1f2e8c2 Mon Sep 17 00:00:00 2001 From: olayway Date: Wed, 10 May 2023 19:28:15 +0200 Subject: [PATCH] [site/content/notes][xs]: note on md hot reload. --- site/content/notes/md-hot-reload.md | 94 +++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 site/content/notes/md-hot-reload.md diff --git a/site/content/notes/md-hot-reload.md b/site/content/notes/md-hot-reload.md new file mode 100644 index 000000000..457dd3a68 --- /dev/null +++ b/site/content/notes/md-hot-reload.md @@ -0,0 +1,94 @@ +# How it isimplemented in contentlayer + +## next-contentlayer + +packages/next-contentlayer/src/index.ts +```js +import { type NextPluginOptions, runBeforeWebpackCompile } from './plugin.js' + +export const defaultPluginOptions: NextPluginOptions = {} + + +export const createContentlayerPlugin = + (pluginOptions: NextPluginOptions = defaultPluginOptions) => + (nextConfig: Partial = {}): Partial => { + return { + ...nextConfig, + // ... + webpack(config: webpack.Configuration, options: any) { + config.watchOptions = { + ...config.watchOptions, + ignored: ['**/node_modules/!(.contentlayer)/**/*'], + } + + config.plugins!.push(new ContentlayerWebpackPlugin(pluginOptions)) + + // ... + return config + }, + } + } + +// This is what we used to import and use in next.config.js +export const withContentlayer = createContentlayerPlugin(defaultPluginOptions) + +class ContentlayerWebpackPlugin { + constructor(readonly pluginOptions: NextPluginOptions) {} + + apply(compiler: webpack.Compiler) { + compiler.hooks.beforeCompile.tapPromise('ContentlayerWebpackPlugin', async () => { + await runBeforeWebpackCompile({ + pluginOptions: this.pluginOptions, + devServerStartedRef, + // this will be `development` when running `next dev` + mode: compiler.options.mode, + }) + }) + } +} +``` + +packages/next-contentlayer/src/plugin.ts +```js +export const runBeforeWebpackCompile = async ({ + mode, + pluginOptions, + devServerStartedRef, +}: { + mode: WebpackOptionsNormalized['mode'] + pluginOptions: NextPluginOptions + devServerStartedRef: { current: boolean } +}) => { + const isNextDev = mode === 'development' + const isBuild = mode === 'production' + + const { configPath } = pluginOptions + + if (isBuild) { + checkConstraints() + await runContentlayerBuild({ configPath }) + } else if (isNextDev && !devServerStartedRef.current) { + devServerStartedRef.current = true + runContentlayerDev({ configPath }) + } +} + +const runContentlayerDev = async ({ configPath }: NextPluginOptions) => { + if (contentlayerInitialized) return + contentlayerInitialized = true + + await pipe( + core.getConfigWatch({ configPath }), + S.tapSkipFirstRight(() => T.log(`Contentlayer config change detected. Updating type definitions and data...`)), + S.tapRight((config) => (config.source.options.disableImportAliasWarning ? T.unit : T.fork(core.validateTsconfig))), + S.chainSwitchMapEitherRight((config) => core.generateDotpkgStream({ config, verbose: false, isDev: true })), + S.tap(E.fold((error) => T.log(errorToString(error)), core.logGenerateInfo)), + S.runDrain, + runMain, + ) +} + +const runMain = core.runMain({ tracingServiceName: 'next-contentlayer', verbose: process.env.CL_DEBUG !== undefined }) + +``` +