Sapper & Markdown으로 블로그 만들기

SapperSvelte 앱을 만들기 위한 툴킷입니다. 프로젝트를 신속하게 시작하고 실행할 수 있도록 도와주는 다양한 규칙이 함께 제공됩니다.

정적 사이트로 배포하거나 서버 측 렌더링과 클라이언트 측 렌더링을 모두 수행하는 node.js 서버+SPA로 배포할 수 있습니다.

참고: 기사 끝부분에서 이에 대한 스크린캐스트를 찾을 수 있습니다.

개념



블로그 게시물을 repo 내부에 마크다운.md 파일로 저장할 것입니다. 그렇게 하면 게시물 편집을 위한 워크플로로 git를 사용할 수 있습니다. 즉, 게시물 검토를 위한 풀 리퀘스트git log, 변경 내역 보기, 여러 작성자가 있는 경우 분기/분기를 의미합니다.

데이터는 데이터베이스가 아닌 정적 파일에서 가져오기 때문에 서버 측 구성 요소가 필요하지 않으며 Sapper의 정적 사이트 생성기를 사용하여 이를 배포할 수 있습니다.

설정


degit 로 앱을 스캐폴딩하여 시작합니다.

공식 svelte/sapper-template 을 사용할 수 있지만 데모 코드가 많이 포함되어 있습니다. 데모 코드가 없는 백지 포크 joshnuss/sapper-template 를 사용하겠습니다.

npx degit joshnuss/sapper-template blog
cd blog
yarn install


게시물 데이터



각 게시물은 posts 디렉토리에 저장되고 파일의 맨 위에 yaml 메타데이터를 포함합니다(앞부분이라고도 함).

게시물posts/example.md은 다음과 같습니다.

--------
title: Everything you wanted to know
summary: A short post about ...
date: 2020-04-01
--------

- this
- is
- markdown


플러그인



빌드 시 .md를 사용하여 이러한 fs.readFile() 파일을 로드할 수 있지만 import 문을 사용하는 더 쉬운 방법이 있습니다.
rollup 가져오기에 대해 .md를 구성하려면 플러그인 @jackfranklin/rollup-plugin-markdown 을 사용합니다.

이를 통해 다음을 수행할 수 있습니다.

import post1 from 'posts/example1.md'
import post2 from 'posts/example2.md'
// ...


