03_Webpack 기본구조
FrontEnd/웹 지식

03_Webpack 기본구조

728x90

Webpack

Webpack은 웹어플리케이션에 도움을 주는 하나의 도구이다.

 

 

 

Webpack의 기본 구조

 

https://webpack.js.org/

 

webpack

webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.

webpack.js.org

 

Webpack의 공식문서에 가면 가장먼저 보이는 이미지가 위 이미지이다.

 

다양한 확장자로이루어져서 서로 연결되어 있는 파일들이 뭔가 깔끔하게 정리된 모습을 확인할 수 있다.

 

Webpack은 Module를볼때

 

1.js

2.sass

3.hbs

4.jpg,png

 

다음과같이 확장자를 분류해서 바라보게 된다.

 

그림을조금더 보면 확장자별로 파일이 정리되어진다는것을 확인할 수 있다.

 

 

만약 A에서 B 파일을 불러내서 A가 B에대해 의존성을 가진 상태라고 생각하여 보자.

이때 bundle이 적용되면 이 의존성관계가 유지되면서 파일이 합쳐지게 된다. 

 

 

Entry

모듈 내부에서 어떤부분에서 시작해야하는지 알려준다.

 

 

모듈 A가 B,C에 의존성이 있다고 생각해보자. 파일별 쪼개진 내용을 Bundle로 담아서 오른쪽과 같은 Bundle파일이 만들어진다. Module A를 선택해서 만들 수 있는것이다.

 

 

 

Output

Webpack이 생성하는 번들 파일에 대한 정보를 설정한다.

즉, Bundle.js의 파일이름과 같은 걸 생성한다.

 

npm init -y

다음 명령어로 package.json파일을 하나 만들어주자.

 

npm install webpack webpack-cli --save-dev

우리는 webpack패키지를 사용할것이기 때문에 이를 설치하고 package.json파일을 보면

 

{
  "name": "circle",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.66.0",
    "webpack-cli": "^4.9.1"
  }
}

webpack이 잘 설치된것을 볼 수 있다.

 

저번 글에서 만들었던 세 파일을 한번 보자.

 

더보기
//index.js
const { getCircleArea, getSquareArea, PI } = require("./mathUtil");
const { logFigureError, logInput, logResult } = require("./log");

const readline = require("readline");
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.question("원하는 도형을 작성해주세요 : (정사각형, 원) ", (figure) => {
  console.log(`선택한 도형 : ${figure}`);

  switch (figure) {
    case "정사각형":
      rl.question("변의 길이를 입력해주세요 : ", (input) => {
        console.log(logInput(input));
        console.log(logResult(input, getSquareArea(input)));
      });
      break;
    case "원":
      rl.question("반지름의 길이를 입력해주세요 : ", (input) => {
        console.log(logInput(input));
        console.log(logResult(input, getCircleArea(input)));
      });
      break;
    default:
      console.log(logFigureError);
      break;
  }
});

 

const logInput = (input) => `입력받은 값 : ${input}`;
const logResult = (figure, result) => `${figure}의 넓이는 : ${result} 입니다.`;
const logFigureError = "지원하지 않는 도형입니다.";

module.exports = {
  logInput,
  logResult,
  logFigureError,
};
//mathUtil.js
const PI = 3.14;
const getCircleArea = (r) => r * r * PI;
const getSquareArea = (d) => d * d;

module.exports = {
  PI,
  getCircleArea,
  getSquareArea,
};

 

파일들 관계를 보면 index.js가 log.js와 mathUtil.js에 대해 의존성을 가진것을 확인할 수 있다.

 

bundling을 하면 이 세 파일이 합쳐질 것이다.

 

 

npx webpack

그냥 webpack을 실행하면 오류가 나게된다. entry와 output을 설정하지 않았기 때문이다.

 

webpack 4이후로는 설정에 대한 정보를 입력하지 않아도 entry의 경로를 src파일의 index파일로, bundle파일의 경로도 dist로 만들어지는 설정이 있어 파일경로만 만들고 부가옵션을 주지않고 실행시켜 보자.

 

즉 파일 배치를 위처럼 재배치해주고 실행하면..

 

오류가 난다!

 

readline 내장모듈이 내장모듈이라고 인지를 시켜주지 않았기 때문이다.

 

npx webpack --target=node

커맨드로 인지를 시켜준 후에 웹팩을 만들어주면

 

 

dist파일안에 main.js라는 이름으로 다음처럼 알아보기는 조금 힘들지만 최적화가 되어서 파일이 만들어졌음을 알 수 있다.

 

 

 

이제 파일로 webpack설정을 해볼건데 그전에 아래 내장모듈에 대해 잠깐 알아보고 가자.

 

const path = require("path");
console.log(__dirname);   //C:\Users\정민규\Desktop\git\front_end_study\10_Webpack\Circle

const pathTest = path.resolve(__dirname, "abc");   // 슬래시가 끼여들면서 절대경로를 생성
console.log(pathTest);  //C:\Users\정민규\Desktop\git\front_end_study\10_Webpack\Circle\abc

 

path모듈을 사용하면 위와같이 파일의 절대경로를 쉽게 접근해서 사용할 수 있다.

 

 

 

webpack.config.js 파일을 만들어서 아래와 같이 webpack 설정을 해두면 이번엔 파일이름까지 설정되어서 잘 적용되는걸 볼 수 있다.

//webpack.config.js

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  target: "node",
};

output의 path는 절대경로밖에 사용할 수 없기때문에 내장모듈을 사용해준다.

 

 

 

Mode

 

 

Package.json

1. 어플리케이션 내부에 직접 포함되는 모듈 

2. 개발 과정에 필요한 모듈

 

이 모듈들을 dependencies, devDependencies를 사용해서 위 모듈들을 구분한다. dependencies가 1번을 의미한다.

 

dependencies : --save

devdependencies : --save-dev 

 

각 모듈을 기록하는방법은 위처럼 붙여서 설치해주면 된다.

 

 

방금 만들었던 구조에서 node_modules를 지워보자.

 

{
  "name": "circle",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.66.0",
    "webpack-cli": "^4.9.1"
  }
}

nodemodules를 지웠기에 실제 파일은 없지만, package.json 파일을 보면 devDependencies에 webpack을 적어둔 것을 알 수 있다.

 

이때

 

npm install

 

위 명령어만 입력해도 webpack이 저절로 설치되게 된다.

 

 

 

DevelopMode & Production

 

개발자와 사용자는 같은 App을 보아도 보는 관점이 다를 것이다. 이에따라서 Webpack도 다른 모드를 지원하고 있다.

 

1. development

2. production

3. none

 

위 세가지 모드를 제공해준다.

 

자 그럼 직접 적용해보자.

 

{
  "name": "circle",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build" : "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.66.0",
    "webpack-cli": "^4.9.1"
  }
}

우선 scripts에서 "build" : "webpack"을 적어두면 굳이 npx 명령어로 치지않아도 웹팩으로 변환해준다.

 

npm run build

해당 명령어로 실행이 가능하다.

 

//webpack.config.js

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  target: "node",
  mode: "none",
};

다음 webpack설정에서 mode : "none"을 추가하고 다시 bundle파일을 보면

 

최적화가 일어나지 않은 상태로 bundle이 된 것을 볼 수 있다.

 

 

그때그때 mode를 바꾸는건 꽤 귀찮은 일이다.

 

//webpack.prod.js

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  target: "node",
  mode: "production",
};

 

위와같이 모드만 다른 파일을 하나 만들고

 

{
  "name": "circle",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --config webpack.prod.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.66.0",
    "webpack-cli": "^4.9.1"
  }
}

build부분을 약간 수정하면 npm run build로 해당 파일을 실행할 수 있다.

 

근데 위 방식도 공통된 부분을 수정하기위해서는 두 파일을 모두 수정해야한다는 번거로움이 생기게 된다.

 

npm install webpack-merge --save-dev

이때는 webpack-merge 라이브러리를 이용할 수 있다.

 

//webpack.common.js

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  target: "node",
};

다음처럼 공통 분모가 들어가는 파일을 하나 만들고

 

//webpack.prod.js
const { merge } = require("webpack-merge");
const common = require("./webpack.common");

module.exports = merge(common, {
  mode: "production",
});

위 라이브러리를 사용하면 손쉽게 두개를 합칠 수 있다.

 

 

 

Loader

다양한 모듈들을 입력받아 처리하는 역할

 

module.exports = {
  module:{
    rules : [loader1,loader2]
  }
}

 

Loader는 위와같은 형태로 사용된다.

rules는 배열타입으로 사용하고자 하는 loader들을 넣으면 된다. 문자열로 넣거나 자세한정보를 담은 객체 형태로 넣는다.

 

Loader를 직접 실습해보기 위해 프로젝트를 하나 만들어주자.

 

npm init -y
npm install webpack webpack-cli --save-dev

 

그후 package.json파일과 webpack라이브러리를 설치해준다.

 

다음과 같은 파일구조를 만들어준 후

 

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Webpack Practice</title>
</head>
<body>
    <script src = "./dist/bundle.js"></script>
</body>
</html>

index.html에서는 bundle만 연결해주고

 

//index.js
function component() {
  const element = document.createElement("div");
  element.innerHTML = "Hello Webpack";

  return element;
}

document.body.appendChild(component(1));

다음과같이 div를 만드는 간단한 함수를 하나적어둔 후에

 

//webpack.config.js
const path = require("path");

module.exports = {
  entry: "./index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  mode: "none",
};

위처럼 webpack설정을하고

 

{
  "name": "webpack-practice",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build" : "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.66.0",
    "webpack-cli": "^4.9.1"
  }
}

build설정을 해주면

 

npm run build

다음명령어로 Webpack적용이 되는것을 볼 수 있다.

 

실제 index.html에서도

잘 출력되는것을 볼 수 있다.

 

 

CSS Loader와 Style Loader

 

CSS파일을 모듈로 읽어오기위해 CSS Loader가, 그 CSS를 style태그로 감싸 넣어주기위해 StyleLoader가 필요하다.

 

npm install style-loader css-loader --save-dev

 

 

이전에 브라우저별 css기능을 지우기 위해서는 reset.css를 사용했는데, 이번에는 normalize.css를 사용해볼 것이다. 둘의 차이는 reset.css는 모든걸 reset시키고, normalize.css는 중복되는 부분만 지워준다는것이 다르다.

 

npm install normalize.css --save

npm에 normalize.css가 있기때문에 사용할 수 있다.

 

 

 

//webpack.config.js
const path = require("path");

module.exports = {
  entry: "./index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
          },
        ],
      },
    ],
  },
  mode: "none",
};

style-loader를 설정하는방법은 위와 같다.

 

div태그의 색을 red로 만드는 간단한 css파일을 하나 만들고

 

div{
	color : red;
}
//index.js
import "normalize.css";
import "./index.css";

function component() {
  const element = document.createElement("div");
  element.innerHTML = "Hello Webpack";

  return element;
}

document.body.appendChild(component(1));

연결해주면 잘적용되는걸 알수 있다.

 

각Loader별로 설정하는법이 다르다.

 

예를들어

 

https://github.com/webpack-contrib/css-loader

 

GitHub - webpack-contrib/css-loader: CSS Loader

CSS Loader. Contribute to webpack-contrib/css-loader development by creating an account on GitHub.

github.com

cssloader의 github readme.md파일의 Options를 보면 css-loader를 설정하는법에 대해 나와있다.

 

//webpack.config.js
const path = require("path");

module.exports = {
  entry: "./index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              modules: true,
            },
          },
        ],
      },
    ],
  },
  mode: "none",
};

위 설명에 참조해서 options를 넣어주고

 

//index.js
import "normalize.css";
import styles from "./index.css";

function component() {
  const element = document.createElement("div");
  element.innerHTML = "Hello Webpack";

  console.log(styles);
  element.classList = styles.helloWebpack;

  return element;
}

document.body.appendChild(component(1));

css파일을 모듈로 가져와서 div element에 저장해서 모듈안에서 어떻게 css내용이 불러와지는지 확인할수 있는지 보는 코드이다. 이방식으로는 className이 같아도 충돌하지 않는 장점이 있다.

 

className이 객체키로 전달되는것을 알 수 있고 그 값이 변형되는 해쉬값이 할당되는것을 알 수 있다.

 

//webpack.config.js
const path = require("path");

module.exports = {
  entry: "./index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              injectType: "singletonStyleTag",
            },
          },
          {
            loader: "css-loader",
            options: {
              modules: true,
            },
          },
        ],
      },
    ],
  },
  mode: "none",
};

위처럼 style-loader도 적용해보자.

 

적용하고 개발자옵션의 style태그를 쭉 내리다보면 우리가 설정한 부분이 해쉬태그로 바뀌어서 적용되어있음을 알 수 있다.

 

 

 

Plugin

 

웹팩의 동작과정에 직접 영향을 줄 수 있다.

 

module.exports = {
    plugins : [nue Plugin({ ...option }), ... ]
}

플러그인도 loader와 유사하게 적용시킬 수 있다.

 

웹팩 html 관리를 해주는 html-webpack plugin을 적용시켜보자.

 

npm i html-webpack-plugin -D

참고로 i는 install, -D는 --save-dev를 줄인 것이다.

 

//webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: "style-loader",
            options: {
              injectType: "singletonStyleTag",
            },
          },
          {
            loader: "css-loader",
            options: {
              modules: true,
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./template.html",
    }),
  ],
  mode: "none",
};

htmlWebpackPlugin을 불러와서 넣어주었다.

 

자동으로 생성되는 html문서가 특정파일을만들어주게끔 template를 사용했다. 

 

원래있던 index.html을 template.html로이름을 변경해주고 직접 적용해보자.

 

dist파일에 index.html이 생긴것을 볼 수 있다.

 

<!--template.html-->
<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Webpack Practice</title>
</head>
<body>
</body>
</html>

또한 위파일에서 시작하였음에도 자동으로 bundle생성된 파일과 연동까지 되는것을 볼수있다.

 

 

다음 글에선 Webpack 설정하는법에 대해 다뤄보겠다.

728x90

'FrontEnd > 웹 지식' 카테고리의 다른 글

GitHub Pull Request  (0) 2022.08.27
05_Webpack 여러 loader들  (0) 2022.01.15
04_Webpack 설정  (0) 2022.01.15
02_Module,Bundle  (0) 2022.01.14
01_마크다운(MARK DOWN)  (0) 2022.01.11