본문 바로가기
기초/프론트엔드 종합반 HTML&CSS, JS, React

7주차_ HTML/CSS/JS로 만드는 스타벅스 웹사이트2

by Hyeon_E 2023. 1. 20.

해결책 만들기

DOM이 기능은 매우 많지만 실제로 복잡한 문제를 다루기에는 그만큼 복잡한 코드를 생산해야하고 코드가  복잡해졌으니 유지하는 것은 고통스러운 일 또한 소프트웨어는 한사람이 계속 코드를 유지하는 것이 아님

그래서 개발자는 여러가지 방법을 사용해 해결책을 생각해 보았음

그 중 React를 공부하는 이유는 시장에서 가장 많이 쓰이고 있고 주류 프레임 워크임

 

React 해결법은 DOM API가 다루기 까다로우니 사용자한테 DOM API보다 훨씬 더 다루기 쉬운 무언가를 제공해 주고 사용자가 다루기 힘든 DOM API는 우리가 제어권을 가지고 다루겠다는 것

 

create Element

일반사용자들이 사용하는 서비스나 혹은 어플리케이션 같은 경우에도 사용자들한테 선택받는데에는 이유가 있음

제일먼저 떠오르는 가장 큰 요소는 바로 편리함(사용이 얼마나 편리한가)

소프트웨어를 위한 소프트웨어 프레임워크나 라이브러리는 소프트웨어를 만들기 위한 소프트웨어라는 차이점만 다를 뿐 서비스나 혹은 일반 어플리케이션과 다를바가 없음

그래서 사용자를 위한 편리함이 제공되어야 채택될 가능성이 높음

개발자들에게 매력적으로 다가갈수 있도록 사용의 편리성을 높여가는 작업을 해주어야 함

 

JSX

함수호출방식으로 React를 쓰게하면 불편하여 사용자가 사용하지 않을테니 편리함을 추구하기 위해서 개발자들이 가장 익숙한 HTML 마크업 구조의 새로운 표현방법을 개발함. 표현방법은 간단하게 함수호출 구문으로 변환이 되는 프로그램을 이용해서 변환을 시킴. 사용자들은 큰 어려움 없이 마크업과 같은 구조로 UI를 만들게 됨

실제 React 앱을 만들때 DOM보다 훨씬 간단한 구조물을 만드는데 성공하였다는 장점과 그것을 생성하는데에 있어서 객체리터럴로 표현하거나 혹은 createEl같은 함수로 호출했을때 UI구조를 파악하기 힘들고 작성하기 힘든 단점을 마크업이라고 하는 형태를 취하면서 구조도 잘 파악이 되고 작성도 훨씬 쉬운 형태로 만듬


to DOM Render(돔 객체를 간단한 객체로 만들기)

import { createEl, render } from "./react";
//이 js파일에서 createEl을 사용하지 않더라도 실제 실행은 트랜스파일링된 bundle파일이
//실행이 되고 createEl이 사용되므로 createEl을 포함시켜주어야 함
/* @jsx createEl*/
const vdom = {
  //가상돔 멋쟁이 vdom
  //내용이 많아지면 복잡하고 번잡스러워짐 -> 개선요소
  tag: "p", //HTML구조 태그 이름,속성들, 자식요소
  props: {}, //속성, 여러개 가질 수 있으니깐 배열 or 객체
  //속성은 이름-값 쌍으로 되어있는데 배열은 이름을 가질 수 없기 때문에 객체로
  children: [
    //children안에는 또다른 태그가 들어가는 것이므로 구조는 똑같은 놈이 들어감
    {
      tag: "h1",
      props: {
        style: "color:red",
      },
      children: ["React 만들기"], //text컨텐츠
    },
    {
      tag: "ul",
      props: { style: "color:orange" },
      children: [
        {
          tag: "li",
          props: {},
          children: ["첫번째"], //text컨텐츠
        },
        {
          tag: "li",
          props: { style: "color:green" },
          children: ["두번째"], //text컨텐츠
        },
        {
          tag: "li",
          props: { style: "color:blue" },
          children: ["세번째"], //text컨텐츠
        },
      ],
    },
  ],
};
//render(vdom, document.querySelector("#root"));
//id가 root인 태그에 자식태그 추가

const vdom2 = createEl(
  //함수호출방법 사용
  "p",
  {},
  createEl("h1", {}, "react 만들기"),
  createEl(
    "ul",
    {},
    createEl("li", { style: "color:purple" }, "첫번째 아이템"),
    createEl("li", { style: "color:pink" }, "두번째 아이템"),
    createEl("li", { style: "color:hotpink" }, "세번째 아이템")
  )
);
// render(vdom2, document.querySelector("#root"));