물론 각 게시물을 하나씩 가져오는 것은 지루할 것입니다. 😅
posts/*.md 와 같은 와일드카드 검색 패턴을 기반으로 한 번에 많은 파일을 가져오는 것이 더 쉬울 것입니다. 플러그인 rollup-plugin-glob 이 정확히 이 작업을 수행합니다. 🚀

NPM 패키지를 추가합니다.

yarn add -D @jackfranklin/rollup-plugin-markdown rollup-plugin-glob


그런 다음 이 플러그인을 사용하도록 rollup 지시하십시오. 업데이트rollup.config.js:

// import plugins
import markdown from '@jackfranklin/rollup-plugin-markdown'
import glob from 'rollup-plugin-glob'

// ....

// remember rollup is creating multiple builds
// make sure to add the new plugins to both the server *and* client builds
export {
  client: {
    plugins: [
      markdown(),
      glob(),
      ...
    ],
    ...
  },

  server: {
    plugins: [
      markdown(),
      glob(),
      ...
    ],
    ...
  }
}


게시물 읽기



이제 .md 를 가져올 수 있으므로 src/posts.js 내부의 게시물에 액세스하기 위한 논리를 중앙 집중화해 보겠습니다.

import all from '../posts/*.md'

export const posts = all


우리가 console.log(posts) 인 경우 게시물의 데이터는 현재 다음과 같습니다.

[
  {
    metadata: {title: 'the title', summary: '...', date: '2020-01-02'},
    html: '<h1>...</h1>',
    filename: 'example.md'
  }
]


UI를 더 쉽게 사용할 수 있도록 약간 변형해 보겠습니다.

다음과 같이 개선할 예정입니다.
  • metadata ( title , summary , date )를 최상위 수준에 둡니다.
  • permalink 필드를 추가합니다. filename를 기반으로 합니다.
  • 게시물 목록을 내림차순으로 date 정렬 (최신 게시물 먼저)
  • src/posts.js 다음과 같이 변경합니다.

    import _ from 'lodash'
    import all from '../posts/*.md'
    
    export const posts = _.chain(all) // begin a chain
                          .map(transform) // transform the shape of each post
                          .orderBy('date', 'desc') // sort by date descending
                          .value() // convert chain back to array
    
    // function for reshaping each post
    function transform({filename, html, metadata}) {
      // the permalink is the filename with the '.md' ending removed
      const permalink = filename.replace(/\.md$/, '')
    
      // convert date string into a proper `Date`
      const date = new Date(metadata.date)
    
      // return the new shape
      return {...metadata, filename, html, permalink, date}
    }
    
    // provide a way to find a post by permalink
    export function findPost(permalink) {
      // use lodash to find by field name:
      return _.find(posts, {permalink})
    }
    


    색인 페이지



    이제 게시물이 있으므로 UI로 이동할 수 있습니다.
    src/routes/index.svelte를 열고 각 게시물에 대해 <article> 태그를 표시합니다.

    <script>
      // import the list of posts
      import {posts} from '../posts'
    </script>
    
    <h1>My Weblog</h1>
    
    <!-- iterate through each post -->
    {#each posts as post}
      <article>
        <!-- link article to /posts/$permalink -->   
        <a href={`/posts/${post.permalink}`}>
          <h2>{post.title}</h2>
          <p>{post.summary}</p>
        </a>
      </article>
    {/each}
    


    블로그 세부정보 페이지



    이제 색인 페이지에 각 게시물의 요약이 표시되어 전체 게시물이 src/routes/posts/[permalink].svelte 라는 페이지/경로를 추가하는 것을 볼 수 있습니다.
    [permalink] 주위에 대괄호를 사용하고 있다는 것을 알 수 있습니까? 이는 permalink가 동적 매개변수임을 sapper에게 알려줍니다. Sapper는 preload() 함수에 모든 매개변수를 제공합니다.

    <script context="module">
      // import the logic for finding a post based on permalink
      import {findPost} from '../../posts'
    
      // sapper calls this to load our data
      export function preload(page) {
        // find the post based on the permalink param
        const post = findPost(page.params.permalink)
    
        // return a list of props
        return { post }
      }
    </script>
    
    <script>
      // this prop is filled from the result of the `preload()`
      export let post
    </script>
    
    <!-- display the post -->
    <h1>{post.title}</h1>
    
    {@html post.html}
    


    배포



    사이트를 배포하기 위해 yarn export 를 사용하여 정적 사이트를 생성할 수 있습니다.
    🛳 zeit를 사용하는 동안 다음을 수행할 수도 있습니다.

    yarn export
    now
    


    그게 다야, 모두 끝났어! 💃

    요약



    Sapper로 정적 사이트를 구축하는 것은 거의 노력이 필요하지 않습니다.
    정적 데이터를 가져올 수 있는 형식으로 변환할 수 있는 유용한 롤업 플러그인이 많이 있습니다. 즉, 많은 경우 데이터에 대한 파서를 작성할 필요조차 없습니다.

    이 접근 방식의 또 다른 좋은 점은 '다용성'입니다. 프로젝트 페이지, 위키, 뉴스 사이트, 책, 랜딩 페이지 등에 동일한 개념이 적용됩니다. git 리포지토리에 넣을 수 있는 모든 데이터는 Sapper 사이트의 드라이버가 될 수 있습니다.

    여기에서 예제 코드를 찾을 수 있습니다.
    https://github.com/joshnuss/sample-blog

    즐거운 코딩! ✌

    추신. 이것은 곧 있을 svelte 과정의 일부입니다. http://svelte.video

    스크린캐스트

    좋은 웹페이지 즐겨찾기