angular.json’ı Anlamak

Üstünkörü Angular CLI *

Cem Topkaya
12 min readMay 6, 2019

add: Adds support for an external library to your project.

build (b): Compiles an Angular app into an output directory named dist/ at the given output path. Must be executed from within a workspace directory.

config: Retrieves or sets Angular configuration values.

doc (d): Opens the official Angular documentation (angular.io) in a browser, and searches for a given keyword.

e2e (e): Builds and serves an Angular app, then runs end-to-end tests using Protractor.

generate (g): Generates and/or modifies files based on a schematic.

help: Lists available commands and their short descriptions.

lint (l): Runs linting tools on Angular app code in a given project folder.

new (n): Creates a new workspace and an initial Angular app.

run: Runs a custom target defined in your project.

serve (s): Builds and serves your app, rebuilding on file changes.

test (t): Runs unit tests in a project.

update: Updates your application and its dependencies. See https://update.angular.io/

version (v): Outputs Angular CLI version.

xi18n: Extracts i18n messages from source code.

Haydi Başlayalım

Uygulama ve kütüphane olmadan bir proje başlatıyoruz

ng new angularjson-anlamak --create-application=false

Bu işlem tamamlandığında ng serve komutunu çalıştırmak bir işe yaramayacak çünkü bir proje oluşturulmuş değil.

Aşağıdaki dosyalar oluşuyor ve burada önemli olan angular.json dosyası sonra tsconfig.json dosyasıdır.

  • angular.json dosyasında:
  • newProjectRoot: 'projects' olarak set edilmiş ama böyle bir dizini oluşturmamış!
  • projects:{} boş çünkü hiç kütüphane ve projeyle başlatmadık

Tüm projelerin ortak kütüphanelerini package.json dosyasında dependencies ve devDependencies içinde göreceğiz. Ancak her kütüphanenin kendine ait paketleri de olacaktır.

Dependencies

dependencies içinde belirtilen paketler şu anlama gelir:

  • Kodumun çalışması için bu pakete ihtiyaç var.
  • Bu paket node_modules dizinimde yoksa, otomatik olarak ekler.
  • Ayrıca, paketin bağımlılıklarında(dependencies) listelenen paketleri ekleyin. Bu paketlere geçiş bağımlılığı(transitive dependencies) denir.

Peer Dependencies * (eş bağımlılıklar)

Kütüphanelerinizin yer aldığı klasörde ayrıca package.json dosyanız olacak ve burada peerDependencies altında yer alan paketler olacak. peerDependencies paketimizin npm paketinin belirli bir sürümüyle uyumlu olduğunu belirtmek için kullanılır. Bir eş bağımlılığı eklemek için package.json dosyanızı elle değiştirmeniz gerekir.

Bir projede kullanmak istediğiniz kütüphanenin eş bağımlılıkları sizin kullandığınız versiyonlarla çatışıyorsa hangi paketin kullanılması gerektiğini geliştirici olarak siz karar verin diye peerDependencies sadece uyarıcı olarak kullanılır.

peerDependencies Yazılımcıya şunları söyler:

  • Kodum senin proje paketinin(package.json) bu sürümüyle uyumlu.
  • Bu paket node_modules içerisinde zaten mevcutsa, hiçbir şey yapmayın.
  • Bu paket node_modules dizininde bulunmuyorsa veya yanlış sürümse, eklemeyin. Ancak, kullanıcıya bulunamadığına dair bir uyarı gösterin.

Referans: blog.angularindepth.com

Şimdi uygulama ve kütüphane eklemek için ng generate komutunu kullanalım.

ng generate (application | library)

--dryRun=true (kısaca -d anahtarı da kullanılabilir) ile oluşacak ve etkilenecek dosyaları görüntülemek için komutumuzun peşine yazıyoruz.

$ ng generate library kutuphane --prefix=cemt --dryRun=true
veya
$ ng g library kutuphane --prefix=cemt -d
ng generate library kutuphane — prefix=cemt — dryRun=true

