React Tutorial #1: Proje Kurulumu (React + Webpack + Babel + ESLint)

Javascript’in en sevdiğim yanlarından biri geniş kütüphane yelpazesi. En sevmediğim yanlarından biri de geniş kütüphane yelpazesi. :) O kadar çok alternatif var ki, insan hangisini seçeceği konusunda stres sahibi olabiliyor. Frontend söz konusuysa bazen seçmek de yetmiyor, seçtiğiniz kütüphaneyi kullanabilmeniz için başka kütüphaneleri de kullanmak durumunda kalabiliyorsunuz. React özelinde, Facebook sıfır konfigürasyon amacı ile “Create React App” gibi kütüphaneler sunuyor ama bu tür araçlarda da özelleştirme yapılmak istendiğinde esneklik bir hayli düşüyor. Bu konularda yeterince Türkçe içerik olmadığını düşündüğümden bu yazı serisini hazırlamaya karar verdim.

Seride yer vermeyi düşündüğüm başlıklar:

Örnek proje olarak, ToDo MVC’nin React örneğini kullanacağım. Mevcut hali hem ES5 ile hem de herhangi bir bundler ya da compiler kullanılmadan geliştirildiğinden seri sonunda hemen hemen baştan yazmış kadar olacağız.

Önemli Not: Bu yazı serisi NPM, Javascript, ECMAScript, React kavramları hakkında temel bilgilere sahip olduğunuz düşünülerek hazırlanmıştır.

Kullandığımız kütüphaneleri tanıtarak adım adım neler yapılacağını açıklamaya çalışalım.

Projeyi todo-app-tutorial klasöründe konumlandıracağız. Klasör içerisinde npm init komutu ile JS projemizi oluşturuyoruz ve projenin yayınlanacağı dist klasörünü oluşturuyoruz. Bu klasör içerisinde, yazı sonunda webpack ile oluşturacağımız projenin birleştirilmiş hali (bundle) ve tarayıcı için oluşturduğumuz index.html dosyası bulunuyor. index.html içeriği:

Bu dosyada özellikle bahsedebileceğimiz kısımlar;

  • Body içerisinde yer alan div elementindeki id="root” ile React projemizde geliştirdiğimiz bileşenlerin DOM’da hangi elementin içerisinde yer alacağını belirtiyoruz. class="todoapp" property’sini ise CSS yazmaktan hiç hoşlanmadığımız için Todo MVC’nin CSS’lerini kullanabilmek amaçlı ekledik. :)
  • script elementindeki src="./bundle.js" webpack tarafından oluşturulacak bundle dosyamızın ismi.

Yazının ana konularından biri olan webpack kurulumuna geçmeden evvel kısa bir tanım yapacak olursak, webpack bir “module bundler”. Çok mu kısa oldu? Webpack, proje içerisinde farklı dosyalara yazdığımız kodları, stil dosyalarını, görselleri alıp birleştiren bir araç diyebiliriz. Elbette daha fazla detayı var ama bu yazıda temel özelliklerini kullanacağız. Bir de webpack-dev-server kullanacağız. Bu kütüphanenin görevi de node.js ile birlikte bir geliştirme ortamı sunmak ve geliştirme sırasında yaptığımız değişiklikleri browser’da görmemizi sağlamak. İlgili kütüphaneleri projemize ekleyelim.

npm install --save-dev webpack webpack-dev-server webpack-cli 

Webpack’i projeye dahil ettik. Şimdi nasıl çalışacağını, yani bundle işlemine hangi dosyadan başlayacağını, kullanacağı eklentileri, üreteceği çıktıları vb. nasıl düzenleyebileceğimize bakalım. Bu konfigürasyon işlemleri için webpack.config.js dosyasını kullanacağız. Proje ana dizinine bu dosyayı ekleyelim ve aşağıdaki şekilde oluşturalım.

