diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..6c59086d --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +enable-pre-post-scripts=true diff --git a/next-sitemap.config.js b/next-sitemap.config.js new file mode 100644 index 00000000..defccf20 --- /dev/null +++ b/next-sitemap.config.js @@ -0,0 +1,9 @@ +/** @type {import('next-sitemap').IConfig} */ + +const dev = process.env.NODE_ENV !== 'production'; + +module.exports = { + siteUrl: dev ? 'http://localhost:3000' : 'https://papermc.io', + exclude: ["/downloads/all"], + generateIndexSitemap: false, +}; diff --git a/package.json b/package.json index 27e46263..7d06b34c 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "scripts": { "dev": "next dev", "build": "next build", + "postbuild": "next-sitemap", "start": "next start", "lint": "next lint" }, @@ -18,6 +19,7 @@ "@headlessui/react": "2.1.2", "clsx": "2.1.1", "next": "13.5.4", + "next-sitemap": "^4.2.3", "react": "18.3.1", "react-dom": "18.3.1", "sharp": "^0.33.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 377a61e9..8a430ee6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ dependencies: next: specifier: 13.5.4 version: 13.5.4(@babel/core@7.24.9)(react-dom@18.3.1)(react@18.3.1) + next-sitemap: + specifier: ^4.2.3 + version: 4.2.3(next@13.5.4) react: specifier: 18.3.1 version: 18.3.1 @@ -1429,6 +1432,10 @@ packages: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + /@corex/deepmerge@4.0.43: + resolution: {integrity: sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==} + dev: false + /@emnapi/runtime@1.2.0: resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==} requiresBuild: true @@ -1866,12 +1873,10 @@ packages: dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: true /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} - dev: true /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} @@ -1879,7 +1884,6 @@ packages: dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - dev: true /@pkgr/core@0.1.1: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} @@ -2565,7 +2569,6 @@ packages: engines: {node: '>=8'} dependencies: fill-range: 7.1.1 - dev: true /browserslist@4.23.2: resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==} @@ -3411,7 +3414,6 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.7 - dev: true /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -3425,7 +3427,6 @@ packages: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: reusify: 1.0.4 - dev: true /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} @@ -3439,7 +3440,6 @@ packages: engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - dev: true /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -3530,7 +3530,6 @@ packages: engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - dev: true /glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} @@ -3767,7 +3766,6 @@ packages: /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - dev: true /is-finalizationregistry@1.0.2: resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} @@ -3787,7 +3785,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 - dev: true /is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} @@ -3809,7 +3806,6 @@ packages: /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - dev: true /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} @@ -4048,7 +4044,6 @@ packages: /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - dev: true /micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} @@ -4056,7 +4051,6 @@ packages: dependencies: braces: 3.0.3 picomatch: 2.3.1 - dev: true /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -4066,7 +4060,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -4085,6 +4078,20 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /next-sitemap@4.2.3(next@13.5.4): + resolution: {integrity: sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==} + engines: {node: '>=14.18'} + hasBin: true + peerDependencies: + next: '*' + dependencies: + '@corex/deepmerge': 4.0.43 + '@next/env': 13.5.4 + fast-glob: 3.3.2 + minimist: 1.2.8 + next: 13.5.4(@babel/core@7.24.9)(react-dom@18.3.1)(react@18.3.1) + dev: false + /next@13.5.4(@babel/core@7.24.9)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-+93un5S779gho8y9ASQhb/bTkQF17FNQOtXLKAj3lsNgltEcF0C5PMLLncDmH+8X1EnJH1kbqAERa29nRXqhjA==} engines: {node: '>=16.14.0'} @@ -4293,7 +4300,6 @@ packages: /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - dev: true /possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} @@ -4342,7 +4348,6 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true /react-dom@18.3.1(react@18.3.1): resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} @@ -4458,7 +4463,6 @@ packages: /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} @@ -4472,7 +4476,6 @@ packages: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 - dev: true /safe-array-concat@1.1.2: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} @@ -4786,7 +4789,6 @@ packages: engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 - dev: true /ts-api-utils@1.3.0(typescript@5.5.3): resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} diff --git a/public/.gitignore b/public/.gitignore new file mode 100644 index 00000000..1d3de1ab --- /dev/null +++ b/public/.gitignore @@ -0,0 +1 @@ +sitemap.xml diff --git a/public/robots.txt b/public/robots.txt index d6cc1cba..8ef923d7 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,3 +1,8 @@ User-agent: * +Disallow: /downloads/all +Disallow: /repository/ +Disallow: /repo/ +Disallow: /api/ Allow: / -Disallow: /downloads/all \ No newline at end of file + +Sitemap: https://papermc.io/sitemap.xml diff --git a/src/components/layout/SoftwareDownload.tsx b/src/components/layout/SoftwareDownload.tsx index b85375d7..75c0fb53 100644 --- a/src/components/layout/SoftwareDownload.tsx +++ b/src/components/layout/SoftwareDownload.tsx @@ -28,7 +28,7 @@ const SoftwareDownload = ({ const [isStable, setStable] = useState(true); const version = isStable ? project.latestStableVersion - : project.latestExperimentalVersion ?? project.latestStableVersion; + : (project.latestExperimentalVersion ?? project.latestStableVersion); const { data: builds } = useVersionBuilds(id, version); const latestBuild = builds && builds.builds[builds.builds.length - 1]; @@ -61,7 +61,7 @@ const SoftwareDownload = ({

