Chrome Geliştirici Araçları'nın HTML, CSS ve JavaScript kullanılarak yazılmış bir web uygulaması olduğunu biliyorsunuzdur. DevTools, yıllar içinde daha fazla özellik, daha akıllı ve daha geniş web platformu hakkında daha bilgili hale geldi. Geliştirici Araçları yıllar içinde genişlemiş olsa da mimarisi, hâlâ WebKit'in bir parçası olduğu zamanki orijinal mimariye büyük ölçüde benziyor.
Bu yayın, DevTools'un mimarisinde yaptığımız değişiklikleri ve nasıl oluşturulduğunu açıklayan bir dizi blog yayınının bir parçasıdır. DevTools'un geçmişte nasıl çalıştığını, avantajlarını ve sınırlamalarını ve bu sınırlamaları hafifletmek için neler yaptığımızı açıklayacağız. Bu nedenle modül sistemlerini, kodun nasıl yüklendiğini ve JavaScript modüllerini nasıl kullandığımızı inceleyelim.
Başlangıçta hiçbir sorun yoktu
Mevcut ön uç ortamında, etrafında araçlar bulunan çeşitli modül sistemleri ve artık standartlaştırılmış JavaScript modülleri biçimi mevcut olsa da DevTools ilk oluşturulduğunda bunların hiçbiri yoktu. DevTools, ilk olarak 12 yıldan uzun bir süre önce WebKit'te kullanıma sunulan kodun üzerine inşa edilmiştir.
Geliştirici Araçları'nda bir modül sisteminden ilk bahsedildiğinde 2012 yılından bahsedildi: İlişkilendirilmiş kaynak listesinin bulunduğu bir modül listesinin kullanıma sunulması.
Bu, o zamanlar DevTools'u derlemek ve oluşturmak için kullanılan Python altyapısının bir parçasıydı.
Bir takip değişikliği, tüm modülleri 2013'te ayrı bir frontend_modules.json
dosyasına (commit) ve ardından 2014'te ayrı module.json
dosyalarına (commit) ayırdı.
Örnek bir module.json
dosyası:
{
"dependencies": [
"common"
],
"scripts": [
"StylePane.js",
"ElementsPanel.js"
]
}
2014'ten beri DevTools'ta modüllerini ve kaynak dosyalarını belirtmek için module.json
kalıbı kullanılmaktadır.
Bu sırada web ekosistemi hızla gelişti ve UMD, CommonJS ve nihayetinde standartlaştırılmış JavaScript modülleri dahil olmak üzere birden fazla modül biçimi oluşturuldu.
Ancak Geliştirici Araçları module.json
biçimini kullanmaya devam etti.
Geliştirici Araçları çalışmaya devam etse de standart dışı ve benzersiz bir modül sistemi kullanmanın bazı dezavantajları vardı:
module.json
biçimi, modern paketleyicilere benzer şekilde özel derleme araçları gerektiriyordu.- IDE entegrasyonu yoktu. Bu nedenle, modern IDE'lerin anlayabileceği dosyalar oluşturmak için özel araçlar gerekiyordu (VS Code için jsconfig.json dosyaları oluşturmaya yönelik orijinal komut dosyası).
- Modüller arasında paylaşımı mümkün kılmak için işlevler, sınıflar ve nesnelerin tümü genel kapsama alındı.
- Dosyalar sıraya bağlıydı. Yani
sources
öğelerinin listelenme sırası önemliydi. Yalnızca bir kişi tarafından doğrulanmış olması dışında, kullandığınız kodun yükleneceğine dair bir garanti bulunmuyordu.
DevTools'daki modül sisteminin ve diğer (daha yaygın kullanılan) modül biçimlerinin mevcut durumunu değerlendirdiğimizde, module.json
kalıbının çözdüğünden daha fazla soruna yol açtığına ve bu kalıptan geçiş planlama zamanının geldiğine karar verdik.
Standartların avantajları
Mevcut modül sistemleri arasından, taşınacak modül olarak JavaScript modüllerini seçtik. Bu karar alındığında JavaScript modülleri hâlâ Node.js'de bir işaretin arkasından yayınlanıyordu ve NPM'de bulunan çok sayıda pakette kullanabileceğimiz bir JavaScript modülü paketi yoktu. Buna rağmen, en iyi seçeneğin JavaScript modülleri olduğu sonucuna vardık.
JavaScript modüllerinin birincil avantajı, JavaScript için standartlaştırılmış modül biçimi olmasıdır.
module.json
aracının dezavantajlarını listelediğimizde (yukarıya bakın) neredeyse hepsinin standart dışı ve benzersiz bir modül biçimi kullanmakla ilgili olduğunu fark ettik.
Standart olmayan bir modül biçimi seçmek, derleme araçlarıyla ve bakım ekibimizin kullandığı araçlarla entegrasyon oluşturmak için zaman ayırmamız gerektiği anlamına gelir.
Bu entegrasyonlar genellikle kararsızdı ve özellikler için destekten yoksundu. Bu nedenle ek bakım süresi gerektiriyordu ve bazen kullanıcılara gönderilecek küçük hatalara yol açıyordu.
JavaScript modüllerinin standart olması, VS Code gibi IDE'lerin, Closure Compiler/TypeScript gibi yazım denetleyicileri ve Rollup/küçültücüler gibi derleme araçlarının yazdığımız kaynak kodunu anlayabilmesi anlamına geliyordu.
Ayrıca, DevTools ekibine yeni katılan bir geliştiricinin, özel bir module.json
biçimini öğrenmek için zaman harcaması gerekmez. Bunun yerine, muhtemelen JavaScript modülleri hakkında bilgi sahibidir.
Elbette, DevTools ilk oluşturulduğunda yukarıdaki avantajlardan hiçbiri mevcut değildi. Standartlar grupları, çalışma zamanı uygulamaları ve JavaScript modüllerini kullanan geliştiricilerin geri bildirimleriyle bugünkü noktaya ulaşmak için yıllarca çalışma yapıldı. Ancak, JavaScript modülleri kullanıma sunulduğunda ya kendi biçimimizi korumayı ya da yeni biçime geçmek için yatırım yapmayı seçme şansına sahip olduk.
Yeni cihazın maliyeti
JavaScript modüllerinin yararlanmak istediğimiz birçok avantajı olmasına rağmen standart olmayan module.json
dünyasında kaldık.
JavaScript modüllerinin avantajlarından yararlanmak için teknik borcu temizlemeye ve özellikleri bozabilecek ve geriye dönük hatalara neden olabilecek bir taşıma işlemi gerçekleştirmeye önemli ölçüde yatırım yapmamız gerekiyordu.
Bu noktada, "JavaScript modüllerini kullanmak istiyor muyuz?" sorusu değil, "JavaScript modüllerini kullanmak ne kadar pahalı?" sorusuydu. Bu noktada, kullanıcılarımızın regresyonlarla kırılması riskini, mühendislerin geçişe oldukça fazla zaman harcamalarının (çok fazla) maliyeti ile çalışacağımız geçici olarak daha kötü olan durumu dengelemek zorundaydık.
Son noktanın çok önemli olduğu ortaya çıktı. Teorik olarak JavaScript modüllerine erişebileceksek de, taşıma sırasında module.json
ve JavaScript modüllerinin ikisini dikkate almamız gereken bir kodla karşılaşırız.
Bunun başarılması teknik açıdan zor olmasının yanı sıra Geliştirici Araçları üzerinde çalışan tüm mühendislerin bu ortamda nasıl çalışacaklarını da bilmeleri gerektiği anlamına geliyordu.
Kendilerine sürekli şu soruyu sormaları gerekir: "Kod tabanının bu kısmı için module.json
mı yoksa JavaScript modülleri mi kullanılıyor ve nasıl değişiklik yaparım?".
Önizleme: Bakım uzmanlarımıza geçiş sürecinde rehberlik etmenin gizli maliyeti beklediğimizden daha büyüktü.
Maliyet analizinin ardından, JavaScript modüllerine geçişin yine de değerli olduğu sonucuna vardık. Bu nedenle, ana hedeflerimiz şunlardı:
- JavaScript modüllerinin kullanımından mümkün olduğunca fazla yararlanın.
- Mevcut
module.json
tabanlı sistemle entegrasyonun güvenli olduğundan ve kullanıcılar üzerinde olumsuz bir etkisi (gerileme hataları, kullanıcıların canını sıkacak durumlar) olmadığından emin olun. - Tüm DevTools geliştiricilerinin taşıma işleminde yol gösterici olması için, öncelikle yanlışlıkla yapılan hataları önlemek amacıyla yerleşik denetim ve dengeler sunar.
E-tablolar, dönüşümler ve teknik borç
Hedef açıkça belli olsa da module.json
biçiminin getirdiği kısıtlamaların geçici bir çözüm üretmesi zor olduğu anlaşıldı.
Kendimizi rahat hissettiğimiz bir çözüm geliştirmeden önce birkaç iterasyon, prototip ve mimari değişiklik yaptık.
Sonunda edindiğimiz taşıma stratejisini içeren bir tasarım belgesi hazırladık.
Tasarım dokümanında ilk süre tahminimiz de (2-4 hafta) belirtilmişti.
Spoiler uyarısı: Taşımanın en yoğun kısmı 4 ay sürdü ve baştan sona 7 ay sürdü!
Ancak ilk plan zamana karşı koydu: DevTools çalışma zamanında, scripts
dizisinde listelenen tüm dosyaları module.json
dosyasında eski yöntemi kullanarak, modules
dizisinde listelenen tüm dosyaları ise JavaScript modülleri dinamik içe aktarma ile yüklemeyi öğretecektik.
modules
dizisinde bulunan tüm dosyalar ES içe aktarma/dışa aktarma işlemlerini kullanabilir.
Ayrıca taşıma işlemini 2 aşamada gerçekleştiririz (son aşamayı 2 alt aşamaya ayırırız, aşağıya bakın): export
ve import
aşamaları.
Hangi modülün hangi aşamada olacağı büyük bir e-tabloda izleniyordu:
İlerleme sayfasının bir snippet'ini buradan inceleyebilirsiniz.
export
-aşama
İlk aşamada, modüller/dosyalar arasında paylaşılması gereken tüm semboller için export
-ifadeleri eklenir.
Dönüşüm, her klasör için bir komut dosyası çalıştırılarak otomatik hale gelir.
module.json
dünyasında aşağıdaki simge mevcut olur:
Module.File1.exported = function() {
console.log('exported');
Module.File1.localFunctionInFile();
};
Module.File1.localFunctionInFile = function() {
console.log('Local');
};
(Burada, Module
modülün adı, File1
ise dosyanın adıdır. Kaynak ağacımızda bu değer front_end/module/file1.js
olacaktır.)
Bu, aşağıdaki gibi dönüştürülür:
export function exported() {
console.log('exported');
Module.File1.localFunctionInFile();
}
export function localFunctionInFile() {
console.log('Local');
}
/** Legacy export object */
Module.File1 = {
exported,
localFunctionInFile,
};
Baştaki planımız, bu aşamada aynı dosya içe aktarma işlemlerini de yeniden yazmaktı.
Örneğin, yukarıdaki örnekte Module.File1.localFunctionInFile
yerine localFunctionInFile
yazıyoruz.
Ancak bu iki dönüşümü ayırmamız halinde otomatikleştirmenin daha kolay ve daha güvenli olacağını fark ettik.
Bu nedenle, "aynı dosyadaki tüm sembolleri taşıma" işlemi, import
aşamasının ikinci alt aşaması olur.
Bir dosyaya export
anahtar kelimesi eklendiğinde dosya "komut dosyası" olmaktan "modül"e dönüştüğü için DevTools altyapısının büyük bir kısmının buna göre güncellenmesi gerekiyordu.
Buna çalışma zamanı (dinamik içe aktarma ile) ve aynı zamanda modül modunda çalışan ESLint
gibi araçlar da dahil edildi.
Bu sorunlar üzerinde çalışırken testlerimizin "sloppy" modunda çalıştığını tespit ettik.
JavaScript modülleri, dosyaların "use strict"
modunda çalıştığını ima ettiğinden bu durum testlerimizi de etkiler.
Sonuçta ortaya çıktığı gibi, önemli düzeyde bir test yöntemi de bu dengesizliği dikkate alıyordu. Hatta with
ifadesini kullanan bir test de yer alıyordu 😅.
Sonuç olarak, ilk klasörü export
ifadeleri içerecek şekilde güncellemek yaklaşık bir hafta ve yeniden yüklemeyle birden fazla deneme aldı.
import
-aşama
Tüm simgeler hem export
-ifadeleri kullanılarak dışa aktarıldıktan hem de genel kapsamda (eski) kaldıktan sonra, ES içe aktarma işlemlerini kullanmak için tüm dosyalar arası simge referanslarını güncellememiz gerekti.
Nihai hedef, tüm "eski dışa aktarma nesnelerini" kaldırarak global kapsamı temizlemektir.
Dönüşüm, her klasör için bir komut dosyası çalıştırılarak otomatik hale gelir.
Örneğin, module.json
dünyasında bulunan aşağıdaki simgeler için:
Module.File1.exported();
AnotherModule.AnotherFile.alsoExported();
SameModule.AnotherFile.moduleScoped();
Bu resimler şuna dönüştürülür:
import * as Module from '../module/Module.js';
import * as AnotherModule from '../another_module/AnotherModule.js';
import {moduleScoped} from './AnotherFile.js';
Module.File1.exported();
AnotherModule.AnotherFile.alsoExported();
moduleScoped();
Ancak bu yaklaşımın bazı sakıncaları vardı:
- Her simge
Module.File.symbolName
olarak adlandırılmamıştır. Bazı simgeler yalnızcaModule.File
veya hattaModule.CompletelyDifferentName
olarak adlandırılıyordu. Bu tutarsızlık, eski genel nesneden içe aktarılan yeni nesneye dahili bir eşleme oluşturmamız gerektiği anlamına geliyordu. - Bazen moduleScoped adları arasında çakışmalar olabilir.
En belirgin olarak, her sembolün yalnızca
Events
olarak adlandırıldığı belirliEvents
türlerini beyan etme kalıbı kullandık. Bu, farklı dosyalarda tanımlanan birden fazla etkinlik türünü dinliyorsanız buEvents
içinimport
-ifadesinde bir ad çakışması yaşanacağı anlamına geliyordu. - Dosyalar arasında döngüsel bağımlılık olduğu ortaya çıktı.
Simgenin kullanımı tüm kod yüklendikten sonra olduğundan bu, global kapsam bağlamında sorunsuzdu.
Ancak bir
import
'e ihtiyacınız varsa döngüsel bağımlılık açıkça belirtilir. DevTools'ta da olduğu gibi, genel kapsamlı kodunuzda yan etki işlevi çağrılarınız yoksa bu hemen bir sorun oluşturmaz. Sonuç olarak, dönüşümü güvenli hale getirmek için bazı düzenlemeler ve yeniden yapılandırmalar yapmak gerekti.
JavaScript modülleriyle yepyeni bir dünya
Eylül 2019'da başlayan işlemden 6 ay sonra, Şubat 2020'de ui/
klasöründe son temizleme işlemleri gerçekleştirildi.
Bu, taşıma işleminin gayrı resmi olarak sona erdiğini işaret ediyordu.
Havanın düzelmesinin ardından, taşıma işlemini 5 Mart 2020'de tamamlandı şeklinde resmi olarak işaretledik. 🎉
Artık DevTools'daki tüm modüller kod paylaşmak için JavaScript modüllerini kullanıyor.
Eski testlerimiz için veya DevTools mimarisinin diğer bölümleriyle entegrasyon sağlamak amacıyla bazı sembolleri hâlâ global kapsama (module-legacy.js
dosyalarına) yerleştiriyoruz.
Bu özellikler zaman içinde kaldırılacak olsa da gelecekteki geliştirmeleri engellemeyecektir.
Ayrıca JavaScript modüllerini kullanmamızla ilgili bir stil kılavuzumuzu da inceleyebilirsiniz.
İstatistikler
Bu taşıma işleminde yer alan CL (değişiklik listesi kısaltması - Gerrit'te bir değişikliği temsil eden terim - GitHub çekme isteğine benzer) sayısına dair muhafazakar tahminler çoğunlukla 2 mühendis tarafından gerçekleştirilen 250 CL civarındadır. Yapılan değişikliklerin boyutu hakkında kesin istatistiklerimiz yok ancak değişen satır sayısıyla ilgili muhafazakar bir tahmin (her CL için eklemeler ve silme işlemleri arasındaki mutlak farkın toplamı olarak hesaplanır) yaklaşık 30.000'dir (tüm DevTools ön uç kodunun yaklaşık %20'si).
export
kullanan ilk dosya Chrome 79'da gönderildi ve Aralık 2019'da kararlı kanalında yayınlandı.
import
'e geçişle ilgili son değişiklik, Mayıs 2020'de kararlı sürümde yayınlanan Chrome 83'te kullanıma sunulmuştur.
Chrome kararlılığına gönderilmiş ve bu taşıma kapsamında kullanıma sunulan bir regresyondan haberdarız.
Bilinmeyen bir default
dışa aktarma nedeniyle komut menüsündeki snippet'lerin otomatik olarak tamamlanması bozuldu.
Başka birkaç regresyonla da karşılaştık. Ancak otomatik test paketlerimiz ve Chrome Canary kullanıcılarımız bu sorunları bildirdi ve Chrome'un kararlı kullanıcılarına ulaşmadan önce bu sorunları düzelttik.
Yolculuğun tamamını (tüm CL'ler bu hataya eklenmemiştir ancak çoğu eklenmiştir) crbug.com/1006759 adresinde görebilirsiniz.
Öğrendiklerimiz
- Geçmişte alınan kararlar projeniz üzerinde uzun süreli bir etki yaratabilir. JavaScript modülleri (ve diğer modül biçimleri) uzun süredir kullanılsa da DevTools, taşıma işlemini haklı çıkaracak durumda değildi. Ne zaman geçiş yapacağınıza ve ne zaman yapmayacağınıza karar vermek zordur ve tahminlere dayanır.
- İlk zaman tahminlerimiz ay yerine hafta olarak yapılmıştı. Bu durum büyük ölçüde, ilk maliyet analizimizde beklediğimizden daha fazla beklenmedik sorun saptamış olmamızdan kaynaklanmaktadır. Geçiş planı sağlam olsa da teknik borç (istediğimizden çok daha fazla) engel teşkil etti.
- JavaScript modülleri taşıma işlemi, çok sayıda (ilgili görünmeyen) teknik borç temizlemesini içeriyordu. Modern ve standartlaştırılmış bir modül biçimine geçiş, kodlamayla ilgili en iyi uygulamalarımızı modern web geliştirmeyle yeniden uyumlu hale getirmemize olanak tanıdı. Örneğin, özel Python paketleyicimizi minimum bir Rollup yapılandırmasıyla değiştirebildik.
- Kod tabanımızdaki büyük etkiye rağmen (kodun yaklaşık% 20'si değişti) çok az sayıda gerileme bildirildi. İlk birkaç dosyayı taşırken çok sayıda sorun yaşadık ancak bir süre sonra sağlam ve kısmen otomatik bir iş akışına sahip olduk. Bu, bu taşıma işleminde sabit kullanıcılarımız üzerindeki olumsuz etkiyi en aza indirdiği anlamına geliyor.
- Bu tür bir taşımanın inceliklerini, bakıcılara öğretmek zor, bazen de imkansızdır. Bu ölçekteki taşıma işlemlerini takip etmek zordur ve çok fazla alan bilgisi gerekir. Bu alan bilgisini, aynı kod tabanında çalışan diğer kişilere aktarmak, yaptıkları iş açısından kendi başına istenilen bir durum değildir. Neleri paylaşacağınızı ve hangi ayrıntıları paylaşmayacağınızı bilmek bir sanattır ancak gerekli bir sanattır. Bu nedenle, büyük taşıma işlemlerinin sayısını azaltmak veya en azından bu işlemleri aynı anda gerçekleştirmemek son derece önemlidir.
Önizleme kanallarını indirme
Chrome Canary, Yeni geliştirilenler veya Beta'yı varsayılan geliştirme tarayıcınız olarak kullanabilirsiniz. Bu önizleme kanalları en yeni Geliştirici Araçları özelliklerine erişmenizi, son teknoloji web platformu API'lerini test etmenizi ve sitenizdeki sorunları kullanıcılarınızdan önce bulmanızı sağlar.
Chrome Geliştirici Araçları Ekibi ile iletişime geçme
Yeni özellikler, güncellemeler veya Geliştirici Araçları ile ilgili başka herhangi bir konu hakkında konuşmak için aşağıdaki seçenekleri kullanın.
- crbug.com adresinden bize geri bildirim ve özellik isteği gönderin.
- Geliştirici Araçları'ndaki Diğer seçenekler > Yardım > Geliştirici Araçları sorunu bildir bölümüne giderek Geliştirici Araçları sorunlarını bildirin.
- @ChromeDevTools hesabına tweet gönderin.
- Geliştirici Araçları'ndaki yenilikler veya Geliştirici Araçları'yla ilgili ipuçları konulu YouTube videolarına yorum bırakın.