본문 바로가기
REFLEX 튜토리얼

파인콘 웰컴페이지 소스 훑어보기

by 일코 2023. 1. 17.

파인콘 웰컴페이지입니다. (링크는 빼놓음)

소스코드는 아래와 같습니다.

간단해 보이지만 파인콘의 핵심이 되는 요소들이 전부 들어가 있으므로

프로젝트 구조와 더불어 이 코드를 한 번 훑어보는 것은 큰 도움이 될 것 같습니다.

"""Welcome to Pynecone! This file outlines the steps to create a basic app."""

from pcconfig import config

import pynecone as pc

docs_url = "https://pynecone.io/docs/getting-started/introduction"
filename = f"{config.app_name}/{config.app_name}.py"


class State(pc.State):
    """The app state."""
    pass


def index():
    return pc.center(
        pc.vstack(
            pc.heading("Welcome to Pynecone!", font_size="2em"),
            pc.box("Get started by editing ", pc.code(filename, font_size="1em")),
            spacing="1.5em",
            font_size="2em",
        ),
        padding_top="10%",
    )


# Add state and page to the app.
app = pc.App(state=State)
app.add_page(index)
app.compile()

 

라인별로 간단히 설명드려보겠습니다.

from pcconfig import config

pcconfig은 파인콘 프로젝트의 설정값이 들어있는 파일입니다.

장고의 settings.py와 비슷한 역할을 하는 듯 싶지만

앱 생성 초기에 내용이 그리 많이 들어있지는 않습니다.

설치된 pynecone의 소스코드를 훑어보면
장고의 settings.py와 비슷한 역할을 하는 파일은
사실 pcconfig.py보다는 constants.py임을 알 수 있습니다.

 

참고로 아래는 pcconfig.py 파일의 전체 코드입니다.

"""
프로젝트폴더/pcconfig.py
"""

import pynecone as pc


config = pc.Config(
    app_name="pynecone_tutorial",
    db_url="sqlite:///pynecone.db",
    env=pc.Env.DEV,
)
여기서 몇 가지 재미있는 사실을 유추할 수 있는데요.
기본적으로 메인 앱 역할을 하는 파일의 위치는
"프로젝트폴더/프로젝트폴더명.py"라는 사실입니다.
다른 하나는, 기본 데이터베이스가 sqlite라는 사실이고,
(pynecone.db가 sqlite포맷이었군요.)

 

import pynecone as pc

파인콘을 임포트하는 구문입니다. pc라는 임포트 컨벤션은
실은 컨벤션 정도가 아니라 거의 문법처럼 사용해야 하는 것 같습니다.
터미널에서 서버를 실행할 때의 커맨드도 pc인 걸 보면 말이죠.

 

filename = f"{config.app_name}/{config.app_name}.py"

메인앱 소스파일은 기본적으로 프로젝트명의 하위 폴더 안에 프로젝트명과 동일한 이름으로 생성하는 게
파인콘의 컨벤션인가봅니다. 우선 응용할 수 있는 수준까지는 파인콘에서 제공하는 컨벤션을 따릅시다.

 

class State(pc.State):
    """The app state."""
    pass

재미있는 부분이 나왔습니다. 앱을 구성하는 index와 별개로
컴포넌트들의 속성을 조회하거나 수정할 수 있는 State라는 클래스입니다.
웰컴페이지 예제에서는 State를 사용하지 않았지만, 다음 포스팅부터는
대부분 State를 사용할 것이기 때문에, 금방 익숙해지실 겁니다.

 

def index():
    return

django의 views.py가 생각나는 함수입니다.
참고로 index라는 함수명은 고정된 값이 아니므로,
main()이나 landing_page() 등으로 함수 이름을 수정하셔도 무방합니다.
다만, 코드 아랫쪽의 app.add_page() 메서드 안에 해당 함수를 인수로만 넣어주면 됩니다.

 

return pc.center(
    pc.vstack(
        pc.heading("Welcome to Pynecone!", font_size="2em"),
        pc.box("Get started by editing ", pc.code(filename, font_size="1em")),
        spacing="1.5em",
        font_size="2em",
    ),
    padding_top="10%",
)

index() 함수의 구현부입니다.
center는 중앙으로 정렬되는 일종의 컨테이너 역할의 컴포넌트,
vstack은 세로로 차곡차곡 쌓아주는 컴포넌트,
heading은 메서드이름 그대로 제목을 쓸 때 이용하는 컴포넌트(css가 kwargs로 들어가 있는 게 특징)
box는 다른 컴포넌트를 박스처럼 감싸주는 컴포넌트이고, pc.code 컴포넌트를 덮고 있습니다.
그 안의 pc.code는 텍스트를 인라인코드 스타일로 변환해줍니다. 내부적으로는 prism을 이용하네요.

그 외에는 css 문법이 키워드인수 형태로 들어가는 게 재미있습니다.

react나 nextjs에 대해 전혀 몰라도 큰 문제는 없겠지만
css나, 컴포넌트 종류에 대해서는 어느 정도 이해를 하고 있어야겠군요.
파인콘에서 제공하는 60여가지의 컴포넌트는 하나하나 포스팅으로 전부 다뤄보겠습니다.

이어서 페이지를 생성하고 state를 적용하는 코드들을 마저 훑어보겠습니다.

app = pc.App(state=State)

드디어 app이라는 인스턴스를 생성했습니다.
pc.App은 파인콘 웹애플리케이션 인스턴스를 생성하는 클래스이고,
코드를 살펴보면 백엔드에서 fastapi 기반으로 돌아갑니다.
이 예제에서는 인스턴스 초기화시에 state값만 넣었지만,
이후의 예제나 컴포넌스 소개 포스팅에서는 다양한 인자를 다뤄보겠습니다.

app 인스턴스는
add_default_endpoints, add_cors, preprocess, postprocess, add_middleware 등 미들웨어를 다루는 메서드나
add_page와 compile 메서드 등 페이지를 앱으로 로딩하거나 자바스크립트로 컴파일해서
.web 폴더 안에 생성해주는 메서드들을 다루고 있습니다.

 

app.add_page(index)

페이지를 앱으로 불러오는 코드입니다. 인수로 들어간 index는 위에서 정의한 함수명인데,
함수가 리턴하는 값은 어떤 컴포넌트라도 무관합니다.
참고로 add_page 안에서 path, title, description, image 등의 파라미터를 통해
타이틀이나 파비콘 등의 페이지 설정도 할 수 있습니다.

아래는 add_page 메서드의 기본 파라미터값입니다.

path = None,
title = "pynecone app",
description = "A pynecone app",
image = "favicon.ico"

 

이제 마지막 라인입니다.

app.compile()

 

파인콘의 실행방식은 다소 특인한데요. compile이라는 과정을 거쳐서
index()에서 정의한 컴포넌트 배치가
함수와 동일한 이름의 자바스크립트로 변환되어 저장됩니다.
저장경로는 프로젝트폴더/.web/pages/함수명.js 입니다.

index.js 파일을 한 번 찾아가 열어볼까요?

import {useEffect, useRef, useState} from "react"

import {useRouter} from "next/router"

import {connect, updateState} from "/utils/state"

import "focus-visible/dist/focus-visible"

import {Box, Center, Code, Heading, VStack} from "@chakra-ui/react"

import NextHead from "next/head"


const EVENT = "ws://localhost:8000/event"

export default function Component() {

    const [state, setState] = useState({"events": [{"name": "state.hydrate"}]})

    const [result, setResult] = useState({"state": null, "events": [], "processing": false})

    const router = useRouter()

    const socket = useRef(null)

    const {isReady} = router;

    const Event = events => setState({

        ...state,

        events: [...state.events, ...events],

    })

    useEffect(() => {

        if (!isReady)

            return;

        if (!socket.current) {

            connect(socket, state, result, setResult, router, EVENT)

        }

        const update = async () => {

            if (result.state != null) {

                setState({

                    ...result.state,

                    events: [...state.events, ...result.events],

                })

                setResult({

                    state: null,

                    events: [],

                    processing: false,

                })

            }

            await updateState(state, result, setResult, router, socket.current)

        }

        update()

    })

    return (

        <Center sx={{"paddingTop": "10%"}}>

            <VStack spacing="1.5em"

                    sx={{"fontSize": "2em"}}>

                <Heading sx={{"fontSize": "2em"}}>

                    {`Welcome to Pynecone!`}</Heading>

                <Box>

                    {`Get started by editing `}

                    <Code sx={{"fontSize": "1em"}}>

                        {`pynecone_tutorial/pynecone_tutorial.py`}</Code></Box></VStack>

            <NextHead>

                <title>{`Pynecone App`}</title>

                <meta name="description"

                      content="A Pynecone app."/>

                <meta property="og:image"

                      content="favicon.ico"/>
            </NextHead></Center>

    )

}

