터미널에서 입력하는 명령어일 경우
>
로 작성함
해당 포스팅의 경우 따라해보기이기 때문에 개념이나 기타 지식에 대한 설명이 부족할 수 있습니다.
이전 포스팅에서 그냥 Python이랑 Flask만 사용해서 프로젝트를 구성하려고 했더니 프론트 라이브러리/프레임워크 붙이는 게 녹록치 않아서.. 아예 백엔드랑 프론트엔드를 분리해 프로젝트를 구성해보려고 한다.
프론트는 Svelte를 사용해보자.
우선 nodejs를 다운로드 받는다.

msi파일이 다운로드되면 실행해서 node를 설치한다. 변경할거없이 그냥 계~~~~~~~~~~속 다음버튼을 누르자
터미널에
> node -v
를 쳤을 때 20.11.0이라고 나오면 설치가 잘 된거다.
참고한 글
https://v3.routify.dev/docs/guide/installation/manual-installation
https://freeseamew.gitbook.io/svelte/4./bind
1. 프로젝트 폴더 경로로 터미널 경로도 맞춰준다 (main.py 파일이 있는 폴더에 들어간다)
원래 있던 파일들중에서는 main.py, venv 폴더, .env 빼고 모두 지우자.
ex)
C:\Users\User\.cursor-tutor\prj가 프로젝트 경로라면
터미널에서 경로도 위와 같도록 맞춰준다.
상위 폴더로(한 단계 바깥폴더로)
> cd ..
하위 폴더로(한 단계 안쪽폴더로)
> cd prj
2. sveltjs 및 routify 설치 (sveltjs 및 routify 가 client폴더 하위에 설치된다.)
> npm init routify@latest







> cd client
* client 경로는 각각 만든 폴더명으로 바꿔 입력하면 됨. 앞으로 만든 폴더명은 client로 작성하겠음
> npm run dev


그리고나서는 우선 터미널에서 Ctrl + C 를 눌러 프론트엔드 서버를 종료하자.
3. IDE로 돌아와 prj/client/src 폴더를 확인해보자.

이런 구조로 되어있는데, 각각 파일 및 폴더는 아래와 같은 역할을 한다.
3-1. components
- 재사용할 템플릿을 넣는다. 예를 들면 Header, Footer, Nav, ProgressBar, List, Table 등등 공통 템플릿을 넣는다고 보면 된다.
3- 2. routes
- routify는 기본적으로 routes 하위 폴더 구조를 기준으로 라우팅해준다. 그리고 그 폴더의 index.svelte를 라우팅해주는거다. * routes/index.svelte을 /경로에서 보여준다.
- 이게 무슨소리냐면 현재 routes/examples/[mode]/{하위폴더들.. 예를들어 history}로 되어있는데 이는 브라우저에 http://localhost:1337/examples/[mode]/history를 입력하면 examples안에 있는 [mode]안에 있는 history폴더를 바라보겠다는 뜻이다.
- [mode]는 무엇이냐하면 파라미터다. mode라는 이름으로 파라미터를 받겠다는거다.
브라우저에 http://localhost:1337/examples/full/history 이라고 입력하면 /routes/examples/[mode] 폴더 내의 _module.svelte에서는 mode라는 변수를 받을 수 있는데 여기에 바로 full이라는 값이 들어가 있다.
- 여기서 또, 그럼 _module.svelte는 뭐냐? 바로 공통 레이아웃을 잡아주는 파일이다. 여기서 기본적인 틀을 잡는다.
폴더는 다 봤으니 파일을 보자
3- 3. App.svelte
- 가장~~~~~최상위의 컴포넌트라고 보면 된다. 딱히 건드릴 코드는 없으니 놔두자. 라우팅에 대한 코드가 들어가있다.
3- 4. main.js
- 실질적인 프론트엔드 서버라고 해야할까? 앱을 실행하면 가장 먼저 실행되는 코드다. 여기 또한 건드릴 게 딱히 없으니 놔두자.
3- 5. types.d.ts
- 흠 일단 무시하자 이번 포스팅들에서는 딱히 건드릴 일 없는 파일이다.
3- 6. package.json
- 실행 스크립트 및 의존성 등이 들어가있다. 웬만하면 건드리지 말자.
3- 7. index.html
- 가장 기본 틀이 될 html 마크업이다. 외부 css나 script를 불러오려면 여기에 추가하면 된다.
3- 8. tsconfig.json
- typescript에 대한 설정값인데 건드릴 부분이 크게 없다.
3- 9. vite.config.js
- vite.js에 대한 설정값인데 건드릴 부분이 크게 없다.
4. 그럼 semantic-ui를 먼저 추가하자.
/client/src/index.html 파일을 열어 jquery 및 css와 js를 불러오는 스크립트를 추가한다.
head 태그 내부의 <script type="module" src="/.routify/routify-init.js"></script> 아래에 추가한다.
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.js"></script>
5. 다음으로는 store 라는 것을 만들어줄건데, 이게 뭐냐면 svelte에서 사용하는 저장소?같은거라고 보면 된다.
왜 만드냐면 우리는 이제 페이지마다 들고 다녀야 하는 데이터가 있을 수 있다. 예를 들면 로그인한 회원의 닉네임이라던가, Header Title 이라던가.. 그리고 또 부모 컴포넌트와 자식 컴포넌트 사이에 데이터를 주고 받아야 할 일이 생길 것이기 때문에 만들어 보려고 한다.
/client/src/ 경로에 store.js 파일을 생성하고 아래 코드를 추가한다.
import { writable } from 'svelte/store'
export const headerName = writable('')
export const userName = writable('')
수정이 가능한 headerName과 userName을 만들었다.
6. 다음은 우선 레이아웃을 만들어보자. /client/src/ 경로에 components라는 폴더를 만들고 그 안에 Header.svelte, Footer.svelte 파일을 만들어주자. 내용은 나중에 입력하면 되니 대충 <div>header~</div>이나 <div>footer~</div> 같은 마크업만 넣어두자.
그리고서 /client/src/routes/_module.svelte 파일을 열어 아래 코드를 추가한다.
<script>
import { headerName } from '../store.js'
import Header from '../components/Header.svelte'
import Footer from '../components/Footer.svelte'
let headerValue;
headerName.subscribe((data) => {
headerValue = data;
})
</script>
<div class="ui">
<Header headerName={headerValue} />
<slot />
<Footer />
</div>
headerName.subscribe(()=>{}) 해당 부분이 바로 store에서 headerValue를 가져오는 코드다.
아래 마크업쪽을 보면 <Header headerName={headerValue} />가 있는데 이게 바로 아까 components에 만든 Header를 불러와 HeaderName이라는 변수명으로 headerValue를 넘겨준다는 것이고, <slot />은 컨텐츠가 들어갈 곳이며 <Footer /> 또한 Footer 컴포넌트를 가져오는거다.
다른 페이지에 들어갔을 때 아래처럼 디폴트 레이아웃이 잡힌다는 뜻이다.
<div class="ui">
<div>Header~</div>
....contents
<div>Footer~</div>
</div>
자 그러면 Header 컴포넌트에 HeaderName을 넘겨주었기 때문에 Header에 해당 값을 뿌려줘보도록 하자.
Header.svelte 파일로 이동해 코드를 아래와 같이 수정한다.
<script>
export let haderName;
</script>
<div>
{headerName}
</div>
이러면 스크립트 단에서 변수로 받아온 headerName을 div에 보여줄 수 있다.
7. 메인 화면을 만들어보자.
/client/src/routes/index.svelte 파일을 열어 아래 코드를 추가한다.
<script>
import { onMount } from "svelte";
import { headerName } from "../store";
onMount(async () => {
headerName.set('메인화면')
})
</script>
<div>
내용입니다
</div>
그리고 서버를 실행한 뒤 브라우저에서 접속해보면 짜잔~