Oluşan klasör yapısını ve angular.json dosyasını inceleyelim. Her şey projects klasöründe oluşacak

angular.json (adı üstünde json -javascript notasyonlu nesne-) anahtarlarına göz atalım:

root
Bu, kütüphane projemizin kök klasörünü gösterir.

sourceRoot
Bu, kütüphanemizin gerçek kaynak kodunun kökenine işaret eder. Yani kodlarımızı barındırdığımız src klasörünü gösterir.

projectType
Bu anahtar projenin bir kütüphane mi(library) yoksa ugulama mı(application) olduğunu belirtir.

prefix
Kütüphaneyi oluştururken --prefix=cemt demiştik. Bunu angular.json içinde kütüphanenin prefix anahtarında görebiliyoruz. Bu öneki bileşenlerin selector kısmında göreceksiniz.

--prefix=cemt

architect
Bu nesne, Angular CLI’ın projemiz için nasıl derleme(build), test etme(test) ve kod standartına uygunluğunu kontrol ettiğini(lint) belirten bölümlere sahiptir.

ng-packagr

Bir kütüphaneyi yazdık ve npmjs.com adresinde yayınlamak istiyoruz. Bunu yapabilmek için önce kodlarımızı derlememiz gerekir:

ng build example-ng6-lib

Derlenen kodun çıktı dosyaları bütün programlama dillerinde genellikle bin, dist veya out klasörüne çıkartılır. Angular CLI içinde varsayılan olarak dist klasörüne çıkartılır. Angular CLI içerisinde klasörlerini tsconfig.json ve ng-package.json ayar dosyalarında aşağıdaki gibi görürüz.

build Etmek için kullanacağımız ng-packagr kütüphanesi “geliştirme sürecinin bir parçası olduğu içindevDependencies anahtarında tutulur.

ng-packagr

Kütüphanemizin build işleminde kullandığı kütüphane ng-packagr iken bu çıktıyı .tgz haline getirmek için npm pack komutunu kullanırız. Build edilmiş ve çıktıların aktarıldığı klasörde npm pack komutunu çalıştırdığımızda bize yayınlamaya(publish) edilmeye hazır tgz dosyasını üretecektir.

"scripts": {
...
"npm_pack": "cd dist/example-ng6-lib && npm pack",
...
},

Yayınlamak için dağıtılabilir (distributable) sıkıştırılmış dosyamızı aşağıdaki komut ile npmjs.com adresine göndermiş oluyoruz.

npm publish ./dist/ng-example-library/ng-example-library-1.2.0.tgz

Bizim örneğimizde çıktımız şöyle olacak:

C:\…\dist\kutuphane> npm pack

Projeye Uygulama (application) Eklemek

Şimdi projemize bir uygulama ekleyeceğiz ama önce oluşacak dosyaları öğrenmemizi kolaylaştırsın diye --minimal=true argumanıyla yaratalım.

Bu parametre:

  • test ayar dosyalarını(karma.conf.js, tsconfig.spec.ts),
  • tüm testleri yapacak test giriş dosyasını(test.ts) olan dosyasını
  • .spec dosyalarını
  • İlk yaratılan Component dosyalarını flat yapıda(.html, .css, .ts, .spec.ts dosyalarını tek bir .ts dosyasında oluşturur) dosyalar oluşturarak bize öğrenme kolaylığı sağlar.

Çıktı aşağıdaki gibi ancak aradaki farkı görmek için aşağıdaki satırları tek tek çalıştırarak oluşan çıktıya göz atabilirsiniz:

$ ng generate application uygulama --minimal=true  --dryRun=true
ng generate application uygulama --minimal=true — dryRun=true
$ ng generate application uygulama --minimal=false --dryRun=true
ng generate application uygulama --minimal=false --dryRun=true

Buna göre projemize eklediğimiz uygulamamız da projects dizininde oluşturulacaktır. Bunu minimal olarak oluşturduğumuzda aşağıdaki dizin yapısına sahip oluruz.

