original text :https://gauliang.github.io/blogs/2022/watch-markdown-files-and-hot-load-the-nextjs-page/
Next.js Provides Fast-Refresh Ability , It can help you to React The edits made by the component provide immediate feedback .
however , When you pass Markdown File provides website content , because Markdown No React Components , Hot update will fail .
How do you do it?
This problem can be solved from the following aspects :
- How the server monitors file updates
- How the server notifies the browser
- How the browser updates the page
- How to get the latest Markdown Content
- How to communicate with Next.js Start up with the development server
Monitoring file updates
Appointment : markdown The documents are stored in Next.js In the root directory of the project
_contents/in
adopt node:fs.watch Module recursive monitoring _contents Catalog , When the document changes , Trigger listener perform .
New file scripts/watch.js monitor _contents Catalog .
const { watch } = require('node:fs');
function main(){
watch(process.cwd() + '/_contents', { recursive: true }, (eventType, filename) => {
console.log(eventType, filename)
});
}
Notification browser
Server through WebSocket Connect to the browser , When the development server finds that the file changes , adopt WS Notify the browser to update the page .
The browser needs to know whether the updated file is related to the route of the current page , therefore , The message sent by the server to the browser should at least contain the current
Update the page route corresponding to the file .
WebSocket
ws It's easy to use 、 Extremely fast and fully tested WebSocket Client and server implementation . adopt ws start-up WebSocket The server .
const { watch } = require('node:fs');
const { WebSocketServer } = require('ws')
function main() {
const wss = new WebSocketServer({ port: 80 })
wss.on('connection', (ws, req) => {
watch(process.cwd() + '/_contents', { recursive: true }, (eventType, filename) => {
const path = filename.replace(/\.md/, '/')
ws.send(JSON.stringify({ event: 'markdown-changed', path }))
})
})
}
The browser connects to the server
Create a new one HotLoad Components , Be responsible for listening for messages from the server , And hot page updates . The components meet the following requirements :
- Maintain a singleton pattern with WebSocekt Server The connection of
- After listening to the server message , Determine whether the current page route is related to the changed file , Ignore if irrelevant
- Server side messages may be sent intensively , You need to do anti shake processing when loading new version content
- load Markdown File and complete the update
- This component is only available in
Development modeWork under the
import { useRouter } from "next/router"
import { useEffect } from "react"
interface Instance {
ws: WebSocket
timer: any
}
let instance: Instance = {
ws: null as any,
timer: null as any
}
function getInstance() {
if (instance.ws === null) {
instance.ws = new WebSocket('ws://localhost')
}
return instance
}
function _HotLoad({ setPost, params }: any) {
const { asPath } = useRouter()
useEffect(() => {
const instance = getInstance()
instance.ws.onmessage = async (res: any) => {
const data = JSON.parse(res.data)
if (data.event === 'markdown-changed') {
if (data.path === asPath) {
const post = await getPreviewData(params)
setPost(post)
}
}
}
return () => {
instance.ws.CONNECTING && instance.ws.close(4001, asPath)
}
}, [])
return null
}
export function getPreviewData(params: {id:string[]}) {
if (instance.timer) {
clearTimeout(instance.timer)
}
return new Promise((resolve) => {
instance.timer = setTimeout(async () => {
const res = await fetch('http://localhost:3000/api/preview/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
})
resolve(res.json())
}, 200)
})
}
let core = ({ setPost, params }: any)=>null
if(process.env.NODE_ENV === 'development'){
console.log('development hot load');
core = _HotLoad
}
export const HotLoad = core
Data preview API
Create data preview API, Read Markdown The contents of the document , And compile it into the format used for page rendering . The results here
Should and [...id].tsx On the page getStaticProps() Method returns a page with exactly the same data structure , relevant
Logic can be reused directly .
newly build API file pages/api/preview.ts,
import type { NextApiRequest, NextApiResponse } from 'next'
import { getPostData } from '../../lib/posts'
type Data = {
name: string
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
if (process.env.NODE_ENV === 'development') {
const params = req.body
const post = await getPostData(['posts', ...params.id])
return res.status(200).json(post)
} else {
return res.status(200)
}
}
Update page
page pages/[...id].tsx Introduction in HotLoad Components , And transmission setPostData() And params to HotLoad Components .
...
import { HotLoad } from '../../components/hot-load'
const Post = ({ params, post, prev, next }: Params) => {
const [postData, setPostData] = useState(post)
useEffect(()=>{
setPostData(post)
},[post])
return (
<Layout>
<Head>
<title>{postData.title} - Gauliang</title>
</Head>
<PostContent post={postData} prev={prev} next={next} />
<BackToTop />
<HotLoad setPost={setPostData} params={params} />
</Layout>
)
}
export async function getStaticProps({ params }: Params) {
return {
props: {
params,
post:await getPostData(['posts', ...params.id])
}
}
}
export async function getStaticPaths() {
const paths = getAllPostIdByType()
return {
paths,
fallback: false
}
}
export default Post
The startup script
to update package.json Of dev Script :
"scripts": {
"dev": "node scripts/watch.js & \n next dev"
},
summary
Above , Overall overview of the general implementation logic . When the specific project is implemented , There are some details to consider ,
Such as : When updating a file, you want to prompt for a different file name on the command line 、 Adjust the matching logic between file and route according to personalized route information .
Next.js Original blog version :https://gauliang.github.io/blogs/2022/watch-markdown-files-and-hot-load-the-nextjs-page/

![[postgraduate entrance examination English] prepare for 2023, learn list8 words](/img/25/d1f2c2b4c0958d381db87e5ef96df9.jpg)






