ЁЯЪЪ рдзрдбрд╛ 12 тАФ Build, deploy рдЖрдгрд┐ observe: рдлрд▓рдХ рднрд┐рдВрддреАрд╡рд░ рд▓рд╛рд╡рдгреЗ
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 12 тАФ рд╢реЗрд╡рдЯрдЪрд╛ рдзрдбрд╛! ┬╖ рдорд╛рдЧреАрд▓: lesson-11-talking-to-backends
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕, рдЖрдгрд┐ рддреНрдпрд╛рд╕реЛрдмрдд рд╢реЗрд╡рдЯрдЪрд╛ рдЯрдкреНрдкрд╛: build рдХрд╛рдп рдХрд░рддреЛ, рдлрд▓рдХ deploy рдХрд╕рд╛ рд╣реЛрддреЛ (рддреНрдпрд╛ рдлрдХреНрдд files рдЕрд╕рддрд╛рдд), рд▓реЛрдХрд╛рдВрдирд╛ рдирд╡реАрди version рджрд┐рд╕рд╛рд╡реЗ рдореНрд╣рдгреВрди cache busting, рдЖрдгрд┐ рдЦрд▒реНрдпрд╛ users рдЪреЗ рдирд┐рд░реАрдХреНрд╖рдг тАФ рдЖрдгрд┐ рддреНрдпрд╛рд╕реЛрдмрдд рдХрд│рд╕-рдкреНрд░рдХрд▓реНрдк (capstone).
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдлрд▓рдХ рддреБрдордЪреНрдпрд╛ рдЯреЗрдмрд▓рд╛рд╡рд░ рдЪрд╛рд▓рддреЛ. рд╕рдЧрд│реНрдпрд╛рдВрдирд╛ рджрд┐рд╕реЗрд▓ рдЕрд╢рд╛ рднрд┐рдВрддреАрд╡рд░ рддреЛ рд▓рд╛рд╡рдгреНрдпрд╛рд╕рд╛рдареА рддреАрди рдЧреЛрд╖реНрдЯреА рдШрдбрддрд╛рдд:
- Build ЁЯПЧя╕П тАФ files bundle рдЖрдгрд┐ minify рдХрд░рд╛, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХреАрд▓рд╛ рддрд┐рдЪреНрдпрд╛
content рдЪрд╛ hash рдЕрд╕рд▓реЗрд▓реЗ рдирд╛рд╡ рджреНрдпрд╛:
app.7f3c2a.js. (рдЖрдкрд▓реНрдпрд╛ рдлрд▓рдХрд╛рд▓рд╛ build рдЕрдЬрд┐рдмрд╛рдд рд▓рд╛рдЧрдд рдирд╛рд╣реА тАФ рддреАрди рд╕рд╛рдзреНрдпрд╛ files тАФ рдЖрдгрд┐ рдЫреЛрдЯреНрдпрд╛ рдлрд▓рдХрд╛рд╕рд╛рдареА рд╣реЗ рдкреВрд░реНрдгрдкрдгреЗ рдпреЛрдЧреНрдп рдЙрддреНрддрд░ рдЖрд╣реЗ.) - Deploy ЁЯЪЪ тАФ files static host рд╡рд░ copy рдХрд░рд╛ рдЖрдгрд┐ CDN рд▓рд╛ рд╡рд╛рдЪрдХрд╛рдВрдЬрд╡рд│ рдкреНрд░рддреА рдареЗрд╡реВ рджреНрдпрд╛: GitHub Pages, S3 + CloudFront, Netlify, Cloudflare Pages. рдлрд▓рдХ рдореНрд╣рдгрдЬреЗ рдлрдХреНрдд files; рдЪрд╛рд▓рд╡рд╛рдпрд▓рд╛ рдХреЛрдгрддрд╛рд╣реА server рдирд╛рд╣реА.
- Cache busting ЁЯзК тАФ HTML рдереЛрдбрд╛ рд╡реЗрд│ cache рд╣реЛрддреЗ, hashed files рдХрд╛рдпрдордЪреНрдпрд╛. рдирд╡реАрди build рдирд╡реАрди рдирд╛рд╡реЗ рдмрдирд╡рддреЛ, рдореНрд╣рдгреВрди рдХреЛрдгрд╛рд▓рд╛рдЪ рдХрдзреА рдЕрд░реНрдзрд╛-рдЬреБрдирд╛ рдлрд▓рдХ рджрд┐рд╕рдд рдирд╛рд╣реА. (рдореНрд╣рдгреВрдирдЪ рдзрдбрд╛ 09 рдордзрд▓реЗ "рд╡рд░реНрд╖рднрд░ cache рдХрд░рд╛" рд╕реБрд░рдХреНрд╖рд┐рдд рдЖрд╣реЗ.)
рдордЧ рддреБрдореНрд╣реА рд▓рдХреНрд╖ рдареЗрд╡рддрд╛ ЁЯСА: рдЦрд▒реНрдпрд╛ browsers рдордзрд▓реЗ JavaScript errors, рдЦрд▒реНрдпрд╛ phones рд╡рд░рдЪреНрдпрд╛ рдЦрд▒реНрдпрд╛ users рдЪреЗ Core Web Vitals, рдЖрдгрд┐ рдХрд╛рдЙрдВрдЯрд░рдЪреЗ calls рдХрд┐рддреА рд╡реЗрд│рд╛ рдЕрдпрд╢рд╕реНрд╡реА рд╣реЛрддрд╛рдд. рдХрд╛рд░рдг рдлрд▓рдХ рддреБрдордЪреНрдпрд╛ рдорд╛рд▓рдХреАрдЪреНрдпрд╛ рдирд╕рд▓реЗрд▓реНрдпрд╛ рд╣рдЬрд╛рд░ devices рд╡рд░ рд░рд╛рд╣рддреЛ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
src["ЁЯУБ ui/index.html ┬╖ styles.css ┬╖ app.js"]
build["ЁЯПЧя╕П build (optional here)<br/>minify ┬╖ bundle ┬╖ hash filenames"]
host["ЁЯЪЪ static host + CDN<br/>GitHub Pages ┬╖ S3+CloudFront ┬╖ Netlify"]
cache["ЁЯзК HTML: short cache ┬╖ hashed assets: 1 year, immutable"]
obs["ЁЯСА observe<br/>JS errors ┬╖ web vitals (RUM) ┬╖ failed API calls"]
src --> build --> host --> cache --> obs
obs -->|"what real users hit"| src
тЭУ рдХрд╛рдп
- Build рдХрд╛рдп рдХрд░рддреЛ: modules bundle рдХрд░рддреЛ, minify, tree-shake, рдЬреБрдиреНрдпрд╛ browsers рд╕рд╛рдареА transpile рдХрд░рддреЛ, critical CSS inline рдХрд░рддреЛ, hashed filenames рдЖрдгрд┐ рдПрдХ manifest рддрдпрд╛рд░ рдХрд░рддреЛ. Tools: Vite, esbuild, Parcel, Rollup.
- Static hosting: server process рдирд╛рд╣реА, patching рдирд╛рд╣реА; CDN TLS,
compression рдЖрдгрд┐ edge caching рд╕рд╛рдВрднрд╛рд│рддреЛ. SPA routing рд▓рд╛ rewrite rule рд▓рд╛рдЧрддреЛ,
рдореНрд╣рдгрдЬреЗ deep links
index.htmlрджреЗрддрд╛рдд. - Cache рд░рдгрдиреАрддреА:
index.htmlтЖТno-cache(рдХрд┐рдВрд╡рд╛ рдЫреЛрдЯрд╛ max-age);/assets/app.<hash>.jsтЖТmax-age=31536000, immutable. - Environments: рдкреНрд░рддреНрдпреЗрдХ pull request рд╕рд╛рдареА preview deploys (CI/CD рд╢рд╛рд│реЗрдЪреА рдлрд╛рдЯрдХреЗ), рдордЧ production. API base URL рдЪрд╛ config build рдордзреВрди рдпреЗрддреЛ, рдЖрдгрд┐ рддреНрдпрд╛рдд рдХреЛрдгрддреАрд╣реА secrets рдирд╕рддрд╛рдд (рдзрдбрд╛ 11).
- Observability:
window.onerror/unhandledrejectionтЖТ рдПрдХ error service; рдЦрд▒реНрдпрд╛ users рдХрдбреВрди LCP/INP/CLS рд╕рд╛рдареАPerformanceObserver(RUM); front-end рдЖрдгрд┐ back-end logs рдЬреЛрдбрдгреНрдпрд╛рд╕рд╛рдареА рдкреНрд░рддреНрдпреЗрдХ API call рд▓рд╛ рдПрдХ request id (API рд╢рд╛рд│реЗрдЪрд╛ рдзрдбрд╛ 12). - Rollback: рдЖрдзреАрдЪрд╛ build рдкреБрдиреНрд╣рд╛ deploy рдХрд░рд╛ тАФ hashed assets рдореБрд│реЗ рджреЛрдиреНрд╣реА versions рд╕реБрд░рдХреНрд╖рд┐рддрдкрдгреЗ рдПрдХрддреНрд░ рд░рд╛рд╣реВ рд╢рдХрддрд╛рдд.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рдХреЛрдгрд╛рд▓рд╛рдЪ рдкреЛрд╣реЛрдЪрддрд╛ рди рдпреЗрдгрд╛рд░рд╛ рдлрд▓рдХ рд╣рд╛ рдлрд▓рдХрдЪ рдирд╛рд╣реА, рдЖрдгрд┐ рдХрд╛рд░рдг deploy рдЪреЗ рджреЛрди рдиреЗрд╣рдореАрдЪреЗ bugs рдкреВрд░реНрдгрдкрдгреЗ рдЯрд╛рд│рддрд╛ рдпреЗрддрд╛рдд: рд▓реЛрдХрд╛рдВрдирд╛ рд╢рд┐рд│реЗ рдкрд╛рди рджрд┐рд╕рдгреЗ (рдЪреБрдХреАрдЪреЗ cache headers) рдЖрдгрд┐ рдХреЛрдгрд╛рдЪреНрдпрд╛рдЪ рд▓рдХреНрд╖рд╛рдд рди рдЖрд▓реЗрд▓реЗ рдореЛрдбрд▓реЗрд▓реЗ release (error reporting рдирд╛рд╣реА). рджреЛрдиреНрд╣реА рд╣реБрд╢рд╛рд░реАрдиреЗ рдирд╛рд╣реА, рддрд░ settings рдиреЗ рд╕реБрдЯрддрд╛рдд.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
рд╣реА рд╢рд╛рд│рд╛рдЪ рдпрд╛рдЪреЗ рдкреНрд░рд╛рддреНрдпрдХреНрд╖рд┐рдХ рдЖрд╣реЗ: рдкреНрд░рддреНрдпреЗрдХ course site рдореНрд╣рдгрдЬреЗ GitHub Pages рд╡рд░рдЪреНрдпрд╛ static files, push рд╡рд░ deploy рд╣реЛрдгрд╛рд▒реНрдпрд╛. рддреБрдордЪрд╛ рдлрд▓рдХрд╣реА рддрд╕рд╛рдЪ рд▓рд╛рд╡рддрд╛ рдпреЗрддреЛ тАФ framework рдирд╛рд╣реА, server рдирд╛рд╣реА, рдПрдХ command.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛ тАФ рдХрд│рд╕-рдкреНрд░рдХрд▓реНрдк (capstone)
# 1) deploy the board (5 minutes, free):
# - copy ui/ into docs/app/ of your fork, commit and push
# - GitHub тЖТ Settings тЖТ Pages тЖТ Source: main /docs
# - open https://<you>.github.io/<repo>/app/ тЖТ your board, on the internet
# (the counter is local-only, so point API at a deployed one or ship a static fallback list)
# 2) see caching in action: DevTools тЖТ Network, reload twice тАФ the second load shows "(disk cache)" for styles.css
# 3) add crash reporting in 6 lines, in app.js:
# window.addEventListener('error', e => navigator.sendBeacon('/api/log', JSON.stringify({msg: e.message, src: e.filename, line: e.lineno})));
# window.addEventListener('unhandledrejection', e => console.warn('unhandled', e.reason));
# 4) measure a real vital in the browser:
# new PerformanceObserver(l => l.getEntries().forEach(e => console.log('LCP', Math.round(e.startTime), 'ms'))).observe({type:'largest-contentful-paint', buffered:true});
# 5) ЁЯПЖ THE CAPSTONE тАФ add a homework list to the board, end to end:
# HTML section with a heading and a list (L02) ┬╖ layout in the grid (L03) ┬╖ state.homework + a component + render (L04тАУ05)
# ┬╖ labels, live region, keyboard pass (L06) ┬╖ tokens only, works in dark mode (L08) ┬╖ lazy/sized images if you add any (L09)
# ┬╖ three new smoke checks (L10) ┬╖ fetch from /api/homework with loading and error faces, textContent only (L11) ┬╖ deployed (L12)
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
рддреБрдордЪрд╛ рдлрд▓рдХ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ URL рд╡рд░ рдЙрддреНрддрд░ рджреЗрддреЛ. рджреБрд╕рд▒реНрдпрд╛ reload рд▓рд╛ CSS disk cache
рдордзреВрди рдпреЗрддреЗ. Console рдордзреНрдпреЗ рдХрд╛рд╣реА throw рдХреЗрд▓реЗ рдХреА error listener рдЪрд╛рд▓рддреЛ, рдЖрдгрд┐
observer milliseconds рдордзреНрдпреЗ LCP рдЫрд╛рдкрддреЛ. Capstone рдлрд▓рдХ smoke_test.py pass
рдХрд░рддреЛ тАФ рддреБрдордЪреНрдпрд╛ рддреАрди рдирд╡реАрди рддрдкрд╛рд╕рдгреНрдпрд╛рдВрд╕рд╣ тАФ рдЖрдгрд┐ homework рдпрд╛рджреА рджреЛрдиреНрд╣реА themes рдордзреНрдпреЗ
рдЖрдгрд┐ рдлрдХреНрдд keyboard рд╡рд░реВрдирд╣реА рдЪрд╛рд▓рддреЗ.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рддреБрдордЪреНрдпрд╛ laptop рд╡рд░рдЪреНрдпрд╛ рддреАрди files рдкрд╛рд╕реВрди рддреБрдореНрд╣реА рдлрд▓рдХ рдПрдХрд╛ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ, cache рд╣реЛрдгрд╛рд▒реНрдпрд╛, рдирд┐рд░реАрдХреНрд╖рдгрд╛рдЦрд╛рд▓рдЪреНрдпрд╛ URL рдкрд░реНрдпрдВрдд рдиреЗрд▓рд╛рдд тАФ рдЖрдгрд┐ рдХреЛрд░реНрд╕рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рдерд░рд╛рддреВрди рдПрдХ рд╕рдВрдкреВрд░реНрдг feature рдЬреЛрдбрд▓реЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
index.htmlрдмрд░рд╛рдЪ рдХрд╛рд│ cache рдХрд░рдгреЗ (рдирд╡реАрди build рдХреЛрдгрд╛рд▓рд╛рдЪ рджрд┐рд╕рдд рдирд╛рд╣реА)- рд▓рд╛рдВрдм cache рд╡реЗрд│реЗрд╕рд╣ hash рдирд╕рд▓реЗрд▓реА asset рдирд╛рд╡реЗ (рддрд╛рдЬреНрдпрд╛ HTML рд╕рд╣ рд╢рд┐рд│реА JS тАФ рд╕рдЧрд│реНрдпрд╛рдд рд╡рд╛рдИрдЯ рдЬреЛрдбреА)
- build config рдордзреНрдпреЗ secrets (рддреА рдкреНрд░рддреНрдпреЗрдХ visitor рд▓рд╛ рдкрд╛рдард╡рд▓реА рдЬрд╛рддрд╛рдд)
- error reporting рдирд╛рд╣реА тАФ рдореЛрдбрддреЛрдб рддреБрдореНрд╣рд╛рд▓рд╛ users рдХрдбреВрди рдХрд│рддреЗ
- rollback рдпреЛрдЬрдиреЗрд╢рд┐рд╡рд╛рдп deploy рдХрд░рдгреЗ; hashed assets рд╕рд╣ рдЬреБрдирд╛ build рдареЗрд╡рдгреЗ рдлреБрдХрдЯ рдЖрд╣реЗ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдХрдВрдкрдиреА рдХрд░рддреЗ рддреНрдпрд╛рддрд▓реЗ рд╕рдЧрд│реНрдпрд╛рдд рд╡рд╛рд░рдВрд╡рд╛рд░ deploys рдореНрд╣рдгрдЬреЗ front-end deploys. Static hosting, hashed assets рдЖрдгрд┐ real-user monitoring рд╣реА рдХрдВрдЯрд╛рд│рд╡рд╛рдгреА рд░рдЪрдирд╛рдЪ рддреНрдпрд╛рдВрдирд╛ рдШрдЯрдирд╛рд╡рд┐рд░рд╣рд┐рдд рдмрдирд╡рддреЗ.
ЁЯОУ рдлрд▓рдХ рддреБрдордЪрд╛ рдЖрд╣реЗ
рд╕реВрдЪрдирд╛ рдлрд▓рдХ тЖТ semantic рд╕рд╛рдВрдЧрд╛рдбрд╛ тЖТ рд╡рд╛рдХрдгрд╛рд░реА рдорд╛рдВрдбрдгреА тЖТ events тЖТ рд╕рддреНрдпрд╛рдЪрд╛ рдПрдХрдЪ рд╕реНрд░реЛрдд тЖТ рдкреНрд░рддреНрдпреЗрдХрдЬрдг рддреЛ рд╡рд╛рдЪреВ рд╢рдХрддреЛ тЖТ frameworks, рд╕рдордЬрд▓реЗрд▓реЗ тЖТ рдЧрдгрд╡реЗрд╢ тЖТ рдЬрд▓рдж тЖТ test рдХреЗрд▓реЗрд▓рд╛ тЖТ рдХрд╛рдЙрдВрдЯрд░рд╢реА рд╕реБрд░рдХреНрд╖рд┐рддрдкрдгреЗ рдмреЛрд▓рдгрд╛рд░рд╛ тЖТ рднрд┐рдВрддреАрд╡рд░ рд▓рд╛рд╡рд▓реЗрд▓рд╛ рдЖрдгрд┐ рд▓рдХреНрд╖ рдареЗрд╡рд▓реЗрд▓рд╛. рддреБрдореНрд╣реА рдлрдХреНрдд UI рд╢рд┐рдХрд▓рд╛ рдирд╛рд╣реАрдд тАФ рддреБрдореНрд╣реА рдПрдХ рдлрд▓рдХ рдЪрд╛рд▓рд╡рддрд╛. ЁЯУМЁЯОУ
рд╕рдВрдкреВрд░реНрдг рд╢рд╛рд│рд╛, рд╕реБрд░реБрд╡рд╛рддреАрдкрд╛рд╕реВрди рд╢реЗрд╡рдЯрдкрд░реНрдпрдВрдд: Database рд╢рд╛рд│рд╛ рд╕рддреНрдп рдЬрдкрддреЗ, API рд╢рд╛рд│рд╛ рдЪрд┐рдареНрдареНрдпрд╛рдВрдирд╛ рдЙрддреНрддрд░ рджреЗрддреЗ, рд╣рд╛ рдлрд▓рдХ рддреЗ рд▓реЛрдХрд╛рдВрдирд╛ рджрд╛рдЦрд╡рддреЛ, рдЖрдгрд┐ CI/CD рд╢рд╛рд│рд╛ рдкреНрд░рддреНрдпреЗрдХ push рд╡рд░ рддреЛ рднрд┐рдВрддреАрд╡рд░ рд▓рд╛рд╡рддреЗ.
git checkout main
python3 ui/mock_api.py # one last look at the board