๐ JavaScript, Barrel ํ์ผ
์๋ฐ์คํฌ๋ฆฝํธ์์ ํน์ ๋๋ ํ ๋ฆฌ ๋ด์ ์ฌ๋ฌ ๋ชจ๋์ ํ๋์ ํ์ผ์์ re-export ํจ์ผ๋ก์จ
๋ค๋ฅธ ํ์ผ์์ ๊ฐ๊ฒฐํ import๋ฌธ์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ index ํ์ผ์ Barrel ํ์ผ์ด๋ผ๊ณ ํฉ๋๋ค.
์ฒ์์ Barrel์ด๋ ๋ช ์นญ์ ๋ชฐ๋ผ ๊ทธ๋ฅ ์ธ๋ฑ์ฑํ๋ค๊ณ ํ๋ฉฐ 1๋ ๋์ ๊ฒ์๋ ์ ๋๋ก ๋ชปํ์๋๋ฐ,
์ต๊ทผ ์ํฐํด์ ๋ณด๋ค ์ด๋ฌํ index ํ์ผ์ Barrel์ด๋ผ ํ๋ค๋ ๊ฒ์ ๋ณด๊ณค ์์ด ์์ํด์ก์ต๋๋ค.
๋ญ ์ด์จ๋ ๋ค๋ค ์์๊ฒ ์ง๋ง ๋ค์ ์ฝ๋๋ค์ ์ฃผ๋ก index.js
, index.ts
๋ก ์ฌ์ฉ๋๋ Barrel ํ์ผ์ ์ผ๋ฐ์ ์ธ ์์์
๋๋ค.
//barrel ์ ์ฉ ์
import { ModuleA } from 'utils/ModduleA';
import { ModuleB } from 'utils/ModduleB';
import { ModuleC } from 'utils/ModduleC';
์์ ๊ฐ์ด ํ์ผ๋น ํ์ค ์ฉ ๋์ด๋ฌ๋ import๋ฌธ์ ์๋์ ๊ฐ์ Barrel ํ์ผ์ ์ ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
// utils/index.ts
export { default as ModuleA } from './ModuleA';
export { default as ModuleB } from './ModuleB';
export { default as ModuleC } from './ModuleC';
// barrel ์ ์ฉ ํ
import { ModuleA, ModuleB, ModuleC } from 'utils';
๐ ๋๋ฌด๋ ๊ท์ฐฎ์ Barrel ํ์ผ ์์ฑ
์ฝ๋ ๋ผ์ธ์ด ๊ธธ์ด์ง๋๊ฑธ ๋๋ฌด๋ ์ซ์ดํ๋ ์ ์๊ฒ Barrel ํ์ผ์ ๊ฐ๋ญ์ ๋จ ๋น ๊ฐ์ ์กด์ฌ์์ผ๋,
๋ฌธ์ ๋ ํ์ผ์ด ์ถ๊ฐ๋๊ฑฐ๋ ์ญ์ ๋๋ฉด ๊ทธ๊ฑฐ์ ๋ํญํด Barrel ํ์ผ์ ์ผ์ผ์ด ์์์ ์ผ๋ก ์์ ํด์ฃผ์ด์ผ ํ๊ณ ,
์ด์ ์ ๋ชจ๋ฅด๊ณ ์ถ๊ฐํ์ง ์์๋ ํ์ผ์ ๋ ์ด๋๊ฐ ํ ์ค์ import ๋ผ์ธ์ด ๋์ด ์ ๋ฅผ ๊ดด๋กญํ์ต๋๋ค.
๊ทธ๋ฌ๋ค ์ด๋๋ ๋ฌธ๋ Node.js์ fs
๋ชจ๋์ ์ด์ฉํ๋ค๋ฉด ๋จ ํ ์ค์ ํฐ๋ฏธ๋ ๋ช
๋ น์ด๋ก
Barrel ํ์ผ์ ์๋ํํ ์ ์๊ฒ ๋ค๋ ์๊ฐ์ด ์ค์ณ ์ง๋๊ฐ์ต๋๋ค.
๐ Barrel ํ์ผ ์๋ํ ์คํฌ๋ฆฝํธ
๋ฐฐ๋ด ํ์ผ ์๋ ์์ฑ ์คํฌ๋ฆฝํธ ์ ์ฉ ์์ ๋ ์ ๊นํ๋ธ์ ์ฌ๋ ค๋จ์ผ๋ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
const fs = require('fs');
JavaScript์ fs
๋ชจ๋์ Node.js์ ํต์ฌ ๋ชจ๋ ์ค ํ๋๋ก,
ํ์ผ ์์คํ ์ ์ ๊ทผํ์ฌ ํ์ผ์ ์ฝ๊ณ , ์ฐ๊ณ , ์์ ํ๊ณ , ์ญ์ ํ๋ ๋ฑ์ ์์ ์ ์ํํ ์ ์๊ฒ ํด ์ค๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ์ด์ฉํ๋ค๋ฉด ํ์ฌ ํ๋ก์ ํธ์ ๋๋ ํ ๋ฆฌ๋ฅผ ์ฝ๊ณ ๋ถ์ํด
์ฌ๊ท์ ์ผ๋ก ํด๋์ ํด๋๋ฅผ ํ๊ณ ๋ค์ด๊ฐ Barrel ํ์ผ์ ์์ฑํ ์ ์๊ฒ ๋ค ์๊ฐํ๊ณ ,
chatGPT์ ๋์์ ๋ฐ์ ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ์์ฑ์์ผฐ์ต๋๋ค.
์ฌ๊ธฐ์ ์ง์ ์ฌ์ฉํ์ค ๋๋ ๋ค์ 3๊ฐ์ง๋ง ์ง์ ์์ ํด ์ฃผ์๋ฉด ๋ฉ๋๋ค.
- ํ์ฅ์ ๋ช
๋ณ๊ฒฝ์ ์ํ
isJavaScript
๋ณ์ ์์ - Barrel ํ์ผ์ ์์ฑํ ๋๋ ํ ๋ฆฌ ๋ชฉ๋ก
- Barrel ํ์ผ์์ export ํ์ง ์์ ์์ธ ํ์ผ ์ด๋ฆ ๋ชฉ๋ก
const fs = require('fs'); // ํ์ผ ์์คํ
๋ชจ๋ ์ฌ์ฉ
const path = require('path'); // ๊ฒฝ๋ก ๊ด๋ จ ๋ชจ๋ ์ฌ์ฉ
// ์์ค ์ฝ๋ ๋๋ ํ ๋ฆฌ ๊ฒฝ๋ก ์ค์
const srcFolderPath = path.join(__dirname, 'src');
let count = 0;
// (์ง์ ์์ ) index.js = true, index.ts = false
const isJavaScript = false;
const extension = isJavaScript ? 'js' : 'ts';
// (์ง์ ์์ ) ์ฒ๋ฆฌ ๋์ ๋๋ ํ ๋ฆฌ ๋ชฉ๋ก
const targetFolderList = ['apis', 'components', 'constants', 'hooks', 'pages', 'states'];
// (์ง์ ์์ ) ์์ธ ํ์ผ ๋ชฉ๋ก
const exceptionFileList = ['exception'];
targetFolderList.forEach((folder) => {
const folderPath = path.join(srcFolderPath, folder); // ๋์ ํด๋์ ์ ์ฒด ๊ฒฝ๋ก ์์ฑ
if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
generateIndexFile(folderPath); // ๋์ ํด๋์์ index.js(ts) ํ์ผ ์์ฑ ํจ์ ํธ์ถ
}
});
// ์ง์ ๋ ๋๋ ํ ๋ฆฌ ๋ด์ ํ์ผ๋ค์ ๊ธฐ๋ฐ์ผ๋ก index.js(ts) ํ์ผ์ ์์ฑํ๋ ํจ์
function generateIndexFile(directoryPath) {
// ํ์ฌ ๋๋ ํ ๋ฆฌ ๋ด์ index.js(ts) ํ์ผ ๊ฒฝ๋ก ์์ฑ
const indexFilePath = path.join(directoryPath, `index.${extension}`);
// ํ์ฌ ์คํฌ๋ฆฝํธ ํ์ผ๊ณผ์ ์๋ ๊ฒฝ๋ก ๊ณ์ฐ
const relativePath = path.relative(__dirname, indexFilePath);
const files = fs.readdirSync(directoryPath); // ๋๋ ํ ๋ฆฌ ๋ด์ ํ์ผ ๋ชฉ๋ก์ ์ฝ์ด์ด
const exportStatementList = []; // export ๊ตฌ๋ฌธ์ ๋ด์ ๋ฐฐ์ด
files.forEach((file) => {
// ํ์ผ์ ์ ์ฒด ๊ฒฝ๋ก ์์ฑ
const filePath = path.join(directoryPath, file);
// ํ์ฅ์๋ฅผ ์ ์ธํ ํ์ผ ์ด๋ฆ ์ถ์ถ
const fileNameWithoutExtension = path.basename(file, path.extname(file));
// ์์ธ ํ์ผ ๋ชฉ๋ก์ ํฌํจ๋๋์ง ํ์ธ
const isException = exceptionFileList.some((exceptionFileName) =>
exceptionFileName.toLowerCase().includes(fileNameWithoutExtension.toLowerCase()),
);
if (isException) return; // ์์ธ ํ์ผ์ธ ๊ฒฝ์ฐ, ๋ค์ ํ์ผ๋ก ๋์ด๊ฐ
if (
fs.statSync(filePath).isFile() &&
(file.endsWith(`.${extension}`) || file.endsWith(`.${extension}x`)) &&
file !== `index.${extension}`
) {
// ํ์ผ์ด ์กด์ฌํ๊ณ ํ์ฅ์๊ฐ .js(ts) ๋๋ .jsx(tsx)์ด๋ฉฐ, ํ์ผ ์ด๋ฆ์ด index.js(ts)๊ฐ ์๋ ๊ฒฝ์ฐ
exportStatementList.push(`export * from './${fileNameWithoutExtension}';`);
} else if (fs.statSync(filePath).isDirectory() && file !== `index.${extension}`) {
// ๋๋ ํ ๋ฆฌ์ธ ๊ฒฝ์ฐ, ํ์ผ ์ด๋ฆ์ด index.js(ts)๊ฐ ์๋ ๊ฒฝ์ฐ
exportStatementList.push(`export * from './${fileNameWithoutExtension}';`);
generateIndexFile(filePath); // ์ฌ๊ท์ ์ผ๋ก ํ์ ๋๋ ํ ๋ฆฌ ์ฒ๋ฆฌ
}
});
const content = exportStatementList.join('\n'); // export ๊ตฌ๋ฌธ์ ์ค ๋ฐ๊ฟ์ผ๋ก ์ฐ๊ฒฐํ์ฌ ๋ด์ฉ ์์ฑ
fs.writeFileSync(indexFilePath, content); // ์์ฑ๋ ๋ด์ฉ์ index.js(ts) ํ์ผ์ ์ฐ๊ธฐ
console.log(`${++count} ${`\t`} ${relativePath}`);
}
๐ ์ฌ์ฉ ๋ฐฉ๋ฒ
์์ ๊ฐ์ด ํ๋ก์ ํธ root ๊ฒฝ๋ก์ ํด๋น ํ์ผ์ ์์ฑํด ์ค๋๋ค.
๊ทธ๋ค์ package.json ํ์ผ์ scripts ๋ถ๋ถ์ node๋ก ํด๋น ํ์ผ์ ์คํ์ํค๋ ๋ช
๋ น์ด๋ฅผ ์ง์ ํด ์ค ๋ค,$ npm run barrel
์ ํฐ๋ฏธ๋์ ์
๋ ฅํ๋ฉด ์ ์ฝ๋์์ ์ง์ ํ๋ ๋๋ ํ ๋ฆฌ์ Barrel ํ์ผ์ด ์๋ ์์ฑ๋ฉ๋๋ค.
๐ ์ ์ฉ ์
๐ ์ ์ฉ ํ
๐ ์ฃผ์ ์ฌํญ
src ํด๋์ ๋ฐ๋ก ์๋ ์์ ํด๋๋ค์ด export ๊ฒฝ๋ก์ root๊ฐ ๋ฉ๋๋ค.
๊ทธ๋ ๊ธฐ์ ๋ชจ๋ ๋ชจ๋๋ค์ด export root ๊ฒฝ๋ก์ ์ด๋ฆ์ผ๋ก export ๋์ด์
ํด๋ ๋ช
, ํ์ผ ๋ช
, ํจ์ ๋ช
, ๋ณ์ ๋ช
์ ๋ฐ๋์ ์ค๋ณต๋์ง ์๊ณ unique **ํด์ผ ํฉ๋๋ค.
ex) export root = @pages, @hooks, @components...
๐ Barrel ํ์ผ์ ์ฌ์ฉํ์ง ๋ง๋ผ?
์คํฌ๋ฆฝํธ๋ฅผ ๋ง๋ค๊ณ ๋๋ฌด ์ ๋์ ํ๋ก์ ํธ์ ๋ช๋ช ๋๋ ํ ๋ฆฌ์ ๋ฐฐ๋ด ํ์ผ์ ์ ์ฉํ๋ค๊ณ
๋ฐ๋์ ๋์ ๋ชจ๋ ํด๋์ ์ค๋ณต์ ์์ ์ ์์ฑํ ํ ์ด ๊ธ์ ๋ด๋ฒ๋ ธ์ต๋๋ค…
๋ญ๊ฐ ๋น์ฐํ ๋ชจ๋ ํ์ผ์ ๋ชจ์์ ๋ด๋ณด๋ด๊ธฐ ํ๋ฉด ์ฑ๋ฅ์์ผ๋ก ๋ถ๋ฆฌํจ์ด ์์ ๊ฑฐ๋ผ ์๊ฐ์ ํ์ผ๋
์ ๊ธ์์ ๋๋ฌด๋ ๋ฌด์๋ฌด์ํ๊ฒ ๋งํ๊ธธ๋ ๋ฐ๋์ ์ ๋ญ๋นํ๋ ์ถ์ด ์ข์ ํ์ต๋๋ค.
ํ๋ฃจ์ข ์ผ ๊ณ ๋ฏผํ ๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด “๊ทธ๋ฅ ์ฌ์ฉํ๋ ํธ์ด ๋ ๋ซ๋ค” ์ ๋๋ค.
๊ทธ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๐ ๋ฐํ์์์๋ ๋๊ฐ๋ค
์ ๊ธ์์๋ ์ ์ ์๋ค์ํผ ๋ฐํ์์๋ ์ง์ฅ์ด ์์ต๋๋ค.
์ฆ, ์ค์ ์ฌ์ฉํ๋ ์ฌ์ฉ์๋ ๋ฐฐ๋ด์ ์ฌ์ฉํ๋ ์ฌ์ฉํ์ง ์์ผ๋ ๋๊ฐ๋ค๋ ๋ง์ ๋๋ค.
ํ์ง๋ง ๋ฌธ์ ๊ฐ ์๊ธฐ๋ ๋ถ๋ถ์ ๋๋ถ๋ถ ๊ฐ๋ฐ ๋จ๊ณ์์ ์กฐ๊ธ ๋ ์๊ฐ์ด ์ง์ฐ๋๋ค๋ ๊ฒ์ธ๋ฐ
์์ฆ ์ปดํจํ
ํ์๊ฐ ์๋ ์ํฅํ์คํ๋ฅผ ์ด๋ค๊ธฐ๋ ํ๊ณ ,
๋ช์ญ ์ค์ import ๋ผ์ธ์ ๋ณด๋ฉฐ ํ๊ฐ ์น์๋ ๊ฒ๋ณด๋ค ์๊ฐ์ด ์กฐ๊ธ ๋ ๊ฑธ๋ฆฌ๋ ๊ฒ ํจ์ฌ ๋ซ๋ค๊ณ ํ๋จํ์ต๋๋ค.
๊ทธ๋ผ ์ฌ๋ฌ๋ถ์ ๊ฐ์์ ํ์คํ ๊ฐ์นํ๋จ์ผ๋ก ๋ฐฐ๋ดํ์ผ์ ์ฌ์ฉ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ์๊ธธ ๋ฐ๋๋๋ค!
๋๊ธ