Webpack 러닝 가이드
  • Webpack 모듈 번들러
  • Web Modules
    • Legacy 모듈 관리
    • ES 모듈 관리
  • Babel
    • Babel JavaScript 컴파일러
    • Babel 독립형 빌드
    • Babel 노드 (Node.js) ✘
    • Babel CLI 구성
    • Babel 플러그인
  • webpack
    • Webpack 개발 환경 구성
      • Webpack 설치
      • Webpack 통합
      • Webpack 구성 파일
      • Webpack 워치
      • Webpack 모드
      • Webpack 별칭 등록
      • Webpack 호환성
      • Webpack 개발 서버
      • Webpack 멀티 페이지 설정
    • Webpack 로더
      • File 로더
      • CSS 로더
      • PostCSS 로더
      • Sass 로더
      • Babel 로더
      • TypeScript 로더
    • Webpack 플러그인
      • 환경 변수 등록
      • 빌드 결과 자동 정리
      • 빌드 결과 자동 주입
      • CSS 파일 개별 추출
      • CSS 파일 크기 최적화
      • CSS 미디어쿼리 스플리팅
      • 이미지 파일 크기 최적화
  • React
    • React App 매뉴얼 구성
      • Webpack 초기 구성
      • Babel 컴파일러 구성
      • CSS 스타일 구성
      • 이미지 구성
      • 환경변수 플러그인
      • HTML 플러그인
      • 최적화 구성
      • 코드 스플리팅
      • 개발 서버
      • 이미지, 폰트 에셋 구성
      • 환경 변수 + HTML 구성
      • 빌드 최적화 구성
      • 빌드 자동 정리 구성
      • 개발 서버 구성
      • 폴리필 구성
Powered by GitBook
On this page

Was this helpful?

  1. Web Modules

ES 모듈 관리

ES Modules을 활용하면 웹 브라우저 환경에서도 모듈 관리가 수월해집니다. (ES 6+ 코드로 변경)

import * as Euid from './modules/Euid/index.js'
import { getNode, createElement, render } from './modules/DOM.js'

// Euid 멤버에서 하위 모듈 추출
const {
  logger: { success, error },
  tester: { test, expect },
  utils: { isFunction },
} = Euid

/* -------------------------------------------------------------------------- */

// 타이머 설정
window.setTimeout(() => {
  console.group('MODULE → 모듈 관리 상태')

  isFunction(getNode)
    ? success('의존성 모듈 관리에 문제가 없어 앱이 정상 작동합니다.')
    : error('의존성 모듈 관리에 문제가 있어 앱이 정상 작동하지 않습니다.')
})

/* -------------------------------------------------------------------------- */
// 테스트

test('createElement() 전달 속성', () => {
  const vNode = createElement('h3', { className: 'heading-3' }, 'TDD')

  expect(vNode.type).toBe('h3')
  expect(vNode.props.children).toBe('tdd')
})

/* -------------------------------------------------------------------------- */

// vNode 생성

const moduleLink = createElement(
  'a',
  {
    href: 'https://bit.ly/3brDMBS',
    rel: 'noopener noreferrer',
    target: '_blank',
    className: 'externalLink',
  },
  '모듈'
)

const cube = createElement('img', {
  className: 'cube',
  alt: '',
  src: './src/assets/cube.gif',
  height: 32,
})

const headline = createElement(
  'h1',
  { className: 'headline' },
  moduleLink,
  ' 관리',
  cube
)

const slogan = createElement(
  'p',
  { className: 'slogan' },
  '웹 브라우저 환경에서의 모듈 관리는 까다롭습니다.'
)

const container = createElement(
  'div',
  { className: 'container' },
  headline,
  slogan
)

/* -------------------------------------------------------------------------- */
// 렌더링

render(container, getNode('#root'))
export * as logger from './logger.js'
export * as tester from './tester.js'
export * as utils from './utils.js'
/* -------------------------------------------------------------------------- */
// 메시지 스타일

const MESSAGE_STYLES = {
  log: `
    color: #1c1c1d;
    font-weight: bold;
    `,
  success: `
    color: #00c712;
    font-weight: bold;
    `,
  info: `
    color: #006afc;
    font-weight: bold;
    `,
  warn: `
    color: #ff9500;
    font-weight: bold;
    `,
  error: `
    color: #ee3327;
    font-weight: bold;
    `,
}

/* -------------------------------------------------------------------------- */
// 메시지 유틸리티

export function log(message, messageStyle = MESSAGE_STYLES.log) {
  console.log(`%c${message}`, messageStyle)
}

export function info(message) {
  return log(`🔵 ${message}`, MESSAGE_STYLES.info)
}

export function success(message) {
  return log(`🟢 ${message}`, MESSAGE_STYLES.success)
}

export function warn(message) {
  return log(`🟠 ${message}`, MESSAGE_STYLES.warn)
}

export function error(message) {
  return log(`🔴 ${message}`, MESSAGE_STYLES.error)
}
import { error } from './logger.js'

// JSON 메서드 추출
const { stringify: _serialize, parse: _deserialize } = window.JSON

// 타입 검사 유틸리티

export function typeIs(data) {
  return Object.prototype.toString.call(data).slice(8, -1).toLowerCase()
}

export function isNumber(data) {
  return typeIs(data) === 'number'
}