8. 이제 백엔드 서버와 API로 소통해보자.
우선 cors 설정을 위해 라이브러리 하나를 다운로드 받자.
> pip install flask_cors
main.py 파일을 열어 API를 하나 추가한다.
from flask import Flask,render_template,session, request, send_from_directory, make_response, jsonify
from openai import OpenAI
from dotenv import load_dotenv
from flask_cors import CORS
import os
import uuid
app = Flask(__name__)
#uuid로 변경
app.secret_key = uuid.uuid4().hex
#서로 다른 도메인인 url이라도 요청 가능하게 CORS처리 (중요)
CORS(app)
# First API
@app.route('/data')
def data():
print('Request:: Data')
try:
return make_response(jsonify({"result": True, "resultCode": 200, "message": "와~ 성공!"}), 200)
except Exception as e:
print('-----------------------')
print('Error:: Data')
print(e)
print('-----------------------')
return make_response(jsonify({"result": False, "resultCode": 500, "message": "실패ㅠㅠ"}), 500)
실행한다.
이제 vite.config.js 파일을 열어 맨 하단으로 스크롤을 내려보자.

해당 부분을

이런식으로 바꿔준다. 포트는 그냥 내가 지정해둔거라 따라하시는 분들은 그냥 그대로 두셔도 무관함
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ''),
secure: false,
}
}
},
이게 무슨 소리냐, 프론트엔드에서 /api/data 로 요청하면 /api는 공백으로 치환하고 localhost:5000의 /data로 요청한다는 뜻이다.
/api/data ▶ http://localhost:5000/api/data ▶ http://localhost:5000/data로 요청
저장했으면 /client/src/routes/index.svelte로 이동해보자.
<script>
import { onMount } from "svelte";
import { headerName } from "../store";
onMount(async () => {
headerName.set('메인화면')
})
let content = '내용입니다.';
const getData = async () => {
const response = await fetch('/api/data', {
method: 'GET'
})
.then((response) => response.json())
.then((data) => {
if(data.result == true){
content = data.message
}else{
content = '요청이 실패했어요..ㅠㅠ';
}
})
.catch((error) => {
console.error('error', error);
});
}
</script>
<div>
<p>
{content}
</p>
<button on:click={getData}>요청</button>
</div>
화면이 모두 그려지고나면 headerName을 "메인화면"으로 바꾸고, content에는 디폴트 값으로 "내용입니다." 를 넣어준다.
그리고 [요청] 이라는 버튼을 만들어 클릭할 경우 getData()라는 함수를 실행해 api서버의 /data에 요청을 보내 값을 받아오고, 그 값을 content에 할당해 컨텐츠 내용을 바꿔주는 코드다.
우선 새 터미널을 하나 열어 프론트엔드 서버를 실행시켜주자.

그리고 경로를 ...\{프로젝트폴더}\{프론트엔드 서버 폴더(나는 client)}로 맞춰준 뒤 아래 명령어를 실행한다.
> npm run dev
그리고 브라우저에 url을 입력해보면? 짜잔~ (포트를 따로 수정하지 않았다면 http://localhost:1337)

요청을 한 번 눌러보자~

아까 python 코드로 리턴해줬던 문구로 변경되는 것을 볼 수 있다.
다음 포스팅에서는 위 내용들을 응용해 백엔드에서 ChatGPT와 소통하고 화면에 실시간으로 뿌려주는 것을 해 볼 예정이다.
다음 포스팅
이전 포스팅
2024.01.30 - [파이썬] - Flask를 이용해 ChatGPT를 이용한 챗봇이 있는 웹페이지 만들어보기 2 [Python, OpenAI, Flask, Cursor IDE]