UNPKG

nuxt-schema-org

Version:

The quickest and easiest way to build Schema.org graphs for Nuxt.

219 lines (214 loc) 7.46 kB
import { useNuxt, createResolver, addTemplate, defineNuxtModule, useLogger, hasNuxtModule, addPlugin, hasNuxtModuleCompatibility, addServerPlugin, addComponent, addImports, addServerHandler } from '@nuxt/kit'; import { defineWebPage } from '@unhead/schema-org'; import { schemaOrgAutoImports, schemaOrgComponents } from '@unhead/schema-org/vue'; import { defu } from 'defu'; import { installNuxtSiteConfig } from 'nuxt-site-config/kit'; import { readPackageJSON } from 'pkg-types'; import { existsSync } from 'node:fs'; import { relative } from 'pathe'; const DEVTOOLS_UI_ROUTE = "/__nuxt-schema-org"; const DEVTOOLS_UI_LOCAL_PORT = 3030; function setupDevToolsUI(options, resolve, nuxt = useNuxt()) { const clientPath = resolve("./client"); const isProductionBuild = existsSync(clientPath); if (isProductionBuild) { nuxt.hook("vite:serverCreated", async (server) => { const sirv = await import('sirv').then((r) => r.default || r); server.middlewares.use( DEVTOOLS_UI_ROUTE, sirv(clientPath, { dev: true, single: true }) ); }); } else { nuxt.hook("vite:extendConfig", (config) => { config.server = config.server || {}; config.server.proxy = config.server.proxy || {}; config.server.proxy[DEVTOOLS_UI_ROUTE] = { target: `http://localhost:${DEVTOOLS_UI_LOCAL_PORT}${DEVTOOLS_UI_ROUTE}`, changeOrigin: true, followRedirects: true, rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "") }; }); } nuxt.hook("devtools:customTabs", (tabs) => { tabs.push({ // unique identifier name: "nuxt-schema-org", // title to display in the tab title: "Schema.org", // any icon from Iconify, or a URL to an image icon: "carbon:chart-relationship", // iframe view view: { type: "iframe", src: DEVTOOLS_UI_ROUTE } }); }); } function extendTypes(module, template) { const nuxt = useNuxt(); const { resolve } = createResolver(import.meta.url); addTemplate({ filename: `module/${module}.d.ts`, getContents: async () => { const typesPath = relative(resolve(nuxt.options.rootDir, nuxt.options.buildDir, "module"), resolve("runtime/types")); const s = await template({ typesPath }); return `// Generated by ${module} ${s} export {} `; } }); nuxt.hooks.hook("prepare:types", ({ references }) => { references.push({ path: resolve(nuxt.options.buildDir, `module/${module}.d.ts`) }); }); } const module = defineNuxtModule({ meta: { name: "nuxt-schema-org", configKey: "schemaOrg", compatibility: { nuxt: ">=3.16.0" }, moduleDependencies: { "@nuxtjs/i18n": { version: ">=8", optional: true }, "nuxt-i18n-micro": { version: ">=1", optional: true }, "nuxt-site-config": { version: ">=3" }, "@nuxt/content": { version: ">=2", optional: true } } }, defaults(nuxt) { return { enabled: true, defaults: true, reactive: nuxt.options.dev || !nuxt.options.ssr, minify: !nuxt.options.dev, scriptAttributes: { "data-nuxt-schema-org": true } }; }, async setup(config, nuxt) { const { resolve } = createResolver(import.meta.url); const { name, version } = await readPackageJSON(resolve("../package.json")); const logger = useLogger(name); logger.level = config.debug ? 4 : 3; if (config.enabled === false) { logger.debug("The module is disabled, skipping setup."); return; } if (!nuxt.options.ssr && nuxt.options.dev) logger.warn("You are using Schema.org with SSR disabled. This is not recommended, Google may not detect your Schema.org, and it adds extra page weight"); await installNuxtSiteConfig(); const runtimeConfig = { reactive: config.reactive, minify: config.minify, scriptAttributes: config.scriptAttributes, identity: config.identity, version }; if (config.reactive) nuxt.options.runtimeConfig.public["nuxt-schema-org"] = runtimeConfig; nuxt.options.runtimeConfig["nuxt-schema-org"] = runtimeConfig; const pluginPath = hasNuxtModule("@nuxtjs/i18n") && nuxt.options.i18n?.locales ? "./runtime/app/plugins/i18n" : "./runtime/app/plugins"; addPlugin({ src: resolve(pluginPath, "init"), mode: config.reactive ? "all" : "server" }); if (config.defaults) { addPlugin({ src: resolve(pluginPath, "defaults"), mode: config.reactive ? "all" : "server" }); } nuxt.options.alias["#schema-org"] = resolve("./runtime"); const usingNuxtContent = hasNuxtModule("@nuxt/content"); const isNuxtContentV3 = usingNuxtContent && await hasNuxtModuleCompatibility("@nuxt/content", "^3"); const isNuxtContentV2 = usingNuxtContent && await hasNuxtModuleCompatibility("@nuxt/content", "^2"); if (isNuxtContentV3) { nuxt.hooks.hook("content:file:afterParse", (ctx) => { if (typeof ctx.content.schemaOrg === "undefined") { return; } const content = ctx.content; const nodes = Array.isArray(content.schemaOrg) ? content.schemaOrg : [defineWebPage(content.schemaOrg)]; const replaceType = (node) => { if (node.type) { node["@type"] = node.type; delete node.type; } Object.entries(node).forEach(([, value]) => { if (typeof value === "object") { replaceType(value); } }); return node; }; const script = { type: "application/ld+json", key: "schema-org-graph", ...config.scriptAttributes, nodes: nodes.map(replaceType) }; content.head = defu({ script: [script] }, content.head); ctx.content = content; }); } else if (isNuxtContentV2) { addServerPlugin(resolve("./runtime/server/plugins/nuxt-content-v2")); } if (!config.reactive) nuxt.options.optimization.treeShake.composables.client["nuxt-schema-org"] = schemaOrgAutoImports[0].imports; for (const component of schemaOrgComponents) { await addComponent({ name: component, export: component, chunkName: "nuxt-schema-org/components", filePath: "@unhead/schema-org/vue" }); } addImports({ from: resolve("./runtime/app/composables/useSchemaOrg"), name: "useSchemaOrg" }); nuxt.hooks.hook("imports:sources", (autoImports) => { schemaOrgAutoImports[0].imports = schemaOrgAutoImports[0].imports.filter((i) => i !== "useSchemaOrg"); autoImports.unshift(...schemaOrgAutoImports); }); extendTypes("nuxt-schema-org", ({ typesPath }) => { return ` declare module '@nuxt/schema' { export interface RuntimeNuxtHooks { 'schema-org:meta': (meta: import('${typesPath}').MetaInput) => void | Promise<void> } } declare module '#app' { export interface RuntimeNuxtHooks { 'schema-org:meta': (meta: import('${typesPath}').MetaInput) => void | Promise<void> } } `; }); if (config.debug || nuxt.options.dev) { addServerHandler({ route: "/__schema-org__/debug.json", handler: resolve("./runtime/server/routes/__schema-org__/debug") }); } if (nuxt.options.dev) setupDevToolsUI(config, resolve); } }); export { module as default };