์ฌ์ฉ์๋ค์ ์์น์์ ์๋น์ค๋ฅผ ์ฌ์ฉ๊ฐ๋ฅํ๊ฒ ํ๋ ค๋ฉด ๋ฐฐํฌ์์ ์ด ํ์ํ๋ค. ๋ฐฐํฌ๋ฅผ ์ํด์ ์๋น์ค๋ฅผ ์ต์ ํํ๋ ์์ ์ด ํ์ํ๊ณ ์ด ๊ณผ์ ์ ๋น๋๋ผ๊ณ ํ๋ค.
์ด๋ ์ฌ๋ฌ ๋ชจ๋์ด ํ๋๋ก ์์ถ๋๊ฑฐ๋, ์ฝ๋ ๋๋ ํ, ๋ชจ๋์ด ๋ฐ๋ฒจ์ ์ํด ํธ๋์คํ์ผ๋ง ๋๋ ๋ฑ์ ์์ ์ด ์ผ์ด๋๋ค.
Webpack์ธ์๋ Vite, Rollup ๋ฑ์ ๋ชจ๋ ๋ฒ๋ค๋ฌ๋ฅผ ํตํด ๋น๋ํ ์ ์๋ค. ์์ฆ์๋ ๋น ๋ฅธ ๋น๋ ์๋๋ก ์ ๋ช ํ vite๊ฐ ์ฌ์ฉ๋ฅ ์ด ์ ์ ๋์์ง๋ ์ถ์ธ์ด๋ค. ํ์ง๋ง ์ฌ์ ํ ์ฌ์ฉ๋ฅ ์ webpack์ด ๋์ ๋ชจ์ต์ ๋ณผ ์ ์์๋ค.
vite๋ณด๋ค ๋ ์ผ์ฐ ๋ฑ์ฅํ webpack์ ๊ธฐ์ค์ผ๋ก ๋ชจ๋ ๋ฒ๋ค๋ฌ์ ๋ํด ๋ํด์ ์ ๋ฐ์ ์ผ๋ก ์ดํดํ๊ณ ๋๋ฉด vite๊ฐ ์ด๋ค ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ํ๋์ง ๋ ์ด๋ค ๊ธฐ๋ฅ์ด ํฅ์๋๋์ง, ์ฃผ์๊ธฐ๋ฅ์ ๋ฌด์์ธ์ง ์ด๋ ค์์์ด ์ดํดํ ์ ์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ค.
webpack๊ณผ ๊ฐ์ ๋ชจ๋ ๋ฒ๋ค๋ฌ๋ ํฌ๊ฒ ์ฌ์ฉ์ ๊ฒฝํ
, ๊ฐ๋ฐ ์์ฐ์ฑ
2๊ฐ์ง ๊ด์ ์์ ์ด์ ์ด ์๋ค.
๋ํ๋์ ๊ทธ๋ํ๋ฅผ ์์ฑํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๋ชจ๋. default๋ src/index.js๋ก ์ค์ ๋๋ค.
module.exports = {
entry: "src/main.js"
}
์์ฑ๋ ๋ฒ๋ค(๋น๋ ๊ฒฐ๊ณผ๋ฌผ)์ ์ค์ ํ๋ ๋ชจ๋. ๋ฒ๋ค์ ๋ด๋ณด๋ผ ์์น์ ํ์ผ์ ์ด๋ฆ์ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ webpack์ ์ค๋ช ํ๋ค. default๋ ./dist/main.js๋ก ์ค์ ๋๋ค.
const path = require('path');
module.exports = {
output: {
path: path.resolve(__dirname, 'dist');
filename: 'webpack-bundle.js',
}
}
webpack์ javascript, JSONํ์ผ๋ง ์ดํดํ ์ ์๋ค. ๊ฐ ๋ชจ๋๋ค์ loader๋ฅผ ์ ์ฉ ํจ์ผ๋ก์ webpack์ด ๊ฐ ๋ชจ๋์ ์ดํดํ ์ ์๊ฒ ๋ณํํ ํ์ ๋ฒ๋ค์ ์ถ๊ฐํ๋ค. ์๋ฅผ ๋ค์ด ts๋ฅผ js๋ก ๋ณํํ๋ค๊ฑฐ๋, ์์ ๋ฒ์ ์ ๋ฌธ๋ฒ์ ํ์ ๋ฒ์ ์ ๋ฌธ๋ฒ์ผ๋ก ๋ณํํ๋๋ก ๋์ ๋ชจ๋์ ์ ์ฉํ๋ค.
ex) babel-loader, ts-loader, css-loader
module.exports = {
module: { // ์ฌ์ฉํ loader๋ค์ ์ ์ธ
rules: [
{
test: /\.(ts|tsx|js|jsx)$/, // ๋ณํ์ ์ ์ฉํ ๋์
use: 'babel-loader' // ์ฌ์ฉ๋ ๋ก๋
}
]
}
}
ํ๋ฌ๊ทธ์ธ ์ธํฐํ์ด์ค๋ฅผ ํตํด ์ปดํ์ผ ํ๋ก์ธ์ค์ ์ง์ ์ ๊ทผํ ์ ์๋ค. ํ๋ฌ๊ทธ์ธ์ ์ปดํ์ผ ๋์ ์๋ก ๋ค๋ฅธ ์ง์ ์์ ์คํ๋๋ ์๋ช ์ฃผ๊ธฐ ํ ์ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ ์ ์์ต๋๋ค. ๊ฐ๊ฐ์ ํ ์ด ์คํ๋ ๋ ํ๋ฌ๊ทธ์ธ์ ํ์ฌ ์ปดํ์ผ ์ํ์ ๋ํ ๋ชจ๋ ์ก์ธ์ค ๊ถํ์ ๊ฐ๋๋ค. Loader์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ค์ ํ์ผ์ ์ ์ฉํ plugin์ ์ถ๊ฐํ๋ค.
๋ง์ด ์ฌ์ฉ๋๋ plugin ์ฌ์ฉ ์์ ๋ฅผ ํตํด ์ดํดํด๋ณด์.
template์ ์ ๋ฌํ๋ฉด, ๋น๋ ๊ฒฐ๊ณผ๋ฌผ์ ์๋์ผ๋ก template์ ์ฝ์ ํด์ฃผ์ด์ ์์ฃผ ํธํ๊ณ ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋ฅ์ด๋ค.
module.exports = {
plugins: [new HtmlWebpackPlugin({ template: 'public/index.html' })]
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- ์๋์ ๊ฐ์ด index.html์ ๋น๋ ๊ฒฐ๊ณผ๋ฌผ(/main.bundle.js)์ ์ฃผ์
-->
<script defer src="/main.bundle.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
๋ชจ๋์ import / require ์ ๋ช ์์ ์ผ๋ก ํ์ง ์์๋ ์๋์ผ๋ก ๋ก๋ํ๋ค.
์๋์ ๊ฒฝ์ฐ React identifier๋ฅผ ๋ง๋ ๋ ๋ง๋ค react ๋ชจ๋์ ์๋์ผ๋ก ๋ก๋ํ๋ค. CRA ์ฌ์ฉ ์ React๋ฅผ ๋ช ์์ ์ผ๋ก importํ์ง ์์๋ ๋์ํ๋ ๊ฒ์ผ๋ก ์๊ณ ์๋๋ฐ, ์๋ง ProvidePlugin์ด ์๋์ฒ๋ผ ์ค์ ๋์ด์์ด ๊ฐ๋ฅํ ๊ฒ์ด ์๋๊น ์ถ๋ค.
new webpack.ProvidePlugin({
React: 'react'
});
function Page () {
return <div>MyPage</div>
}
์ด์ธ์๋ DefinePlugin(ํ๊ฒฝ๋ณ์์ค์ ), BannerPlugin(๋ฒ๋ค ์๋จ์ ์ง์ ๋ ๋ฌธ์์ด ์ฝ์ ) ๋ฑ์ ํ๋ฌ๊ทธ์ธ์ด ์ ๊ณต๋๋ค.
webpack ์ค์ ์, mode
์ต์
์ ์ค์ ํ ์ ์๋ค. ๊ฐ์ development | none | production
์ด ๋ ์ ์๋๋ฐ, ๊ฐ ํ๊ฒฝ์ ๋ง๊ฒ ๋น๋ ๊ฒฐ๊ณผ๋ฌผ์ ์ต์ ํํด์ค๋ค.
์๋ฅผ ๋ค์ด development์ production ๋ชจ๋๋ฅผ ๋น๊ตํ๋ฉด, ๋น๋ ๊ฒฐ๊ณผ๋ฌผ ํฌ๊ธฐ๊ฐ ์ค์ด๋ ๋ค.
production
(default) ๋ฒ๋ค ์ฌ์ด์ฆ๋ฅผ ์ค์ด๊ณ ์ฝ๋๋ฅผ ๋๋
ํํ๋ค.development
๋น ๋ฅด๊ฒ ๋น๋๋๋ค.none
์ต์
์ ์ค์ ํ์ง ์๋๋ค.$ webpack --config webpack.config.js --mode=production
์ถ๊ฐ์ ์ผ๋ก mode์ ๋ฐ๋ผ ์ ์ฉํ๊ณ ์ถ์ ์ต์ ์ ๋ด์ฉ์ด ๋ค๋ฅผ ์๊ฐ ์๋ค. ์๋์ ๊ฐ์ด 2๋ฒ์งธ ํ๋ผ๋ฏธํฐ argv๋ฅผ ํตํด mode์ ์ ๊ทผํ๊ณ , ์ด ๊ฐ์ ๋ฐ๋ผ ๋ถ๊ธฐ ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ๋ฉด๋๋ค.
const config = {
entry: './index.js',
//...
};
module.exports = (env, argv) => {
if (argv.mode === 'development') {
config.devtool = 'source-map';
}
if (argv.mode === 'production') {
//...
}
return config;
};
์ ํ๋ฆฌ์ผ์ด์ ์ ๋น ๋ฅด๊ฒ ๊ฐ๋ฐํ๋๋ฐ ์ฌ์ฉํ ์ ์๋ค. ์ด๋ ์๋ฒ๋ฅผ ์คํํ์ฌ ๋น๋ ๊ฒฐ๊ณผ๋ฌผ์ ์ ๊ณตํ๋ค.
์ฌ์ฉ์ ์ํด ์์กด์ฑ์ ์ค์นํ๊ณ , server๋ฅผ ์คํํ ์ ์๋ค.
$ npm install --save-dev webpack webpack-dev-server
$ webpack serve
http://[devServer.host]/webpack-dev-server
๊ฒฝ๋ก๋ฅผ ์
๋ ฅํ๋ฉด ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋ ํ์ผ๋ค์ ํ์ธํ ์ ์๋ค.source map์ ์ข
๋ฅ
์ข
๋ฅ๊ฐ ๋ง์ ์ด๋ค source map์ ๊ณจ๋ผ์ผํ ์ง ๊ณ ๋ฏผ์ด ๋ ์ ์๋ค. Webpack ๊ณต์๋ฌธ์์์ ์ถ์ฒํ๋ ๊ฑด, ๊ฐ๋ฐ ํ๊ฒฝ์ ๋ฒ๋ค ํฌ๊ธฐ๋ณด๋ค ์๋๊ฐ ์ค์ํ๊ณ ๋ฐฐํฌ ๋ชจ๋์์๋ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ๋ ์ค์์ ํ๋ฏ๋ก ๊ฐ ํ๊ฒฝ์ ์ ํฉํ mapping ์คํ์ผ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
eval
์๋๋ ๋น ๋ฅด๋ค. ํธ๋์คํ์ผ๋ ์ฝ๋์ ๋งคํ๋์ด ์ค ๋ฒํธ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ํ์ํ์ง ์๋๋ค.eval-source-map
์ฒ์ ๋น๋๋ ๋๋ฆฌ์ง๋ง, ์ฌ๋น๋๋ฅผ ๋น ๋ฅด๊ฒ ํ๋ค. ์ค ๋ฒํธ๊ฐ ์๋ณธ ์ฝ๋์ ๋งคํ๋๋ค.source-map
์ ์ฒด ์์ค๋งต์ ๋ณ๋์ ํ์ผ๋ก ๋ด๋ณด๋ธ๋ค. build, rebuild ์๋๊ฐ ๋๋ฆฌ์ง๋ง ๊ณ ํ์ง์ด๋ค. ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ฌ ๋ฐฐํฌ์ ์ ํฉํ์ง๋ง, ๋ฐฐํฌ ํ๊ฒฝ์์ ์์ค๋งต์ ์ ๊ทผํ์ง ๋ชปํ๋๋ก ํด์ผํ๋ค.์ฌ๋ฌ devtools ์ค eval-source-map
์ผ๋ก ์ค์ ํ์ ๋์ ๊ฒฐ๊ณผ๋ค. (์ฝ๋๊ฐ ๊ธธ์ด ๋ง์ด ์๋ตํ๋ค)
// bundle ์ฝ๋ ์ผ๋ถ
/***/
"./src/App.tsx": /*!*********************!*\\
!*** ./src/App.tsx ***!
\\*********************/
/***/
((__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{
"use strict";
eval(/* ์๋ต */ "//*#__PURE__*/React.createElement(\\"div\\", null, ms);\\n }))\\n},
{\\n path: _constants__WEBPACK_IMPORTED_MODULE_1__.ROUTE_LOGIN_URL,\\n
element: /*#__PURE__*/React.createElement(pages_LoginPage__WEBPACK_IMPORTED_MODULE_0__
[\\"default\\"], null)\\n}, {\\n path: '/',\\n element: /*#__PURE__*/
/* ์๋ต */
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJn
//# sourceURL=webpack-internal:///./src/App.tsx\\n");
/***/
}
),
์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด #sourceMappingURL์ด ์๋๋ฐ, ์ด๋ ์์ฑ๋ source map์ ์ฐธ์กฐํ๋ฉฐ ์๋์ ๊ฐ์ ๋ด์ฉ์ด ํฌํจ๋ผ์๋ค.
// ๊ฐ ๋ชจ๋์ ๋ํด ์์ฑ๋ source map
{ "version":3,
"file":"./src/App.tsx.js",
"mappings":";;;;;;;;;;;;;;;AAAwC;AAC0C;AACH;AACxB;AACH;AACV;AACJ;AACQ;AACAAA.. // ...์ดํ ์๋ต
"sources":["webpack:///./src/App.tsx?1c6d"],
"sourcesContent":["import LoginPage from 'pages/LoginPage';\\nimport { ROUTE_FORM_URL, ROUTE_REQUESTS_URL, ROUT // ...์ดํ ์๋ต
"names": ["LoginPage","ROUTE_FORM_URL","ROUTE_REQUESTS_URL","ROUTE_LOGIN_URL","RouterProvider","createBrowserRouter","AuthContextProvider","Reque // ...์ดํ ์๋ต
"sourceRoot":""
}