자신의 웹사이트에 dev.to 게시물 포함
31190 단어 webdevsvelteopensourcetutorial
아직 확인하지 않으셨다면 제 웹사이트는 SvelteKit 및 Tailwind CSS로 구축되었으며 여기에서 완전히 오픈 소스입니다: https://github.com/nunogois/nunogois-website
이 기능에 대한 기본 커밋here을 확인할 수 있지만 아래에서 중요한 부분을 분석해 보겠습니다.
API
우선 게시물을 가져와야 합니다. API 을 사용하면 매우 쉽습니다. "게시 날짜별로 정렬된 게시된 기사"를 반환하는 getLatestArticles 엔드포인트를 사용했습니다.
제 경우에는 다음과 같습니다.
GET
https://dev.to/api/articles/latest?username=nunogois
- 브라우저에서 이 URL에 액세스하여 테스트할 수 있습니다.페이지 매김은 나중에 생각해야 할 것입니다.
어쨌든 이것을 내 웹사이트와 통합하기 위해 SvelteKit에서 내가 가장 좋아하는 기능 중 하나인 SvelteKit's endpoints을 활용했습니다.
src/routes/api.ts
에서 볼 수 있습니다.// ...
export async function get(): Promise<EndpointOutput> {
return {
body: {
// ...
blog: await loadBlog()
}
}
}
export const loadBlog = async (): Promise<JSONString[]> =>
await fetch('https://dev.to/api/articles/latest?username=nunogois').then((res) => res.json())
그런 다음 이 끝점은 내
index.svelte
구성 요소에 대한 소품으로 blog
배열을 전달하는 내 Blog
파일에서 가져옵니다.<script context="module">
export async function load({ fetch }) {
// ...
const res = await fetch('/api')
if (res.ok) {
return {
props: await res.json()
}
}
}
</script>
<script lang="ts">
//...
export let blog
</script>
<Blog {blog} />
블로그
내
Blog
구성 요소는 단일 페이지 웹 사이트의 섹션에 불과합니다. 여기서 관련된 부분은 src/pages/blog.svelte
에서 볼 수 있는 각 블로그 게시물에 대해 무언가를 반복하고 렌더링하는 것입니다.{#each filteredBlog as { slug, title, description, readable_publish_date, cover_image, tag_list, positive_reactions_count, comments_count, reading_time_minutes }}
<div class="border border-light-gray rounded-xl">
<a sveltekit:prefetch href={`/blog/${slug}`} class="flex flex-col h-full">
<img src={cover_image} alt={title} class="w-full rounded-t-xl object-cover" />
<h4 class="flex justify-center items-center text-lg font-medium p-2 border-light-gray">
{title}
</h4>
<span class="text-xs text-gray-300 mb-1"
>{readable_publish_date} - {reading_time_minutes} min read</span
>
<span class="text-xs text-gray-300">{tag_list.map((tag) => `#${tag}`).join(' ')}</span>
<div class="text-xs my-3 mx-5 text-justify">
{description}
</div>
<div class="flex-1 grid grid-cols-2 text-sm content-end">
<div class="flex justify-center items-center border-t border-light-gray border-r p-1">
<Icon icon="fa:heart" width="16px" class="inline-block mr-1" />
{positive_reactions_count}
</div>
<div class="flex justify-center items-center border-t border-light-gray border-r p-1">
<Icon icon="fa:comment" width="16px" class="inline-block mr-1" />
{comments_count}
</div>
</div>
</a>
</div>
{/each}
이것은 모든 Tailwind CSS 클래스와 약간의 조정으로 인해 현재 약간 엉망이지만 지금은 정확히 내가 원하는 대로 보입니다. 곧 자체 구성 요소로 리팩토링해야 합니다(
BlogItem
또는 이와 유사한 것).이제 모든 블로그 게시물이 표시되었으므로 게시물을 열고 읽을 수 있는 방법이 필요합니다. 위의 앵커 태그를 확인하십시오.
<a sveltekit:prefetch href={`/blog/${slug}`}...
slug
는 블로그 게시물을 고유하게 식별합니다.강타
SvelteKit의 멋진 기능을 더 많이 활용하여 새
src/routes/blog/[slug].svelte
파일을 만들었습니다.<script context="module" lang="ts">
// ...
import Icon from '@iconify/svelte'
export async function load({ page, fetch }) {
const url = `https://dev.to/api/articles/nunogois/${page.params.slug}`
const response = await fetch(url)
return {
status: response.status,
props: {
post: response.ok && (await response.json())
}
}
}
</script>
<script lang="ts">
export let post
</script>
<div class="flex justify-center">
<div class="flex flex-col w-full px-4 md:px-24 max-w-screen-lg text-justify pt-16">
<div class="border-b border-light-gray md:border md:rounded-xl">
<img src={post.cover_image} alt={post.title} class="w-full rounded-t-xl object-cover mb-4" />
<div class="md:px-4">
<div class="flex">
<h3 class="w-full text-left text-2xl md:text-3xl font-medium">
{post.title}
</h3>
<a href={post.url} class="w-8"
><Icon icon="fa-brands:dev" width="32px" class="inline-block" /></a
>
</div>
<div class="flex flex-col pt-2 pb-6 gap-1 text-xs text-gray-300">
<span>{post.readable_publish_date}</span>
<span>{post.tags.map((tag) => `#${tag}`).join(' ')}</span>
</div>
<div class="blog-post">
{@html post.body_html}
</div>
</div>
</div>
<a href={post.url} class="mt-5 text-center">React to this blog post on DEV Community 👩💻👨💻</a>
<a href="/" class="my-5 text-center text-sm">www.nunogois.com</a>
</div>
</div>
이것은 URL에서
slug
를 가져오고 이를 사용하여 각 기사 끝점을 가져와 소품에 전달합니다. 그런 다음 원하는 대로 게시물을 렌더링하기만 하면 됩니다.CSS
다음은 블로그 게시물과 포함된 콘텐츠를 올바르게 표시하기 위해 지금까지 추가한 특정 CSS
src/app.css
입니다..blog-post p {
margin-bottom: 20px;
}
.blog-post > .crayons-card {
border-width: 1px;
--tw-border-opacity: 1;
border-color: rgb(51 51 51 / var(--tw-border-opacity));
border-radius: 0.75rem;
margin-bottom: 20px;
}
.blog-post > .crayons-card > .c-embed__cover img {
object-fit: cover;
max-height: 200px;
border-top-left-radius: 0.75rem;
border-top-right-radius: 0.75rem;
}
.blog-post > .crayons-card > .c-embed__body {
padding: 20px;
}
.blog-post > .crayons-card > .c-embed__body > h2 {
margin-bottom: 8px;
color: #93ceff;
}
.blog-post > .crayons-card > .c-embed__body > .truncate-at-3 {
font-size: 0.875rem;
margin-bottom: 8px;
}
.blog-post > .crayons-card > .c-embed__body > .color-secondary {
font-size: 0.875rem;
}
.blog-post > .crayons-card .c-embed__favicon {
max-height: 18px;
width: auto;
margin-right: 14px;
}
여기에서 어떻게 보이는지 확인할 수 있습니다. https://www.nunogois.com/blog/hello-world-4pdf
내가 그렇게 말하면 꽤 멋져 보입니다!
동적 sitemap.xml 및 rss.xml
보너스 라운드의 경우 동적
sitemap.xml
및 rss.xml
를 설정해 보겠습니다.참고: 여기에서는 배포 후 표시되도록 어떻게든 코드에서 엔드포인트를 참조해야 했기 때문에
index.svelte
에서 가져오는 것입니다.fetch('/sitemap.xml')
fetch('/rss.xml')
소스 파일은 다음과 같습니다.
사이트맵.xml
https://www.nunogois.com/sitemap.xml
다음은
src/routes/sitemap.xml.ts
입니다.import { loadBlog } from './api'
const website = 'https://www.nunogois.com'
export async function get(): Promise<unknown> {
const posts = await loadBlog()
const body = sitemap(posts)
const headers = {
'Cache-Control': 'max-age=0, s-maxage=3600',
'Content-Type': 'application/xml'
}
return {
headers,
body
}
}
const sitemap = (posts) => `<?xml version="1.0" encoding="UTF-8" ?>
<urlset
xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="https://www.google.com/schemas/sitemap-news/0.9"
xmlns:xhtml="https://www.w3.org/1999/xhtml"
xmlns:mobile="https://www.google.com/schemas/sitemap-mobile/1.0"
xmlns:image="https://www.google.com/schemas/sitemap-image/1.1"
xmlns:video="https://www.google.com/schemas/sitemap-video/1.1"
>
<url>
<loc>${website}</loc>
<changefreq>daily</changefreq>
<priority>0.7</priority>
</url>
${posts
.map(
(post) => `
<url>
<loc>${website}/blog/${post.slug}</loc>
<changefreq>daily</changefreq>
<priority>0.7</priority>
</url>
`
)
.join('')}
</urlset>`
rss.xml
https://www.nunogois.com/rss.xml
다음은
src/routes/rss.xml.ts
입니다.import { loadBlog } from './api'
const website = 'https://www.nunogois.com'
export async function get(): Promise<unknown> {
const posts = await loadBlog()
const body = xml(posts)
const headers = {
'Cache-Control': 'max-age=0, s-maxage=3600',
'Content-Type': 'application/xml'
}
return {
headers,
body
}
}
const xml = (
posts
) => `<rss xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:atom="https://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Nuno Góis - Full-Stack Developer</title>
<link>${website}</link>
<description>Full-Stack Developer from Portugal. Experienced with every step of developing and delivering software projects using .NET C#, JavaScript, Go, Python, and more.</description>
${posts
.map(
(post) =>
`
<item>
<title>${post.title}</title>
<description>${post.description}</description>
<link>${website}/blog/${post.slug}/</link>
<pubDate>${new Date(post.published_timestamp)}</pubDate>
<content:encoded>${post.description}
<br />
<a href="${website}/blog/${post.slug}">
Read more
</a>
</content:encoded>
</item>
`
)
.join('')}
</channel>
</rss>`
결론
도중에 몇 가지 수정 및 최적화를 수행하여 다음과 같은 Lighthouse 점수를 얻었습니다.
누노 고이스 👨🏻💻
@nunogois_dev
nunogois.com 몇 가지 업데이트와 새로운 dev.to 블로그 통합으로 Lighthouse에서 매우 산뜻해 보입니다 😎이 새로운 기능을 테스트하고 즐겨야 하므로 곧 몇 가지 사항을 게시해야 하므로 계속 지켜봐 주시기 바랍니다.
오후 22:14 - 2022년 6월 15일
이 통합은 확실히 완료되지 않았으며 이 게시물을 올바르게 표시하려면 이 게시물을 게시한 직후 몇 가지 추가 작업을 수행해야 할 것입니다. 그래도 꽤 재미있고 쉽게 할 수 있는 일이었습니다.
또한 웹 사이트 코드를 약간 리팩토링하고 정리하는 데 시간이 좀 걸릴 것이므로(모든 곳에 적절한 유형이 있어야 함) 계속 지켜봐 주시기 바랍니다.
내 웹사이트를 기반으로 자유롭게 웹사이트를 만들거나 영감을 받아보세요. 그렇다면 다음 문서를 살펴보는 것이 좋습니다.
또한 공유해 주세요. 확인하고 싶습니다!
Reference
이 문제에 관하여(자신의 웹사이트에 dev.to 게시물 포함), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/nunogois/embed-devto-posts-into-your-own-website-36jj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)