Open book000 opened 1 year ago
SSGだから外部サービスに頼るしかないのではなどと思ってますが
たしかに…
https://www.algolia.com/ Algoliaとかよく見るけど、おいくら万円くらいかかるのかわからん
10,000 search + 10,000 recommend requests/mo and 10,000 records/mo
クレカ登録不要ならまあ上限いったらごめんなさいにすればいいかしらねえ
10,000 search + 10,000 recommend requests/mo and 10,000 records/mo
無料である程度使えるなら、とりあえず使ってみるのはありかねえ
26 はブログ記事に限っての絞り込みなのでちょっと違います。
issueの件名変えたほうが良きかねえ。ブログ記事の絞り込み機能とか。こっちは ContentList.vue
で一覧データ取得はやってるから、カテゴリ(まだカテゴリ自体存在しないけど)とか著者での絞り込みとかならできそう。しらんけど。
issueの件名変えたほうが良きかねえ。
かえました
:igyo:
ドキュメント更新時にドキュメントを Algolia に投げるコードを書く感じかなあ
https://sunday-morning.app/posts/2021-03-27-generate-contentful-algolia-index
検索結果の表示と表示結果からの遷移を考えると、アンカーが付けられる各タイトル部分とそれ以下のドキュメントでインデックスつけたほうがよさそう。
とりあえずざっとMarkdownからASTつくってheadingとそれ以下のコンテンツに分ける処理
/* eslint-disable no-console */
import { fromMarkdown } from 'mdast-util-from-markdown'
import { gfmTable } from 'micromark-extension-gfm-table'
import { gfmTableFromMarkdown } from 'mdast-util-gfm-table'
import fs from 'node:fs'
import { toString } from 'mdast-util-to-string'
import { Content } from 'mdast-util-from-markdown/lib'
import { Logger } from '@book000/node-utils'
import matter from 'gray-matter'
const htmlCommentRegex = /<!--[\S\s]*?-->/g
async function parse(content: string) {
const ast = fromMarkdown(content, {
extensions: [gfmTable],
mdastExtensions: [gfmTableFromMarkdown],
})
// headingとそれ以下の内容を取得
const results: {
title: string | null
asts: Content[]
content: string | null
}[] = []
for (const node of ast.children) {
if (node.type === 'heading') {
// 前項目のコンテンツ処理
const last = results[results.length - 1]
if (last) {
last.content = toString(last.asts).replace(htmlCommentRegex, '').trim()
}
// 新しい項目追加
const title = toString(node)
results.push({
title,
asts: [],
content: null,
})
continue
}
// headingでない場合は前項目に追加
const last = results[results.length - 1]
if (last) {
last.asts.push(node)
} else {
results.push({
title: null,
asts: [node],
content: null,
})
}
}
return results
}
function getFiles(directory: string): string[] {
const files = fs.readdirSync(directory)
const results: string[] = []
for (const file of files) {
const path = `${directory}/${file}`
if (fs.statSync(path).isDirectory()) {
results.push(...getFiles(path))
} else {
results.push(path)
}
}
return results
}
async function main() {
const logger = Logger.configure('main')
const directory = './files'
const files = getFiles(directory)
const results: {
pageTitle: string
path: string
heading: string | null
content: string
}[] = []
for (const path of files) {
if (!path.endsWith('.md')) {
continue
}
logger.info(`Parsing ${path}...`)
const frontMatter = matter(fs.readFileSync(path, 'utf8'))
const parsed = await parse(frontMatter.content)
for (const p of parsed) {
if (!p.content) {
continue
}
results.push({
pageTitle: frontMatter.data.title,
path: path.replace(directory, '').replace('.md', ''),
heading: p.title,
content: p.content,
})
}
}
fs.writeFileSync('./results.json', JSON.stringify(results, null, 2), 'utf8')
}
;(async () => {
await main()
})()
generateしたら /search
ルートが消えました(どこからもリンクされていないので)。静的ルート書かなきゃならなそう…
クライアントサイドでalgoliaにリクエストを出していいのか、よくわかりません
動かすためには .env
に ALGOLIA_API_KEY
と ALGOLIA_APPLICATION_ID
を設定しなければなりません。値は https://www.algolia.com/account/api-keys/all?applicationId=RF6OC1MM2P にて閲覧可能。
DocSearch とやらを公開したら使うのがよさそう? https://docsearch.algolia.com/
そっちのが一般的なんかねえ。 とりあえず、検索が絶対なきゃならんってわけでもないと思うので、公開後に両方試してみて比較してからでもいいと思う。
ルールとか探すときにワード検索できたら楽ですよねってやつです 検索画面とか作るのがなかなかめんどくさそうですが…。