const vdom3 = (
  //마크업과 같은 구조 이용
  //실행안됨 Babel로 돌려보면 밑에것을 babel이 위에 함수호출방식으로 바꿔줌
  //그래서 /* @jsx createEl*/을 사용해 명시해줌
  //하지만 인자가 없는 경우 null로 넘겨주어 아직 오류가 남
  <p>
    <h1>React 만들기</h1>
    <ul>
      <li style="color:green">첫번째 아이템</li>
      <li style="color:yellowgreen">두번째 아이템</li>
      <li style="color:turquoise">세번째 아이템</li>
    </ul>
  </p>
);
render(vdom3, document.querySelector("#root"));
export function createDom(node) {
  //vdom은 전체를 뜻하니 node라는 변수명이 좋겠군
  //Dom을 만들려면 Dom api를 사용할 수 밖에 없음
  if (typeof node === "string") {
    //하위요소가 태그일땐 객체로 들어오는데 태그가 아니면 문자열로 들어옴
    return document.createTextNode(node);
    //문자열이면 Text컨텐츠로 넣어주기
  }
  const element = document.createElement(node.tag);
  //이렇게 만들어진 객체에 속성을 부여할려면 createElement가 반환한 객체를 이용해야해서 변수와 함께

  Object.entries(node.props).forEach(
    ([name, value]) =>
      //name과 value를 배열로 넘김
      element.setAttribute(name, value)
    //속성 넣어주기
  );

  node.children.map(createDom).forEach(element.appendChild.bind(element));
  //children이 있는지를 순회해서 객체가 있는지를 보고 처리를 순회
  //재귀호출 패턴
  //부모 앨리먼트에 자식요소로 새로만든 dom앨리먼트들이 샥샥 추가됨

  return element;
}

export function createEl(tag, props, ...children) {
  props = props || {};  //undefined나 null이 들어왔을 경우를 위한 방어코드
  return {
    //가변인자 children 배열이됨
    tag, //이름이 변수와 같으니 생략가능 tag: tag
    props,
    children,
  };
}

export function render(vdom, container) {
  container.appendChild(createDom(vdom));
  //container에 자식 추가
  //바깥쪽에서 내부구조에 관심을 갖지 않게 함(알지 안아도 되게)
}

Webpack과 Babel 세팅

npm init -y

기본적인 패키지 만들기

npm install webpack-cli --save-dev

webpack 설치 개발환경에만 쓸것이기 때문에 --save-dev를 넣어줌

npm install webpack-dev-server babel-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin --save-dev

webpack-dev-server: 실행결과 확인을 위해 웹서버가 필요

babel-loader: babel 설치

@babel/core @babel/preset-env @babel/preset-react: babel 플러그인 설치

html-webpack-plugin: Html 파일을 만들고 혹은 템플릿화해서 실제로 번들링할때 쓸 수 있는 플러그인

 

※실제 본인은 설치했더니 오류가 났음. 다행히 오류를 개선하고 잘 실행되게 바꿈

이유는 Node.js버전 문제. 전에 강의를 들으며 버전을 맞추기 위해 낮은 버전을 사용했는데 그로 인해서 webpack이 설치되지 않아 반복적으로 webpack을 설치하라 하고 설치해도 설치가 안되었던 것

혹여 webpack을 사용하려고 하는데 설치했는데도 불구하고 webpack을 반복적으로 설치하라고 하며 실행이 안되는 경우

Node.js버전문제가 아닌지 확인해보는 것이 좋을듯

 

//기본적으로 node.js파일
//webpack.config파일의 구조는 웹팩에 입력값으로 config파일을 제공해주는 역할을 함
//웹팩이 필요로 한 스팩 형태대로 객체를 export 해주어야함
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  //객체의 모양은 웹팩이 기본가이드 하고 있어서 웹팩 가이드에 따라 필요한 것들을 넣어주면 됨
  mode: "development", //개발형태 파일
  //최종적으로 서비스할 목적으로 만드는가, 개발중인 형태 파일을 만드는가
  entry: "./src/app.js", //입력정보. 즉 어떤 JS파일에서 시작할 것인지
  output: {
    //출력정보. 여러가지가 필요해서 객체로
    path: path.resolve(__dirname, "dist"), //현재 디렉토리, 출력할 디렉토리
    filename: "bundle.js",
  },
  //1.어느 디렉토리에 쓸꺼야? 2.어떤 이름을 쓸꺼야?
  devServer: {
    //devServer을 쓸수 있도록 세팅
    compress: true, //압축해라
    port: 9999, //어떤 포트 쓸꺼야?
  },
  module: {
    //변환과정에서 변환시켜줄
    rules: [
      //rules안에 지정하는 것을 loader라고 하는데 여러개니깐 배열이고
      {
        //여러가지 파일(css,img 등)이 들어오는 babel-loader는 JS파일만 처리하므로 필요없는 파일 제거
        test: /\.js$/, //정규식. 파일명이 js인 파일들. 정규식에 매칭되는 파일들만 loader에게 넘김
        //배열안에 각각의 객체로 어떻게 동작하는게 좋을지 옵션정보를 넣어줌
        exclude: /node_modules/, //node_modules폴더 loader제외
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"], //presets에는 설치했던 babel플러그인을 세팅하면 됨
          },
        },
      },
    ],
  },
  plugins: [
    //마지막처리과정을 변환시켜줄
    //html웹팩 플러그인은 html파일을 받아서 최종적인 번들링 파일에 아웃풋으로 내보낼때
    //사용될 html을 생성해주고 거기에다가 템플릿화해서 다른 부가적인 처리를 할 수도 있는 기능제공
    new HtmlWebpackPlugin({
      title: "setup webpack & babel",
      template: "index.html", //어떤 html파일을 쓸것인지
    }),
    //함수니깐() 인스턴스를 만들어주어야함(new) 이런정보는 해당하는 패키지의 문서를 보면 알 수 있음
  ],
  //웹팩은 크게 2가지 정보를 세팅함(module, plugins)
  //entry -> module -> plugins-> output
  //기본적인 구성
};

webpack.config.js파일 설정

{
  "presets": ["@babel/preset-env"]
}

babel.config.json파일 설정

npm run dev

서버 실행하기

댓글