มารู้จัก Yarn workspaces กันดีกว่า

Published on
Web Development
2019/07/yarn-workspaces
Discord

วันนี้มีทริปเล็กๆน้อยๆมาแนะนำครับ นั้นก็คือ Yarn Workspaces ปกติแล้วเวลาเราจัดการกับ Node.js app ที่มี node_modules เยอะๆกันยังไงนะ ตัวอย่างเช่น มี folder หลัก ข้างในก็เป็น node api 1 folder มี react app ข้างในอีก 1 folder เวลาติดตั้ง dependencies มันก็จะแยก node_modules กันแต่ละโฟลเดอร์ แต่ถ้าใช้ Yarn workspaces มันจะแชร์ node_modules กันครับ เรียกได้ว่าทั้งสะดวก ทั้งประหยุดพื้นที่ Hard disk ได้เยอะเลย

การติดตั้งและใช้งาน Yarn

หน้าเว็บ Yarn มีขั้นตอนการติดตั้งอยู่ครับ สามารถเลือก OS และ Version ของ Yarn ได้เลย https://yarnpkg.com/en/docs/install

ส่วน Mac OS ก็ติดตั้งผ่าน Homebrew ง่ายๆเลยครับ

brew install yarn

สำหรับใครที่ไม่เคยใช้งาน Yarn ต้องบอกเลยว่าคำสั่งแทบเหมือนกันกับ NPM ครับ เช่น

  • สร้างโปรเจ็คใหม่ ถ้า NPM จะเป็น npm init
yarn init
  • เพิ่ม library/dependency NPM จะเป็น npm install NAME
yarn add PACKAGE_NAME
  • ลบ Library
yarn remove PACKAGE_NAME
  • Install dependencies (เท่ากับ npm i หรือ npm install)
yarn

# หรือ
yarn install

รันคำสั่ง Script ใน package.json ปกติใน NPM จะต้องใช้คำสั่ง run (ถ้าไม่ใช่ default script) เช่น

npm run start-custom-server

แต่ Yarn ใช้ script ได้เลย ไม่ต้องมี run

yarn start-custom-server

มารู้จัก Workspaces

Workspaces เป็นเหมือนกับการ Setup Microservice คือโปรเจ็คนึงของเรา อาจจะมีหลายๆ project ย่อยๆ ตัว Workspaces จะมาช่วยให้เราจัดการกับ project ได้ง่ายขึ้น (หากใครเคยได้ยิน Lerna ซึ่ง repo ดังๆ เช่น Babel, Create React App, Jest ก็ใช้ Lerna แต่ว่า Lerna จะทำอะไรได้มากกว่า Workspace ซึ่งเน้นจัดการกับ dependencies ง่ายครับ)

เคยมั้ยที่เรา มี โฟลเดอร์นึง และภายในมี Node.js app อยู่ 3-4 ตัว เวลาเราจะเพิ่ม library เข้าไปใหม่ ก็ต้อง cd เข้าไป install กลับมา/สลับ folder บ้าง อะไรพวกนี้?

cd projectA
yarn add awesomeLib
cd ../projectB
yarn add awesomeLib
cd ../projectC
yarn add awesomeLib

จะดีกว่ามั้ย ถ้าเรามีตัว base ไว้จัดการ project ย่อยๆ?

ก็เลยเกิดเป็นที่มาของ Yarn workspace นั่นเอง

Workspaces จะติดตั้งมาตั้งแต่ Yarn version 1.0.0 ขึ้นไป ฉะนั้นใครที่ Yarn version ต่ำจะไม่สามารถใช้ได้นะครับ

เริ่มต้นใช้งาน

ง่ายๆเลย เราต้องมี package.json อยู่ที่ root folder ของเรา ตอนนี้จำลองง่ายๆ ผมจะสร้างrootFolder และภายในจะมี Node app 3 ตัวครับ

เริ่มแรกผมสร้าง folder และ ไฟล์ package.json ขึ้นมาดังนี้

mkdir myAwesomeApp
touch package.json

และไฟล์ package.json ใส่แบบนี้ลงไป

{
  "private": true,
  "workspaces": ["appA", "appB", "appC"]
}