İlk property olan entry webpack’in bundle işlemine nereden başlayacağını belirtiyor. Birazdan projeye dahil edeceğimiz ./src/index.js dosyası projemizin başlangıç noktası olacak ve webpack sırasıyla bütün import edilen dosyaları gezecek bizim için. module.rules ise hangi modüllerin ne şekilde yorumlanacağını belirliyor. Örneğin, /\.(js|jsx)$/ regex’ine uyan dosyalar yani ".js” ve ".jsx” uzantılı dosyalar babel-loader ile yorumlanacak. Babel’in ne olduğuna ve projeye nasıl ekleyeceğimize birazdan değineceğiz. output property’si ile webpack’in tek bir dosya haline getirdiği çıktı ile ilgili konfigürasyonu tanımlıyoruz. Bu projede dist klasöründe bundle.js isimli bir çıktı oluşturacağız. devServer kısmıda ise yukarıda bahsettiğimiz, geliştirme anında değişiklikleri izleyebilmek için gerekli konfigürasyon ayarlarını yapacağız. contentBase geliştirme ortamının nereden host edileceğini, open bundle işlemi bittiğinde tarayıcının otomatik olarak açılması gerektiğini, hot ise projede yapılan değişiklikler sonrası projenin yeniden yüklenmesi için kullanılıyor. plugins içerisinde hangi eklentileri kullanacağımızı belirttik. Bu yazıda sadece HotModuleReplacementPlugin kullanacağız. Son olarak da tarayıcıda sayfalarımızı debug etmek istersek, kaynak kodlarını kullanabilmemizi sağlayacak olan devtool property’sine source-map ekledik.

Webpack içinde kullandığımız loader modüllerini de projeye dahil edelim.

npm install babel-loader style-loader css-loader react-hot-loader --save-dev

Webpack’i nasıl konfigüre edeceğimize değindik ve bir ara babel adı geçti. Babel’i de kısaca özetleyecek olursak, babel bir “compiler”. Javascript ile geliştirme yaparken çoğunlukla ECMAScript’in yeni versiyonlarını kullanıyoruz fakat tarayıcılar ES özelliklerinin tamamını desteklemiyor. Babel bizim yeni özelliklerle yazdığımız javascript kodlarını anlıyor ve tarayıcıların anlayacağı ES5 formatına dönüştürüyor. Webpack de babel-loader ile birlikte bundle işlemini yapabiliyor.

npm install @babel/core @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties --save-dev

Babel için yukarıdaki script ile gerekli modülleri projeye dahil edeceğiz ama kısacık yaptığımız tanım sonrası 4 tane paket eklememiz biraz tuhaf değil mi? Yukarıda tanımını yaptığımız Babel, babel/core olarak belirttiğimiz paket aslında. Peki diğer preset ve plugin içeren paketler nedir? Tanım içerisinde, Babel’in kodları tarayıcının anlayabileceği formata çevirdiğini söylemiştik. JavaScript framework konusunda bir derya. TypeScript, React vb. bir çok kütüphane var ve herbirinin kendine has özellikleri var. Babel da bu framework’ler ile gelen özellikleri transpile edebilmek için preset sunuyor. babel/preset-env en sade JavaScript özelliklerini içeren bir set. Projemizde react da kullanacağımız için babel/preset-react modülünü ekledik. plugin ise, ES ile gelen bir özelliği kullanmak istediğimizde ve o stage’de gelen diğer özelliklere ihtiyacımız olmadığında projeye dahil ettiğimiz mini preset olarak tanımlanabilir. Örneğin, class içerisinde static olarak state, propTypes gibi tanımlar yapacağız fakat dahil ettiğimiz preset paketleri bu özelliği kapsamıyor. Bu yüzden babel/plugin-proposal-class-properties eklentisini dahil ediyoruz.

Babel’in konfigürasyonunu ise babel.config.js isimli dosya ile yapacağız. Bu dosyayı da proje dizininde oluşturalım ve içeriğini aşağıdaki şekilde güncelleyelim. Bu dosya içerisinde yukarıda bahsettiğimiz preset ve plugin tanımlarını yaptık.

Babel’i de projeye ekledikten sonra yazı başlığında belirttiğimiz diğer bir konuya geçebiliriz: ESLint bir JavaScript linter. Biraz daha açalım yine. Sözlük tanımıyla lint, yazılan kodların belirlenen standartlara uygun olup olmadığını tespit etmek için kullanılan bir statik analiz türü. Örnek verecek olursak, tek bir kez atama yapılacak bir değişken için var ya da let kullanılmasın const kullanılsın istiyoruz. Bunu ESLint ile sağlayabiliriz.

