Skip to content

Latest commit

ย 

History

History
408 lines (280 loc) ยท 11.1 KB

webpack.md

File metadata and controls

408 lines (280 loc) ยท 11.1 KB

Webpack

์›นํŒฉ์ด๋ž€ ๋ชจ๋“ˆ์„ ์œ„ํ•œ ๋ฒˆ๋“ค๋Ÿฌ์ด๋‹ค. ๋ชจ๋“ˆ์ด๋ž€ import, export๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉฐ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ ์กฐ๊ฐ์ด๋ฉฐ ๋ฒˆ๋“ค๋ง์ด๋ž€ js, css, asset ํŒŒ์ผ ๋“ฑ์„ ํ•˜๋‚˜์˜ ํŒŒ์ผ๋กœ ๋ฌถ์–ด์ฃผ๋Š” ์ž‘์—…์„ ์˜๋ฏธํ•œ๋‹ค.

์›นํŒฉ์€ ๋ชจ๋“ˆํ™” ๋„๊ตฌ๋กœ์„œ ๋‹ค์–‘ํ•œ ๋กœ๋”๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŒŒ์ผ์„ ํ•˜๋‚˜๋กœ ๋ฒˆ๋“ค๋งํ•˜๊ธฐ ๋•Œ๋ฌธ์— HTTP ์š”์ฒญ ํšŸ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค ํฌ๋งท์˜ ๋ชจ๋“ˆ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค


Dependency Graph

ํ•œ ํŒŒ์ผ์ด ๋‹ค๋ฅธ ํŒŒ์ผ์„ ํ•„์š”๋กœํ•˜๋ฉด ์›นํŒฉ์€ ์ด๊ฒƒ์„ dependency๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉฐ ์ด๋ฅผ ํ†ตํ•ด ์ด๋ฏธ์ง€๋‚˜ ์›น ํฐํŠธ์™€ ๊ฐ™์ด ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ๋ฆฌ์†Œ์Šค๋ฅผ dependency๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

์›นํŒฉ์€ ๋ฒˆ๋“ค๋ง ์ž‘์—… ์‹œ dependency graph๋ฅผ ๊ทธ๋ฆฌ๋Š”๋ฐ dependency graph๋Š” ์ •์˜๋œ entry์—์„œ ์ถœ๋ฐœํ•ด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ•„์š”ํ•œ ๋ชจ๋“ˆ์„ ํฌํ•จํ•˜๋Š” ๊ทธ๋ž˜ํ”„๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋นŒ๋“œํ•œ๋‹ค. ๊ทธ๋ž˜ํ”„๋ฅผ ์™„์„ฑ์‹œํ‚จ ํ›„ ํ•˜๋‚˜ ๋˜๋Š” ์†Œ์ˆ˜์˜ ๋ฒˆ๋“ค๋กœ ๋ฒˆ๋“ค๋งํ•ด ๋ธŒ๋ผ์šฐ์ €์— ๋กœ๋“œํ•  ์ค€๋น„๋ฅผ ๋๋‚ธ๋‹ค.


Core Concepts

๋‹ค์Œ์€ ์›นํŒฉ์„ ์ดํ•ดํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ํ•ต์‹ฌ ๊ฐœ๋…๋“ค์— ๋Œ€ํ•œ ์„ค๋ช…์ด๋‹ค.


Entry

entry๋ž€ dependency graph์˜ ์ถœ๋ฐœ์ ์ด๋‹ค. entry๋ฅผ ํ†ตํ•ด depency graph๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ํฌํ•จํ•  ๋ชจ๋“ˆ์˜ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

// webpack.config.js

module.exports = {
  entry: './path/to/my/entry/file.js',
};

Output

output์€ ๋ฒˆ๋“ค๋ง ์™„๋ฃŒ๋œ ํŒŒ์ผ์„ ๋‚ด๋ณด๋‚ผ ์œ„์น˜๋ฅผ ์ง€์ •ํ•œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ dist ๋””๋ ‰ํ† ๋ฆฌ ํ•˜์œ„ ๊ฒฝ๋กœ์— ์ €์žฅ๋˜๋ฉฐ ํŒŒ์ผ ์ด๋ฆ„์ด๋‚˜ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋กœ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