- {isStable ? description : experimentalWarning ?? description} + {isStable ? description : (experimentalWarning ?? description)}

{ +const SEO = ({ + title, + description, + keywords, + canonical, +}: SEOProps): ReactElement => { return ( {title + " | PaperMC"} @@ -15,6 +21,8 @@ const SEO = ({ title, description, keywords }: SEOProps): ReactElement => { + + diff --git a/src/pages/community/guidelines.tsx b/src/pages/community/guidelines.tsx index 49a39d66..956b767f 100644 --- a/src/pages/community/guidelines.tsx +++ b/src/pages/community/guidelines.tsx @@ -11,6 +11,7 @@ const CommunityGuidelines: NextPage = () => ( title="Community Guidelines" description="Community Guidelines for the PaperMC community." keywords={["papermc", "paper", "minecraft", "community", "guidelines"]} + canonical="/community/guidelines" />

diff --git a/src/pages/community/index.tsx b/src/pages/community/index.tsx index 189a65cd..7f7773f3 100644 --- a/src/pages/community/index.tsx +++ b/src/pages/community/index.tsx @@ -9,6 +9,7 @@ const CommunityIndex: NextPage = () => ( title="Community" description="We're happy to have you as a part of the PaperMC community!" keywords={["papermc", "paper", "minecraft", "sponsor", "community"]} + canonical="/community" />
diff --git a/src/pages/contribute.tsx b/src/pages/contribute.tsx index d0078d44..3e981a9f 100644 --- a/src/pages/contribute.tsx +++ b/src/pages/contribute.tsx @@ -13,6 +13,7 @@ const Contribute: NextPage = () => ( title="Contributing" description="Without contributors our projects wouldn't be possible. Find out how you can help." keywords={["papermc", "paper", "minecraft", "sponsor", "contributing"]} + canonical="/contribute" />
diff --git a/src/pages/downloads/all.tsx b/src/pages/downloads/all.tsx index 5d3e56a9..b9aa6bba 100644 --- a/src/pages/downloads/all.tsx +++ b/src/pages/downloads/all.tsx @@ -46,6 +46,7 @@ const LegacyDownloads: NextPage = ({ title="Build explorer" description="Build explorer for PaperMC projects. Proceed with caution!" keywords={[]} + canonical="/downloads/all" />
diff --git a/src/pages/downloads/index.tsx b/src/pages/downloads/index.tsx index 855dcba6..833b6d5e 100644 --- a/src/pages/downloads/index.tsx +++ b/src/pages/downloads/index.tsx @@ -22,6 +22,7 @@ const Downloads: NextPage = () => { "waterfall", "downloads", ]} + canonical="/downloads" />

diff --git a/src/pages/downloads/paper.tsx b/src/pages/downloads/paper.tsx index 50b68ef3..392b0214 100644 --- a/src/pages/downloads/paper.tsx +++ b/src/pages/downloads/paper.tsx @@ -20,6 +20,7 @@ const PaperDownloads = ({ project }: ProjectProps): ReactElement => { "downloads", "jar", ]} + canonical="/downloads/paper" /> { "downloads", "jar", ]} + canonical="/downloads/velocity" /> { "downloads", "jar", ]} + canonical="/downloads/waterfall" /> = ({ project }) => { description="PaperMC is a Minecraft software organization focusing on improving the game’s ecosystem with faster and more secure software." keywords={["papermc", "paper", "velocity", "minecraft", "performance"]} + canonical="/" />
diff --git a/src/pages/javadocs.tsx b/src/pages/javadocs.tsx index 31b84e0e..66a1d791 100644 --- a/src/pages/javadocs.tsx +++ b/src/pages/javadocs.tsx @@ -34,6 +34,7 @@ const Javadocs: NextPage = ({ "velocity", "waterfall", ]} + canonical="/javadocs" />

diff --git a/src/pages/software/folia/index.tsx b/src/pages/software/folia/index.tsx index 4ab7ba3a..40d5da3e 100644 --- a/src/pages/software/folia/index.tsx +++ b/src/pages/software/folia/index.tsx @@ -29,6 +29,7 @@ const FoliaHome = ({ project }: HangarProjectProps): ReactElement => { "multithreading", "fork", ]} + canonical="/software/folia" /> { "bungeecord", "fork", ]} + canonical="/software/waterfall" /> { title="Sponsors" description="Without contributors our projects wouldn't be possible. Find out how you can help." keywords={["papermc", "paper", "minecraft", "sponsor", "contributing"]} + canonical="/sponsors" />
diff --git a/src/pages/team.tsx b/src/pages/team.tsx index fd64165b..48a5bb29 100644 --- a/src/pages/team.tsx +++ b/src/pages/team.tsx @@ -20,6 +20,7 @@ const Team: NextPage = () => { description="Meet the team behind PaperMC, a Minecraft software organization focusing on improving the game’s ecosystem with faster and more secure software." keywords={["papermc", "paper", "minecraft", "team"]} + canonical="/team" />