$ ng generate application uygulama --minimal=true

Biraz üstüne konuşalım. Tüm projenin angular tarafındaki ayarlarını tuttuğumuz angular.json dosyasındaki projects listesi hem library hem application türünde iki parçadan oluşuyor. Başlangıç projesi ise kutuphane olarak görünüyor.

angular.json dosya yapısı

--prefix=cemt anahtarını vermiştik. Kütüphane içindeki tüm bileşenleri otomatik olarak bu önek ile yarattığını ilk bileşenlerde görebiliyoruz.

Kütüphanemizi Build Edelim

Bunun için npm run build komutunu konsola yazmak yeterli. Aşağıdaki büyük ekran çıktısını parçalayarak inceleyeceğiz:

package.json içinde build işlemi için bir script oluşturulmuş halde gelecek:

npm run build

Bu scripti tetiklemek için npm run build yazıyoruz. package.json içinde bu komut ng build olarak çalışacak. Çalıştırılabilir ve Angular CLI’ın esas parçası olan ng komutu angular.json ayar dosyasını arayacak ve defaultProject içindeki aktif projeyi derlemek için build tanımına göre çalışacaktır.

Varsayılan proje bilgilerini değiştirip npm run build ile tüm projelerimizi derleyince aşağıdaki çıktıyı elde ederiz.

Eğer ng build <projeAdi> komutunu çalıştırırsanız defaultProject değerine bakılmaksızın belirttiğiniz proje build edilecektir.

ng build <proje adı>

NPM Hattı

Bir kütüphaneniz vardı, ng build ile derlediniz be bir klasöre (genelde dist/projeAdi olur ve angular.json içinde ayarlanır) çeşitli paketleme yöntemleriyle çalışacak şekilde NPM paketi oluşturdu.

Oluşan paketin klasör hali
dist dizinine paketi açacağını belirten angular.json dosyası ve ayarı

Bu klasör içinde ng-packagr çalıştırılırsa dizin içindeki her şey tar.gz (tarball) dosyasına atılır. Artık dosyaları bir dll taşır gibi taşıyabilirsiniz. Sonrasında dilediğiniz projeye npm install ile yükleyebilirsiniz.

Veya bu tarball dosyasını veya dizinini, dilediğiniz npm sunucusuna (npmjs, verdaccio, yarnpkg vs.) yükleyebilirsiniz

Eğer bu kütüphaneyi bir scope altında yaratmışsanız:

Ve kendi verdaccio NPM sunucunuzu kurup çalıştırdığınızda:

$ npm install -g verdaccio
$ verdaccio

Yeni bir kullanıcı oluşturup paketlerinizi buraya publish ediyorsanız:

$ npm adduser --registry http://localhost:4873

ister publish ederken sunucunuzu seçerek yükleyebilirsiniz:

$ npm publish --registry http://localhost:4873

ister .npmrc dosyasına bu bilgiyi yazarak yükleyebilirsiniz:

//.npmrc 
registry=http://localhost:4873

ister ng-package.json içinde ister package.json içinde publishConfig özelliğinde belirtip yükleyebilirsiniz:

"publishConfig": {
"registry": "http://localhost:4873"
}

Daha sonra bu paketi başka bir projeye install etmek isterseniz .npmrc dosyasında bir değişiklik yaparak @scope_bilgisi ile belirttiğiniz paketleri verdaccio sunucunuza doğrudan yönlendirebilirsiniz. Nasıl mı?

Önce bilmelisinizki tüm NPM paketleri için https://registry.npmjs.com adresine sorulur. Bunu görmek için npm config ls komutu yeter:

# npm config ls
; cli configs
metrics-registry = "https://registry.npmjs.com/"
scope = ""
user-agent = "npm/6.13.4 node/v12.14.1 win32 x64"
; userconfig C:\Users\cem.topkaya\.npmrc
registry = "https://registry.npmjs.com/"
strict-ssl = true
; builtin config undefined
prefix = "C:\\Users\\cem.topkaya\\AppData\\Roaming\\npm"
; node bin location = C:\Program Files\nodejs\node.exe
; cwd = C:\Users\cem.topkaya\git\gui_nrf_test
; HOME = C:\Users\cem.topkaya
; “npm config ls -l” to show all defaults.