npm install eslint eslint-config-airbnb eslint-plugin-react eslint-plugin-jsx-a11y eslint-plugin-babel babel-eslint eslint-plugin-import --save-dev

Yine az şey tanımladık, çok şey ekledik. Hemen nedenini açıklamaya çalışalım. ESLint ile kullanabileceğimiz birçok kural var. Bütün bu kuralları tek tek okuyup, bunu kullanayım bunu kullanmayayım diye düşünmek yerine bu işi bizim yerimize yapan eklentiler kullanıyoruz. Airbnb’nin JavaScript guide’ları oldukça kabul görmüş bir kural seti ve temel olarak onu kabul edebiliriz. Bunun yanında React için kuralları içeren eslint-plugin-react eklentisini ve de JSX elementlerinde linting için eslint-plugin-jsx-a11y eklentisini ekledik. Babel’i de lint etmek için eslint-plugin-babeleklentisini, eslint’in kodları parse ederken babel’i kullanabilmesi için de babel-eslint eklentisini ekledik. Tekerleme gibi oldu ama başta da söylediğim gibi, ihtiyaç ihtiyacı doğurdu… Projede ESLint kurallarına uymayan kullanımları görebilmek için kullandığınız editöre ESLint eklentisini indirebilirisiniz. Eklenti kurmadan, eslint cli ile de hataları tespit etmek mümkün ama eklentiyi kurmak geliştirme sürecini oldukça kolaylaştıracaktır.

ESLint konfigürasyonu için de .eslintrc.js ve .eslintignore dosyalarını kullanacağız. eslintrc linting için gerekli tanımları içeriyor ve içeriği aşağıdaki şekilde tanımladık. eslintignore ise lint etmek istemediğimiz klasör ve dosyaları içeriyor.

Kurulum işlemlerini tamamladık sayılır. Son olarak .editorconfig dosyamızı da ekleyelim projeye. EditorConfig de projeyi geliştirirken farklı farklı text editor’leri ya da IDE’ler kullanırsak, hepsinde aynı formatta kodlar yazılması amacıyla kullanılıyor. Örneğin indentation iki boşluk olsun gibi. Bunun için yine kullandığınız editör eklentilerinden editorconfig eklentisini indirip kurabilirisiniz.

Bu kadar karmaşık konfigürasyondan sonra şu karikatürü ekleyip, React kısmına geçebiliriz. :)

npm install classnames director pluralize prop-types react react-dom todomvc-app-css todomvc-common uuid --save

Yukarıdaki script ile uygulamamız için gerekli modülleri projeye dahil ediyoruz. react react-dom prop-types dışındaki eklentiler başta belirttiğim todomvc’nin örnek uygulamasında kullanılan eklentiler.src klasöründeki kodların üzerinden geçmeyeceğim. Kodlara GitHub üzerinden erişebilirsiniz. src klasöründeki bileşenleri ve diğer yardımcı dosyaları projeye dahil edelim.

Son olarak projemiz ile ilgili script’leri package.json dosyamıza ekleyelim. Bu scriptler, projenin başlatılması ve lint kurallarının çalıştırılması için kullanılacak. package.json dosyası içerisindeki scripts tag’ine aşağıdaki eklemeleri yapalım.

"lint": "eslint . --cache && echo \"eslint: no lint errors\"",
"lint:fix": "eslint . --fix && echo \"eslint: no lint errors\"",
"start": "webpack-dev-server --config ./webpack.config.js --mode development"

npm run lint ile projemizde linting işlemi yapabilir ve kurallara uymayan satırları görebiliriz. lint:fix ile ESLint’in otomatik olarak çözebileceği hataları çözmesini sağlayabiliriz. npm run start ise development ortamımızı başlatıyor. npm run start diyerek uygulamayı başlatıp, src klasöründe oluşturduğumuz sayfaları değiştirerek, değişikliklerin tarayıcıya yansımış olduğunu görebilirsiniz.

Biraz fazlaca uzun oldu. Umarım faydalı olmuştur. Yazı içerisinde yazdığım adımları kendimden sıfırdan deneyerek hata olmadığını teyit ettim ama yine de bu adımlarda bir sorun yaşarsanız bu bölümün kaynak kodlarına GitHub üzerinden erişebilirsiniz.

Sonraki yazı: Unit Test & Test Coverage (Mocha + Enzyme + Chai + Sinon + Istanbul)