clean ํ”„๋กœํผํ‹ฐ๋ฅผ true๋กœ ์„ค์ •ํ•˜๋ฉด output ๊ฒฝ๋กœ์˜ ๋””๋ ‰ํ† ๋ฆฌ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

// webpack.config.js

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'webpack-practice.bundle.js',
  },
};

Loaders

์›นํŒฉ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ json ํŒŒ์ผ๋งŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค. loader๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ json ํŒŒ์ผ์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์œ ํ˜•์˜ ๋ฆฌ์†Œ์Šค๋“ค์„ dependency graph์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“ˆ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

v๋กœ๋”๋Š” test์™€ use ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๋Š”๋ฐ, test์—๋Š” ํŒŒ์ผ์˜ ํ˜•์‹์„, use์—๋Š” test์—์„œ ์ง€์ •ํ•œ ์œ ํ˜•์˜ ํŒŒ์ผ์„ ๋ณ€ํ™˜ํ•  ๋•Œ ์‚ฌ์šฉํ•  loader๋ฅผ ๋ช…์‹œํ•ด์•ผํ•œ๋‹ค.

// webpack.config.js

const path = require('path');

module.exports = {
  output: {
    filename: 'webpack-practice.bundle.js',
  },
  module: {
    rules: [{ test: /\.txt$/, use: 'raw-loader' }],
  },
};

loader๋ฅผ ์„ค์ •ํ•ด์ฃผ๋ฉด ํŒŒ์ผ ์œ ํ˜•์— ์ƒ๊ด€์—†์ด import๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.


Plugins

loader๋Š” ํŠน์ • ์œ ํ˜•์˜ ํŒŒ์ผ์„ ๋ชจ๋“ˆ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•˜์ง€๋งŒ plugin์€ ๋ฒˆ๋“ค ์ตœ์ ํ™”, asset ๊ด€๋ฆฌ ๋ฐ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • ๋“ฑ์— ์‚ฌ์šฉ๋œ๋‹ค.

plugin์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” plugin ํŒจํ‚ค์ง€๋ฅผ import๋‚˜ requireํ•ด ๊ฐ€์ ธ์˜จ ๋‹ค์Œ plugins ํ”„๋กœํผํ‹ฐ์— ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค.

const HtmlWebpackPlugin = require('html-webpack-plugin'); 
const webpack = require('webpack'); 

module.exports = {
  module: {
    rules: [{ test: /\.txt$/, use: 'raw-loader' }],
  },
  plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};


Setup for React app without CRA

๋‹ค์Œ์€ create react app(cra) ์—†์ด ์›นํŒฉ์„ ๊ตฌ์„ฑํ•˜๋Š” ์˜ˆ์ œ์ด๋‹ค.

Why it is better to avoid Create React App(CRA)

cra๋Š” ์›นํŒฉ๊ณผ ์›นํŒฉ ๊ตฌ์„ฑ ์š”์†Œ๋“ค์„ ์•Œ์ง€ ๋ชปํ•˜๋”๋ผ ๋ฆฌ์•กํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฆฌ์•กํŠธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•ด์ฃผ๋Š” ๋„๊ตฌ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ cra๋Š” ์›นํŒฉ ์„ค์ •์„ ์ œํ•œํ•˜๊ณ  ๋ถˆํ•„์š”ํ•œ dependency๋“ค์ด ๋งŽ์œผ๋ฉฐ ํ™˜๊ฒฝ ์„ค์ •์„ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ •์˜ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.


Install Webpack

๊ฐ€์žฅย ๋จผ์ € ์›นํŒฉ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ด์•ผํ•œ๋‹ค.

npm install webpack
	or
yarn add webpack

Configure Webpack

๋‹ค์Œ์œผ๋กœ ์›นํŒฉ config ํŒŒ์ผ์ธ webpack.config.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

Add Development mode

webpack.config.jsํŒŒ์ผ์—์„œ mode๋ฅผ development๋กœ ์„ค์ •ํ•œ๋‹ค.

// webpack.config.js

module.exports = {
  mode: 'development',
};
yarn add --dev webpack-cli

์›นํŒฉ cli ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•œ ํ›„ ๋นŒ๋“œํ•˜๋ฉด dist ๋””๋ ‰ํ† ๋ฆฌ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒŒ์ผ์ด ์‹คํ–‰๋œ๋‹ค.

// src/index.js

const test = 'test';
// dist/main.js

(() => {
  var __webpack_modules__ = {
    './src/index.js': () => {
      eval(
        "const test = 'test';\r\n\n\n//# sourceURL=webpack://webpack-practice/./src/index.js?"
      );
    },
  };


  var __webpack_exports__ = {};
  __webpack_modules__['./src/index.js']();
})();

์›นํŒฉ์€ ๋ชจ๋“ˆ ๋ฒˆ๋“ค๋ฆฌ์ด๋‹ค. ๋‹ค๋ฅธ ์„ค์ •์ด ์—†์œผ๋ฉด src ๋””๋ ‰ํ† ๋ฆฌ์— ์ƒ์„ฑํ•œ index.js๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋ชจ๋“  dependency๋“ค์„ ํ•˜๋‚˜์˜ ํŒŒ์ผ ์ฆ‰, main.js๋กœ ๋ฒˆ๋“ค๋งํ•œ๋‹ค.

Add the Webpack server

๋‹ค์Œ์€ ์ €์žฅ ๋ฐ ์ƒˆ๋กœ๊ณ ์นจ ์—†์ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ฝ”๋“œ ๋ณ€๊ฒฝ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด webpack-server๋ฅผ ์„ค์น˜ํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.

yarn add --dev webpack-server webpack-dev-server

์œ„์™€ ๊ฐ™์ด ํŒจํ‚ค์ง€ ์„ค์น˜ ํ›„ package.json ์Šคํฌ๋ฆฝํŠธ์— webpack serve ๋ช…๋ น์„ ์ถ”๊ฐ€ํ•œ๋‹ค

// package.json

"scripts": {
  "start": "webpack serve"
},

์ด์ œ yarn์„ ํ†ตํ•ด ์‚ฌ์ดํŠธ๋ฅผ ์ปดํŒŒ์ผ ๋ฐ serve ํ•  ์ˆ˜ ์žˆ๋‹ค.

Add HTML Webpack Plugin

index.html์„ ์ƒ์„ฑํ•˜๊ณ  ๋ฒˆ๋“ค๋œ js ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด html-webpack-plugin์„ ์„ค์น˜ํ•ด์•ผํ•œ๋‹ค.

yarn add html-webpack-plugin

์„ค์น˜ ํ›„ ํ•ด๋‹น plugin์„ ๊ฐ€์ ธ์™€ ์›นํŒฉ ์„ค์ • ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

// webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');

const htmlWebpackPlugin = requrie('html-webpack-plugin');

