본문 바로가기

Front-End

Mono Repo 로 svelte 프로젝트 세팅하기 (With pnpm + Typescript + create-svelte)

현재 사이드 프로젝트로 활동하는 팀에서 이메일로 전송할 html 파일을 디자인 하자는 이야기가 나와서,

가장 가벼워 보이는 svelte 를 한번 테스트 해보기위해 프로젝트를 세팅해보려고 마음을 먹었다.

( 몇일후 알게된건데, 이메일 자체만으로는 JS 스크립트를 실행할수가 없다,,, ㅠㅠ )

 

그렇지만,, 이것저것 검색해보았지만, 작성일 기준 (11.02) 으로 제대로 동작하는것이 없고,

한글로 작성된 포스트가 딱히 유효한 글이 없었다.

이렇게 svelte 프로젝트 세팅을 기록 겸 나와 같이 세팅하고자 하는분들께 도움이 되었으면 하는 글을 써본다.

pnpm 과 svelte 가 생소한 분들이 있을수 있으나,,, 공식 홈 링크만 제공하고 자세한 정보는 구글링,,,,

 

Svelte • Cybernetically enhanced web apps

Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app. Instead of using tec

svelte.dev

 

 

Fast, disk space efficient package manager | pnpm

Fast, disk space efficient package manager

pnpm.io

pnpm 설치

먼저 pnpm 을 설치하는것은 아주 간단하다.

$ npm i -g pnpm

 

완료 되었다면 이제 프로젝트를 설치 해보자.

현재 내가사용하고 있는 데스크탑 PC 는 window 인데, 무슨일인지 pnpm create 명령어가 실행되지 않는다.

그래서 npm 을 사용해 create 하고, pnpm 으로 교체하는 작업을 하기로 했다.

타입스크립트로 create-svelte 를 설치하기 위해서는 다음 명령어를 입력하면된다.

create-svelte (svelteKit)

$ npm create svelte@latest svelte-app

이렇게 실행하게 되면 어떤식으로 세팅할지 물어보는데, 나는 아래와 같이 선택하였다. 

이미 익스텐션으로 ESLint 와 Prettier 를 사용중이라서, 굳이 하지 않았다.

Playwright 은? 뭔지 모른다.

이렇게 내 인생 첫 svelte 프로젝트가 설치되었다.

이 상태는 종속성 패키지들이 설치되지 않은 상태이다. 폴더 내로 진입해서 패키지를 설치하자

$ cd svelte-app
$ pnpm install

install 하게 되면 다음과 같이 설치된다.

프로젝트를 실행시켜 보고싶은 두근거리는 마음을 가다듬고 실행시켜보자

개발 서버로 프로젝트 시작 명령어는 dev 이다.

$ pnpm dev

이제 http://127.0.0.1:5173/ 으로 접속해보자. vsc 터미널에서 바로 ctrl + 클릭해도 된다.

생각보다 더 대문짝만한 환영인사다. 살짝 레트로한 감성이 풍기는 언박싱 페이지다.

여기에 나는 앞으로 모노레포를 구성해서 사용할건데, 자세한 내용은 생략하고 구성하는 과정만 포스팅 하도록 하겠다.

먼저 다음과 같은 파일을 생성한다.

 

이렇게 root 디렉토리에 생성해준후, 바로 packages 폴더를 생성해준다.

그다음 packages.json 을 생성하는데, 아래와 같이 생성하면 된다.

여기서 name, author 는 자신의 깃허브 닉네임등을 넣고, repository 는 이 프로젝트 구성과 상관이 없다.

engines 항목에 node 버전과 pnpm 버전은 자신이 사용하는 버전 혹은 의존성에서 요구되는 버전을 사용하면된다.

이 상태로 다음 명령어를 입력한다.

$ pnpm install

그러면 다음과 같은 구조가 된다.

이제 packages 안의 폴더로 이동시키고, 공용 모듈 폴더도 만들어보자

아까 만든 svelte-app 폴더를 packages 안으로 옮기고, common 폴더도 생성한다.

이제 이 common 안에 모든 공용 모듈 파일들이 들어간다.

간단한 예제로, react 에서 drag 를 구현하는 이벤트 핸들러를 공용모듈로 만들어보자.

packages/common/src/utils

import { MouseEvent, MutableRefObject } from "react";

const drag = {
  onDragStart(
    e: MouseEvent,
    isClick: MutableRefObject<boolean>,
    targetOffset: MutableRefObject<number>
  ) {
    e.preventDefault();
    isClick.current = true;
    targetOffset.current = e.clientX;
  },

  onDragEnd(e: MouseEvent, isClick: MutableRefObject<boolean>) {
    e.preventDefault();
    isClick.current = false;
  },

  onDragMove(
    e: MouseEvent,
    isClick: MutableRefObject<boolean>,
    targetOffset: MutableRefObject<number>,
    scrollRef: MutableRefObject<HTMLUListElement | null>
  ) {
    e.preventDefault();
    if (isClick.current && scrollRef.current) {
      const moveX = targetOffset.current - e.clientX;

      scrollRef.current.scrollLeft += moveX;
      targetOffset.current = e.clientX;
    }
  },
};

export default drag;

이 코드를 다음과같이 넣어두자.

이제 common 폴더내의 package.json 을 다음과 같이 수정한다.

 

