minimimi
[Shell Script] 01. boilerplate 폴더/파일 생성하기 with. ChatGPT 본문
Intro
react를 이용한 atomic design 시스템 개발을 하던 중 atom을 만들 때 마다 동일한 패턴의 파일을 생성하고, atom/index.ts에 export { default as Button } from "./Button";과 같이 export 구문을 수동으로 추가해줘야 했습니다.
보일러 플레이트 폴더 구조와 파일을 스크립트를 이용하여 생성할 수 있을 것으로 기대하여 스크립트를 개발해보기로 하였습니다.
하지만 스크립트를 작성해본 적이 없었다. chatGPT와 함께
스크립트를 작성해본 적이 없기 때문에 GPT의 도움으로 작성을 시작하였습니다.
스크립트 문법에 대해서 잘 알지 못하였지만 gpt가 작성해준 코드를 보며 이해해보며 작성할 수 있었습니다.
모든 스크립트의 파일 명 앞에 _ prefix를 이용하여 npm에 올릴 때 포함되지 않도록 하였습니다.
_constants.sh
RED='\\033[0;31m'
GREEN='\\033[0;32m'
YELLOW='\\033[0;33m'
BLUE='\\033[0;34m'
NC='\\033[0m' # No Color
터미널의 색상을 바꾸기 위한 색깔 상수를 저장합니다.
_generate_boilerplate.sh
# Check if correct number of arguments provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <directory> <filename>"
exit 1
fi
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$SCRIPT_DIR/_constants.sh"
directory=$1
filename=$2
# Create directory if it doesn't exist
if [ ! -d "src/$directory/$filename" ]; then
mkdir -p "src/$directory/$filename"
echo -e "${GREEN}+ src/$directory/$filename${NC}"
else
echo -e "src/$directory/$filename"
fi
# Call touch_file.sh script to create the file
scripts/_touch_file.sh "$directory" "$filename" "tsx"
scripts/_touch_file.sh "$directory" "$filename" "scss"
scripts/_touch_file.sh "$directory" "$filename" "stories.tsx"
scripts/_touch_file.sh "$directory" "$filename" "ts"
scripts/_update_index.sh "$directory" "$filename"
Line by Line
# Check if correct number of arguments provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <directory> <filename>"
exit 1
fi
argument에 <directory> <filename> 가 필수이기에 없다면 종료해줍니다.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$SCRIPT_DIR/_constants.sh"
상수 파일을 import하기 위해 source 키워드를 이용하여 파일에 접근 가능하게 합니다.
# Create directory if it doesn't exist
if [ ! -d "src/$directory/$filename" ]; then
mkdir -p "src/$directory/$filename"
echo -e "${GREEN}+ src/$directory/$filename${NC}"
else
echo -e "src/$directory/$filename"
fi
src/$directory/$filename 디렉토리가 존재하지 않는다면 디렉토리를 생성합니다.
# Call touch_file.sh script to create the file
scripts/_touch_file.sh "$directory" "$filename" "tsx"
scripts/_touch_file.sh "$directory" "$filename" "scss"
scripts/_touch_file.sh "$directory" "$filename" "stories.tsx"
scripts/_touch_file.sh "$directory" "$filename" "ts"
scripts/_update_index.sh "$directory" "$filename"
_touch_file.sh와 _update_index.sh를 호출하여 보일러 플레이트 파일을 생성하고, index.ts에 export문을 업데이트해줍니다.
_touch_file.sh
# Check if correct number of arguments provided
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <directory> <filename> <extension>"
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_constants.sh"
directory="$1"
filename="$2"
extension="$3"
# Create index.ts file
if [ "$extension" = "ts" ]; then
index_file_path="src/$directory/$filename/index.ts"
# Check if file already exists
if [ -e "$index_file_path" ]; then
echo -e "[$0]\\tSkip: File $index_file_path already exists in src/$directory/$filename."
exit 1
fi
cat <<EOF >"$index_file_path"
export { default } from "./${filename}";
EOF
echo -e "${GREEN} + index.ts${NC}"
exit 0
fi
# Set file path
file_path="src/$directory/$filename/$filename.$extension"
# Check if file already exists
if [ -e "$file_path" ]; then
echo -e "[$0]\\tSkip: File $filename.$extension already exists in src/$directory/$filename."
exit 1
fi
# Create the file with proper indentation
if [ "$extension" = "scss" ]; then
cat <<EOF >"$file_path"
.Mini-${filename} {
}
EOF
# Create tsx file
elif [ "$extension" = "tsx" ]; then
cat <<EOF >"$file_path"
import React from 'react';
import classNames from "classnames";
import './$filename.scss'
export type ${filename}Props = React.DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
> & {};
const $filename = ({...props}: ${filename}Props) => {
return (
<div {...props} className={classNames("Mini-${filename}", props.className)}>
{props.children ?? "$filename"}
</div>
);
}
export default $filename;
EOF
# Create stories.tsx file
elif [ "$extension" = "stories.tsx" ]; then
cat <<EOF >"$file_path"
import React from "react";
import $filename, { ${filename}Props } from "./$filename";
import styles from "./$filename.scss";
import classNames from "classnames";
export default {
component: $filename,
title: "$filename",
};
const cx = classNames.bind(styles);
const Template = (args: ${filename}Props) => <$filename {...args} />;
export const Default = Template.bind({});
Default.args = {
$filename: {
title: "Default $filename",
state: "$filename",
},
};
EOF
fi
echo -e "${GREEN} + $filename.$extension${NC}"
exit 0
Line by Line
# Create index.ts file
if [ "$extension" = "ts" ]; then
index_file_path="src/$directory/$filename/index.ts"
# Check if file already exists
if [ -e "$index_file_path" ]; then
echo -e "[$0]\\tSkip: File $index_file_path already exists in src/$directory/$filename."
exit 1
fi
cat <<EOF >"$index_file_path"
export { default } from "./${filename}";
EOF
echo -e "${GREEN} + index.ts${NC}"
exit 0
fi
확장자가 ts일 경우 index_file_path파일을 생성하고, export { default } from "./${filename}";를 컨텐츠를 채워줍니다.
그 외 확장자가 tsx, scss, stories.tsx 인 경우 각각에 맞는 파일을 생성하고 컨텐츠를 채워줍니다. 이 확장자의 경우는 $filename.$extenstion 으로 파일 명이 정해지기에 if…elif…fi 구문으로 묶어주었습니다.
# Set file path
file_path="src/$directory/$filename/$filename.$extension"
# Check if file already exists
if [ -e "$file_path" ]; then
echo -e "[$0]\\tSkip: File $filename.$extension already exists in src/$directory/$filename."
exit 1
fi
# Create the file with proper indentation
if [ "$extension" = "scss" ]; then
cat <<EOF >"$file_path"
.Mini-${filename} {
}
EOF
# Create tsx file
elif [ "$extension" = "tsx" ]; then
# ... 이하 생략
fi
echo -e "${GREEN} + $filename.$extension${NC}"
exit 0
_update_index.sh
# Check if correct number of arguments provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <directory> <component_name>"
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_constants.sh"
directory="$1"
component_name="$2"
index_file="src/$directory/index.ts"
# Check if index.ts file exists
if [ -f "$index_file" ]; then
# Check if the export line already exists
if grep -q "export { default as $component_name } from \\"./$component_name\\";" "$index_file"; then
echo -e "[$0]\\tSkip: Export line already exists in $index_file"
exit 0
fi
# Append export line to the end of the file
echo "export { default as $component_name } from \\"./$component_name\\";" >>"$index_file"
echo -e "src/$directory"
echo -e "${YELLOW} + $index_file${NC}"
else
echo -e "[$0]\\tError: $index_file does not exist."
exit 1
fi
Line by Line
# Check if the export line already exists
if grep -q "export { default as $component_name } from \\"./$component_name\\";" "$index_file"; then
echo -e "[$0]\\tSkip: Export line already exists in $index_file"
exit 0
fi
index.ts에 export 구문이 있는 지 확인합니다. 프로젝트에서 .eslintrc.js를 사용하고 있기에 포멧을 맞출 수 있고 export { default as $component_name } from \\"./$component_name\\"; 라인만 확인하면 됩니다.
해당 export 구문이 없다면 추가해줍니다.
실행 결과
atom 디렉토리에 Textarea 를 추가하는 스크립트를 실행합니다.
Textarea 보일러 플레이트를 생성하고 atom/index.ts 를 업데이트하였습니다.
개선 사항
CheckBox 폴더에 CheckBox.stories.tsx 폴더만 존재하지 않아 스크립트를 실행하니 터미널 로그가 이쁘게 나오지 않네요. echo 구문을 수정하여 생성 및 업데이트를 먼저 echo하고 그 외 스킵한 구문은 가장 아래로 내리면 더 보기 좋은 echo문을 만들 수 있을 것 같습니다.
다음 포스트
'프로그래밍 공부 > Unix' 카테고리의 다른 글
[Shell Script] 02. boilerplate 폴더/파일 생성하기 with. ChatGPT (0) | 2024.03.25 |
---|---|
[리눅스/유닉스] Window 10 MS Store에서 우분투(Ubuntu) 쉘(Shell)설치하기 (0) | 2019.08.26 |