Note: "private": true นั้นจำเป็นต้องใส่ครับ

ต่อมาที่ผมต้องการคือ สร้าง folder ขึ้นมา 3 ตัว ชื่อแบบที่ตั้งไว้ใน workspaces ครับ คือ appA, appB และ appC และข้างในทั้ง 3 folders ก็มีไฟล์ package.json ของตัวเอง ระบุ name และ dependencies เอาไว้

{
  "name": "appA",
  "version": "1.0.0",
  "dependencies": {
    "express": "4.17.1"
  }
}

ทั้ง 3 ไฟล์เหมือนกันหมด ต่างกันแค่ name จากนั้นทำการสั่ง install ที่ตัว root folder

yarn install

yarn install v1.16.0
info No lockfile found.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...

จะเห็นว่าเรามีโฟลเดอร์ node_modules ที่ถูกเพิ่มมาใน root folder ทีนี้ ไปสร้างไฟล์ app.js ใน appA เพื่อสร้างเว็บ Node.js ง่ายๆ ตัวนึง

const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.json({ message: 'Running on appA' })
})

app.listen(5000, () => console.log('App is running'))

ในโฟลเดอร์ appA มีแค่ไฟล์ package.json และไฟล์ app.js ด้านบน จากนั้นสั่ง

node app.js

ลองเปิดเว็บ browser http://localhost:5000

จะเห็นว่า App เรารันได้ปกติ ไม่มีปัญหาโดยมันแชร์ node_modules จากตัว root folder นั่นเอง (ใน sub folder ไม่ต้องมี node_modules เลย)

คราวนี้ ถ้าสมมติ แต่ละ folder มี app ของตัวเอง แล้วเวลาจะสั่ง start server ก็ต้องเข้าไปโฟลเดอร์แล้ว node app.js ก็ไม่น่าสนุกเท่าไหร่

เราลองเพิ่ม script ลงไปใน package.json ของ appA ดังนี้

{
	"name": "appA",
	"version": "1.0.0",
+	"scripts": {
+		"start": "node app.js"
+	},
	"dependencies": {
		"express": "4.17.1"
	}
}

ปกติภายใน subfolder เวลาเราจะสั่งรัน เราจะใช้

yarn start

ทีนี้พอมี workspaces เราจะไปที่ root folder ครับ จากนั้นใช้คำสั่ง

yarn workspace FOLDER_NAME SCRIPT_NAME

# ตัวอย่าง
yarn workspace appA start

Note เราสามารถสั่งติดตั้ง dependencies ที่ root folder ได้ ด้วยคำสั่ง เช่น ติดตั้ง react ที่ appB yarn workspace appB add react react-dom --dev

เราสามารถดู info ด้วยคำสั่ง

yarn workspaces info

จะได้รายละเอียดของ workspaces

yarn workspaces v1.16.0
{
  "appA": {
    "location": "appA",
    "workspaceDependencies": [],
    "mismatchedWorkspaceDependencies": []
  },
  "appB": {
    "location": "appB",
    "workspaceDependencies": [],
    "mismatchedWorkspaceDependencies": []
  },
  "appC": {
    "location": "appC",
    "workspaceDependencies": [],
    "mismatchedWorkspaceDependencies": []
  }
}

Note: ถ้าหากว่า subfolder มีการกำหนด dependencies คนละ version กันเช่น express 4.17.0 กับ 4.17.1 ตัว yarn ก็จะไม่ link ไป node_modules ที่ตัว root นะครับ แต่จะติดตั้ง node_modules ใน sub folder ที่เวอร์ชั่นไม่ตรง ฉะนั้นก็ระวังเรื่อง version ด้วยนะครับ

Reference


หวังว่าทริคเล็กๆน้อยๆนี้จะมีประโยชน์ไม่มากก็น้อยนะครับ ขอให้สนุกกับการเขียนโค๊ด ส่วนด้านล่างเป็น Repo เผื่อใครสนใจเข้าไปดูหรือลองรันเล่นๆก็ได้ แต่จริงๆก็ไม่ต่างจากบทความเท่าไหร่ :smile:

Happy Coding

Buy Me A Coffee
Authors
Discord