-
[MindBook] Nextron + Typescript + TailwindCSS 설치하기Studying/Proj 과정 2024. 2. 3. 17:53
개요
Electron은 NodeJS를 기반으로 Javascript, HTML, CSS를 사용해 데스크톱 애플리케이션을 만들 수 있는 프레임워크입니다. 웹에 윈도우, 맥, 리눅스 환경에 모두 사용 가능한 애플리케이션을 지원합니다.
(대학 과제로 MindBook 프로젝트를 만들었을 때 데스크톱 애플리케이션을 구현하고 싶었는데, 당시엔 Javascript는 물론 React가 뭔지도 모르는데다 서칭 능력도 형편 없어서 그냥 Vue.js로 부랴부랴 웹 환경의 프로토타입을 만든 적이 있습니다. 그때 조금 더 자세히 공부했으면 좋았을텐데.. 지금이라도 간간히 MindBook을 데스크톱 애플리케이션 버전으로 다시 만들어볼까 싶습니다)
Nextron 프로젝트 빌드하기
아래 명령어를 통해 Nextron application을 생성합니다.
npx create-nextron-app appName
Nextron은 Tailwind CSS, Ant Design, MUI, Emotion 등 다양한 CSS 프레임워크에 더하여 Typescript까지 지원하는 다양한 예시 템플릿을 제공합니다. 모든 템플릿은 여기서 확인할 수 있으며, 프로젝트에 쓰일 템플릿을 결정한 뒤, --example 옵션을 붙인 명령어로 설치할 수 있습니다.
만약 TypeScript와 Tailwind 템플릿을 사용하고 싶다면, 다음 명령어를 입력하면 됩니다.
npx create-nextron-app my-app --example basic-lang-typescript with-tailwindcss
프로젝트를 생성했다면 필요한 모든 종속성들을 설치합니다.
npm install # OR yarn
이제 다음 명령어로 Nextron+Tailwind+Typescript 애플리케이션을 실행시킬 수 있습니다.
npm run dev # OR yarn dev
실행시킨 결과 화면입니다.
Nextron 프로젝트 파일 구조
Electron은 크게 보면 main 폴더와 render 폴더 두 개의 프로세스로 동작합니다.
main 폴더는 데이터베이스 통신 및 파일 처리 등 서버에서 실행되는 파일을 담고, renderer 폴더는 실제 클라이언트 화면에 그려지는 page 파일을 담습니다.
두 서버/클라이언트 프로세스는 ipcMain, ipcRenderer 라는 두 가지 IPC(Inter Procss Communication) 모듈을 통해 통신합니다.
그 외는 아래와 같습니다.
- main/helpers - 서버에서 실행되는 파일을 모아둡니다. BrowseWindow 인스턴스를 생성해 윈도우 데스크톱 애플리케이션을 생성합니다. initial size, position 같은 기본 윈도우 애플리케이션 옵션들을 options라는 props으로 입력받습니다.
- main/background.js - 클라이언트에서 실행되는 파일을 모아둡니다. createWindow 함수가 초기화되는 장소이자 Next.js 애플리케이션을 Electron 애플리케이션으로 제공합니다.
- resources/ - 이미지, 아이콘 등 애플리케이션 내에서 사용되는 정적 리소스 파일을 저장합니다.
더 자세한 폴더 구조 및 용도는 아래 블로그에서 친절하고 자세하게 설명하고 있습니다.
Nextron이 동작하는 과정
넥스트론은 개발 모드인지 운영 모드인지 자동으로 확인합니다. 개발 모드의 경우 localhost url을 가져가 Eletron 애플리케이션으로 제공합니다. 반면 운영 모드의 경우 Next.js 빌드에서 생성한 정적 파일을 가져와 렌더링 합니다.
관련 코드는 main/background.ts 파일을 보면 더 자세하게 확인 가능합니다.
// /main/background.ts const isProd = process.env.NODE_ENV === 'production' // 프로젝트가 저장되는 경로 설정 if (isProd) { serve({ directory: 'app' }) } else { app.setPath('userData', `${app.getPath('userData')} (development)`) } ;(async () => { await app.whenReady() // createWindow 초기화 const mainWindow = createWindow('main', { width: 1000, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), }, }) // 운영모드, 개발모드 접속 경로 설정 if (isProd) { await mainWindow.loadURL('app://./home') } else { const port = process.argv[2] await mainWindow.loadURL(`http://localhost:${port}/home`) mainWindow.webContents.openDevTools() } })()
가장 먼저 환경 변수를 사용해 운영 모드인 경우(process.env.NODE_ENV === 'production')와 개발 모드를 구분짓습니다.
getPath('userData')는 Electron에서 사용되는 함수인데, /userData 폴더를 만들어 해당 폴더에 프로젝트를 저장합니다.
그 다음 helper/create-window.ts에서 정의한 대로 createWindow를 초기화 시키고,
본격적으로 프로그램이 실행됐을 때 접속할 경로를 지정해줍니다.
방금 위에서 개발 모드의 경우 localhost, 운영 모드의 경우 정적 파일을 가져온다고 했듯이, 운영 모드는 app 폴더에 있는 ./home.html 파일 자체가 실행되고, 개발 모드는 `http://localhost:${port}/home` 이라는 페이지가 실행됩니다.
운영 모드는 파일 자체가 돌아가고, 개발 모드는 서버가 실행된다는 것입니다. 이는 실행할 때마다 서버가 돌아가서 비용이 증가하는 걸 막기 위해 서버로 구동하지 않는 것이라고 합니다.
Pages
Page 함수는 기본 Next.js 애플리케이션 방식을 그대로 따른다고 합니다.
Next.js에서는 페이징을 할 때 꼭 라우터 폴더 하위에 page.tsx 파일을 만듭니다. 만약 about-us/page.tsx 폴더를 생성하면 localhost:3000/about-us url에 접속했을 때 page.tsx 반환값이 화면에 그려집니다.
단 Next.js가 app 폴더 하위에 폴더명=pathname 이라는 규칙으로 페이지를 구성했다면, Nextron은 조금 더 깔끔하게 renderer/pages/ 하위에 파일명=pathname으로 작성할 수 있나봅니다.
간단한 코드를 작성하고 실행시키면 잘 작동하는 걸 볼 수 있습니다.
"use client" import Link from "next/link"; const Home = () => { return ( <> <h1>Hello World</h1> <p>Welcome to my Nextron desktop app</p> <Link href="/next"> <a>Go to next page</a> </Link> </> ); }; export default Home;
Layouts
레이아웃 파일도 기존 Next.js 방식을 그대로 사용합니다.
만약 NavBar, Header, Footer와 같이 모든 페이지에 적용시키고 싶은 컴포넌트가 있을 때 최상위 layout.tsx 파일에 선언해주면 모든 페이지에 적용됩니다.
/renderer 폴더 하위에 다음과 같은 layout.tsx 파일을 생성해보겠습니다.
const Layout = ({ children }) => { return ( <> <nav> <h2>Nav Logo</h2> {/* more navbar code here */} </nav> <main>{children}</main> </> ); }; export default Layout;
하지만 실행시키면 아무 일도 발생하지 않습니다. 왜냐하면 Nextron은 create-nex-app 패키지로 생성된 애플리케이션에서 제공하는 _app.ts 파일을 자동으로 포함하지 않기 때문에 수동으로 하나 만들어서 레이아웃을 포함시켜야 합니다.
/pages 하위에 _app.tsx 파일을 생성한 뒤 다음과 같이 Layout을 부르겠습니다.
import Layout from "../layout"; export default function MyApp({ Component, pageProps }) { return ( <Layout> <Component {...pageProps} /> </Layout> ); }
그리고 실행시켜보면,
위와 같이 페이지 상단에 Nav Logo라는 글자가 들어간 걸 볼 수 있습니다.
Nextron 웹팩 프로세스
Next.js 를 사용한 Nextron 애플리케이션은 클라이언트/서버 두 개의 webpack 프로세스를 통해 실행됩니다.
간혹 서버 사이드 렌더링을 지원하지 않는 라이브러리를 사용하려면 당장 현재 프로세스가 서버인지 클라이언트인지 확인해야 합니다. Nextron 공식 문서는 다음과 같은 확인 방법을 제시합니다.
import electron from 'electron'; const Home = () => { const moduleName = electron.moduleName || false; if (moduleName) { // we can use `electron.moduleName` } }; export default Home;
useEffect() 훅과 브라우저를 활용해 현재 클라이언트 프로세스에서 동작하는지 확인할 수 있습니다.
import { useEffect } from "react"; const Home = () => { useEffect(() => { if (typeof window === "undefined") { // we are on the client process. } }, []); return <div></div>; }; export default Home;
프로젝트 빌드하기
개발 환경에서 구현을 마치고 프로젝트를 빌드하려면 다음 명령어를 입력합니다.
npm run build # OR yarn build
Win64 용 실행 파일을 생성하려면 다음 명령어를 입력합니다.
npm run build:win64 # OR yarn build:64
참고 사이트
'Studying > Proj 과정' 카테고리의 다른 글
[Portfolly] ErrorBoundary로 컴포넌트 단위 에러 화면 띄우기 (0) 2024.01.11 [Portfolly] 북마크, 좋아요 낙관적 업데이트로 개선하기 (0) 2024.01.10 [Portfolly] react-query로 뒤로 가기 가능한 무한 스크롤 재구현 (0) 2024.01.09 [Portfolly] 포트폴리오 CRUD를 react-query로 마이그레이션 (0) 2023.12.25 [Portfolly] 직접 반응형 카테고리 Slider 만들기 (0) 2023.12.24