From 689edeaf244d7e19b395988ad818a02feeb986b9 Mon Sep 17 00:00:00 2001 From: Jaybe Date: Sat, 15 Nov 2025 15:18:23 +0900 Subject: [PATCH] =?UTF-8?q?feat(perf-seo):=20exporter=EC=97=90=20robots=20?= =?UTF-8?q?=EB=A9=94=ED=83=80=20=EC=98=B5=EC=85=98=20=EC=B6=94=EA=B0=80(TD?= =?UTF-8?q?D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/exporter/html.ts | 4 +++- lib/exporter/robots.meta.tag.test.ts | 29 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 lib/exporter/robots.meta.tag.test.ts diff --git a/lib/exporter/html.ts b/lib/exporter/html.ts index 14c1932..05b5956 100644 --- a/lib/exporter/html.ts +++ b/lib/exporter/html.ts @@ -2,7 +2,7 @@ import type { Page, FormField } from '@/lib/schema/page' import type { AssetManager } from '@/lib/assets/assetManager' export type Exported = { html: string; css: string; js: string } -export type ExportOptions = { assetManager?: AssetManager; fontPreconnect?: boolean } +export type ExportOptions = { assetManager?: AssetManager; fontPreconnect?: boolean; robotsMeta?: string } function renderFaq(section: { props: { items: Array<{ q: string; a: string }> } }) { const itemsRaw: Array<{ q: string; a: string }> = Array.isArray(section.props.items) ? section.props.items : [] @@ -251,6 +251,7 @@ function buildHead(page: Page, opts?: ExportOptions) { } const custom = page.analytics?.customHeadHtml || '' const preconnect = opts?.fontPreconnect !== false + const robotsMeta = (opts?.robotsMeta && opts.robotsMeta.trim().length > 0) ? `` : '' return ` @@ -259,6 +260,7 @@ function buildHead(page: Page, opts?: ExportOptions) { ${preconnect ? '' : ''} + ${robotsMeta} ${escapeHtml(page.seo.title)} diff --git a/lib/exporter/robots.meta.tag.test.ts b/lib/exporter/robots.meta.tag.test.ts new file mode 100644 index 0000000..ca44dd3 --- /dev/null +++ b/lib/exporter/robots.meta.tag.test.ts @@ -0,0 +1,29 @@ +import { describe, it, expect } from 'vitest' +import { exportPage, type ExportOptions } from '@/lib/exporter/html' +import { pageSchema, type Page } from '@/lib/schema/page' + +function makePage(): Page { + return pageSchema.parse({ + title: 'Meta Robots', + locale: 'en', + theme: { primaryColor: '#2563eb', fontFamily: 'Inter' }, + sections: [ { type: 'hero', props: { heading: 'Hello', subheading: 'World', imageUrl: 'https://img/h.png' } } ], + form: { actionUrl: '', fields: [], spamProtection: { honeypotFieldName: '_hp', minSubmitSeconds: 2 } }, + seo: { title: 't', description: 'd' }, + }) +} + +describe('meta robots', () => { + it('기본적으로 head에 robots 메타가 없다', () => { + const page = makePage() + const out = exportPage(page) + expect(out.html).not.toContain(' { + const page = makePage() + const opts: ExportOptions = { robotsMeta: 'noindex,nofollow' } + const out = exportPage(page, opts) + expect(out.html).toContain('') + }) +})