Registry ayarını kullanıcının .npmrc dosyasından çekiyor gördüğünüz üzere. Sadece o dosyayı açınca içinde şunu görürüz:

%UserProfile%\.npmrc

Verdaccio sunucunuz http üstünde koşacağı için ssl-strict özelliğini false yapmanız gerekebilir. Sorun olabiliyor kimi zaman (npm sürümüne göre değişebilir)

# npm set strict-ssl false

Tüm paketler için npm install komutu doğrudan belirttiğiniz registry üstünden okusun isterseniz: “npm config set registry

npm config set registry http://localhost:4873

Ardından ilgili @scope_adı için registry ayarını .npmrc dosyasında aşağıdaki komutla set edebilirsiniz:

npm config set @scope_adınız:registry http://localhost:4873

Sonuçlarını görmek için:

# npm config ls
; cli configs
metrics-registry = “https://registry.npmjs.com/"
scope = “”
user-agent = “npm/6.13.4 node/v12.14.1 win32 x64”
; userconfig C:\Users\cem.topkaya\.npmrc
@scope_adınız:registry = "http://localhost:4873"
registry = "https://registry.npmjs.com/"
strict-ssl = true
; builtin config undefined
prefix = “C:\\Users\\cem.topkaya\\AppData\\Roaming\\npm”
; node bin location = C:\Program Files\nodejs\node.exe
; cwd = C:\Users\cem.topkaya\git\gui_nrf_test
; HOME = C:\Users\cem.topkaya
; “npm config ls -l” to show all defaults.

