Skip to content

ssi02014/react-npm-deploy-boilerplate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

41 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ’ป ๋ฆฌ์•กํŠธ ๋””์ž์ธ ์‹œ์Šคํ…œ NPM ๋ฐฐํฌ ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ

  • UI Kits, Design System ๊ตฌ์ถ•์„ ์œ„ํ•œ NPM์œผ๋กœ ์˜คํ”ˆ์†Œ์Šค ๋ฐฐํฌ์— ์ตœ์ ํ™” ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ
  • 2023๋…„ 6์›” ๊ธฐ์ค€ ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ๊ตฌ์ถ•๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์›นํŒฉ ๊ฐœ๋ฐœ ์„œ๋ฒ„, ๋ถˆ ํ•„์š”ํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ, ๋กœ๋” ๋“ฑ ๋ชจ๋‘ ์ œ๊ฑฐ ํ›„ ๊ฒฝ๋Ÿ‰ํ™”
  • ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ UI ํ…Œ์ŠคํŠธ๋Š” ์›นํŒฉ ๊ฐœ๋ฐœ ์„œ๋ฒ„๋ฅผ ๋„์šฐ์ง€ ์•Š๊ณ , Storybook์„ ์ด์šฉ (ํ•˜๋‹จ ๋‚ด์šฉ ์ฐธ๊ณ )
  • cjs, esm ๋ชจ๋‘ ์ง€์›

๐Ÿ“— ๊ตฌ์„ฑ

  • React v18
  • Babel์„ ์ด์šฉํ•œ ํŠธ๋žœ์ŠคํŒŒ์ผ๋ง
  • Rollup์„ ์ด์šฉํ•œ ๋ฒˆ๋“ค๋ง
  • TypeScript v5
  • @emotion
  • Storybook v7

์Šคํ† ๋ฆฌ๋ถ ๊นƒํ—ˆ๋ธŒ ํŽ˜์ด์ง€


์˜์กด์„ฑ ์„ค์น˜

  • ํ•ด๋‹น ๋ ˆํฌ๋Š” yarn ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €๋กœ ๊ตฌ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํŠน์ • ์ด์Šˆ๊ฐ€ ์—†๋‹ค๋ฉด yarn์„ ์ด์šฉํ•ด ์˜์กด์„ฑ ์„ค์น˜๋ฅผ ๊ถŒ์žฅ
yarn
or
yarn install

package.json ์ˆ˜์ •

  • ํ•ด๋‹น ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ๋ฅผ cloneํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด package.json ์ˆ˜์ •์ด ํ•„์š”ํ•จ
  • name, version, description, repository/url, author, homepage ... ๋“ฑ ์ˆ˜์ • ํ•„์š”
{
  "name": "react-npm-deploy-boilerplate", // (*)
  "version": "1.0.0", // (*)
  "description": "react-npm-deploy-boilerplate", // (*)
  "scripts": {
    // ...
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/ssi02014/react-npm-deploy-boilerplate.git" // (*)
  },
  "author": "Gromit", // (*)
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/ssi02014/react-npm-deploy-boilerplate.git/issues" // (*)
  },
  "homepage": "https://github.com/ssi02014/react-dev-env-boilarplate", // (*)
  // ...
}

์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ

  • src/components์—์„œ ์ปดํฌ๋„ŒํŠธ ์ž‘์—…

// src/components/Button/Button.tsx
import React from 'react';
import styled from '@emotion/styled';

interface Props {
  children: React.ReactNode;
  size?: 'medium' | 'large';
}

const Button = ({ children, size = 'medium' }: Props) => {
  return <StyledButton size={size}>{children}</StyledButton>;
};

  • src/stories/components์—์„œ {Component}.stories.tsx ํ˜•ํƒœ๋กœ ํŒŒ์ผ ์ƒ์„ฑ ํ›„ ์Šคํ† ๋ฆฌ๋ถ์œผ๋กœ UI ํ…Œ์ŠคํŠธ ์ง„ํ–‰
  • ์Šคํ† ๋ฆฌ๋ถ์—์„œ UI ํ…Œ์ŠคํŠธ ์ง„ํ–‰ ํ›„ src/index.tsx์—์„œ export

export { default as theme } from '@shared/theme';
export { default as Button } from '@components/Button';

