๐ ์์ํ๊ธฐ ์ ์
React ํ๋ก์ ํธ๋ฅผ ์ํ TypeScript ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ๋ฐ, ๋ฒ์ ๊ด๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ๋ฐํํ๋ ๊ณผ์ ์ ๊ฐ๋จํ์ง๋ง ๋ช ๊ฐ์ง ์ค๋น ์ฌํญ์ด ํ์ํฉ๋๋ค.
๐ Node.js ๋ฐ npm ์ค์น
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ๋ฐํ๋ ค๋ฉด Node.js์ npm์ด ์ค์น๋์ด ์์ด์ผ ํฉ๋๋ค. ์ด๋ฏธ ์ค์น๋์ด ์๋์ง ํ์ธํ์ธ์.
node -v
npm -v
์ค์น๋์ด ์์ง ์๋ค๋ฉด Node.js ๊ณต์ ์น์ฌ์ดํธ ํน์ NVM์ ํตํด Node.js๋ฅผ ์ค์นํด์ฃผ์ธ์.
๐ npm ํ์๊ฐ์
npm์ ํจํค์ง๋ฅผ ์ฌ๋ฆฌ๊ธฐ ์ํด์๋ ๊ณ์ ์ด ํ์ํฉ๋๋ค.
๊ณ์ ์ด ์๋ค๋ฉด ํ์๊ฐ์
์ ํด์ฃผ์ธ์.
๐ ๋จ๊ณ๋ณ ๊ฐ์ด๋
๐ 1. CRA๋ก React + TypeScript ํ๋ก์ ํธ ์์ฑ
$ npx create-react-app react-ts-lib --template typescript
ํ์ ์คํฌ๋ฆฝํธ ํ ํ๋ฆฟ์ ์ด์ฉํด ๋ฆฌ์กํธ ํ๋ก์ ํธ๋ฅผ ์์ฑํด์ค๋๋ค.
๐ 2. ํด๋ ๊ตฌ์กฐ ์ก์์ฃผ๊ธฐ
ํ๋ก์ ํธ ์์ฑ ํ ์ธ๋ชจ ์๋ ํ์ผ๋ค ๋ค ์ณ๋ด์ค๋๋ค.
๊ทธ ํ src ์๋์ lib ํด๋๋ฅผ ์์ฑํ๊ณ ๋ฐฐํฌํ ์ปดํฌ๋ํธ๋ฅผ ๋ด์ ํด๋๋ฅผ ์์ฑํด ์ค๋๋ค.
์ด๋ ๊ฒ ํด์ค์ผ ๊ฐ๋ฐ ์๋ฒ๋ฅผ ์คํ ํ์ ๋ ๋๋ฒ๊น
ํ๊ธฐ๋ ํธํ๊ณ
๋ฐฐํฌ ์ lib ํด๋ ์๋์ ํ์ผ๋ค๋ง ์ปดํ์ผํด์ฃผ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ๊ตฌ๋ถ๊ฐ๋ ์๊ธฐ๊ณ ํธํด์ง๋๋ค.
๋ํ ์ง์
์ ์ธ ์ํธ๋ฆฌ ํ์ผ์ ๋ง๋ค์ด์ค์ผ ๋๊ธฐ ๋๋ฌธ์ src/lib/index.ts
์ ์์ฑํด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ์ export ํด์ค๋๋ค.
barrel ํ์ผ์ ๋ง๋ค์ด๋๋ฉด ๊ด๋ฆฌํ๊ธฐ ํธํ๋ ์ฐธ๊ณ ํด์ฃผ์ธ์.
[React, JS, TS] ๊ฐ๊ฒฐํ import๋ฅผ ์ํ index(barrel) ํ์ผ์ ์๋์ผ๋ก ์์ฑํด๋ณด์
๐ 3. tsconfig.json ํ์ผ ์ค์
ํ์
์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ฐฐํฌํ๊ธฐ ์ TS ์ปดํ์ผ๋ฌ ํ๋์ด
JS ํ์ผ๊ณผ ํ์
ํ์ผ๋ก ์ปดํ์ผ ํด ์ฃผ์๊ธฐ ๋๋ฌธ์ ์ค์ ํ์ผ์ธ tsconfig.json
์ ์์ข ๋ด์ค๋๋ค.
{
"compilerOptions": {
"target": "es5", // ์ปดํ์ผ๋ JS ์ฝ๋์ ECMAScript ๋ฒ์
"lib": ["dom", "dom.iterable", "esnext"], // ํฌํจํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ชฉ๋ก
"allowJs": true, // JS ํ์ผ ์ปดํ์ผ ํ์ฉ
"noEmit": false, // ์ปดํ์ผ๋ฌ๊ฐ ์ถ๋ ฅ ํ์ผ ์์ฑ
"declaration": true, // .d.ts ์ ์ธ ํ์ผ ์์ฑ
"outDir": "dist", // ์ปดํ์ผ๋ ํ์ผ ์ ์ฅ ๋๋ ํ ๋ฆฌ
"skipLibCheck": true, // ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ ํ์
์ฒดํฌ ์คํต
"esModuleInterop": true, // CommonJS ๋ชจ๋์ ES6์ฒ๋ผ ์ฌ์ฉ
"allowSyntheticDefaultImports": true, // ๋ํดํธ ๋ชจ๋ import ๋ฌธ๋ฒ ์ฌ์ฉ ํ์ฉ
"strict": true, // ์๊ฒฉํ ํ์
์ฒดํน ํ์ฑํ
"forceConsistentCasingInFileNames": true, // ํ์ผ ์ด๋ฆ ๋์๋ฌธ์ ์ผ๊ด์ฑ ๊ฐ์
"noFallthroughCasesInSwitch": true, // switch๋ฌธ์ case๋ฌธ ๋์ด๊ฐ ๋ฐฉ์ง
"module": "esnext", // ๋ชจ๋ ์์คํ
(์ต์ ECMAScript)
"moduleResolution": "node", // ๋ชจ๋ ํด์ ๋ฐฉ์ (Node.js)
"resolveJsonModule": true, // JSON ๋ชจ๋ ๊ฐ์ ธ์ค๊ธฐ ํ์ฉ
"isolatedModules": true, // ํ์ผ์ ๋
๋ฆฝ์ ๋ชจ๋๋ก ์ปดํ์ผ
"jsx": "react-jsx" // JSX ์ฝ๋ ์ฒ๋ฆฌ ๋ฐฉ์ (React JSX)
},
// ์ปดํ์ผํ ํ์ผ ํจํด
"include": ["./src/lib/**/*.tsx", "./src/lib/**/*.ts"]
}
์ ์์ฑ ์ค ์ค์ํ ์์ฑ 4๊ฐ์ง๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
noEmit
์ปดํ์ผ๋ฌ์ ์ถ๋ ฅ ํ์ผ ์์ฑ ์ฌ๋ถ์ ๋๋ค.
๋น์ฐํ ๊ด๋ จ ํ์ผ๋ค์ด ์ธ์ ๋ฐ์ผ๋ก ๋์์ผ ํ๊ธฐ ๋๋ฌธ์false
๋ก ์ค์ ํฉ๋๋ค.declaration
์ปดํ์ผ๋ฌ์๊ฒ ํ์ ์ ์ธ์ง์์ผ์ฃผ๋ d.ts ํ์ผ์ ์์ฑ ์ฌ๋ถ์ ๋๋ค.
ํ์ ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋ฉด ๋น์ฐํtrue
๋ก ์ค์ ํฉ๋๋ค.outDir
๋น๋ ํ์ผ์ ์์ฑ ๊ฒฝ๋ก์ ๋๋ค.
๋ณด์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ด๋ จ ๋น๋ ์ฐ์ถ๋ฌผ์dist
๋ก ํ๋๊ฒ ๊ตญ๋กค์ด์ด์ ๋ฐ๋ผ๊ฐ๋๋ค.include
์ปดํ์ผํ ํ์ผ๋ค์ ํจํด์ ์ง์ ํฉ๋๋ค. ์ฌ๊ธฐ์๋src/lib
๋๋ ํ ๋ฆฌ ์๋์ ๋ชจ๋.tsx
,.ts
ํ์ผ๋ค์ด ํฌํจ๋ฉ๋๋ค.
๐ 4. package.json ์ปดํ์ผ ์คํฌ๋ฆฝํธ ์์ฑ
{
...
"dependencies": {
...
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"compile": "rm -rf dist && mkdir dist && tsc"
},
...
}
package.json ํ์ผ์ scripts ๋ถ๋ถ์ ์์ ๊ฐ์ ๋ด์ฉ์ ์ถ๊ฐํด์ค๋๋ค.
์์ฐจ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ์๋ํฉ๋๋ค.
dist ํด๋ ์ญ์ (๊ธฐ์กด ์ฐ์ถ๋ฌผ ์ญ์ ) → dist ํด๋ ์์ฑ → ์ปดํ์ผ
๋ช ๋ น์ด๋ฅผ ์คํํ๋ฉด ์ ์๋ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๐ 5. package.json์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๋ณด ์์ฑ
npm์ ์ฌ๋ฆฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ณด๋ฉด ๋ญ ์ ๋ณด๊ฐ ๋ง์ต๋๋ค.
์ด๋ฐ ์ ๋ณด๋ค์ ๋ฑ๋กํด๋์ผ ๋๊ฐ ๋ง๋ค์๋์ง, github ์ฃผ์๊ฐ ์ด๋์ธ์ง ์ ์ ์๊ฒ ์ฃ ?
๊ทธ๋ฌ๊ธฐ ์ํด package.json์ ๋ค์๊ณผ ๊ฐ์ ์ ๋ณด๋ค์ ์์ฑํด์ค๋๋ค.
{
"name": "npm์ ๋ฑ๋กํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ด๋ฆ",
"version": "0.1.0",
"private": false,
"main": "dist/index.js",
"types": "dist/index.d.ts",
"browser": "./browser/specific/main.js",
"author": {
"name": "์ด๋ฆ",
"email": "์ด๋ฉ์ผ",
"url": "์น์ฌ์ดํธ"
},
"description": "ํจํค์ง ์ค๋ช
",
"keywords": ["react", "๊ฒ์ ์ต์ ํ๋ฅผ ์ํ ํค์๋ ๋ฐฐ์ด"],
"dependencies": {
...
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"compile": "rm -rf dist && mkdir dist && tsc"
},
...
}
์ฌ๊ธฐ์ ์ค์ํ ์์ฑ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
name
npm์ ๋ฑ๋กํ ํจํค์ง ์ด๋ฆ์ ๋๋ค.
npm์ ํจํค์ง๋ฅผ ์ฌ๋ฆฌ๋ ค๋ฉด ์ค๋ณต๋์ง ์์ ์ด๋ฆ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ npm์ ๊ผญ ํ๋ฒ ๊ฒ์ํด๋ณด์ธ์.private
๊ณต๊ฐํ๋ ค๊ณ ๋ฐฐํฌํ๋ ๊ฑด๋ฐ ๋น๊ณต๊ฐ ํ๋ฉด ์๋๊ฒ ์ฃ ? false๋ก ๊ณต๊ฐํด์ค์๋ค.main
๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ง์ ์ ์ธ ์ํธ๋ฆฌ ํ์ผ์ ์ง์ ํด์ค๋๋ค.types
ํ์ ๋ค์ด ์ ์ธ๋์ด ์๋ ์ํธ๋ฆฌ ํ์ผ์ ์ง์ ํด์ค๋๋ค.
๐ 6. npm์ ๋ฐํ
npm์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ฐํํ๊ธฐ ์ํด npm ๊ณ์ ์ด ํ์ํฉ๋๋ค. ์๋ ๋ช ๋ น์ด๋ก npm ๋ก๊ทธ์ธ์ ์ํํฉ๋๋ค.
npm login
๋ก๊ทธ์ธ ์ ๋ณด๋ฅผ ์ ๋ ฅํ ํ, npm ํจํค์ง๋ฅผ ๋ฐํํฉ๋๋ค.
npm publish --access=public
--access=public
์ต์
์ ์ ์ธํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
402 Payment Required - PUT https://registry.npmjs.org/@lasbe/react-ts-lib - You must sign up for private packages
์ ์์ ์ผ๋ก ๋ฐํ์ ๋ง์น๋ฉด ์์ ๊ฐ์ด ๊ฒ์ํด์ ํจํค์ง๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
๐ 7. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ๋ฐํ ๋ฐ ๋ฒ์ ๊ด๋ฆฌ
ํจํค์ง๋ฅผ ๋ฐํํ ํ ์ ๋ฐ์ดํธ๋ฅผ ํ๋ ค๋ฉด ๋ฐ๋์ package.json์ ๋ฒ์ ์ ๋ํ์ค์ผ ํฉ๋๋ค.
์ด ๋ฒ์ ์ Semantic Versioning (SemVer) ๊ท์น์ ๋ฐ๋ผ์ผ ์ฌ์ฉ์์๊ฒ ํผ๋์ด ์์ผ๋ฉฐ ๋ค์๊ณผ ๊ฐ์ ์์๋ก ์์ ํ๋ฉด ๋ฉ๋๋ค.
- ํจํค์ง ์์
- ์ปดํ์ผ
- ๋ฒ์ ์์
- ๋ฐํ
๐ 8. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ
์ผ๋ฐ์ ์ผ๋ก ํจํค์ง ์ค์นํ๋ ๊ฒ์ฒ๋ผ ์ค์นํ๊ณ import ํด์ ์ฌ์ฉํ๋ฉด ์ ์ง ๋ชจ๋ฅผ ๋ฟ๋ฏํจ์ด ๋ฐ๋ ค์ต๋๋ค.
์ฌ๋ฌ๋ถ๋ ๋ณธ์ธ๋ง์ ํจํค์ง๋ฅผ ํ๋ฒ ๋ฐฐํฌํด๋ณด๋ ๊ฑธ ์์์ผ๋ก ์คํ์์ค ์ํ๊ณ์ ๊ธฐ์ฌํด๋ณด๊ธธ ๋ฐ๋๋๋ค!
๋๊ธ