[Sapper] export로 완전 정적 사이트 만들기 [Svelte]


(Sapper 강한 헬로 월드 화면)

앞으로 온다든지 오지 않는다든가, 해외에서는 이미 오고 있다고 말해지고 있는 web 프런트 엔드 JS 의 프레임워크(컴파일러)의 Svelte.
이번은 그 Svelte를 웹 애플리케이션 제작 용도로 확장하는 프레임워크, Sapper의 이야기.

{참고}
  • 최근 이름을 자주 보는 svelte/sapper를 시험해 보았다 ~그 1 도입편~
  • Vue 사용하면 초에 기억할 수 있는 Svelte 입문

  • 정적 생성



    SSR 메인 프레임워크로 만든 사이트를 Netlify 등의 정적 파일 호스팅 서비스로 운용한다.
    Nuxt.js로 말하면 nuxt generate, Next.js로 말하면 next export가 해당한다.

    Sapper에서는 sapper export가 그에 해당한다.

    문제점 : 페이지 전환 시 API 요청이 실행됨



    ※오류 핸들링은 생략

    /src/routes/example.svelte
    
    <script context="module">
        export async function preload() {
    
            const res = await this.fetch('https://your-api-endpoint-here.com/');
            const data = await res.json();
    
            if (res.status === 200) {
                return { post: data };
            }
        }
    </script>
    
    <script>
        export let post;
    </script>
    
    {@html post.content}
    

    위와 같은 svelte 를 sapper export 해, 톱 페이지에 액세스 후 이 svelte 에 대응하는 페이지 (/example )에 a 태그 천이 해 보면, 클라이언트측으로부터 API 서버에의 fetch 가 발생해 버린다.

    즉, preload 함수 (Nuxt.js asyncData/Next.js getInitialProps)가 그대로 클라이언트 측에서 실행됩니다.
    ※ Sapper 에서는 a 태그는 디폴트로 History API 를 사용한 천이가 된다

    API 서버가 그다지 강하지 않을 때나, 리밋트가 마련되고 있는 등, 이 사양은 받을 수 없는, 완전 정적으로 하고 싶다고 느끼었을 때에 다음의 방법으로 해결할 수 있다.

    솔루션 : API 통신에 프록시 준비


    this.fetch 대상을 갑자기 API 서버로 만드는 대신 로컬로 향합니다.

    /src/routes/example.svelte
    <script context="module">
        export async function preload() {
            //ここでいきなり https://~~ ではなく、ローカルを参照する
            const res = await this.fetch('api.json');
            const data = await res.json();
    
            if (res.status === 200) {
                return { post: data };
            }
        }
    </script>
    

    그리고이 지역을 향한 곳

    /src/routes/api.json.js
    
    import fetch from 'node-fetch'
    
    export async function get(req, res) {
        fetch(`https://your-api-endpoint-here.com/`)
            .then(response => response.json())
            .then(json => {
                res.writeHead(200, {
                    'Content-Type': 'application/json'
                });
                res.end(JSON.stringify(json))
            })
    }
    
    

    그리고 API 서버와 통신하여 내용을 반환하는 js를 설치한다.
    (통신 라이브러리에 node-fetch를 사용하고 있지만, 비슷한 것이라면 무엇이든 좋다고 생각한다)

    이 상태에서 sapper export 하면, API 서버로부터의 응답 내용이 정적 파일( json )로서 확실히 써내져 페이지 천이시도 이 로컬 json 를 참조하게 된다.




    sapper export 때의 메커니즘
    Docs • Sapper #How it works
  • sapper build 생성 된 프로덕션 파일 (이 단계에서는 여전히 SSR)을 크롤링하고 루트에서 모든 a 태그를 캡처하여 정적 파일로 만듭니다.
  • preload 함수의 this.fetch 끝도 캡처하여 정적 파일로 만듭니다.

  • 그러나



    Is it possible to run preload once for completely static html generate when "sapper export" was used? · Issue #972 · sveltejs/sapper

    If preload is calling this.fetch and that's getting a file at a local path, that response will also be saved when export is crawling the site. If the data is coming from a remote server, you can make a local endpoint that proxies to the remote endpoint, and have this.fetch request that.

    정적 파일로 하는 것은 로컬 패스만.
    그래서 this.fetch 에 리모트 패스를 직접 쓰는 것이 아니라, 일단 로컬 패스로 해, 프록시 하면, 프록시 한 내용을 캡쳐 해 정적 파일이 생성된다, 하는 구조.



    이 Svelte/Sapper는 Vue/Nuxt를 한 적이있는 사람이라면 꽤 붙어 쉽다고 느꼈습니다.
    학습면에서 말하면 공식 튜토리얼이 충실한 것도 매력입니다.
    개인적으로 Sapper의 a 태그를 역기능으로 전력 캡쳐하는 구조는 마음에 들었습니다.
    루트 지정하지 않아도 좋기 때문에 편합니다.

    $Thank$ $You$.

    좋은 웹페이지 즐겨찾기