Tüm registry ayarını verdaccio üstüne kaydırsaydınız (yani npm config set registry http://localhost:4873 deseydiniz) verdaccio bulamadığı paketler için https://registry.npmjs.com/ adresine bakıp dönen sonuçları verecekti. Yani proxy gibi davranacaktı. Ancak yukarıdaki komutla, sadece @ilgili_scope_altındaki paketler için verdaccio geçerli kılındı. Diğer paketleri doğrudan kendi makinamızdan

registry = "https://registry.npmjs.com/"

satırındaki bilgide geçen adrese sorarak getirecektir.

Kaynakça:

Uçtan Uca Test

Bir proje yaratalım ng new e2e-project ile. Biraz environment dosyalarını inceleyelim. Normalde sistem ortam değişkenlerini (system environment) kullanabiliyorduk angular 5 mi 6 mı bilemedim. Ama sonrasında environment.prod.ts ve diğer ortam dosyalarıyla bu ihtiyacımızı görür hale geldik. Peki environment.**.ts dosyası nasıl aktif ediliyor?

ng build|serve --help yapıp --configuration anahtarının ne yaptığına bakalım:

ng build|serve --prod 
veya
ng build|serve --configuration=production

Ön tanımlı olarak --prod geliyor. Angular projesinin çalıştırılması için önce yapılandırılması (build) gerekir. Sonrasında sunulması (serve) ile projeyi internet gezgininde görebiliriz. Projenin yapılandırılması için (build) ayarlarımızı angular.json içinde aşağıdaki

"projects": {
.."e2e-project": {
...."architect": {
......"build": {
........"options": {
................. tüm konfigürasyonlar için yapılandırma ayarları
........},
........"configurations": {
.........."production": {
.................. -c=--prod uygulamayı canlıya çıkarma ayarlar
..........},
.........."dev": {
.................. -c=--dev yapılandırmanın geliştirme ayarları
..........},
.........."e2e": {
.................. -c=--e2e uygulamayı uçtan uca çıkarma ayarları
..........},

build altında varsayılan olarak production (--prod) geliyor malûmumuz. İçeriğine bakarsak:

  • typescript olarak kodlanmış projemizi outputPath ile hangi dizine (/dist/proje_adı) javascript kodları olarak çıkaracağını
  • main ile projenin başlangıç dosyasını (src/main.ts)
  • tsConfig ile Typescript kodlarını Javascript kodlarına dönüştürmenin ayarlarını nereden okuyacağını (tsconfig.app.json)
  • AheadOfTime kullanıp kullanmayacağını
  • Her ortama uygun (production, development, e2e test, kullanıcı kabul test, smoke test, benimOzelGelistirmem vs.) yapılandırma (build) ayarlarını configurations içinde belirtebileceğimizi görüyoruz. Biraz daha ayrıntıya bakalım.

Şimdi ortama göre özel konfigürasyonları nasıl veriyoruz bakalım:

production Adıyla tanımlı yapılandırmada fileReplacements içinde 0..* dosya tanımı vererek yer değiştirmelerini sağlayabiliriz. Yukarıdaki ayara göre şu olur:

src/environments/environment.ts dosyası olarak src/environments/environment.prod.ts dosyasını kullanır. Böylece prod içinde tanımlı ortam değişkenlerini uygulamanızın içinde kullanabiliriz.

Ref: https://angular.io

Özetle; build (inşa) edilirken -c anahtarına verdiğimiz değeri (production) ayarlarda buldu ve içerisindeki yapılandırmaya uygun işler yaparak projeyi derledi (environment.prod.ts dosyasını environment.ts ile değiştirdi vs.). Şimdi bir ayar daha ekleyip tekrar ng serve -c yerel_makinede_gelistirme diyelim. Sözde aynı projeyi, kendi makinamızda geliştirme yaparken farklı, uzakta bir makine üstünde (örn. amazonun bedava verdiği uzak masaüstü yapılabilen makinelerde) farklı ayarlarda çalıştırmak isteyelim. Her makinede veri tabanı sunucusuna ve apiye farklı portlardan erişiyor olalım. Bu bilgiyi her ortam için farklı port.**.json dosyalarında tutuyor olalım. Ama önce JSON dosyasını **.component.ts dosyamızda kullanabilelim.

angular’da JSON Dosyalarını Kullanmak

Http ile istek yapabilir, **.d.ts dosyası içinde tanımlanıp çekilebilir ama biz şöyle yapalım:

import {hede} from '../assets/port.json'

Derlerdiğimizde angular bize bir öneriyle hata verecek:

Angular’a sen .json da bak demek için tsconfig.json da:

  • --resolveJsonModule, .json dosyalarından çekilen tiplerin içe aktarılmasına izin verir.
  • Bir modülden dışa aktarmak için module.exports.bıdı kullanılır ancak JSON dosyasında böyle bir ihraç olmaz. --esModuleInterop, sayesinde veri varsayılan dışa aktarma olmamasına rağmen varsayılan şekilde içe aktarmalara izin verir.
{
...,
"compilerOptions": {
...,
"resolveJsonModule": true,
"esModuleInterop": true
}
}

Şimdi yerel makinede ve uzak makinede çalışırken port bilgilerinin ortamlara göre değişmesi için önce ortamlara göre ayarları ve bu ortamlarda yer değiştirecek dosyaların bilgilerini fileReplacements içinde belirtelim.

Önce çıktılara bakalım sonra ayarlara:

ng serve — configuration=yerel_makinede_gelistirme
ng serve — configuration=uzak_makinede_gelistirme

build içinde tanımlı ayarı serve içinde çağırıyoruz. ng build|serve -c xxx komutundaki xxx yerine ayar tanımında kullandığımız alan adını kullanıyoruz.

ng build komutu projenin “architect->build” ayarlarından (configurations) önce options kısmındaki ayarları alır ve varsayılan olarak production kısmındaki ayarlar ile ezerek build işlemini gerçekleştirir.

Aynı mantıkta ng serve komutu projenin “architect->serve” options içinde adreslenmiş edilmiş build ayarlarını alır ve ön tanımlı olarak production içinde tanımlı ayarlarıyla (projeAdı:build:production) ezerek oluşan nihai seçeneklere göre yapılandırır. Eğer production ayarı da yoksa @angular-devkit/build-angular:dev-server paketindeki ön tanımlı ayarlar ile başlar.

Özetle ayar dosyasından yukarıya doğru çıkarak tüm seçeneklere (options) ulaşacaksınız.

Projemizi bir jenkins hattında koşturuyor gibi uçtan uca testlerimizin ayarlarını yaparak devam edelim.

hangi ng komutu hangi ayarlara erişir

configurations” boşken varsayılan ayarlar devreye girer. Ancak “devServerTarget” boş olduğunda uygulama ayaklandırılamaz (serve edilemez) ve e2e testleri çatlar. “devServerTarget” ayarlarını ister ana projenin serve kısmından alın isterseniz her kütüphane için tekrar tanımlayın, ama muhakkak uygulamayı ayaklandıracak bir “devServerTarget” olsun.

e2e Testlerini koştururken kullanacağımız ayarları testi çalıştırmak istediğimiz projenin içinde tanımlamış olmamı gerekiyor:

{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"e2e-project": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
..........
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
....
},
"build_yerel_makinede_gelistirme": {...},
"build_uzak_makinede_gelistirme": {...},
"jenkins_ayari": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.e2e.ts"
},
{
"replace": "src/assets/port.json",
"with": "src/assets/port.cicd.e2e.json"
}
]

}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "e2e-project:build"
},
"configurations": {
"production": {
"browserTarget": "e2e-project:build:production"
},
"yerel_makinede_gelistirme": {...},
"uzak_makinede_gelistirme": {...},
"e2e_jenkins": {
"browserTarget": "e2e-project:build:jenkins_ayari"
}
}
},
....
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "e2e-project:serve"
},
"configurations": {
"production": {
"devServerTarget": "e2e-project:serve:production"
},
"jenkins": {
"devServerTarget": "e2e-project:serve:e2e_jenkins"
}
}
}
}
}
},
"defaultProject": "e2e-project"
}

