Angular 6 → 22: жаңарту жолы және неден сүрінесің
Осы бетте
Бірінші ереже: бір-бірден нұсқа
Angular мажорлық нұсқаны шамамен жарты жылда бір рет шығарады. Жаңарту командасы:
npx ng update @angular/core@17 @angular/cli@17ng update package.json ішіндегі нөмірді ғана өзгертпейді. Ол миграцияларды іске қосады — кодыңды жаңа нұсқаға сай қайта жазатын скрипттер. Миграциялар N-нен N+1-ге өтуге арналып жазылған. 12-ден 17-ге секірсең, 13, 14, 15 және 16 миграциялары орындалмайды, қолмен ретке келтіруге тура келеді.
Сондықтан цикл мынадай:
- Бір нұсқаға жаңарту.
- Құрастыру, тесттерді жүргізу, қолданбаны ашу.
- Бөлек коммитпен сақтау.
- Келесі нұсқа.
Әр нұсқаға бөлек коммит — дәл бір сатыға кері қайтуға және git bisect арқылы қайсысында бір нәрсе бұзылғанын табуға мүмкіндік.
Nx-тегі монорепозиторий үшін ng update орнына — nx migrate: ол Angular-ды да, Nx-тің өзін де, плагиндерді де келісімді түрде жаңартады.
npx nx migrate 21 # пишет новые версии в package.json и migrations.json
pnpm install
npx nx migrate --run-migrationsРесми Angular Update Guide нұсқаулығымен салыстырып отыр: «қайдан» және «қайда» дегенді таңдайсың, ол қолмен не істеу керегін көрсетеді.
Жол картасы: үлкен сатылар қайда
Жаңартулардың көбі — «жаңарттым, бір-екі ескертуді түзедім, кеттім». Бірақ іргелі бір нәрсе өзгеретін бірнеше саты бар.
| Нұсқа | Не өзгереді | Қаупі неде |
|---|---|---|
| 6 | ng update, RxJS 6 | ескі RxJS импорттарын (rxjs/add/operator/...) pipe()-ге қайта жазу керек |
| 8 | import() арқылы жалқау жүктеу | маршруттардағы './module#Module' түріндегі жолдар ескірген |
| 9 | әдепкі бойынша Ivy қозғалтқышы | View Engine үшін құрастырылған ескі кітапханалар; шаблондарды қатаңырақ тексеру |
| 12–13 | View Engine жойылды, IE11 енді қолдау көрмейді | Ivy-ді қолдамайтын кітапханалар мүлде жұмыс істемей қалады |
| 14–15 | standalone-компоненттер, типтелген формалар | ескіше өмір сүруге болады, бірақ жаңа код басқаша жазылады |
| 16–17 | сигналдар, жаңа control flow (@if, @for), esbuild-тегі құрастырушы | шаблондарды үлкен, бірақ механикалық рефакторинг |
| 19 | әдепкі бойынша standalone: true | NgModule бар компоненттерге айқын standalone: false керек |
| 20–22 | билдердің ауысуы, zone.js әдепкілерден кетеді, CDK оверлейлерді өзгертеді | төменде толығырақ |
Тәжірибеде ең ауыр саты — 9 және 13: мәселе әдетте сенің кодыңда емес, Ivy-ге ешкім жаңартпаған тәуелділіктерде. Шешімі біреу: кітапхананы ауыстыру немесе алып тастау.
Бізде қалай болды
Монорепозиторийге дейін бізде қолданбаның оннан астам көшірмесі болды, әрқайсысы бөлек жаңартылатын — яғни, шын мәнінде, жаңартылмайтын. Монорепоға көшу (толығырақ — nx-monorepo-from-copies) Angular 16-да басталды. Әрі қарай:
- 16 → 17 — бастағаннан бір-екі ай өткен соң, бөлек коммитпен.
- 17 → 19 — бір жарым жылдан кейін. Бұл қате: неғұрлым ұзақ тұрсаң, соғұрлым көп жиналады.
- 19 → 20 → 21 → 22 — бір күнде, үш бөлек коммитпен, Nx 20 → 23 және TypeScript 5.7 → 6.0-мен бірге.
Соңғы секіріс дәл код ортақ болғандықтан жылдам болды: миграциялар барлық қолданбадан бірден өтті. Бірақ «бір күнде» — тек жаңарту ғана. Салдарын тағы екі апта ретке келтірдік.
20-саты: жаңа билдер
Ескі @angular-devkit/build-angular:browser билдері (webpack негізінде) @angular/build:application-ге (esbuild негізінде) ауыстырылды. Әр қолданбаның project.json файлында:
// было
"executor": "@angular-devkit/build-angular:browser",
"options": { "main": "src/main.ts", "buildOptimizer": true, "vendorChunk": true }
// стало
"executor": "@angular/build:application",
"options": { "browser": "src/main.ts" }Опциялардың бір бөлігі жай жоғалды (buildOptimizer, vendorChunk, namedChunks) — жаңа құрастырушыға олар керек емес. Нәтиженің құрылымы да өзгерді: файлдар енді dist/<app>/browser/ ішінде жатады. Деплой dist/<app>/ көшірсе — серверге артық папка кетеді. Біз мұны CI-да ұстадық.
Жаңа құрастырушы айтарлықтай жылдам. Бірақ ол модульдердің ретіне қатаңырақ — және бұл келесі тармаққа алып келеді.
Тырма: импорт сақиналары
Жаңартудан кейін беттердің бір бөлігі рантаймда NG0919 («Cannot read @Component metadata») қатесімен құлай бастады. Құрастыру өтіп жатты.
Себебі — циклдік импорт. Мысал:
// list.page.ts
import { EditDialog } from './edit.dialog'; // страница открывает диалог
// edit.dialog.ts
import { ListPage } from './list.page'; // диалог берёт тип у страницы
Сақинадағы модульдер болжауға келмейтін ретпен жүктеледі. Angular imports: [EditDialog] оқыған кезде EditDialog класы әлі undefined болуы мүмкін. Ескі құрастырушы оларды кездейсоқ «сәтті» ретпен жүктейтін. Жаңасы — жоқ.
Сақинаны қалай үзу керек, жақсыдан нашарға қарай:
- Ортақ нәрсені үшінші файлға шығару. Тұрақтылар, токендер, интерфейстер — екеуі де тәуелді
*.constants.tsне*.interface.tsішіне. - Тек типті импорттау. Тек тип керек болса,
import type { ListPage } from './list.page'. TypeScript мұндай импортты компиляция кезінде алып тастайды, рантаймда сақина жоқ. - Типті әлсірету. Мысалы,
MatDialogRef<EditDialog>орнынаMatDialogRef<any>. Жұмыс істейді, бірақ тип тексерісін жоғалтады.
Шынын айтсам: жаңартуды тезірек шығару үшін бірнеше жерде үшінші нұсқаны істедік. Бұл қарыз, ол жазылып қойылған. Дұрысы — екіншісі.
Ал кітапханалар арасында сақиналар пайда болмас үшін қатаң шекаралар керек: тәуелділіктер тек бір бағытта, линтермен тексеріледі.
Тырма: диалогтардың астындағы тосттар
Angular CDK-ны 22-ге жаңартқаннан кейін қалқымалы хабарламалар (тосттар) модальді терезелердің астында пайда бола бастады.
Себебі: CDK 22 әдепкі бойынша оверлейлерді (диалогтар, ашылмалы тізімдер, тултиптер) Popover API арқылы — браузердің top layer деп аталатын қабатында рендерлейді. Top layer бүкіл құжаттың үстінен салынады, ал z-index оған әсер етпейді. Кәдімгі құжаттағы z-index: 1001 бар тост санды қанша көтерсең де, top layer-дегі диалогтың астында қалады.
Ескі мінез-құлықты бір провайдермен қайтарамыз:
import { OVERLAY_DEFAULT_CONFIG } from '@angular/cdk/overlay';
providers: [
{ provide: OVERLAY_DEFAULT_CONFIG, useValue: { usePopover: false } },
]Сабақ: тек Angular-дың ғана емес, CDK мен Material-дың да changelog-ын оқы. Олар бірге жаңартылады, ал мінез-құлықты бөлек өзгертеді.
21-саты: zone.js және HttpClient
zone.js — барлық асинхронды оқиғаларды (шертулер, таймерлер, HTTP) ұстап алып, Angular-ға «бірдеңе болды, экранды тексер» дейтін кітапхана. Angular одан сигналдарға қарай кетіп барады, жаңа қолданбалар zone.js-сіз жасалады.
Бар қолданба үшін жаңарту кезіндегі миграция ештеңе өзгермеуі үшін айқын провайдер қосты:
bootstrapApplication(AppComponent, {
...appConfig,
providers: [provideZoneChangeDetection(), ...appConfig.providers],
});Бұл миграцияның дұрыс мінез-құлқы: жаңарту мінез-құлықты байқатпай өзгертпеуі керек. Zoneless-ке көшу — бөлек тестілеуі бар бөлек міндет.
Сол сияқты миграция HTTP-клиент XMLHttpRequest-те қалуы үшін provideHttpClient(...) ішіне withXhr() қосты. Егер сенде прогресі бар файл жүктеу болса — жаңартудан кейін оны тексер.
Жаңартудан кейін: жетілдіру
Нұсқаны жаңарту — соңы емес. Жаңа Angular код жазудың жаңа тәсілдерін ұсынады, оларға біртіндеп көшкен жөн, әйтпесе бір-екі жылдан кейін тағы «ескі код» болады:
- конструктор арқылы енгізудің орнына
inject(); - компонент күйі үшін сигналдар (
signal,computed); *ngIf/*ngForорнына@if/@for;- жазылымдар үшін
takeUntilDestroyed().
inject()-ге көшуді бөлек міндет ретінде жасадық: бір кітапханаға бір коммит. Осылай ревью кішкентай болып қалады, ал бір нәрсе бұзылса — қай жерде екені түсінікті. Көбіне ресми автоматты миграциялар бар (ng generate @angular/core:inject және соған ұқсастар) — қолмен қайта жазба, соларды іске қос.
Чек-лист
- Бір уақытта бір мажорлық нұсқа, бөлек коммит.
package.jsonқолмен түзету емес,ng update/nx migrate.- Әрқайсысынан кейін: құрастыру, тесттер, қолданбаны көзбен қарау.
- Бастамас бұрын — тәуелділіктер тізімі: қайсысы мақсатты нұсқаны қолдамайды.
- Angular және CDK/Material changelog-ы.
- Жаңа рантайм қателері (NG0919 және т. б.) — алдымен импорт сақиналарын ізде.
- Бір нұсқада бір жарым жыл тұрма: жылына екі жаңарту үш жылда бір жаңартудан арзан.
Байланысты жазбалар: nx-monorepo-from-copies, tailwind-v3-to-v4-monorepo, ci-nx-affected.