Babel Coder

เจาะลึก 5 ฟีเจอร์สำคัญใน create-react-app v2

beginner

React Developer รุ่นเดอะ ย่อมเข้าใจความเจ็บปวดของการใช้ React เป็นอย่างดี สมัยก่อนจะขึ้นโปรเจคด้วย React ทีอย่างกับกำลังเริ่มพิธีบูชายัญ เอาเป็นว่าอย่าได้ถามเลยว่าใครฆ่าประเสริฐ เพราะ Webpack กับ Babel นี่หละที่กำลังฆ่าเรา!

เมื่อโปรเจคอย่าง create-react-app ได้อุบัติขึ้นบนโลกนี้ ทุกอย่างก็ดูโทนสีพาสเทลไปหมด จากเดิมที่ต้องตั้งค่า Webpack Babel และเครื่องมืออันโหดร้ายเยี่ยงสัตว์ป่าทั้งหลาย ตอนนี้เราสามารถเริ่มโปรเจค React ได้อย่างง่ายดายไร้ซึ่ง config

และแล้วตอนนี้ create-react-app ก็ได้ก้าวสู่เวอร์ชัน 2 แล้ว เรามาส่องกันดีกว่าว่านอกจากเลขเวอร์ชันที่ขยับขึ้นแล้ว มีอะไรที่น่าสัมผัสอีกบ้าง

สารบัญ

1. Yarn Plug’n Play คืออะไร ใช้ยังไง?

โดยปกติแล้วเราออกคำสั่ง yarn install packages ต่าง ๆ ที่จะใช้ในโปรเจคก็จะถูกไล่เรียงว่าสิ่งไหนคือของที่เราต้องการใช้ จากนั้นจึงทำการดาวน์โหลดและจัดเก็บไว้พร้อมทำการแตกไฟล์สู่แคช รอบหน้าถ้าใช้แพคเกจเดิมจะได้ดึงจากแคชมาใช้ได้เลย ท้ายสุดของกระบวนการ เครื่องมือเราจะทำการสำเนาแพคเกจที่ใช้ไปยังโฟลเดอร์ node_modules ภายใต้โปรเจคเราเอง

จากกระบวนการดังกล่าวคำถามหลักจึงเป็นว่า ทำไมเราต้องสำเนาไฟล์มาลง node_modules ด้วย?

Yarn Plug’n’Play คือของเล่นใหม่ที่ช่วยให้โปรเจคของเราไม่ต้องสำเนาไฟล์สู่ node_modules อีกต่อไป และยังช่วยให้การ resolve แพคเกจต่าง ๆ ไวขึ้นด้วย รายละเอียดเพิ่มเติมสามารถอ่านได้ที่ Yarn Plug’n Play คืออะไร? ลองทำโปรเจคให้ไร้ซึ่ง node_modules กันเถอะ!

Create React App เวอร์ชัน 2 มาพร้อมกับฟีเจอร์ Yarn Plug’n’Play หากเราต้องการใช้ฟีเจอร์นี้เพียงแค่ใส่ options ด้วยคำว่า --use-pnp คือจบ

/ # npx create-react-app app-v2 --use-pnp
npx: installed 63 in 2.473s

Creating a new React app in /app-v2.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts...

yarn add v1.11.1
info No lockfile found.
[1/5] Resolving packages...
[2/5] Fetching packages...
info fsevents@1.2.4: The platform "linux" is incompatible with this module.
info "fsevents@1.2.4" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/5] Linking dependencies...
[5/5] Building fresh packages...
success Saved lockfile.
success Saved 3 new dependencies.
info Direct dependencies
├─ react-dom@16.5.2
├─ react-scripts@2.0.3
└─ react@16.5.2
info All dependencies
├─ react-dom@16.5.2
├─ react-scripts@2.0.3
└─ react@16.5.2
Done in 26.93s.

Success! Created app-v2 at /app-v2

หลังการสร้างโปรเจคด้วย --use-pnp เราจะได้ไฟล์สำคัญสำหรับฟีเจอร์นี้โผล่ขึ้นมา นั่นคือ .pnp.js

app-v2
  |- README.md
  |- package.json
  |- public
  |- src
  |- yarn.lock
  |- .pnp
  |- .pnp.js
  |- .gitignore

และภายใต้ package.json จะมีการระบุว่าเราใช้ Yarn Plug’n’Play อยู่ นั่นคือ "pnp": true