export function isString(data) {
  return typeIs(data) === 'string'
}

export function isBoolean(data) {
  return typeIs(data) === 'boolean'
}

export function isFunction(data) {
  return typeIs(data) === 'function'
}

export function isArray(data) {
  return typeIs(data) === 'array'
}

export function isObject(data) {
  return typeIs(data) === 'object'
}

/* -------------------------------------------------------------------------- */
// 배열 유틸리티

export function makeArray(likeArray) {
  return Array.from
    ? Array.from(likeArray)
    : Array.prototype.slice.call(likeArray)
}

/* -------------------------------------------------------------------------- */
// 시리얼라이즈 유틸리티

export const serialize = (data, prettiy) =>
  !prettiy ? _serialize(data) : _serialize(data, null, 2)

export const deserialize = (json) => _deserialize(json)

/* -------------------------------------------------------------------------- */
// 믹스인 유틸리티

export function mixins() {
  return makeArray(arguments).reduce((o1, o2) => {
    for (let key in o2) {
      if (o2.hasOwnProperty(key)) {
        const o1Value = o1[key]
        const o2Value = o2[key]
        if (isObject(o2Value)) {
          o1Value && _checkValueType(isObject, o1Value, key)
          o1[key] = mixins(o1Value ?? {}, o2Value)
        } else if (isArray(o2Value)) {
          o1Value && _checkValueType(isArray, o1Value, key)
          o1[key] = [...(o1Value ?? []), ...o2Value]
        } else {
          o1[key] = o2Value
        }
      }
    }
    return o1
  }, {})
}

const _checkValueType = (method, value, key) => {
  if (!method(value)) {
    const message = `혼합할 각 객체 ${key} 속성 유형이 다릅니다.`
    error(message)
  }
}
import { log, success, error } from './logger.js'
import { serialize } from './utils.js'

// 테스트 유틸리티
export const test = (title, callback) => {
  console.group(`TEST → ${title}`)
  try {
    log('테스트 결과:')
    callback()
  } catch (error) {
    error('테스트 실패: ' + error.message)
  }
  console.groupEnd()
}

// 익스펙트 유틸리티
export const expect = (actual /* 실제 값 */) => ({
  toBe: (expected /* 기대 값 */) => {
    expected !== actual
      ? error(
          `결과 값(${serialize(actual)})과 기대 값(${expected})이 다릅니다.`
        )
      : success(
          `결과 값(${serialize(actual)})과 기대 값(${expected})이 같습니다.`
        )
  },
  notToBe: (expected) => {
    // ...
  },
  toBeGreaterThan: (expected) => {
    // ...
  },
  toBeLessThan: (expected) => {
    // ...
  },
})
import { isString, isFunction } from './Euid/utils.js'

/* -------------------------------------------------------------------------- */
// 유틸리티 함수

export function getById(idName) {
  return document.getElementById(idName)
}

export function getNode(selector, context = document) {
  return context.querySelector(selector)
}

export function getNodeList(selector, context = document) {
  return context.querySelectorAll(selector)
}

/* -------------------------------------------------------------------------- */

// vNode 생성 유틸리티
export function createElement(type, props, ...children) {
  props = { ...props, children }

  // type이 함수 컴포넌트인 경우
  if (isFunction(type)) {
    // 함수 호출 (props 전달)
    return type.call(null, props)
  }

  return { type, props }
}

// [비공개] 속성 바인딩 유틸리티
const _bindProps = (element, props) => {
  // props 복제
  props = { ...props }

  // children 속성 제거
  delete props.children

  Object.entries(props).forEach(([prop, value]) => {
    // 클래스 속성 설정
    if (prop === 'className') {
      element.classList.add(value)
    }

    // 이벤트 속성
    const isEventProp = /^on/.test(prop)
    const propIsClassName = prop !== 'className'

    if (isEventProp && propIsClassName) {
      element.addEventListener(prop.replace(/on/, '').toLowerCase(), value)
    }

    // 나머지 속성
    if (!isEventProp && propIsClassName) {
      element.setAttribute(prop, value)
    }
  })
}

// [비공개] vNode 렌더링 유틸리티
const _renderElement = (vNode) => {
  // vNode가 텍스트인 경우
  if (isString(vNode)) {
    return document.createTextNode(vNode)
  }

  // vNode = {type, props}
  // 요소 생성
  const element = document.createElement(vNode.type)

  // 속성 바인딩
  _bindProps(element, vNode.props)

  // 자식(들) 순환
  vNode.props.children
    // 재귀 호출
    .map(_renderElement)
    // 자식 노드 마운트
    .forEach((childNode) => element.appendChild(childNode))

  // 요소 반환
  return element
}

/* -------------------------------------------------------------------------- */

// vNode → DOM 노드 마운트(mount)
export const render = (vNode, domNode) =>
  domNode.appendChild(_renderElement(vNode))

IE 웹 브라우저는 ES Modules를 지원하지 않습니다.

참고

PreviousLegacy 모듈 관리NextBabel JavaScript 컴파일러

Last updated 4 years ago

Was this helpful?

JavaScript modules - JavaScript | MDN
JavaScript 모듈 - Mozilla Developer Network
JavaScript modules via script tag | Can I use... Support tables for HTML5, CSS3, etc
ES6 모듈 브라우저 지원율
Logo
<script type="module"> 브라우저 지원율
Logo