react, next, chakra-ui 등의 임포트문이 눈에 띄네요.
그리고 아래 리턴되는 html 코드가 바로 next.js를 거쳐 컴파일된 소스입니다.
위 코드를 통해 서버가 실행되는 것이지요.

이 포스팅 시리즈의 목적은 react나 next.js 등 자바스크립트에 대한 이해 없이
파인콘으로 웹앱을 구현하고자 함이므로, 자바스크립트에 대해서는 다루지 않겠습니다.
다만 react나 next.js 등의 프레임워크에 대해 조금 깊게 알아보고 싶으신 분은
노마드코더의 무료 강의를 추천드립니다.

ReactJS로 영화 웹 서비스 만들기 – 노마드 코더 Nomad Coders

 

ReactJS로 영화 웹 서비스 만들기 – 노마드 코더 Nomad Coders

React for Beginners

nomadcoders.co

NextJS 시작하기 – 노마드 코더 Nomad Coders

 

NextJS 시작하기 – 노마드 코더 Nomad Coders

The React Framework for Production

nomadcoders.co

 

그럼 이번 포스팅은 여기서 마치겠습니다.

수고하셨습니다.

 

 


부록 : 웰컴페이지의 link 컴포넌트 오류 해결방법

웰컴페이지 오류 때문에 pynecone이 다소 설익은 프레임워크라고 생각하신다면 경기도 오산입니다.
현재 빠르게 대처중이라고 하니, 부록을 남기는 것도 의미가 있겠나 싶지만
컴파일 과정에서 사소한 오류가 있어 보이므로, 같이 위 오류를 수정해봅시다.

우선 오류메시지는 다음과 같습니다.


Unhandled Runtime Error

Error: Multiple children were passed to <Link> with `href` of `https://pynecone.io/docs/getting-started/introduction` but only one child is supported https://nextjs.org/docs/messages/link-multiple-children Open your browser's console to view the Component stack trace.


Link 컴포넌트 안에는 1개의 href가 들어와야 하는데, 여러 개의 href가 붙었다는 메시지입니다.
'우린 파인콘 인트로덕션 href 밖에 넣은 적이 없는데?'
그럼, 컴파일된 index.js 파일을 열고, Link 컴포넌트가 어떻게 컴파일되어 있는지 살펴보겠습니다.

...

오류가 나지 않게 수정을 했는데
pc run 실행시 다시 컴파일이 되어버려서
포스팅은 포기합니다.
pinecone-io를 0.1.11로 다운그레이드해도
고쳐지지는 않는군요.

 

포스팅은 여기서 진짜로 마치겠습니다.
다음 포스팅에서는 간단한 인터랙션이 있는 예제 앱을 같이 하나 만들어보겠습니다.


다음 포스팅

2023.01.17 - [pynecone] - 파인콘 첫 번째 예제, 카운터 앱

 

파인콘 첫 번째 예제, 카운터 앱

카운터 앱 만들어보기 파인콘의 공식문서에서 제공하고 있는 첫 번째 예제, 카운터 앱을 같이 만들어봅시다. 전체 소스코드와 영문 설명은 아래 링크의 문서에서 확인하실 수 있습니다. https://py

martinii.fun

 

 


국내 유일의 파이썬+한컴오피스 업무자동화 입문강의

 

움짤로 빠르게 배우는 파이썬-아래아한글 자동화 레시피 - 인프런 | 강의

파이썬으로 아래아한글을 다루는 짧은 예제코드들을 소개하고, 중간중간의 결과를 GIF로 보여드립니다. 동영상 강의가 아니지만 오히려 빠르게 배울 수 있고, 따라하기도 쉽습니다., - 강의 소개

www.inflearn.com

 

댓글