UNPKG

@theguild/components

Version:
122 lines (121 loc) 4.41 kB
import { createRequire } from "module"; import path from "path"; import nextra from "nextra"; import nextBundleAnalyzer from "@next/bundle-analyzer"; import { applyUnderscoreRedirects } from "./underscore-redirects.js"; const warnings = /* @__PURE__ */ new Set(); const require2 = createRequire(import.meta.url); function getFrontMatterASTObject(node) { const [n] = node.data.estree.body; return n.declaration.declarations[0].init.properties; } function isExportNode(node, varName) { if (node.type !== "mdxjsEsm") return false; const [n] = node.data.estree.body; if (n.type !== "ExportNamedDeclaration") return false; const name = n.declaration?.declarations?.[0].id.name; if (!name) return false; return name === varName; } const rehypeCheckFrontMatter = () => (ast, file) => { const [filePath] = file.history; if (!filePath) return; const relativePath = path.relative(process.cwd(), filePath); const fileName = path.parse(relativePath).name; const isPage = relativePath.startsWith("app/") && fileName === "page" || relativePath.startsWith("/content/"); if (!isPage) return; function warnOnce(message) { const msg = `[@theguild/components] SEO issue in "${relativePath}": ${message}`; if (!warnings.has(msg)) { warnings.add(msg); console.warn(msg); } } const frontMatterNode = ast.children.find((node) => isExportNode(node, "metadata")); const frontMatter = getFrontMatterASTObject(frontMatterNode); const description = frontMatter.find((o) => o.key.value === "description")?.value.value; if (!description) { warnOnce("The description is missing"); } else if (description.length > 160) { warnOnce( `The description "${description}" is too long, should be less than 160 characters, not ${description.length}` ); } else if (description.length < 50) { warnOnce( `The description "${description}" is too short, should be more than 50 characters, not ${description.length}` ); } }; const defaultNextraOptions = { defaultShowCopyCode: true, whiteListTagsStyling: ["iframe", "video", "source"], search: { codeblocks: true }, mdxOptions: { // Check front matter only in production (when Webpack is used) // Should be rehype since frontMatter is attached in remark plugins rehypePlugins: process.env.NODE_ENV === "production" ? [rehypeCheckFrontMatter] : [] } }; function withGuildDocs({ nextraConfig, ...nextConfig } = {}) { if (nextConfig.webpack?.toString().includes("applyUnderscoreRedirects")) { throw new Error( "`applyUnderscoreRedirects` in `nextConfig.webpack` was already configured, remove it from your config" ); } const withBundleAnalyzer = nextBundleAnalyzer({ enabled: process.env.ANALYZE === "true" }); const withNextra = nextra({ ...defaultNextraOptions, ...nextraConfig }); const nextraClientPath = path.relative( process.cwd(), path.join(require2.resolve("nextra/package.json"), "..", "dist", "client") ); return withBundleAnalyzer( withNextra({ reactStrictMode: true, poweredByHeader: false, basePath: process.env.NEXT_BASE_PATH, ...nextConfig, env: { SITE_URL: process.env.SITE_URL || "", ...nextConfig.env }, webpack(config, meta) { applyUnderscoreRedirects(config, meta); return nextConfig.webpack?.(config, meta) || config; }, experimental: { // TODO: Provoke white flash ⚪️💥 on initial loading with dark theme // optimizeCss: true, ...nextConfig.experimental, turbo: { resolveAlias: { // Fixes when Turbopack is enabled: Module not found: Can't resolve '@theguild/remark-mermaid/mermaid' "@theguild/remark-mermaid/mermaid": path.relative( process.cwd(), path.join( require2.resolve("@theguild/remark-mermaid/package.json"), "..", "dist", "mermaid.js" ) ), "nextra/components": path.join(nextraClientPath, "components", "index.js"), "nextra/setup-page": path.join(nextraClientPath, "setup-page.js") } } }, images: { unoptimized: true, // doesn't work with `next export`, ...nextConfig.images } }) ); } export { defaultNextraOptions, withGuildDocs };