Contributing - lekakid/ArcaRefresher GitHub Wiki

개발 ν™˜κ²½μ„ μ€€μˆ˜λ°”λžλ‹ˆλ‹€.

ν”„λ‘œμ νŠΈ 폴더 ꡬ쑰

image

  • component: μ—¬λŸ¬κ³³μ—μ„œ κ³΅ν†΅μœΌλ‘œ μ‚¬μš©λ˜λŠ” μ»΄ν¬λ„ŒνŠΈ λͺ¨μŒ
  • core: λ¦¬ν”„λ ˆμ…” κ΅¬ν˜„μ— ν•„μš”ν•œ 슀트링, Redux Store λ“± λͺ¨μŒ
  • feature: 각쒅 κΈ°λŠ₯ μ»΄ν¬λ„ŒνŠΈ λͺ¨μŒ
  • func: ν•¨μˆ˜ λͺ¨μŒ
  • menu: κ³΅ν†΅λœ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ œκ³΅ν•˜κΈ° μœ„ν•œ μ»΄ν¬λ„ŒνŠΈ λͺ¨μŒ
  • hooks: λ¦¬μ•‘νŠΈ μ»€μŠ€ν…€ ν›… λͺ¨μŒ

κΈ°λŠ₯ ν΄λ”μ˜ ꡬ쑰

image

{GroupName}
|-- {FeatureName}
|   |-- ArticleMenu.jsx
|   |-- ConfigMenu
|   |   |-- View.jsx
|   |   `-- index.jsx
|   |-- ContextMenu
|   |   |-- View.jsx
|   |   `-- index.jsx
|   |-- Feature.jsx
|   |-- FeatureInfo.jsx
|   `-- slice.jsx
|-- {FeatureName}
|   |-- ...

각 κΈ°λŠ₯ μ»΄ν¬λ„ŒνŠΈμ™€ 메뉴 κ΅¬ν˜„ μ»΄ν¬λ„ŒνŠΈλŠ” feature/index.jsx와 menu/index.jsxμ—μ„œ Webpack context κΈ°λŠ₯을 톡해 μžλ™μœΌλ‘œ ν¬ν•¨λ©λ‹ˆλ‹€.

μ£Όμ˜μ‚¬ν•­

  • /ArticleMenu, /ConfigMenu, /ContextMenu, /Feature, /slice.jsx 의 이름을 λ°”κΏ”μ„  μ•ˆλ©λ‹ˆλ‹€.
  • Group이 μ„œλ‘œ λ‹€λ₯Έ κΈ°λŠ₯이더라도 이름이 κ°™μ•„μ„  μ•ˆλ©λ‹ˆλ‹€.

μ„€μ • λ°μ΄ν„°μ˜ 관리

πŸ’‘ redux slice의 기본적인 μž‘μ„±λ²•μ€ Redux Toolkit λ¬Έμ„œλ₯Ό μ°Έκ³ λ°”λžλ‹ˆλ‹€.

각 κΈ°λŠ₯λ“€μ˜ μ„€μ • λ°μ΄ν„°λŠ” slice.jsx의 λ¦¬λ“€μ„œ μ •μ˜λ₯Ό 톡해 κ΄€λ¦¬λ©λ‹ˆλ‹€.
defaultStorage 였브젝트λ₯Ό 톡해 μœ μ €μŠ€ν¬λ¦½νŠΈ ν™•μž₯ ν”„λ‘œκ·Έλž¨μ΄ 관리할 데이터λ₯Ό μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

const defaultStorage = {
  myNewConfig: 'hello!',
};

defaultStorageλŠ” 이후 initialState.storage에 ν• λ‹Ήν•©λ‹ˆλ‹€.

🚫 ν• λ‹Ήν•˜λŠ” 이름(storage)을 λ°”κΎΈλ©΄ μ•ˆλ©λ‹ˆλ‹€.

const initialState = {
  storage: getValue(Info.ID, defaultStorage),
  // 이 μ•„λž˜μ— μΈν„°νŽ˜μ΄μŠ€ μ œμ–΄μš© state μΆ”κ°€
  show: true,
};

storageλ₯Ό μ œμ–΄ν•˜λŠ” λ¦¬λ“€μ„œλŠ” 이름이 $둜 μ‹œμž‘ν•΄μ•Όν•©λ‹ˆλ‹€. $둜 μ‹œμž‘ν•˜λŠ” λ¦¬λ“€μ„œλ₯Ό ν˜ΈμΆœν•  λ•Œ λ§ˆλ‹€ μ €μž₯ν•  데이터에 λ³€ν™”κ°€ μžˆλ‹€κ³  νŒλ‹¨ν•©λ‹ˆλ‹€. μžμ„Έν•œ κ΅¬μ‘°λŠ” core/storage.jsx의 createMonkeySyncMiddlewareλ₯Ό μ°Έκ³ λ°”λžλ‹ˆλ‹€.

export const slice = createSlice({
  name: Info.ID,
  initialState,
  reducers: {
    // μ•„λž˜μ™€ 같이 μΆ”κ°€ν•©λ‹ˆλ‹€.
    toggleShow(state) {
      state.show = !state.show;
    },
    // storageλ₯Ό μ œμ–΄ν•˜λŠ” λ¦¬λ“€μ„œλŠ” νƒ­κ°„ 동기화 ꡬ뢄을 μœ„ν•΄ 이름을 $둜 μ‹œμž‘ν•΄μ•Όν•©λ‹ˆλ‹€!!
    $setMyNewConfig(state, action) {
      state.storage.myNewConfig = action.payload;
    },
  },
});

μ„€μ • λ°μ΄ν„°μ˜ μ—…λ°μ΄νŠΈ

const defaultStorage = {
  version: 1,
  contextRange: 'articleItem',
  variant: 'badge',
  memo: {},
};

function formatUpdater(storage, defaultValue) {
  // version 0 => 1
  const version = storage?.version || 0;

  switch (version) {
    case 0: {
      const memo = Object.fromEntries(
        Object.entries(storage.memo).map(([key, msg]) => [key, { msg }]),
      );
      const data = getValue('UserColor');
      if (data) {
        Object.entries(data.color).forEach(([key, color]) => {
          (memo[key] ??= {}).color = color;
        });
        deleteValue('UserColor');
      }

      const updateStorage = { ...storage };
      updateStorage.memo = memo;
      updateStorage.version = 1;
      return updateStorage;
    }
    default:
      console.warn('μ§€μ›ν•˜μ§€ μ•ŠλŠ” 버전 λ°μ΄ν„°μž…λ‹ˆλ‹€.', storage);
      return defaultValue;
  }
}

const initialState = {
  storage: getValue(Info.ID, defaultStorage, formatUpdater),
};

getValue의 3번째 인자둜 formatUpdaterν•¨μˆ˜λ₯Ό 받을 수 μžˆμŠ΅λ‹ˆλ‹€. μ €μž₯ 데이터 내에 version 값을 μ§€μ •ν•˜κ³  이 값에 따라 데이터λ₯Ό ν•„μš”μ— 따라 λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ³€ν™˜ μ „ λ°μ΄ν„°λŠ” λ‚΄λΆ€ μ €μž₯μ†Œμ— {FeatureName}_v{version} λ°±μ—…λ°μ΄ν„°λ‘œ λ‚¨μŠ΅λ‹ˆλ‹€.