naver/fe-news ๋‰ด์Šค๋ ˆํ„ฐ ๋ทฐ์–ด (๋น„๊ณต์‹)

๋ชฉ์ฐจ
๋ชฉ์ฐจ

    2020-10

    ๋งํฌ & ์ฝ์„๊ฑฐ๋ฆฌ

    Introducing the New JSX Transform

    JSX๋Š” ์ผ๋ฐ˜ JavaScript ์ฝ”๋“œ๋กœ transpile ๋˜์ง€ ์•Š์œผ๋ฉด, ๋ธŒ๋ผ์šฐ์ €๋Š” ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์•„๋ž˜ ์˜ˆ์ œ ์ฝ”๋“œ์™€ ๊ฐ™์ด ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋Š” React.createElement๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€ํ™˜๋œ๋‹ค.

    import React from 'react';
    
    // ์ž‘์„ฑ๋œ ์ฝ”๋“œ
    function App() {
      return <h1>Hello World</h1>;
    }
    
    // ๋ณ€ํ™˜๋œ ์ฝ”๋“œ
    function App() {
      return React.createElement('h1', null, 'Hello world');
    }
    

    ๊ทธ๋Ÿฌ๋‚˜, React.createElement์˜ ์‚ฌ์šฉ์€ ๋‹ค์Œ์˜ 2๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์กด์žฌํ•œ๋‹ค.

    • React ์Šค์ฝ”ํ”„ ๋‚ด์— ์žˆ์–ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ (์ฆ‰, React import๋ฅผ ํ•„์š”)
    • ์ ์šฉ๋œ ์ผ๋ถ€ ์„ฑ๋Šฅ ํ–ฅ์ƒ๊ณผ ๋‹จ์ˆœํ™”๋ฅผ ์ง€์›ํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ

    ์ƒˆ๋กœ์šด Transform์€ Babel ๊ฐœ๋ฐœํŒ€๊ณผ์˜ ํ˜‘์—…์„ ํ†ตํ•ด ๋‹ค์Œ์˜ ์ด์ ๋“ค์„ ์ œ๊ณตํ•œ๋‹ค.

    • React import ์—†์ด JSX๋ฅผ ์‚ฌ์šฉ
    • ๋ฒˆ๋“ค ํฌ๊ธฐ์˜ ๊ฐœ์„ (์‚ฌ์šฉ์ž์˜ ์„ค์ • ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.)
    • ํ•™์Šต์ด ํ•„์š”ํ•œ React์˜ ๊ฐœ๋…์  ๋ถ€๋ถ„์„ ๊ฐ์†Œ์‹œ์ผœ ์ฃผ๋Š” ๊ฐœ์„ ์„ ํ™œ์„ฑํ™”ํ•œ๋‹ค.

    ์ƒˆ๋กœ์šด Transform์€ React 17(ํ–ฅํ›„ 0.14.x, 15.x, 16.x ๋“ค๋„ ์ง€์› ์˜ˆ์ •)์„ ํ†ตํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ปดํŒŒ์ผ๋Ÿฌ(Babel, TS) ์ „์šฉ entry point๋ฅผ ์ œ๊ณตํ•ด React.createElement ๋Œ€์‹  ํŠน๋ณ„ํ•œ ํ•จ์ˆ˜๋ฅผ ์ž๋™์œผ๋กœ import ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€ํ™˜๋œ๋‹ค.

    // ์ž‘์„ฑ๋œ ์ฝ”๋“œ (React import ์—†์ด ์ž‘์„ฑ)
    function App() {
      return <h1>Hello World</h1>;
    }
    
    // ๋ณ€ํ™˜๋œ ์ฝ”๋“œ (์•„๋ž˜ ๋ชจ๋“ˆ์€ ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ํ†ตํ•ด ์ž๋™ import)
    import {jsx as _jsx} from 'react/jsx-runtime';
    
    function App() {
      return _jsx('h1', { children: 'Hello world' });
    }
    

    We now generally consider Moment to be a legacy project in maintenance mode

    Moment ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋” ์ด์ƒ์˜ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ์—†์ด ์œ ์ง€ ๋ณด์ˆ˜๋งŒ ํ•œ๋‹ค.

    ๋Œ€์•ˆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

    • Luxon: Moment์˜ ์ง„ํ™”๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ค๋žœ ๊ธฐ๊ฐ„ Moment ์ปจํŠธ๋ฆฌ๋ทฐํ„ฐ์ธ Isaac Cambron์ด ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋‹ค.
    • Day.js: ์œ ์‚ฌํ•œ API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Moment๋ฅผ ์ตœ์†Œํ•œ์œผ๋กœ ๋Œ€์ฒดํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค.
    • date-fns: Date ๊ฐ์ฒด๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
    • js-Joda: JSR-310 ๊ธฐ๋ฐ˜์˜ Java SE8 java.time ํŒจํ‚ค์ง€๋ฅผ ํฌํŒ… ํ•˜์˜€๋‹ค.

    Effective limited parallel execution in JavaScript

    ๋ณ‘๋ ฌ ์‹คํ–‰์— ํšจ๊ณผ์ ์œผ๋กœ ์ œํ•œ์„ ๋‘๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

    ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด์„œ ์ ์ ˆํ•˜๊ฒŒ ๋ณ‘๋ ฌ ์‹คํ–‰์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค ์ค€๋‹ค. promise-pool

    The Ugly Side of React Hooks

    ์š”์ฆ˜ ๋งŽ์€ React ๊ด€๋ จ ๊ธ€๋“ค์ด class component๋ณด๋‹ค๋Š” hooks๋ฅผ ๊ถŒ์žฅํ•˜๋Š”๋ฐ, ์ œ๋ชฉ์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ, ์ด ๊ธ€์€ ๊ทธ์™€ ๋ฐ˜๋Œ€์ด๋‹ค. React ๊ณต์‹ ๋ฌธ์„œ์—์„œ ๋งํ•˜๋Š” hooks์˜ motivation์„ ํ•˜๋‚˜ํ•˜๋‚˜ ์ง‘์œผ๋ฉฐ ๋น„ํŒํ•œ๋‹ค.

    Vue.js 3.0 "One Piece"

    ์˜ค๋žœ ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„ ๋์— ๋“œ๋””์–ด Vue 3.0(์ฝ”๋“œ๋ช… "One Piece")์˜ ๊ณต์‹ ๋ฆด๋ฆฌ์Šค๊ฐ€ ๊ณต๊ฐœ๋˜์—ˆ๋‹ค. Progressive framework ์ฝ˜์…‰ํŠธ๋ฅผ ์ง€ํ–ฅํ•˜๋Š” Vue.js์˜ ์ƒˆ๋กœ์šด ์ถœ๋ฐœ์„ ์ฃผ๋ชฉํ•ด ๋ณด์ž.

    Deno 1.4

    TypeScript ๋Ÿฐํƒ€์ž„์ธ Deno์˜ ์ƒˆ๋กœ์šด ๋ฒ„์ „์ธ 1.4๊ฐ€ ๋ฆด๋ฆฌ์Šค๊ฐ€ ๊ณต๊ฐœ๋˜์—ˆ๋‹ค. ์ด๋ฒˆ ๋ฆด๋ฆฌ์Šค์—๋Š” ์›น์†Œ์ผ“ ์ง€์›๊ณผ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” watch ๋ชจ๋“œ ์ง€์›์ด ์ถ”๊ฐ€๋˜์—ˆ๋‹ค. ์ ์  ์‹ค๋ฌด์—์„œ ํ™œ๋ฐœํ•œ ์‚ฌ์šฉ์ด ์ฆ๊ฐ€ํ•  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€๋œ๋‹ค.

    ํŠœํ† ๋ฆฌ์–ผ

    React Component Patterns

    ๋‹ค์–‘ํ•œ React Component ํŒจํ„ด(Compound, Flexible Compound ๊ทธ๋ฆฌ๊ณ  Provider Pattern)๋“ค์„ ์†Œ๊ฐœํ•˜๊ณ , ๊ฐ ํŒจํ„ด๋“ค์˜ ์‚ฌ์šฉ์ด ์–ด๋–ค ๊ฒฝ์šฐ์— ์ ํ•ฉํ•œ์ง€ ๊ทธ๋ฆฌ๊ณ  ๊ฐ๊ฐ์˜ trade-offs ๋“ค์„ ์†Œ๊ฐœํ•œ๋‹ค.

    React-use hooks

    React์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜(custom) hook ์ด๋‹ค. ์œ ์šฉํ•œ hook์ด ๋งŽ์ด ์žˆ์œผ๋‹ˆ ๊ฐœ๋ฐœํ•  ๋•Œ ๋งŒ๋“ค๊ธฐ ๋ณด๋‹ค ํ•„์š”ํ•œ hook์„ ์ฐพ๊ณ  ์ด์šฉํ•ด ๋ณด๋ฉด ์ข‹๋‹ค.

    Logical assignment operators in JavaScript

    ๋…ผ๋ฆฌ ํ• ๋‹น ์—ฐ์‚ฐ์ž๊ฐ€ (EcmaScript 2021)์— ์ถ”๊ฐ€๋  ์˜ˆ์ •์ด๋‹ค. stage-4

    ๊ฐ„๋žตํ•˜๊ฒŒ ์•Œ์•„๋ณด๋ฉด,

    OR ์—ฐ์‚ฐ

    x ||= y;
    
    x || (x = y)
    

    ๋‘ ํ‘œํ˜„์‹์€ ๋™์ผํ•˜๋‹ค.

    AND ์—ฐ์‚ฐ

    x &&= y;
    
    x && (x = y);
    

    ๋‘ ํ‘œํ˜„์‹์€ ๋™์ผํ•˜๋‹ค.

    A Gentle Introduction to Code Splitting with React

    React๋ฅผ ์‚ฌ์šฉํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ์ฝ”๋“œ ๋ถ„ํ•  ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•œ๋‹ค.

    ๋ถ„ํ• ํ•˜๋Š” ๋ฐฉ๋ฒ•

    1. Route level
      import React, { Suspense } from 'react';
      import { Location, Router } from '@reach/router';
      
      import Loading from './components/Loading';
      
      const Home = React.lazy(() => import('./components/Home'));
      const AppointmentForm = React.lazy(() => import('./components/AppointmentForm'));
      const PreviousAppointments = React.lazy(() => import('./components/PreviousAppointments'));
      
      class App extends React.Component {
        render() {
          return (
            <Location>
              {({ location }) => (
                <Suspense fallback={<Loading />}>
                  <Router location={location}>
                    <Home path="/" />
                    <AppointmentForm path="/newAppointment" />
                    <PreviousAppointments path="/previousAppointments" />
                  </Router>
                </Suspense>
              )}
            </Location>
          );
        }
      }
      
    2. Component level
      class PreviousAppointments extends Component {
        constructor(props) {
          super(props);
      
          this.state = { map: null };
      
          this.handleClick = this.handleClick.bind(this);
        }
      
        handleClick() {
          import('./components/Map').then(module =>
            this.setState(() => ({
              map: module.default,
            })),
          );
        }
      
        render() {
          const { map: Map } = this.state;
      
          return (
            <>
              <div>Previous Appointments</div>
              ...
              {Map ? <Map /> : <button onClick={this.handleClick}>Show Map</button>}
            </>
          );
        }
      }
      

    ๋‘ ๋ถ„ํ•  ๋ฐฉ๋ฒ•์„ ์ž˜ ์ด์šฉํ•ด์„œ ์„ฑ๋Šฅ์„ ๋†’์ด๊ณ  ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ตœ์ ํ™” ์‹œํ‚ค์ž.

    Decorators

    2020๋…„ 9์›”์— ์ œ์‹œ๋œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋“ค์ด๋‹ค.

    ๋ช‡ ๊ฐ€์ง€๋งŒ ์‚ดํŽด๋ณด๋ฉด,

    @logged

    ๋ฉ”์„œ๋“œ์˜ ์‹œ์ž‘๊ณผ ๋์— ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

    import { logged } from "./logged.mjs";
    
    class C {
      @logged
      m(arg) {
        this.#x = arg;
      }
    
      @logged
      set #x(value) { }
    }
    
    new C().m(1);
    // starting m with arguments 1
    // starting set #x with arguments 1
    // ending set #x
    // ending m
    

    @tracked

    ํ•„๋“œ ๊ฐ’์„ ์ถ”์ (tracking)ํ•ด ๊ฐ’์˜ ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒ๋˜๋ฉด, render ๋ฉ”์„œ๋“œ๋ฅผ ํŠธ๋ฆฌ๊ฑฐ ํ•œ๋‹ค.

    import { tracked } from "./tracked.mjs";
    
    class Element {
      @tracked counter = 0;
    
      increment() { this.counter++; }
    
      render() { console.log(counter); }
    }
    
    const e = new Element();
    e.increment();  // logs 1
    e.increment();  // logs 2
    
    

    ๋„๊ตฌ

    Comlink

    ์˜ˆ์ œ ์ฝ”๋“œ ์ด๋ฏธ์ง€ (ํด๋ฆญํ•˜๋ฉด ํ™•๋Œ€ํ•ด์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.)

    ํฌ๋กฌ ๊ฐœ๋ฐœํŒ€์—์„œ ๊ณต๊ฐœํ•œ ์•„์ฃผ ์ž‘์€ ํฌ๊ธฐ(1.1kb)์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, WebWorkers ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์ดˆ๊ธฐ ์ ‘๊ทผ ์žฅ๋ฒฝ์„ ์ œ๊ฑฐํ•ด ์ค€๋‹ค. ์ข€ ๋” ์ถ”์ƒ์  ์ˆ˜์ค€์—์„œ ๋ณด์ž๋ฉด, postMessage์™€ ES6 Proxies์— ๋Œ€ํ•œ RPC ๊ตฌํ˜„์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

    Webpack์„ ๋ฒˆ๋“ค๋Ÿฌ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด comlink-loader๋ฅผ ๊ฐ™์ด ์‚ฌ์šฉํ•ด, ์ฝ”๋“œ์˜ ์ผ๋ถ€ ์ˆ˜์ •(๋˜๋Š” ์—†์ด)์„ ํ†ตํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ชจ๋“ˆ๋“ค์„ WebWorkers ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค.

    GitHub CLI

    GitHub์˜ ๊ณต์‹ CLI ๋„๊ตฌ๋กœ Beta ๊ธฐ๊ฐ„์„ ๋๋‚ด๊ณ , ์–ผ๋งˆ ์ „ 1.0 ๋ฒ„์ „์„ ์„ ๋ณด์˜€๋‹ค. ํ„ฐ๋ฏธ๋„ ์ƒ์—์„œ GitHub PR์„ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๊ด€๋ฆฌ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค.