Storybook ve Rollup Kullanarak Node Package Manager’e (NPM) React Componenti Publish Etmek
NPM nedir?
NPM dünyanın en büyük yazılım kayıt defteridir. Her kıtadan açık kaynak geliştiricileri, paketleri paylaşmak ve ödünç almak için npm’yi kullanır ve birçok kuruluş özel geliştirmeyi yönetmek için de npm kullanır. (npmjs.com)
Günümüzde geliştirdiğimiz web uygulamalarının çoğu bileşen tabanlıdır ve bileşenlerden tam olarak yararlanmak için bunları yalnızca aynı uygulamada değil, farklı uygulamalarda da yeniden kullanıyoruz.
Her yeni React uygulamamızda kullanmak durumunda olduğumuz komponentleri NPM’e publish ederek, her seferinde componenti tekrar yazmak yerine basit bir komut ile bağımlılık olarak projemize ekleyebiliriz (npm i xxx).
Storybook Nedir?
Storybook, UI bileşenlerini ve sayfalarını ayrı ayrı oluşturmak için açık kaynaklı bir araçtır. Kullanıcı arabirimi geliştirme, test etme ve belgeleme işlemlerini kolaylaştırır. (Storybook)
Storybook kullanarak, oluşturacağımız komponentin nasıl göründüğünü test etmek için her defasında projeyi build edip tekrar konfigüre etmek yerine, sanal bir ortamda izleme imkanı bulacağız. Böylece create-react-app kullanmak zorunda kalmamış oluruz. İlerde bahsedeceğim react ve react-dom bağımlılıklarını ekleyeceğimiz projede tek yapmamız gereken şey React komponenti oluşturmak olacak.
Rollup Nedir?
Rollup, küçük kod parçalarını bir kitaplık veya uygulama gibi daha büyük ve daha karmaşık bir şeye derleyen JavaScript için bir modül paketleyicidir. (rollup.js)
Alternatifi olan Browserify veya Webpack, export ederken kaynak dosyanın hepsini bundle ederken, Rollup yalnızca kullanılması gereken kısımlarını bundle ederek optimizasyon sağlar.
Başlayalım
Bu uygulamada daha önceden publish ettiğim bir komponenti (SimplestGallery) sıfırdan publish edeceğim. Uyguladığım adımları kendi komponentinize uygulayarak siz de NPM’de bir pakete sahip olabilirsiniz.
Paket ismi seçmek
İlk önce paketinizin isminin daha önce npm’de kayıtlı olmadığından emin olmalısınız. remarkablemark.org sitesinden oluşturacağınız paketin mevcut olup olmadığını kontrol edebilirsiniz. Paketimin isminin mithat-react-gallery olacağına karar verdim ve mevcut olmadığından emin oldum.
Paket ismiyle bir klasör oluşturalım.
C:\Users\marma\OneDrive\Belgeler> mkdir mithat-react-gallery
Ben belgeler klasörümün altında oluşturdum. İçerisinde Türkçe karakter barındırmayan herhangi bir dizinde oluşturabilirsiniz.
cd mithat-react-gallerycode .
Klasörü VS Code’da açalım.
Proje dizinindeyken (C:\Users\marma\OneDrive\Belgeler\mithat-react-gallery) aşağıdaki bloğu çalıştıralım.
npm init
Bu komut bize bir package.json dosyası oluşturacaktır. İlk başta bütün aşamaları enter tuşuyla onaylayalım. entry point: (index.js) olmasına dikkat edelim. Bunlar daha sonra değiştirilebilir şeyler olduğundan ilk aşamada detaylara inmeyeceğim.
Hala projemizin kök dizinindeyken
mkdir src
komutuyla src klasörü oluşturalım. Şimdi src klasörümüzün içerisinde index.js dosyası ve components klasörü oluşturalım. Components klasörünün içerisinde de bir index.js dosyası ve oluşturacağımız komponentimizin ismiyle bir klasör oluşturalım. Bu noktada oluşturacağımız komponentin isminin paketimizin ismiyle aynı olmasına gerek yoktur. Mesela benim oluşturacağım paketin ismi mithat-react-gallery iken bu bu paketten kullanmak istediğim komponenin ismi Gallery. Daha sonra bu paketi bir React komponentinden import ederken şöyle bir kullanım görürüz :
import {Gallery} from 'mithat-react-gallery'
Komponentimizin ismiyle oluşturduğumuz klasörün için bir index.js dosyası ve Komponentİsmi.js dosyası oluşturacağız. Komponentİsmi.js dosyasında dikkat etmemiz gereken kısım bunun bir React komponenti olacağı ve isimlendirme kurallarının React isimlendirme kurallarına uymasıdır. Ben daha önce belirttiğim gibi Gallery.js isminde bir dosya oluşturdum. Bu adımları tamamladıktan sonraki dosyaların ve klasörlerin görünümü şu şekilde olmalıdır:
Şu ana kadar bu projenin React ile herhangi bir bağlantısı olmadığını farketmişsinizdir. Sırada kullanacağımız bağımlılıkları yüklemek var. Projemizin kök dizinine gidip react ve react-dom kütüphanelerini yükleyelim.
npm install react react-dom --save-dev
Dikkat etmemiz gereken şey — save-dev flagını kullanarak, react ve react-dom’u devDependency olarak yüklememiz. devDependency olarak yüklediğimiz bu iki kütüphaneyi ayrıca peerDependencies’nin altında da belirtmemiz gerekiyor. Sonuç olarak package.json dosyamızın şu şekilde genişlediğini görürüz:
“devDependencies”: {“react”: “^17.0.2”,“react-dom”: “^17.0.2”},“peerDependencies”: {“react”: “^17.0.2”,“react-dom”: “^17.0.2”}
Storybook’u Projeye Ekleyelim
npx sb init
Yukarıdaki bloğu projemizin kök dizininde çalıştırdığımızda, biraz zaman alacaktır, src klasörü içinde stories ve kök dizinde .storybook klasörlerinin oluşturulduğunu görüyoruz. Ek olarak package.json dosyamıza da bir şeyler(!) eklendi.
Komponenti Yazmasak Mı Artık ?!
Bu noktaya kadar herhangi bir problem yaşamadan geldik ve artık eğlenceli ve daha hızlı kısımlar geldi. src\components\Gallery\Gallery.js dosyasının bir React komponenti olduğunu söylemiştim. Peki artık bu dosyayı doldurma vakti geldi. Ben daha önce publish ettiğim SimplestGallery componentimin kodlarıyla dolduruyorum. Sonuçta bir React komponenti ve içerisinde hooklar, proplar vs. her şeyi barındırabilir.
Komponenti default olarak export etmememiz bu kısımda dikkat etmemiz gereken kısım. Komponenti geliştirirken Storybook ile görüntüleyelim. Komponentimizin ismi değişmeyeceğinden geçici süreliğine aşağıdaki gibi bir kullanım izleyip exportlarını tamamlayalım.
export const Gallery = ()=>{return (<h1>Gallery!</h1>)
}
src\components\Gallery\index.js dosyasının içerisinde komponentimizi export edelim.
export * from './Gallery'
ayrıca src\components\index.js dosyasından da export edelim.
(src\components\index.js)export * from '../components/Gallery'
src\index.js:
(src\index.js)export * from './components/Gallery'
Böylece oluşturduğumuz toplam 3 adet index.js dosyasını, komponenti export etmek için kullandık.
Storybook’da komponentimizi görüntüleyebilmek için bir story oluşturmamız gerekiyor. Bunun için öncelikle src\stories klasörünün içindeki bütün oluşturulan dosyaları silelim. Aynı klasör içinde Gallery.stories.js isminde bir dosya oluşturalım.
Bu dosyanın içini aşağıdaki gibi dolduralım (Storybook ile ilgilenirseniz şuradan dökümanı okuyabilirsiniz):
import { storiesOf } from '@storybook/react'import React from 'react'import { Gallery } from '../components/Gallery'const stories = storiesOf('App test', module);stories.add('app',()=>{return <Gallery />})
Dosyaları kaydedip kök dizinde şunu çalıştıralım:
npm run storybook
Bu bloğu çalıştırdıktan sonra browserda bir sekme açılacak (http://localhost:6006/) ve oluşturduğumuz komponenti görebiliyor olacağız. Şimdi komponent üzerinde değişiklik yaptığımızda burada canlı değişimleri gözlemleyebiliriz.
Diyelim ki komponentimizi geliştirdik ve artık NPM’e publish edilmeye hazır. Rollup bağımlılıklarını yükleyelim. Projemizin kök dizinine gidelim ve şunu çalıştıralım. — save-dev flagının olduğuna dikkat edelim.
npm install rollup rollup-plugin-babel @rollup/plugin-node-resolve rollup-plugin-peer-deps-external --save-dev
Şimdi de React kodlarında bulunan JSX’i çeviren @babel/preset-react presetini yükleyelim:
npm install @babel/preset-react --save-dev
Rollup bağımlılığını yükledikten sonra package.json dosyasında devDependencies altında görebiliyoruz.
Rollup Config Dosyası
Rollup’ı kullanarak paketimizin ihtiyacı olan kod parçalarını oluşturacağız. Bunun için bir config dosyası gerekiyor. Hangi dosyadan okuma yapıp nereye yazılacağını belirteceğiz.
Projemizin kök dizininde rollup.config.js adında bir dosya oluşturalım. Bu dosyanın içini şununla dolduralım:
import babel from 'rollup-plugin-babel';import resolve from '@rollup/plugin-node-resolve';import external from 'rollup-plugin-peer-deps-external';export default [{input :'./src/index.js',output:[{file:'dist/index.js',format:'cjs'},{file:'dist/index.js',format:'es',exports:'named',}],plugins:[babel({exclude : 'node_modules/**',presets : ['@babel/preset-react']}),external(),resolve(),]}]
Artık paketi oluşturacak kodları barındıran dosyayı oluşturmak için package.json dosyasında build-lib adında bir script oluşturabiliriz:
Package.json
...,
“scripts”:{...,"build-lib":"rollup -c",
...},
...
Bütün değişiklikleri kaydedelim daha sonra kök dizinde henüz yazdığımız npm run build-lib komutunu çalıştıralım:
npm run build-lib
Herşey yolunda gidiyorsa kök dizinde dist klasörü oluşmuş olması gerekir. İçerisindeki index.js dosyasını incelediğimizde komponentimize benzeyen bir kod parçası görüyoruz. Ancak bu kadar uzun olmasına gerek var mı? Biraz daha sadeleşebilir:
npm install --save-dev rollup-plugin-terser
komutunu çalıştırıp rollup.config.js dosyamıza geri dönelim ve şunları ekleyelim:
...;
...;
...;import {terser} from 'rollup-plugin-terser';export default [{ ...,
...,
plugins:[
...,
...,
terser() ]]
Değişiklikleri kaydedip build-lib komutumuzu çalıştıralım:
npm run build-lib
Şimdi dist/index.js dosyasındaki farkı görebiliyoruz. Eskisinden daha karmaşık ve optimize.
Publish etmeden önceki yapacağımız son işlem package.json içerisindeki “main”:”index.js” alanını değiştirmek. Şununla değiştirelim:
...,
"main": "dist/index.js",
...
“type”:”module” alanı ekleyelim:
...,“license”: “ISC”,“type”: “module”,“devDependencies”: {...
Değişiklikleri kaydedelim.
Publish it!
Artık bizi kimse bu paketi paylaşmamıza engel olamaz! Hemen npm.js sitesine gidip bir kullanıcı oluşturalım. Kullanıcı adı, email ve şifre gerektiren kolay bir kayıt olma süreci sonrasında projemize geri dönelim. Projemizin kök dizininde npm login komutunu çalıştırıp bu bilgileri girerek ve e-mail adresimize gelen tek kullanımlık kod ile giriş yapalım:
npm login
Giriş yaptığımıza göre tek yapmamız gereken şey npm publish komutunu çalıştırarak paketimizi daha sonra kullanabilmek üzere npm’e publish etmek olacak:
npm publish
TEBRİKLER! npm’de bir paketiniz herkese açık bir şekilde barınıyor. Peki, bunu bir deneyelim bakalım. npm.js sitesinde paketimizin ismini aratalım ya da profilimizden paketimizi bulup install komutunu kopyalayalım:
npm i mithat-react-gallery
Yeni oluşturduğumuz ya da daha önceden var olan bir React projemize bunu yükleyelim.
Sonuç
İstediğim gibi çalışıyor ve bütün propları öneriyor.
Umarım faydalı olmuştur. Bir dahaki yazıya kadar… Hoşçakalın 🤗