From 6b4bf7df336740f5e14adb5f830d8dd183498b64 Mon Sep 17 00:00:00 2001 From: "naoto.kido" Date: Fri, 18 Apr 2025 19:12:17 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20robots.xml=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- app/routes/home.tsx | 4 +- package.json | 3 +- _routes.json => public/_routes.json | 0 public/robots.txt | 4 ++ scripts/gen-sitemap.js | 95 +++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 4 deletions(-) rename _routes.json => public/_routes.json (100%) create mode 100644 public/robots.txt create mode 100644 scripts/gen-sitemap.js diff --git a/.gitignore b/.gitignore index b56bec2..9128043 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ *storybook.log -**.env \ No newline at end of file +**.env + +/public/sitemap.xml \ No newline at end of file diff --git a/app/routes/home.tsx b/app/routes/home.tsx index bfa7745..6486547 100644 --- a/app/routes/home.tsx +++ b/app/routes/home.tsx @@ -18,8 +18,8 @@ export function meta({ }: Route.MetaArgs) { const members: MemberCardProps[] = [ { name: "Naoto Kido", role: "owner", description: "card.memberCard.descriptions.naoido", stacks: ['Kubernetes', 'AWS', 'Java', 'Go-wordmark', 'Flutter'], headerImage: "/assets/images/headers/naoido.webp", iconImage: "https://avatars.githubusercontent.com/u/54303857", githubName: "naoido" }, { name: "Naoki Miura", role: "coowner", description: "card.memberCard.descriptions.thirdlf03", stacks: ['Go-wordmark', 'Javascript', 'Rust', 'Python', 'Neovim'], headerImage: "/assets/images/headers/thirdlf03.webp", iconImage: "https://avatars.githubusercontent.com/u/114989748", githubName: "thirdlf03" }, - { name: "Takumi Matsubara", role: "frontend", description: "card.memberCard.descriptions.annkoatama", stacks: ['Typescript', 'Swift', 'React'], headerImage: "/assets/images/headers/annkoatama.webp", iconImage: "https://avatars.githubusercontent.com/u/152017354", githubName: "AnnkoATAMA" }, - { name: "Kentaro Doi", role: "backend", description: "card.memberCard.descriptions.kenta-afk", stacks: ['Javascript', 'Python', 'php', 'Laravel', 'Typescript'], headerImage: "/assets/images/headers/kenta_afk.webp", iconImage: "https://avatars.githubusercontent.com/u/148222450", githubName: "kenta-afk" }, + { name: "Takumi Matsubara", role: "frontend", description: "card.memberCard.descriptions.annkoatama", stacks: ['Typescript', 'Python', 'Java', 'Swift', 'React'], headerImage: "/assets/images/headers/annkoatama.webp", iconImage: "https://avatars.githubusercontent.com/u/152017354", githubName: "AnnkoATAMA" }, + { name: "Kentaro Doi", role: "backend", description: "card.memberCard.descriptions.kenta-afk", stacks: ['Python', 'php', 'Laravel', 'Typescript', 'Javascript'], headerImage: "/assets/images/headers/kenta_afk.webp", iconImage: "https://avatars.githubusercontent.com/u/148222450", githubName: "kenta-afk" }, ] const notices: NoticeCardProps[] = [ diff --git a/package.json b/package.json index d3c16e9..a570038 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,9 @@ "private": true, "type": "module", "scripts": { + "gen-sitemap": "node ./scripts/gen-sitemap.js", + "prebuild": "npm run gen-sitemap", "build": "react-router build", - "postbuild": "cp _routes.json build/client/_routes.json", "dev": "react-router dev", "start": "react-router-serve ./build/server/index.js", "typecheck": "react-router typegen && tsc", diff --git a/_routes.json b/public/_routes.json similarity index 100% rename from _routes.json rename to public/_routes.json diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..0e19d85 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://object-t.com/sitemap.xml \ No newline at end of file diff --git a/scripts/gen-sitemap.js b/scripts/gen-sitemap.js new file mode 100644 index 0000000..39f9eb4 --- /dev/null +++ b/scripts/gen-sitemap.js @@ -0,0 +1,95 @@ +import { execSync } from "child_process"; +import fs from "fs"; +import path from "path"; + +const BASE_URL = "https://object-t.com/blog"; + +const repoDir = "tmp"; +const repoPath = path.resolve(repoDir); + +const urlEntries = []; + +try { + if (fs.existsSync(repoPath)) { + console.log(`[INFO] Removing existing directory: ${repoPath}`); + fs.rmSync(repoPath, { recursive: true, force: true }); + } + + console.log(`[INFO] Cloning repository into ${repoPath}...`); + execSync(`git clone https://github.com/object-t/object-t-blog ${repoDir}`, { stdio: 'inherit' }); + + const articlesJsonPath = path.join(repoPath, "articles.json"); + if (!fs.existsSync(articlesJsonPath)) { + throw new Error(`articles.json not found in the cloned repository at ${articlesJsonPath}`); + } + console.log(`[INFO] Reading articles list from ${articlesJsonPath}...`); + const raw = fs.readFileSync(articlesJsonPath, "utf-8"); + const data = JSON.parse(raw); + + console.log("[INFO] Processing articles for sitemap..."); + for (const article of data) { + const id = article.id; + if (!id || typeof id !== 'string' || !id.endsWith(".md")) { + console.warn(`[WARN] Skipping invalid or non-markdown entry: ${JSON.stringify(article)}`); + continue; + } + + const slug = id.replace(/\.md$/, ''); + const loc = `${BASE_URL.replace(/\/$/, '')}/${slug}`; + + console.log(`[INFO] Processing ID: ${id} -> ${loc}`); + const filePathInRepo = path.join("articles", id); + + try { + const command = `git log -1 --format="%cI" -- "${filePathInRepo}"`; + const lastmodRaw = execSync(command, { + encoding: "utf-8", + cwd: repoPath, + }).trim(); + + if (!lastmodRaw) { + console.warn(`[WARN] Lastmod is empty for ${id}. Skipping sitemap entry.`); + continue; + } + const lastmod = lastmodRaw; + console.log(`[INFO] Lastmod: ${lastmod}`); + + urlEntries.push(` + + ${loc} + ${lastmod} + `); + } catch (error) { + const stderr = error.stderr?.toString('utf-8').trim(); + console.error(`[ERROR] Error getting git log for ${id}: ${stderr || error.message}. Skipping sitemap entry.`); + } + } + console.log("[INFO] Finished processing articles."); + + const sitemapXml = ` +${urlEntries.join('')} +`; + + console.log("\n--- Generated Sitemap ---"); + console.log(sitemapXml); + + try { + const outputFilePath = "public/sitemap.xml"; + fs.writeFileSync(outputFilePath, sitemapXml, "utf-8"); + console.log(`\n[INFO] Sitemap successfully written to ${outputFilePath}`); + } catch (writeError) { + console.error(`\n[ERROR] Failed to write sitemap to file: ${writeError.message}`); + } +} catch (error) { + console.error("\n[ERROR] An overall error occurred:", error.message); +} finally { + if (fs.existsSync(repoPath)) { + console.log(`[INFO] Cleaning up ${repoPath}...`); + try { + fs.rmSync(repoPath, { recursive: true, force: true }); + console.log("[INFO] Cleanup successful."); + } catch (cleanupError) { + console.error(`[ERROR] Error during cleanup: ${cleanupError.message}`); + } + } +} \ No newline at end of file From f67ab9dd063cd3f4d1ee534491b8e4b574da320e Mon Sep 17 00:00:00 2001 From: "naoto.kido" Date: Fri, 18 Apr 2025 19:18:17 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E6=97=A5=E4=BB=98=E3=81=AE=E5=BD=A2?= =?UTF-8?q?=E5=BC=8F=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/gen-sitemap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gen-sitemap.js b/scripts/gen-sitemap.js index 39f9eb4..6877e31 100644 --- a/scripts/gen-sitemap.js +++ b/scripts/gen-sitemap.js @@ -51,7 +51,7 @@ try { console.warn(`[WARN] Lastmod is empty for ${id}. Skipping sitemap entry.`); continue; } - const lastmod = lastmodRaw; + const lastmod = new Date(lastmodRaw).toISOString(); console.log(`[INFO] Lastmod: ${lastmod}`); urlEntries.push(`