해당 글은 Github Packages Registry를 이용한 패키지 배포를 이용해서 작성한 글입니다. 더붙어 Github Docs을 참고하여 작성하였습니다.
이번에 진행하는 일에서 React Component로 제작해서 배포해야 할 일이 생겼다. 그래서 기존에 CRA로 제작한 Component를 Babel을 통하여 Package로 배포하려고 생각하고 진행하였다. 이 글은 그 과정에서 만난 여러가지 이슈들과 과정을 작성한 것이다.
물론 NPM에 올리는 것이 아닌, Github Registry에 올리는 것이기 때문에 프로젝트 최상단 루트에 다음과 같은 파일,.npmrc
,을 생성시켜준다.
// .npmrc
@조직명:registry=https://npm.pkg.github.com/
해당 파일을 생성시켜놓게 되면, @조직명/
시작하는 패키지를 다운받을 때, NPM에서 찾는게 아닌, Gtihub Registry를 찾게 된다. 이제 package.json
을 수정해주자. 이 때, 아래 필드는 필수적으로 작성해주어야 한다.
// package.json
{
"name": "@조직명/패키지명", // 반드시 소문자로 작성해야 한다.
"version": "0.0.1",
"private": "false", // 해당 필드를 제거하거나, false로 작성해준다.
"description": "패키지 설명",
"repository": { // 한 줄로 작성하지말고, 다음과 같이 세부적으로 작성해준다.
"type": "git",
"url": "https://github.com/조직명/Repository명"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
}
이제 배포를 위한 준비는 모두 완료되었다. 이제 yarn publish
또는 npm publish
를 통해서 배포를 진행할 수 있다. 배포를 위한 준비를 완료했으니, 이제 Babel을 통해서 최신문법으로 작성된 Javascript 코드를 컴파일 해보자. 기본적으로 본인의 개발환경은 다음과 같다.
CRA + Typescript
이제 여기서 Babel을 통해서 코드를 컴파일하고, 그 컴파일된 코드를 Github Registry에 올려서 언제든지 사용할 수 있도록 제작할 것이다. 이제 배포할 때 필요한 패키지를 설치해보자.
yarn add -D @babel/cli
yarn add -D @babel/preset-env @babel/preset-react @babel/preset-typescript
yarn add -D @babel/plugin-proposal-class-properties
아래는 본인은 사용했지만, 자신이 사용한 코드 및 라이브러리에 따라서 선택적으로 설치 및 사용하면 되겠다.
yarn add -D @babel/plugin-proposal-object-rest-spread
yarn add -D @babel/plugin-proposal-optional-chaining
yarn add -D babel-plugin-styled-components
필요한 라이브러리를 전부 설치했으면 이제 .babelrc
파일을 작성해주자. 해당 파일도 프로젝트 제일 최상단 경로에 저장하면 된다.
// .babelrc
{
"presets": [
"@babel/preset-env",
[
"@babel/preset-react",
{
"runtime": "automatic"
}
],
"@babel/preset-typescript"
],
"plugins": [
[
"module-resolver",
{
"root": "./src",
"extensions": [
".ts",
".tsx"
]
}
],
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-optional-chaining",
"babel-plugin-styled-components"
],
"ignore": [
"src/types",
"src/react-app-env.d.ts",
"src/setupTests.ts"
]
}
해당 파일을 그대로 사용하기 전에 짚고 넘어가야할 부분이 존재한다.
React 17 버전 이상일 경우, 기존의 import React from 'react'
가 더 이상 필요하지 않다. 그렇기 때문에, @babel/preset-react
의 옵션에서 runtime
을 automatic 으로 설정해주어야지 정상적으로 컴파일된 파일이 작동하게 된다.
코드를 작성할 때, 본인은 tscofnig.json
을 손봐서 모든 import 파일을 절대경로로 사용하고 있다. 하지만 배포할 때에는 이 것을 전부 상대경로로 바꾸어줘야 하기 때문에 module-resolver
를 사용한다. 그런데 이 때 extensions
를 설정해주지 않으면 기본 확장자가 .js
, .jsx
파일을 대상으로 진행하여 타입스크립트 파일은 정상적으로 적용되지 않는 경우가 발생한다. 그렇기에 추가적으로 .ts
, .tsx
확장자를 추가해주도록 하자.
컴파일을 진행할 때, type declaration도 같이 컴파일해버리면 곤란하기 때문에, 따로 ignore
에 추가하여 스킵한다음에 추후에 따라 추가시키도록 하자.
이제 컴파일할 준비도 거의 완성되간다. 마지막으로 아까 수정했던 package.json
을 추가적으로 수정해주도록 해보자.
{
"files": [ // 배포를 진행할 파일 및 폴더를 지정한다.
"lib",
"README.md"
]
"main": "lib/modules/index.js", // 모듈의 시작점 파일경로를 작성해준다.
"scripts": {
"start": "react-scripts start",
"test": "react-scripts test",
"clean": "rimraf lib",
"precompile": "yarn test && yarn clean",
"compile": "babel src --out-dir lib --extensions .ts,.tsx --copy-files --no-copy-ignored",
"postcompile": "cp -r ./src/types ./lib/types"
},
"peerDependencies": { // 종속성 중복처리를 위한 추가 작성
"react": ">=17.0.1"
},
"types": "lib/types/index.d.ts"
}
컴파일하는 과정은 다음과 같다.
.ts
, .tsx
파일 대상으로 컴파일 진행--copy-files
와 --no-copy-ignored
는 옵션사항이기 때문에 선택적으로 사용해주자. ]컴파일이 끝난 후, 권한을 처리할 차례이다. 아래 단계를 진행해보자.
먼저 조건이 필요하다. 우리가 자주 사용하는 Github 계정과 Package Registry에 접근할 수 있는 Access Token을 생성해보도록 해보자.
Github Settings -> Developer settings -> Personal access tokens 와 같은 경로로 이동을 해보도록 하자.
그리고 난 후에, Generate new token을 클릭하여 자신의 Password를 입력해주면 어떠한 권한을 이 Token에 부여할지 선택을 할 수 있다!
본인은 기본적으로 repo
, write:packages
, delete:packages
를 선택하여 생성하였다.
이제 생성을 누르면 목록에 Token값이 적혀있을건데, 현재 화면에서 벗어나게 되면 두 번 다시는 볼 수 없으니 바로 복사를 하여 안전한 곳에 저장해두도록 합시다. 😀
<Your_Access_Token>
자리에 아까 복사한 토큰을 넣어주자.//npm.pkg.github.com/:_authToken=<Your_Access_Token>
$ npm login --registry=https://npm.pkg.github.com
> Username: <Github_Name>
> Password: <Your_Access_Token>
> Email: <Your_Github_Email>
컴파일이 끝난 후, yarn publish
를 통하여 정상적으로 Github Registry에 Package를 올릴 수 있게 된다!
보편적인 모듈에서는 svg와 같은 에셋들이 포함되지 않지만, 본인이 배포하는 모듈에는 svg파일이 포함되어야 했다. 그런데 컴파일된 코드에서는 svg파일을 못불러오는 상황이 발생하기에 svg를 React Component로 변경하여 컴파일해주는 추가작업을 진행하였다. 만약 자신의 모듈에 svg를 포함하여 배포하려면 다음 방법을 추가적으로 진행해보도록 하자.
먼저 본인의 svg 파일 관리는 다음과 같이 진행하고 있었다.
// tree
src
ㄴ lib
ㄴ svg
ㄴ index.ts
ㄴ menu.svg
ㄴ search.svg
// src/lib/svg/index.ts
export { ReactComponent as MenuIcon } from './menu.svg';
export { ReactComponent as SearchIcon } from './search.svg';
이러한 구조에서 필요한 아이콘들을 다른 Component에서 불러와 사용 중이였지만, 수정할 필요가 있었다.
yarn add -D @svgr/cli
해당 라이브러리를 설치했다면, 컴파일 과정에서 한 가지 더 추가 및 수정해주면 된다.
// package.json
{
"scripts": {
"toSvgComponent": "npx @svgr/cli -d ./src/lib/svg ./src/lib/svg --ignore-existing && rm -f ./src/lib/svg/index.js",
"precompile": "yarn test && yarn clean && yarn toSvgComponent",
"compile": "babel src --out-dir dist --extensions .js,.ts,.tsx --copy-files --no-copy-ignored",
"postcompile": "cp -r ./src/types ./dist/types"
}
}
그리고 아까 src/lib/svg/index.ts
파일을 다음과 같이 수정해주었다.
// src/lib/svg/index.ts
import MenuIcon from './Menu'
import SearchIcon from './Search';
export {
MenuIcon,
SearchIcon
};
이렇게 변경시키는 이유는 yarn toSvgComponent
를 진행하게 되면, svg 파일이 .js
와 같은 React Component 파일로 떨어지게 된다. 위 코드는 그것을 이용하는 것이다.
:)