{
  "name": "@yoon0cean/common",
  "private": true,
  "version": "0.0.0",
  "main": "dist/index.js",
  "module": "dist/index.js",
  "typings": "dist/index.d.ts",
  "scripts": {
    "postinstall": "pnpm run build",
    "build": "tsc -p .",
    "build:watch": "tsc -p . --watch"
  },
  "dependencies": {
    "react": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.0",
    "typescript": "^4.4.2"
  }
}

 

tsconfig.json 도 수정한다.

{
  "compilerOptions": {
    "outDir": "dist",
    "declaration": true,
    "target": "esnext",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "jsx": "react-jsx",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "resolveJsonModule": true,
    "isolatedModules": true
  },
  "include": ["src"],
  "exclude": ["dist"]
}

 

 

다 수정되었다면, common 폴더에서 다음 명령어를 실행한다.

/my-first-svelte/packages/common

$ pnpm install

이렇게 되면 dist 폴더가 생기는데, 이 안에 타입스크립트가 컴파일된 모듈 파일이 생긴다.

이 파일을 이제 packages 내에서 공용모듈로 사용할수 있다.

아까 옮겨뒀던 svelte-app 폴더로 가서 이 모듈을 사용해보자.

svelte-app/package.json 파일을 수정한다.

{
  "name": "@yoon0cean/svelte-app",
  "version": "0.0.1",
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "preview": "vite preview",
    "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
    "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
  },
  "dependencies": {
    "@yoon0cean/common": "workspace:^0.0.0"
  },
  "devDependencies": {
    "@fontsource/fira-mono": "^4.5.0",
    "@neoconfetti/svelte": "^1.0.0",
    "@sveltejs/adapter-auto": "next",
    "@sveltejs/kit": "next",
    "@types/cookie": "^0.5.1",
    "svelte": "^3.46.0",
    "svelte-check": "^2.7.1",
    "svelte-preprocess": "^4.10.6",
    "tslib": "^2.3.1",
    "typescript": "^4.7.4",
    "vite": "^3.1.0"
  },
  "type": "module"
}

아까 기본으로 생긴 package.json 파일에 name 항목과 @yoon0cean/common 항목을 추가한다.

다시 이 폴더내에서 install 해주게 되면,

/my-first-svelte/packages/svelte-app

$ pnpm install

/my-first-svelte/packages/svelte-app 내에서 common 폴더 내 모듈을 사용할수가 있게된다.

+page.svelte 파일을 열어 모듈을 불러와 보자.

+page.svelte

<script>
	import Counter from './Counter.svelte';
	import welcome from '$lib/images/svelte-welcome.webp';
	import welcome_fallback from '$lib/images/svelte-welcome.png';
	import drag from "@yoon0cean/common/dist/drag";
</script>

<svelte:head>
	<title>Home</title>
	<meta name="description" content="Svelte demo app" />
</svelte:head>

<section>
	<h1>
		<span class="welcome">
			<picture>
				<source srcset={welcome} type="image/webp" />
				<img src={welcome_fallback} alt="Welcome" />
			</picture>
		</span>

		to your new<br />SvelteKit app
	</h1>

	<h2>
		try editing <strong>src/routes/+page.svelte</strong>
	</h2>

	<Counter />
</section>

<style>
	section {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		flex: 0.6;
	}

	h1 {
		width: 100%;
	}

	.welcome {
		display: block;
		position: relative;
		width: 100%;
		height: 0;
		padding: 0 0 calc(100% * 495 / 2048) 0;
	}

	.welcome img {
		position: absolute;
		width: 100%;
		height: 100%;
		top: 0;
		display: block;
	}
</style>

자동 완성이 잘 안된다면, ctrl + shift + p 을 열어 ts server 와 eslint server 를 재시작 시켜보자.

그래도 안된다면 직접 경로를 입력하여 가져와 보자.

근데 그래도 안된다면 댓글 남겨주세요 ! 😊

이 방식은 모듈 불러오는것이 트리쉐이킹 방식으로 가져오는것이라서, 불편하게 느껴진다면 

이렇게 index.ts 파일을 하나 만들어서 내보내 주게되면, '@yoon0cean/common' 과 같은 경로로 불러와진다.

실제로 비교는 못해봤지만, 정확히 트리쉐이킹이 되는 방식은 처음 소개한 방법이다.

추후 바벨이나 minify, gzip 등을 해서 사용하면 더 좋을것이다.

마지막으로 각 프로젝트 폴더내로 이동해가면서 start 명령어나 build 명령어를 사용하고 싶지 않다면 ( 상당히 귀찮다 ),

root 디렉터리의 package.json 을 열고 scripts 항목에 다음과 같이 작성한다.

"scripts": {
    "preinstall": "pnpm dlx only-allow pnpm",
    "start:svelte-app": "pnpm --filter @yoon0cean/svelte-app start",
    "build:svelte-app": "pnpm --filter @yoon0cean/svelte-app build"
},

이후 svelte-app 프로젝트를 실행시키고 싶다면

$ pnpm start:svelte-app

이런식으로 사용하면 된다.

다른 프로젝트가 늘어나게되면

"start:새프로젝트폴더명" : "... @새프로젝트package.json에명시한name프로퍼티 start" 형태로 늘려나가면 된다.

이런식으로 Mono Repo 로 svelte 프로젝트 세팅하기 (With PNPM + Typescript + create-svelte) 를 해볼수 있다.