Skip to content

Instantly share code, notes, and snippets.

@Tusko
Last active August 10, 2023 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tusko/b9ef1aa1a2dc0b77c827af39dfa0e710 to your computer and use it in GitHub Desktop.
Save Tusko/b9ef1aa1a2dc0b77c827af39dfa0e710 to your computer and use it in GitHub Desktop.
Vite Plugin SSR Sitemap
import { SitemapStream } from "sitemap";
import { createWriteStream } from "node:fs";
import { resolve } from "node:path";
export function ssrSitemap(opts) {
const pages = new Set();
let config;
let hasVitePlusinSSR = false;
const defaultOtps = {
host: "https://localhost", // no trailing slash
exclude: [],
filename: "sitemap.xml",
pagesFolder: "/pages/", // with slashes
i18n: {
locales: [],
localeDefault: null,
},
};
const mergedOpts = { ...defaultOtps, ...opts };
return {
name: "ssrSitemap",
configResolved(resolvedConfig) {
config = resolvedConfig;
hasVitePlusinSSR = config.plugins.find((plugin) =>
plugin.name.includes("vite-plugin-ssr"),
);
},
async transform(_, file) {
if (config?.ssr && config.command === "build" && hasVitePlusinSSR) {
const splitRoot = file.split(mergedOpts.pagesFolder);
if (splitRoot.length > 1) {
const splitLocale = splitRoot[1].split("/");
const [page] = splitLocale;
const { exclude = [] } = mergedOpts;
if (!exclude.includes(page) && !pages.has(page)) {
pages.add(page);
}
}
}
},
async writeBundle({ dir }) {
if (dir.includes("client")) {
const sitemap = new SitemapStream({
hostname: mergedOpts.host,
});
const writeStream = createWriteStream(
resolve(dir, mergedOpts.filename),
);
sitemap.pipe(writeStream);
pages.forEach((url) => {
if (mergedOpts.i18n.locales.length) {
mergedOpts.i18n.locales.forEach((locale) => {
const localeUrl =
mergedOpts.i18n.localeDefault &&
locale === mergedOpts.i18n.localeDefault
? ""
: locale;
sitemap.write(`${localeUrl}/${url}`);
});
} else {
sitemap.write(url);
}
});
sitemap.end();
await new Promise((r) => writeStream.on("finish", r));
}
},
};
}
import vue from "@vitejs/plugin-vue";
import { defineConfig, loadEnv } from "vite";
import ssr from "vite-plugin-ssr/plugin";
import { ssrSitemap } from "./server/sitemap-generator";
import { locales, localeDefault } from "./locales";
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
return {
plugins: [
vue(),
ssr({ prerender: true }),
eslintPlugin(),
visualizer(),
ssrSitemap({
host: env.VITE_APP_SITEMAP_HOST,
i18n: {
locales,
localeDefault,
},
exclude: env.VITE_APP_SITEMAP_EXCLUDES.split(",").map((page) =>
page.trim(),
),
}),
],
define: {
"process.env": {},
}
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment