프론트엔드 개발환경의 이해와 실습 4

4️⃣

🖥 웹팩(Webpack) - 심화편

5 - 1. 웹팩 개발 서버



5 - 2. API 서버 연동

// webpack.config.js
  devServer: {
    ...,
    before: (app) => {
      // app : 개발서버를 받는다
      app.get("/api/users", (req, res) => {
        // app은 서버어플리케이션에서 많이 사용하는 expressjs 라는 프레임워크
        // expressjs의 서버인스턴스를 app 이라는 이름으로 웹팩데브서버가 넣어준다.
        // before함수 안에서 웹팩데브서버의 기능을 확장 할 수 있다.
        // app.get 메소드로 이루어진 api를 만들어내는 함수.
        // "/api/users" 라는 api 를 만들고 이쪽으로 요청이 들어오면 req 부터의 함수를 실행한다.
        // 응답을 위한 res 객체로 api 응답을 줄 수 있다.
        res.json([
          { id: 1, name: "Bill" },
          { id: 2, name: "James" },
          { id: 3, name: "mia" },
        ]);
      });
    },
  },

//app.js
import axios from "axios";

document.addEventListener("DOMContentLoaded", async () => {
  const res = await axios.get("/api/users");
  console.log(res);

  document.body.innerHTML = (res.data || [])
    .map((user) => {
      return `<div>${user.id}: ${user.name}</div>`;
    })
    .join("");
});


//GET.json
// 아까만든 json 배열을 가져온다.
[
  { "id": 1, "name": "Bill" },
  ...
]

// webpack.config.js
const apiMocker = require("connect-api-mocker");

    devServer: {
    ...,
    before: (app) => {
        app.use(apiMocker("/api", "mocks/api"));
        // apiMocker(urlRoot: any, pathRoot: any): (req: any, res: any, next: any) => any
        //"/api" ->  api 로 요청오는건 모커가 처리하는 것.
    },
    },



// webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      "/api": "http://localhost:8081", // 프록시
    },
  },
}

// src/model.js
const model = {
  async get() {
    // const { data } = await axios.get('http://localhost:8081/api/keywords');

    const { data } = await axios.get("/api/keywords")
    return data
    // 프록시에서 api주소를 바꿨기때문에 위와같이 작성하면 잘 받아온다
  },
}

5 - 3. API 서버 연동(실습)

5 - 4. API 서버 연동(풀이)

// webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      "/api": "http://localhost:8081", // 프록시
    },
  },
}

5 - 5. 핫로딩

  devServer: {
      ...
    hot: true,
  },
// entry 포인트인 src/app.js
if (module.hot) {
  console.log("hot module on!");
  // module.hot.accept -> 변경을 감지할 모듈을 정할 수 있다.
  // result.js 파일이 변경되었을 때만 해당 콘솔을 찍는다.
  // 감지하고자 하는 모듈이 변경되었음을 인지하고 콜백함수 실행
  // 변경된 모듈만 변경된다.
  module.hot.accept("./result", async () => {
    console.log("result module change!");
    resultEl.innerHTML = await result.render();
    // result가 변경되면 
    // 변경된 result모듈의 랜더함수 실행 
  });
  module.hot.accept("./form", async () => {
    console.log("form module change!");

    formEl.innerHTML = await form.render();
  });
}

5 - 6. 핫로딩(실습)

5 - 7. 핫로딩(풀이)

5 - 8. 최적화


//webpack.config.js
const mode = process.env.NODE_ENV || "development";
// 외부환경변수에 따라서 웹팩을 devleopment || production 으로 빌드할수있다.

module.exports = {
  // module.exports -> node 의 모듈 시스템
  mode,
  ...
}

//package.json
  "scripts": {
    "build": "NODE_ENV=production webpack --progress", 
  },
  // "NODE_ENV=production webpack --progress" 또는 "NODE_ENV=development webpack --progress",
  // 로 빌드시 어떻게 파일이 변화하는지 확인할 수 있다.


//webpack.config.js
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = {
  devserver: {...},
  optimization: {
    // minimizer - 압축할수있는 플러그인을 추가
    minimizer: mode === "production" ? [new OptimizeCSSAssetsPlugin()] : [],
  },
}
//webpack.config.js
const TeserWebpackPlugin = require("terser-webpack-plugin");

module.exports = {
  devserver: {...},
  optimization: {
    minimizer:
      mode === "production"
        ? [
            new OptimizeCSSAssetsPlugin(),
            new TeserWebpackPlugin({
              // 생성자에 옵션값을 전달
              terserOptions: {
                compress: {
                  drop_console: true, // 콘솔로그를 제거
                },
              },
            }),
          ]
        : [],
  },
}
//webpack.config.js
  optimization: {
    minimizer:
      mode === "production"
        ? [
            new OptimizeCSSAssetsPlugin(),
            new TeserWebpackPlugin({
              // 생성자에 옵션값을 전달
              terserOptions: {
                compress: {
                  drop_console: true, // 콘솔로그를 제거
                },
              },
            }),
          ]
        : [],
    splitChunks: {
      Chunks: "all",
    },
    //중복부분을 지워준다.
  },


// app.js
  import(/* webpackChunkName: "result" */ "./result.js").then(async (m) => {
    // 해당 주석을 보고 result라는 번들 결과를 따로 만들어준다.
    const result = m.default;
    const resultEl = document.createElement("div");
    resultEl.innerHTML = await resultEl.render();
    document.body.appendChild(resultEl);
  });


//webpack.config.js
  externals: {
    axios: "axios",
    // 웹팩으로 빌드할때 axios 모듈을 사용하는 부분이있으면 전역변수 axios를 사용하는것으로 간주해라.
    // 전역에 axios를 가지고 있어야함 ( 이왕이면 dist 안에 )
  },
//webpack.config.js
const CopyPlugin = require("copy-webpack-plugin");

plugins: [
    new CopyPlugin({
      patterns: [
        {
          from: "./node_modules/axios/dist/axios.min.js",
          to: "./axios.min.js",
          //from 어디에 있는걸 복사할지
          // to: ./axios.min.js ~로 받아온다. (dist)}
        },
      ],
    }),
]

// index.html
<body>
    <script type="text/javascript src="axios.min.js"></script>
</body>

5 - 9. 최적화(실습)

5 - 10. 최적화(풀이)

🖥 마무리

6 - 1. 정리