Projeye yeni bir kütüphane ekleyince:

# ng lint @isleme/goruntu
Linting "@isleme/goruntu"...
All files pass linting.
# ng test @isleme/goruntu
10% building 1/1 modules 0 active22 11 2020 14:14:03.518:WARN...
22 11 2020 14:14:03.686:INFO [karma-server]:....

Anca e2e için bir ayar olmadığından hata verecektir:

Diyor ki; en azından e2e’yi çalıştırmak için kullanacağım builder’ı verseydin. Kütüphane içinde projenin ayaklandırılacağı sunucu bilgisini devServerTarget ile protractor ayalarını protractorConfig ile varsa ek ayarları configurations ile vermemiz gerekir. Yahut tüm bunları komut satırında belirtmemiz (builder hariç) yeterli olacaktır.

"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "projects/isleme/goruntu/e2e/protractor.conf.js",
"devServerTarget": "e2e-project:serve",
"port": 4900 //e2e-project:serve içindeki yerine istersen
},
"configurations": {
"jenkins": {
"devServerTarget": "e2e-project:serve:serve_jenkins"
}
}
}

Veya sadece builder kalır kalanı komut satırından veririz:

"e2e": {
"builder": "@angular-devkit/build-angular:protractor"
}

Komut olarak:

# ng e2e @islem/goruntu                                            \
--devServerTarget="e2e-project:serve:serve_jenkins" \
--port=4701 \
--protractorConfig="projects/isleme/goruntu/e2e/protractor.conf.js"\
--webdriver-update=false

--

--

Cem Topkaya
Cem Topkaya

Written by Cem Topkaya

Evlat, kardeş, ağabey, eş, baba, müzik sever, öğrenmek ister, paylaşmaya can atar, iyi biri olmaya çalışır, hakkı geçenlerden helallik ister vs.

Responses (1)