{
  "name": "app-v2",
  "version": "0.1.0",
  "private": true,
  "installConfig": {
    "pnp": true
  },
  "dependencies": {
    "react": "^16.5.2",
    "react-dom": "^16.5.2",
    "react-scripts": "2.0.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}

สร้างโปรเจคเสร็จแล้วก็รันซิ จะรอพระเจิมก่อนรึ! ออกคำสั่ง yarn start ใต้โปรเจคไปเลย

ฮัดช่า errors จัดเต็มมาก~

Error: Package "webpack-dev-middleware@3.4.0" (via "/usr/local/share/.cache/yarn/v3/npm-webpack-dev-middleware-3.4.0-1132fecc9026fd90f0ecedac5cbff75d1fb45890/node_modules/webpack-dev-middleware/lib/fs.js") is trying to require the package "webpack" (via "webpack/lib/node/NodeOutputFileSystem") without it being listed in its dependencies (memory-fs, mime, range-parser, webpack-log, webpack-dev-middleware)

หากใครเจอข้อผิดพลาดราว ๆ นี้ก็หาต้องตกใจไม่ นี่คือข้อผิดพลาดบางประการของ Yarn ซึ่งบางอย่างก็แก้ไขแล้ว (อยู่ใน master แต่ยังไม่ได้ปล่อยเป็นเวอร์ชันใหม่) บางอย่างก็กำลังแก้ สามารถติดตามและตามติด ๆ ถึงปัญหานี้ได้จาก ที่นี่

2. CSS Modules สามารถใช้งานได้แล้ว

CSS Modules เป็นหลักการที่ไฟล์ CSS ต่างคอมโพแนนท์จะมีชื่อคลาสที่ไม่ชนกัน หากเราไม่ได้ใช้คุณสมบัตินี้ ถ้าคอมโพแนนท์ Article มีคลาสของ CSS ชื่อ .title ที่กำหนดสีแดงสำหรับข้อความ ส่วนคอมโพแนนท์ Dashboard ก็มีคลาส .title แต่กำหนดสีข้อความเป็นสีเขียว เมื่อผ่านการรวมไฟล์ CSS เข้าด้วยกัน คลาส .title จากทั้งสองย่อมชนกันอันเป็นเหตุสร้างความสับสนให้เราได้ว่า สุดท้ายแล้วแต่ละคอมโพแนนท์จะมี .title เป็นสีใดกันแน่

Create React App เวอร์ชันแรกนั้นไม่สนับสนุน CSS Modules แต่การมาของเวอร์ชันใหม่นี้ทำให้เราสามารถใช้คุณสมบัตินี้ได้ เพียงแค่เราต่อท้ายนามสกุลไฟล์ด้วย .module.css เพียงเท่านี้คุณสมบัติดังกล่าวก็จะถูกเปิดใช้งาน

สมมติเรามีไฟล์ Article.module.css ดังนี้

.title {
  color: red;
}

และไฟล์ Dashboard.module.css เช่นข้างล่าง

.title {
  color: green;
}

เมื่อเราทำการสร้างคอมโพแนนท์ Article พร้อมเรียกใช้ Article.module.css จะค้นพบว่าผลลัพธ์นั้นเป็นไปตามหลักการของ CSS Modules

import React from 'react'

import styles from './Article.module.css'

export default () => <h2 className={styles.title}>Article Title!</h2>

// ผลลัพธ์ของการแสดงผล
// คลาส Article_title_xydd6 จะใช้ title ที่เป็นสีแดง
// <h2 class="Article_title_xydd6">Article Title!</h2>

จากผลลัพธ์ที่เกิดขึ้นพบว่า CSS Modules จะทำการสร้างชื่อคลาสใหม่ด้วยการเติมชื่อไฟล์และชื่อคลาส พร้อมค่าแฮช คือ [filename]_[classname]_[hash]

CSS Modules นั้นแม้ชื่อจะบอกว่าเป็น CSS แต่ก็สามารถใช้ควบคู่กับ SCSS/SASS ได้เช่นกัน ข้อมูลเพิ่มเติมสามารถศึกษาได้จาก ลิงก์นี้ครับ

3. กำหนด Proxy ด้วยตนเอง

ก่อนหน้านี้เราสามารถตั้งค่า proxy ได้ผ่านทางไฟล์ package.json เช่นถ้าเรายิงรีเควสผ่าน fetch แล้วต้องการให้ผ่านเข้าสู่ API Server ของเรา เราสามารถใส่ proxy ได้ดังนี้

"proxy": "http://localhost:5000",

สำหรับ Create React App เวอร์ชันใหม่นี้ เมื่อเราต้องการความยืดหยุ่นในการตั้งค่า proxy มากขึ้น เราสามารถใช้แพคเกจ http-proxy-middleware เข้าช่วยได้

ก่อนอื่นให้ทำการติดตั้งแพคเกจดังกล่าวผ่านคำสั่ง yarn add http-proxy-middleware จากนั้นจึงทำการสร้างไฟล์ setupProxy.js ไว้ใต้โฟลเดอร์ src พร้อมทำการตั้งค่า proxy ตามใจปรารถนา ดังนี้

const proxy = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(proxy('/api', { target: 'http://localhost:5000/' }));
  app.use(proxy('/*.svg', { target: 'http://localhost:7000/' }));
};

เพียงเท่านี้เมื่อ request ใด ๆ ขึ้นด้วย /api ก็จะวิ่งไปใช้ API Server ของเราที่ http://localhost:5000 และนำไปสู่ http://localhost:7000 เมื่อการร้องขอเป็นไฟล์นามสกุล SVG

4. การใช้งาน Babel Macros

ไม่ใช่เรื่องง่ายที่จะตั้งค่าการทำงานของ Babel เพิ่มเติมในโปรเจคอย่าง Create React App นั่นเพราะโปรเจคนี้ไม่สนับสนุนการสร้าง .babelrc ขึ้นมาเอง หากเรากระเหี้ยนกระหือรืออยาก custom Babel จริง ๆ โปรเจคอย่าง react-app-rewired เหมือนจะเป็นทางออกสำหรับปัญหานี้

แต่ก็นั่นละฮะ การคอนฟิค Babel นี่ไม่ใช่อะไรที่ชวนลั๊ลลาซักเท่าไหร่ ยุ่งยาก น่าเบื่อ น่าเอาไปฆ่าหมกส้วมยิ่งนัก แถม plugins ที่เราใช้อาจคอนฟิคแล้วชนกันเละเป็นโจ๊กก็ได้

ความไม่มีโรคเป็นลาภอันประเสริฐฉันใด การไร้ซึ่งคอนฟิคของ Babel ก็ดีงามพระรามแปดฉันนั้น เหตุนี้โปรเจคอย่าง babel-plugin-macros จึงถือกำเนิดขึ้นเพื่อให้การใช้งานสิ่งที่เรียกว่า Macros ไร้ซึ่งคอนฟิคอย่างแท้ทรู เมื่อคอนฟิคไม่ต้องมี .babelrc ก็ไม่ต้องใช้นั่นเอง

Create React App เวอร์ชัน 2 สนับสนุนการทำงานกับ Babel Macros ดังนั้นแล้วการใช้งานอะไรแปลก ๆ จาก JavaScript เดิม ๆ เช่น GraphQL จึงสามารถใช้งานได้อย่างง่ายดายโดยไม่ต้องทำการตั้งค่า Babel เพิ่มเติม

สมมติเราต้องการใช้งาน GraphQL ผ่านแท็ก gql เมื่อเราใช้งาน Create React App เวอร์ชันสองควบคู่กับ graphql-tag macro แล้ว เราสามารถลุยสดด้นโค้ดได้ เช่นนี้

import gql from 'graphql-tag.macro';

const query = gql`
  query {
    hello {
      world
    }
  }
`;

5. การทำงานกับ Jest ที่ดีขึ้น

Create React App เวอร์ชันใหม่นี้มาพร้อมกับ Jest 23 ที่มี Interactive Snapshot Mode ที่ช่วยให้เราทำงานกับ Snapshot ได้ง่ายขึ้น ดังรูป

Interactive Snapshot Mode

นอกจากนี้ Create React App v2 ยังเพิ่ม globalSetup และ globalTeardown ทำให้ตอนนี้เราสามารถเซ็ตอัพโค้ดบางอย่างให้เริ่มทำงานก่อนทำ test ทั้งหมด และตั้งค่าโค้ดให้ทำงานหลังการรัน test ทั้งหมดได้ ตามลำดับ

เรียนรู้การใช้งาน React กับ Create React App v2

ตอนนี้ทางเพจ Babel Coder กำลังมีคอร์สอบรม React Fundamentals ครับ ในคอร์สนี้เราจะได้เรียนรู้การใช้งาน React กันอย่างเข้มข้นผ่าน Create React App v2 รวมถึงการใช้งาน React Router เพื่อจัดการเส้นทางภายในเว็บเรา การจัดการฟอร์มด้วย React รวมไปถึงการจัดการการไหลของข้อมูลอย่างมีประสิทธิภาพด้วย Redux ทั้งหมดนี้สามารถอ่านรายละเอียดเพิ่มเติมได้ ที่นี่ครับ

React Fundamentals

สรุป

แม้ Create React App v2 จะมีการเพิ่มฟีเจอร์ต่าง ๆ เข้ามามากมาย แต่ก็มีหลายอย่างเปลี่ยนไปเช่นกัน เช่น เลิกสนับสนุน .mjs เป็นต้น เพื่อน ๆ ท่านใดสนใจรายละเอียดเพิ่มเติมสามารถอ่านได้จาก ที่นี่ครับ

เอกสารอ้างอิง

2.0.3 (October 1, 2018) (2018). Retrieved Oct, 3, 2018, from https://github.com/facebook/create-react-app/blob/master/CHANGELOG.md#203-october-1-2018

Create React App 2.0: Babel 7, Sass, and More (2018). Retrieved Oct, 3, 2018, from https://reactjs.org/blog/2018/10/01/create-react-app-v2.html


แสดงความคิดเห็นของคุณ


Piyapong Srisurb2 เดือนที่ผ่านมา

กรณีที่เราใช้ Create React App v2 ถ้าเราจะใช้พวก eslint bable webpack เราใช้คำสั่ง eject ได้เลยใช้ไหมครับ แล้วมันแตกต่างยังไงกับการติดตั้ง package เหล่านั้นเอง