angular.json’ı Anlamak
Üstünkörü Angular CLI *
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.
--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
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.
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çin” devDependencies
anahtarında tutulur.
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:
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=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.
--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:
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.
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.
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:
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:
- https://ordina-jworks.github.io/architecture/2019/09/13/angular-include-assets-libraries.html
- https://medium.com/angular-in-depth/creating-a-library-in-angular-6-part-2-6e2bc1e14121
- https://nitayneeman.com/posts/understanding-the-angular-cli-workspace-file/#newprojectroot
- https://medium.com/@tomsu/how-to-build-a-library-for-angular-apps-4f9b38b0ed11
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:
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.
“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