์ด๋ฏธ์ง€ ์‚ฌ์šฉ

import image from '../../assets/sheep.jpg';
import testUrl, { ReactComponent as TestSVG } from '../../assets/test.svg';

const Component = ({ children, size = 'medium' }: Props) => {
  return (
    <>
      {/* image test */}
      <img width={300} src={image}></img>

      {/* svg component test */}
      <TestSVG />

      {/* svg url test */}
      <img src={testUrl} alt="" />
    </>
  );
};

๋นŒ๋“œ์™€ ๋ฐฐํฌ

  • ์ปดํฌ๋„ŒํŠธ ์ž‘์—… ํ›„ ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ build ์ง„ํ–‰
yarn build
  • build๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ dist ํด๋”๊ฐ€ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค. ์‹ค์งˆ์ ์œผ๋กœ ํ•ด๋‹น ํด๋”๋ฅผ npm์— ๋ฐฐํฌํ•˜๊ฒŒ ๋œ๋‹ค.

  • ์‚ฌ์‹ค ํ˜„์žฌ ์ €์žฅ์†Œ๋Š” github actions์„ ํ†ตํ•ด ์ž๋™ ๋นŒ๋“œ ๋ฐ npm ๋ฐฐํฌ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค. ๋˜ํ•œ, ์Šคํ† ๋ฆฌ๋ถ ํŽ˜์ด์ง€๋„ ์ž๋™ ๋นŒ๋“œ ํ›„์— github page๋กœ ๋ฐฐํฌ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.
  • ์œ„ ๊ณผ์ •์€ master ๋ธŒ๋žœ์น˜๋กœ๋งŒ ์ปค๋ฐ‹์ด ์˜ฌ๋ผ๊ฐ€๋ฉด ์ด๋ฅผ ํŠธ๋ฆฌ๊ฑฐ ์‚ผ์•„ ์ž๋™์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค.
  • ๋ฐฐํฌ ์ „์— package.json version ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ๋Š” ๊ฒƒ์„ ๊ผญ! ์žŠ์ง€๋ง์ž.

npm deploy ํ›„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ ๋ฐ ์‚ฌ์šฉ๋ฒ•

yarn add (๋ณธ์ธ ๋ฐฐํฌ ์ €์žฅ์†Œ)
import { Button } from 'react-npm-deploy-boilerplate';

function App() {
  return (
    <div>
      <Button>ํ•˜์ด</Button>
      <Button size="large">๋ฐ”์ด</Button>
    </div>
  )
}

export default App;

storybook

  • storybook์„ ํ†ตํ•ด์„œ ui ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ํ„ฐ๋ฏธ๋„๋กœ ์ž…๋ ฅ์„ ํ†ตํ•ด ์Šคํ† ๋ฆฌ๋ถ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
yarn storybook

  • ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์Šคํ† ๋ฆฌ๋ถ ์ฝ”๋“œ ์ž‘์„ฑ
// src/stories/components/Button.stories.tsx
import React from 'react';
import { StoryFn } from '@storybook/react';
import Button from '@components/Button';

export default {
  title: 'components/Button',
  argTypes: {
    variant: {
      options: ['primary', 'secondary'],
      control: { type: 'check' },
    },
    size: {
      options: ['medium', 'large', 'small'],
      control: { type: 'select' },
    },
  },
};

interface Props {
  size: 'medium' | 'large' | 'small';
  select: any[];
}

const Template: StoryFn<Props> = ({ size }: Props) => {
  return (
    <div>
      <Button size={size}>์•ˆ๋…•</Button>
    </div>
  );
};

export const Default = {
  render: Template,

  args: {
    size: 'medium',
  },
};

// ...

storybook github page ๋ฐฐํฌ

  • build:storybook์œผ๋กœ ๋นŒ๋“œ ํ›„์— deploy:storybook์œผ๋กœ github page๋กœ ๋ฐฐํฌ
yarn build:storybook
yarn deploy:storybook

rollup alias(์ ˆ๋Œ€ ๊ฒฝ๋กœ) ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•

// tsconfig.paths.json
{
  "compilerOptions": {
    "paths": {
      "@components/*": ["src/components/*"],
      "@shared/*": ["src/shared/*"],
      // ์—ฌ๊ธฐ๋‹ค ์ถ”๊ฐ€
    },
  }
}