module.exports = {
  mode: 'development',
  devServer: {
    port: 8001,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

์ด์ œ template ํ”„๋กœํผํ‹ฐ์— ์ง€์ •๋œ ๊ฒฝ๋กœ์— ์œ„์น˜ํ•œ html ํŒŒ์ผ์„ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

yarn start ์ปค๋งจ๋“œ๋กœ ๋นŒ๋“œ ํ›„ localhost:8001์—์„œ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ํ†ตํ•ด source๋ฅผ ํ™•์ธํ•˜๋ฉด index.htmlํŒŒ์ผ์—์„œ script ํƒœ๊ทธ๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ํ”Œ๋Ÿฌ๊ทธ์ธ์— ์˜ํ•ด ์ถ”๊ฐ€๋˜์–ด์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Link JavaScript with HTML

๋‹ค์Œ์€ html ํŒŒ์ผ์„ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ €์— js ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํ‘œ์‹œํ•ด์•ผํ•œ๋‹ค.

๋จผ์ € index.html ํŒŒ์ผ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

// index.html

...
  <body>
    <h1>This is a html file.</h1>
    <div id="fromjs"></div>
  </body>
...

index.js ํŒŒ์ผ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

document.querySelector('#fromjs').innerHTML = `<h1>From index.js</h1>`;

๋‹ค์‹œย yarn์„ ํ†ตํ•ด ๋นŒ๋“œํ•˜๋ฉด "This is a html file."ย ์•„๋ž˜์— js ํŒŒ์ผ์„ ํ†ตํ•ด ์ถ”๊ฐ€ํ•œ "From index.js" ๋‚ด์šฉ์ด ์ถœ๋ ฅ๋œ๋‹ค.


Add React to Webpack

๋‹ค์Œ๊ณผย ๊ฐ™์ด ๋ฆฌ์•กํŠธ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

yarn add react react-dom --save

์„ค์น˜ ํ›„ index.js ํŒŒ์ผ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render('Hello from index.js', document.querySelector('#fromjs'));

์ด์ œ ํ„ฐ๋ฏธ๋„์—์„œ yarn start ์ปค๋งจ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ReactDOM์„ ํ†ตํ•ด ๋ Œ๋”ํ•œ ์ปจํ…์ธ ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ 'Hello from index.js'๊ฐ€ ์•„๋‹Œ <h1>Hello from index.js</h1>๋ฅผ ์ž…๋ ฅํ•  ๊ฒฝ์šฐ ์ปดํŒŒ์ผ ๋˜์ง€ ์•Š๋Š”๋‹ค.

์ด๋•Œ ํ•„์š”ํ•œ ๊ฒƒ์ด ๋ฐ”๋กœ babel์ด๋‹ค.

Add Babel to Webpack

ํŠธ๋žœ์ŠคํŒŒ์ผ์ด๋ž€ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ๋ณ€ํ™˜์‹œํ‚ค๋Š” ์ž‘์—…์„ ์˜๋ฏธํ•œ๋‹ค. babel์€ ES6 ๋ฌธ๋ฒ•์œผ๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋ฅผ ES5 ๋ฌธ๋ฒ•์œผ๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผํ•ด์ฃผ๋Š” ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ์ด๋ฉฐ babel-loader๋Š” babel๊ณผ ์›นํŒฉ์„ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๋Š” loader์ด๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

yarn add @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/preset-react babel-loader 

ํŒจํ‚ค์ง€ ์„ค์น˜ ํ›„ webpack.config.js ํŒŒ์ผ์˜ module ํ”„๋กœํผํ‹ฐ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  devServer: {
    port: 8001,
  },
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react', '@babel/preset-env'],
            plugins: ['@babel/plugin-transform-runtime'],
          },
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

babel ์„ค์น˜ ๋ฐ babel-loader๋ฅผ ์›นํŒฉ๊ณผ ์—ฐ๊ฒฐํ•˜๋Š” ์„ค์ •์„ ์™„๋ฃŒํ•œ ํ›„์— index.js ํŒŒ์ผ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(<h1>Hello from js</h1>, document.querySelector('#fromjs'));

Add CSS to Webpack

๋‹ค์Œ์€ CSS๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์›นํŒฉ์— ์ถ”๊ฐ€ํ•˜๋Š” ์˜ˆ์ œ์ด๋‹ค.

๋จผ์ € css-loader์™€ style-loader ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

yarn add css-loader style-loader

webpack.config.js ํŒŒ์ผ์˜ moduel ํ”„๋กœํผํ‹ฐ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react', '@babel/preset-env'],
            plugins: ['@babel/plugin-transform-runtime'],
          },
        },
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },

์ด์ œ src ํ•˜์œ„ ๊ฒฝ๋กœ์— cssํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ณ  index.js์—์„œ css ํŒŒ์ผ์„ importํ•˜๋ฉด ํ”„๋กœ์ ํŠธ์— css ์Šคํƒ€์ผ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

// src/styles/style.css

* {
  color: red;
}
// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './styles/styles.css';

ReactDOM.render(<h1>Hello from js</h1>, document.querySelector('#fromjs'));



Reference