आधुनिक फ्रंटएंड इंजिनिअरिंग दहा वर्षांपूर्वीसारखे अजिबात दिसत नाही. तुम्ही फक्त HTML आणि CSS लिहित नाही आहात. आता एका सामान्य प्रोजेक्टमध्ये विशिष्ट Node.js रनटाइम, लॉक केलेले पॅकेज मॅनेजर व्हर्जन, बिल्ड टूल्सचा गुंता आणि डिप्लॉयमेंट पाईपलाईन्स असतात ज्यामध्ये सर्व काही अचूकपणे जुळणे अपेक्षित असते. पहिल्या npm install पासून अंतिम प्रोडक्शन बिल्डपर्यंत, काही लहान फरक निर्माण होतात. तुमचा सहकारी Node 20 वापरतो, तर तुम्ही Node 18 वापरता. तुमच्या मशीनवरील एखादे ग्लोबल CLI टूल त्यांच्या मशीनवरील गहाळ डिपेंडन्सी (dependency) लपवून ठेवते. मग तो वाक्यप्रचार येतो जो कोणालाही ऐकायला आवडत नाही: "माझ्या मशीनवर हे व्यवस्थित चालते."
Docker तुमच्या फ्रंटएंड टूलकिटमध्ये आपले स्थान मिळवते कारण ते ती अनिश्चितता दूर करते. ते तुमच्या ॲप्लिकेशनला आवश्यक असलेला नेमका रनटाइम, सिस्टम लायब्ररीज आणि डिपेंडन्सीजसोबत एकत्र बांधते (bundles). तुम्ही Windows वर कोडिंग करत असाल, macOS वरून शिप करत असाल किंवा Linux क्लाउड इन्स्टन्सवर डिप्लॉय करत असाल, तरीही त्याचे वर्तन (behavior) सारखेच राहते.
फ्रंटएंड डेव्हलपर्सनी याकडे लक्ष का दिले पाहिजे
Docker ज्या समस्या सोडवते त्या केवळ काल्पनिक नाहीत. त्या प्रत्येक स्प्रिंटमध्ये समोर येतात.
व्हर्जन कॉन्फ्लिक्ट्समुळे (version conflicts) वेळ वाया जातो. एखाद्या जुन्या क्लायंट प्रोजेक्टसाठी Node 18 आवश्यक आहे, तुमच्या साईड प्रोजेक्टसाठी Node 20 आणि नवीन स्टार्टअप कामासाठी Node 22 लागते. कंटेनर्सशिवाय, तुम्हाला हे व्हर्जन मॅनेजर्सद्वारे हाताळावे लागते. जोपर्यंत ते काम करते तोपर्यंत ठीक आहे, पण नंतर अडचणी येतात. npm च्या व्हर्जनमधील थोडासा फरक peer dependencies कशा रिझॉल्व्ह होतात यावर परिणाम करू शकतो, ज्यामुळे तुमचा बिल्ड खराब होऊ शकतो, जो दुसऱ्या कोणाकडे तरी व्यवस्थित चालत असेल. जेव्हा एखादे फ्रेमवर्क नवीन रिलीज जाहीर करते, तेव्हा फीडबॅक लूप म्हणजे दोन तास पुन्हा पुन्हा इन्स्टॉल करणे नसावे. त्याऐवजी फक्त एक फाईल बदलणे आणि कंटेनर रीस्टार्ट करणे पुरेसे असावे.
ग्लोबल पॅकेजेस हे देखील शांतपणे त्रास देणारे दुसरे एक कारण आहे. तुमच्याकडे सहा महिन्यांपूर्वी इन्स्टॉल केलेले Angular CLI, Expo किंवा Prisma ग्लोबल असू शकते. एखादा नवीन डेव्हलपर तेच टूल नवीन इन्स्टॉल करतो आणि त्याला वेगळे व्हर्जन मिळते. अचानक तुमचे बिल्ड स्क्रिप्ट्स असे वॉर्निंग्स देऊ लागतात जे इतर कुठेही दिसत नाहीत. Docker सर्व काही 'प्रोजेक्ट-लोकल' ठेवून ही समस्या सोडवते. तुम्ही तुमच्या Dockerfile मध्ये Node व्हर्जन ठरवता. डिपेंडन्सीज कंटेनरच्या आत इन्स्टॉल होतात, तुमच्या होस्ट ऑपरेटिंग सिस्टमपासून वेगळ्या (isolated) राहतात. तुमचा लॅपटॉप macOS, Windows किंवा Ubuntu असू शकतो; ॲप्लिकेशनला प्रत्येक वेळी अगदी सारखेच एन्व्हायर्नमेंट (environment) मिळते.
ऑनबोर्डिंगचे फायदे दुर्लक्षित करणे कठीण आहे. नवीन कर्मचाऱ्यांना Homebrew इन्स्टॉलेशन, nvm aliases आणि ग्लोबल परमिशन फिक्सेस कव्हर करणाऱ्या तीन पानांच्या readme ची गरज नसते. ते फक्त Docker इन्स्टॉल करतात, रिपॉझिटरी क्लोन करतात आणि एक कमांड चालवतात. ज्या सेटअपसाठी पूर्वी पूर्ण दुपार लागायची, तो आता काही मिनिटांत होतो. आणि जेव्हा ते प्रोजेक्ट बदलतात, तेव्हा मागे काहीही राहत नाही. कोणतेही विनाकारण राहिलेले ग्लोबल टूल्स नाही. PATH precedence साठी भांडणारे व्हर्जन मॅनेजर्स नाहीत. त्यांचे लोकल मशीन स्वच्छ राहते.
इमेजेस आणि कंटेनर्स: मूलभूत गोष्टी
जर तुम्हाला Docker नवीन असेल, तर याची संज्ञा (terminology) ऐकायला जितकी कठीण वाटते तितकी सोपी आहे. Docker इमेज म्हणजे एक ब्लूप्रिंट (blueprint) आहे. यामध्ये तुमचा सोर्स कोड, Node.js रनटाइम, तुमची लॉकफाईल आणि ॲप चालवण्यासाठी आवश्यक असलेली प्रत्येक डिपेंडन्सी असते. कंटेनर म्हणजे त्या इमेजपासून तयार झालेली एक 'लाईव्ह इन्स्टन्स' (live instance) आहे. इमेजला एक रेसिपी समजा आणि कंटेनरला प्रत्यक्ष जेवण समजा. तुम्ही एकाच रेसिपीपासून शंभर वेळा सारखाच केक बनवू शकता. होस्ट कॉम्प्युटरवर काय इन्स्टॉल आहे याची काळजी न करता तुम्ही एका इमेजपासून सारखेच कंटेनर्स तयार करू शकता.
एक प्रॅक्टिकल Dockerfile
चला एका ठोस सुरुवातीच्या बिंदूकडे पाहूया. जर तुम्ही
