#typescript #caching #next.js
Вопрос:
Я хочу создать простой статический сайт блога, и когда я экспортирую свои страницы, все происходит хорошо и быстро.
Но в режиме разработки мое создание сообщений происходит медленно, и я хочу кэшировать их, чтобы это было сделано только один раз. Это делается в post.ts
файле, и мой кэш есть const posts: Post[] = []
.
Я ожидаю , что после ввода yarn dev
post.ts
файл будет загружен один раз, и я смогу заполнить и повторно использовать свой кэшированный массив записей, но, как ни странно, этот модуль ts загружается много раз.
import fs from 'fs'
import path from 'path'
// ...
console.log('????? reloading page')
const posts: Post[] = [] // cached posts, hope to generate once
let postsGenerated = false
export async function getSortedPostsData(): Promise<Post[]> {
// Get file names under /posts
const pendings: Promise<any>[] = []
if (postsGenerated) {
console.log(' Using cache ')
return sortPostsByDate(posts)
} else {
console.log('==== Calculating all')
postsGenerated = true
}
let i = 0
traverseDir('content/blog', (path) => {
if (path.includes('.md')) { ... })
}
await Promise.all(pendings)
return sortPostsByDate(posts)
}
В результате иногда используется кэш, иногда нет. Даже при перезагрузке одной и той же страницы кэш не всегда вызывается. Почему? И как это улучшить ?
Комментарии:
1. Не могли бы вы привести минимальный воспроизводимый пример для дальнейшей отладки этого поведения?
Ответ №1:
Вероятно, именно так работает быстрое обновление. Вы не можете быть уверены, что сервер не перезагрузит .ts
файл после запуска разработки. Не уверен, насколько это улучшит, но вы можете попробовать использовать файл в качестве кэша вместо пустой константы, чтобы сохранять проанализированные данные при перезагрузке.
const devPostsCache = 'devPostsCache.json';
export async function getSortedPostsData(): Promise<Post[]> {
// Get file names under /posts
const pendings: Promise<any>[] = []
const postGenerated = fs.existsSync(devPostsCache);
if (postsGenerated) {
const posts = JSON.parse(fs.readFileSync(devPostsCache));
return sortPostsByDate(posts)
} else {
console.log('==== Calculating all')
postsGenerated = true
}
let i = 0
traverseDir('content/blog', (path) => {
if (path.includes('.md')) { ... })
}
// not sure what pending promises exactly do
// I'll assume you get an array of post
const parsedPosts = await Promise.all(pendings);
fs.writeFileSync(devPostsCache, JSON.stringify(parsedPosts));
return sortPostsByDate(posts)
}
и удаляйте его каждый раз, когда вы начинаете разработку со predev
скрипта
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"predev": "rm devPostsCache.json"
},
Обновить
Другой подход, который я нашел, чтобы избежать слишком частой перекомпиляции кода, — это изменение конфигурации onDemandEntries.
module.exports = {
onDemandEntries: {
// period (in ms) where the server will keep pages in the buffer
maxInactiveAge: 360 * 1000,
// number of pages that should be kept simultaneously without being disposed
pagesBufferLength: 10,
},
}
По умолчанию используется 60 * 1000
значение maxInactiveAge и 2 для длины буфера страниц.
Я также попытался изменить некоторые конфигурации webpack, но это не сработало, потому что nextjs перекомпилирует все это по запросу.
Комментарии:
1. На консоли появляется быстрое обновление, и я подумал, что это может быть причиной. Однако это не кажется полностью последовательным. Файл кажется намного проще, чем я думал сначала. Это немного грустно, так как это не нужно для производства.
Ответ №2:
Возможно, я ошибаюсь, но это звучит как пример использования, когда динамический маршрут, getStaticPaths и getStaticProps могут работать для вас.
getStaticPaths проверит существующие файлы и проложит для них маршруты, а getStaticProps при необходимости получит нужную запись. При экспорте все они извлекаются и генерируются.
https://nextjs.org/docs/advanced-features/static-html-export
https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation
Комментарии:
1. Я действительно им пользуюсь
2. Если вы используете его, то вы должны иметь возможность генерировать сообщение на основе маршрута только по требованию, а не все сразу? Или вы уже это делаете, и даже это медленно генерируется при открытии страницы публикации?