paint-brush
Frontend қолданбаларының шығарылымдарында орта айнымалыларымен жұмыс істеубойынша@egorgrushin
Жаңа тарих

Frontend қолданбаларының шығарылымдарында орта айнымалыларымен жұмыс істеу

бойынша Egor Grushin11m2024/10/30
Read on Terminal Reader

Тым ұзақ; Оқу

Frontend қолданбалары дәстүрлі түрде әр орта үшін бөлек құрастыруды қажет етеді (әзірлеу, кезеңдік кезең, өндіріс), себебі ортаның айнымалы мәндері құрастыру уақытында ендірілген, бұл шығару уақытының артуына әкеледі. Мен фронтальды қолданбаны бір рет құрастыру және орналастыру уақытында оларды нақты мәндермен ауыстыру үшін толтырғыштар мен сценарийді пайдалану арқылы орналастыру кезінде ортаға тән айнымалы мәндерді енгізу шешімін ұсынамын. Бұл әдіс шығару процесін жеңілдетеді, құрастыру уақытын қысқартады, орталар арасындағы сәйкестікті қамтамасыз етеді және құрастыруға қатысты қателердің қаупін азайтады. Сонымен қатар, айнымалы инъекциядан кейін файл атауын хэштеуді басқару арқылы тәсіл тиімді шолғыш кэштеуін және қолданбаның жалпы өнімділігін сақтайды.
featured image - Frontend қолданбаларының шығарылымдарында орта айнымалыларымен жұмыс істеу
Egor Grushin HackerNoon profile picture
0-item


Миллиондаған алдыңғы қатарлы қолданбалар қоршаған ортаға қатысты құрылымдарды басқарады. Әрбір орта үшін — әзірлеу, кезеңдік кезең немесе өндіріс болсын — фронтендік қолданбаның бөлек құрылымы жасалып, дұрыс орта айнымалы мәндері орнатылуы керек. Бірнеше қолданбалар қатысса, құрастырулар саны көбейеді, бұл көңілсіздікті арттырады. Бұл ұзақ уақыт бойы жиі кездесетін мәселе болды, бірақ ортаның айнымалы мәндерін өңдеудің жақсы жолы бар. Мен бұл процесті оңтайландырудың жолын таптым және осы мақалада мен сізге құру уақытын қысқартатын және жобаларыңыздағы орталар арасындағы сәйкестікті қамтамасыз етуге көмектесетін тиімді процесті жасау үшін қадамдық нұсқаулық беремін.


Қоршаған ортаның айнымалыларын түсіну

Бастамас бұрын, менің ойымша, біз қайталау жасауымыз керек. Веб-қосымшалар әрдайым дерлік "орта айнымалылары " деп аталатын айнымалыларға сүйенеді, олар көбінесе ішкі жүйенің соңғы нүктелерін, интеграциялық жүйелерді, төлем жүйесінің кілттерін, шығарылым нөмірлерін және т.б. Әрине, бұл айнымалы мәндердің мәндері қолданба орналастырылған ортаға байланысты әр түрлі болады.


Мысалы, төлем шлюзімен әрекеттесетін қолданбаны елестетіңіз. Әзірлеу ортасында төлем шлюзінің URL мекенжайы тестілеуге арналған құм жәшігін (https://sandbox.paymentgateway.com) көрсетуі мүмкін, ал өндіріс ортасында ол тікелей қызметке (https://live.paymentgateway.com) нұсқайды. ). Сол сияқты, деректер қауіпсіздігін қамтамасыз ету және орталарды араластырмау үшін әр орта үшін әртүрлі API кілттері немесе кез келген басқа ортаға арнайы параметр пайдаланылады.


Frontend әзірлеудегі қиындықтар

Backend қолданбаларын құру кезінде бұл мәселе емес. Бұл айнымалы мәндерді қолданба кодында жариялау жеткілікті, себебі бұл айнымалы мәндердің мәндері серверлік орта орналастырылған сервер ортасында сақталады. Осылайша, сервер қолданбасы іске қосу кезінде оларға қол жеткізеді.


Дегенмен, алдыңғы қатарлы қосымшалармен жұмыс біршама күрделене түседі. Олар пайдаланушы шолғышында іске қосылғандықтан, олардың нақты орта айнымалы мәндеріне қатынасы жоқ. Мұны шешу үшін, бұл айнымалы мәндердің мәндері әдетте құрастыру уақытында фронтендік қолданбаға «пісірілген». Осылайша, қолданба пайдаланушының шолғышында іске қосылғанда, барлық қажетті мәндер алдыңғы бағдарламаға ендірілген.


Бұл тәсіл, көптеген басқалар сияқты, ескертумен бірге келеді: әрбір құрастыруда сәйкес мәндер болуы үшін әрбір орта үшін бірдей фронтондық қолданбаның бөлек құрастыруын жасау керек.


Мысалы , бізде үш орта бар делік:

  • ішкі тестілеуге арналған әзірлеу;

  • интеграциялық тестілеу кезеңі;

  • және тұтынушылар үшін өндіріс.


Жұмысыңызды сынаққа жіберу үшін қолданбаны құрастырып, оны әзірлеу ортасына орналастырасыз. Ішкі тестілеу аяқталғаннан кейін, оны кезеңге орналастыру үшін қолданбаны қайта құру керек, содан кейін өндіріске орналастыру үшін оны қайтадан жасау керек. Егер жобада біреуден көп қосымшалар болса, мұндай құрастырулардың саны айтарлықтай артады. Сонымен қатар, осы құрастырмалар арасында кодтық база өзгермейді — екінші және үшінші құрастырмалар бірдей бастапқы кодқа негізделген.


Мұның бәрі босату процесін көлемді, баяу және қымбат етеді, сонымен қатар сапаны қамтамасыз ету қаупін тудырады. Мүмкін құрастыру әзірлеу ортасында жақсы сыналған болуы мүмкін, бірақ кезең құрастыру техникалық тұрғыдан жаңа, яғни қате үшін жаңа әлеует бар.


Мысал: Сізде X және Y секунд құрастыру уақыты бар екі қолданба бар. Осы үш орта үшін екі қолданба да құрастыру уақытында 3X + 3Y алады. Дегенмен, әрбір қолданбаны бір рет құрастырып, сол құрастыруды барлық орталарда пайдалана алсаңыз, жалпы уақыт X + Y секундына дейін қысқарып, құрастыру уақытын үш есе қысқартады.

Бұл ресурстар шектеулі және құрастыру уақыттары бірнеше минуттан бір сағатқа дейін ауытқитын фронталды құбыр желілерінде үлкен өзгеріс тудыруы мүмкін. Мәселе жаһандық барлық дерлік интерфейс қолданбаларында бар және жиі оны шешудің ешқандай жолы жоқ. Дегенмен, бұл, әсіресе бизнес тұрғысынан алғанда, күрделі мәселе.

Үш бөлек құрылымды жасаудың орнына жай ғана біреуін жасап, оны барлық орталарда орналастырсаңыз тамаша емес пе? Мен дәл осылай жасаудың жолын таптым.


Фронт қолдануды оңтайландыру. Нұсқаулық

Ортаның айнымалы мәндерін орнату


  1. Алдымен, қажетті ортаның айнымалы мәндері тізімделетін алдыңғы жобаның репозиторийінде файл жасау керек. Оларды әзірлеуші жергілікті жерде пайдаланады. Әдетте, бұл файл .env.local деп аталады, оны көптеген заманауи фронттер жақтаулары оқи алады. Міне, осындай файлдың мысалы:


     CLIENT_ID='frontend-development' API_URL=/api/v1' PUBLIC_URL='/' COMMIT_SHA=''


    Ескертпе: әртүрлі шеңберлер орта айнымалылары үшін әртүрлі атау конвенцияларын талап етеді. Мысалы, React бағдарламасында айнымалы атауларының алдына REACT_APP_ қосу керек. Бұл файл қолданбаға тікелей әсер ететін айнымалы мәндерді міндетті түрде қамтуы қажет емес; ол сондай-ақ жөндеуге арналған пайдалы ақпаратты қамтуы мүмкін. Мен COMMIT_SHA айнымалы мәнін қостым, оны кейінірек осы құрастыруға негізделген тапсырманы қадағалау үшін құрастыру тапсырмасынан шығарамыз.


  2. Әрі қарай, ортаның айнымалы мәндерін анықтауға болатын environment.js деп аталатын файлды жасаңыз. Фронт интерфейсі бұларды сізге енгізеді. Мысалы, React үшін олар process.env нысанында сақталады:


     const ORIGIN_ENVIRONMENTS = window.ORIGIN_ENVIRONMENTS = { CLIENT_ID: process.env.CLIENT_ID, API_URL: process.env.API_URL, PUBLIC_URL: process.env.PUBLIC_URL, COMMIT_SHA: process.env.COMMIT_SHA }; export const ENVIRONMENT = { clientId: ORIGIN_ENVIRONMENTS.CLIENT_ID, apiUrl: ORIGIN_ENVIRONMENTS.API_URL, publicUrl: ORIGIN_ENVIRONMENTS.PUBLIC_URL ?? "/", commitSha: ORIGIN_ENVIRONMENTS.COMMIT_SHA, };


  1. Мұнда сіз window.ORIGIN_ENVIRONMENTS айнымалылар үшін барлық бастапқы мәндерді шығарып аласыз. ORIGIN_ENVIRONMENTS нысаны, оларды браузер консолінде көруге мүмкіндік береді. Оған қоса, оларды ENVIRONMENT нысанына көшіру керек, мұнда кейбір әдепкі мәндерді де орнатуға болады, мысалы: publicUrl әдепкі бойынша / деп есептейміз. Қолданбада осы айнымалылар қажет болған жерде ENVIRONMENT нысанын пайдаланыңыз.


    Осы кезеңде сіз жергілікті дамудың барлық қажеттіліктерін орындадыңыз. Бірақ мақсат - әртүрлі орталарды өңдеу.


  2. Ол үшін келесі мазмұны бар .env файлын жасаңыз:

 CLIENT_ID='<client_id>' API_URL='<api_url>' PUBLIC_URL='<public_url>' COMMIT_SHA=$COMMIT_SHA

Бұл файлда ортаға тәуелді айнымалылар үшін толтырғыштарды көрсеткіңіз келеді. Олар бірегей және бастапқы кодыңызбен ешбір жағдайда сәйкес келмейтін болса, сіз қалаған кез келген нәрсе болуы мүмкін. Қосымша сенімділік үшін сіз тіпті пайдалана аласыз UUID – Әмбебап бірегей идентификаторлар.


Орталар бойынша өзгермейтін айнымалылар үшін (мысалы, орындау хэші) нақты мәндерді тікелей жаза аласыз немесе құрастыру тапсырмасы кезінде қолжетімді мәндерді пайдалана аласыз (мысалы, $COMMIT_SHA ). Фронт құрылымы осы толтырғыштарды құрастыру процесі кезінде нақты мәндермен ауыстырады:


Файл
Файл

  1. Енді сіз толтырғыштардың орнына нақты мәндерді қою мүмкіндігіне ие боласыз. Бұл әрекетті орындау үшін inject.py файлын жасаңыз (мен Python таңдадым, бірақ сіз бұл мақсат үшін кез келген құралды пайдалана аласыз), ол алдымен толтырғыштарды айнымалы атауларға салыстыруды қамтуы керек:


 replacement_map = { "<client_id>": "CLIENT_ID", "<api_url>": "API_URL", "<public_url>": "PUBLIC_URL", "%3Cpublic_url%3E": "PUBLIC_URL" }

public_url екі рет тізімделгенін және екінші жазбада жақшалардан құтылғанын ескеріңіз. Бұл сізге CSS және HTML файлдарында қолданылатын барлық айнымалылар үшін қажет.


  1. Енді өзгерткіміз келетін файлдар тізімін қосамыз (бұл Nginx үшін мысал болады):


 base_path = 'usr/share/nginx/html' target_files = [ f'{base_path}/static/js/main.*.js', f'{base_path}/static/js/chunk.*.js', f'{base_path}/static/css/main.*.css', f'{base_path}/static/css/chunk.*.css', f'{base_path}/index.html' ]


  1. Содан кейін біз injector.py файлын жасаймыз, онда біз құрастыру артефакті файлдарының (мысалы, JS, HTML және CSS файлдары) кескіні мен тізімін аламыз және толтырғыштарды ағымдағы ортадағы айнымалы мәндермен ауыстырамыз:


 import os import glob def inject_envs(filename, replacement_map): with open(filename) as r: lines = r.read() for key, value in replacement_map.items(): lines = lines.replace(key, os.environ.get(value) or '') with open(filename, "w") as w: w.write(lines) def inject(target_files, replacement_map, base_path): for target_file in target_files: for filename in glob.glob(target_file.glob): inject_envs(filename, replacement_map)


Содан кейін, inject.py файлында осы жолды қосыңыз ( injector.py импорттауды ұмытпаңыз):

 injector.inject(target_files, replacement_map, base_path)


  1. Енді біз inject.py сценарийінің тек орналастыру кезінде жұмыс істейтініне көз жеткізуіміз керек. Python орнатып, барлық артефактілерді көшіргеннен кейін оны CMD пәрменіндегі Dockerfile файлына қосуға болады:
 RUN apk add python3 COPY nginx/default.conf /etc/nginx/conf.d/default.conf COPY --from=build /app/ci /ci COPY --from=build /app/build /usr/share/nginx/html CMD ["/bin/sh", "-c", "python3 ./ci/inject.py && nginx -g 'daemon off;'"]That's it! This way, during each deployment, the pre-built files will be used, with variables specific to the deployment environment injected into them.


Міне бітті! Осылайша, әрбір орналастыру кезінде, оларға енгізу ортасына тән айнымалы мәндермен алдын ала құрастырылған файлдар пайдаланылады.


Файл: Файл


Браузерді дұрыс кэштеу үшін файл атауының хэшингін өңдеу

Бір нәрсе – егер құрастыру артефактілеріңіз файл атауларында мазмұн хэшін қамтыса, бұл инъекция файл атауларына әсер етпейді және бұл шолғышты кэштеу кезінде қиындықтар тудыруы мүмкін. Бұны түзету үшін, енгізілген айнымалылары бар файлдарды өзгерткеннен кейін сізге қажет:


  1. Жаңартылған файлдар үшін жаңа хэш жасаңыз.
  2. Бұл жаңа хэшті файл атауларына қосыңыз, сондықтан браузер оларды жаңа файлдар ретінде қарастырады.
  3. Жаңа файл атауларына сәйкестендіру үшін кодыңыздағы ескі файл атауларына (мысалы, импорт мәлімдемелері) кез келген сілтемелерді жаңартыңыз.


Мұны жүзеге асыру үшін inject.py файлына хэш кітапханасының импортын ( import hashlib ) және келесі функцияларды қосыңыз.


 def sha256sum(filename): h = hashlib.sha256() b = bytearray(128 * 1024) mv = memoryview(b) with open(filename, 'rb', buffering=0) as f: while n := f.readinto(mv): h.update(mv[:n]) return h.hexdigest() def replace_filename_imports(filename, new_filename, base_path): allowed_extensions = ('.html', '.js', '.css') for path, dirc, files in os.walk(base_path): for name in files: current_filename = os.path.join(path, name) if current_filename.endswith(allowed_extensions): with open(current_filename) as f: s = f.read() s = s.replace(filename, new_filename) with open(current_filename, "w") as f: f.write(s) def rename_file(fullfilename): dirname = os.path.dirname(fullfilename) filename, ext = os.path.splitext(os.path.basename(fullfilename)) digest = sha256sum(fullfilename) new_filename = f'{filename}.{digest[:8]}' new_fullfilename = f'{dirname}/{new_filename}{ext}' os.rename(fullfilename, new_fullfilename) return filename, new_filename


Дегенмен, барлық файлдардың атын өзгерту қажет емес. Мысалы, index.html файл атауы өзгеріссіз қалуы керек және оған қол жеткізу үшін атын өзгерту қажет екенін көрсететін жалаушаны сақтайтын TargetFile сыныбын жасаңыз:


 class TargetFile: def __init__(self, glob, should_be_renamed = True): self.glob = glob self.should_be_renamed = should_be_renamed


Енді inject.py ішіндегі файл жолдарының массивін TargetFile сынып нысандарының массивімен ауыстыру керек:

 target_files = [ injector.TargetFile(f'{base_path}/static/js/main.*.js'), injector.TargetFile(f'{base_path}/static/js/chunk.*.js'), injector.TargetFile(f'{base_path}/static/css/main.*.css'), injector.TargetFile(f'{base_path}/static/css/chunk.*.css'), injector.TargetFile(f'{base_path}/index.html', False) ]


Жалау орнатылған болса, файлдың атын өзгертуді қосу үшін injector.py ішіндегі inject функциясын жаңартыңыз:


 def inject(target_files, replacement_map, base_path): for target_file in target_files: for filename in glob.glob(target_file.glob): inject_envs(filename, replacement_map) if target_file.should_be_renamed: filename, new_filename = rename_file(filename) replace_filename_imports(filename, new_filename, base_path)


Нәтижесінде артефакт файлдары мына атау пішімін сақтайды: <origin-file-name> . <injection-hash> . <extension> .


Инъекция алдында файл атауы:

Инъекция алдында файл атауы


Инъекциядан кейінгі файл атауы: Инъекциядан кейінгі файл атауы


Бірдей орта айнымалылары пайдаланушы шолғышына файлды дұрыс кэштеуге мүмкіндік беретін бірдей файл атауын береді. Енді осы айнымалы мәндердің дұрыс мәндері шолғыш кэшінде сақталатынына кепілдік бар, нәтижесінде клиент үшін жақсы өнімділік.


Жеңілдетілген орналастыруға арналған шешім

Әрбір орта үшін жеке құрылымдарды жасаудың дәстүрлі тәсілі шектеулі ресурстары бар командалар үшін мәселе болуы мүмкін бірнеше маңызды тиімсіздіктерге әкелді.


Енді сізде ұзартылған орналастыру уақыттарын, шамадан тыс құрастыруларды және алдыңғы қосымшалар үшін сапаны қамтамасыз етудегі жоғары тәуекелдерді шеше алатын шығарылым процесінің жоспары бар - мұның барлығы. Барлық орталарда кепілдік берілген консистенцияның жаңа деңгейін енгізу кезінде.


N құрастыру қажет емес, сізге тек біреуі керек. Алдағы шығарылым үшін сынақтан өткен құрастыруды жай ғана орналастыруға болады, ол сонымен қатар ықтимал қате мәселелерін шешуге көмектеседі, өйткені бірдей құрастыру барлық орталарда пайдаланылады. Сонымен қатар, бұл сценарийдің орындалу жылдамдығы тіпті ең оңтайландырылған құрылымға қарағанда салыстыруға келмейтін жылдамырақ. Мысалы, MacBook 14 PRO, M1, 32 ГБ жергілікті эталондары келесідей:


Менің көзқарасым шығару процесін жеңілдетеді, тиімді кэштеу стратегияларына мүмкіндік беру арқылы қолданбаның өнімділігін қолдайды және құрастыруға қатысты қателер оны орталарға енгізбеуін қамтамасыз етеді. Бұған қоса, бұрын жалықтыратын құрастыру тапсырмаларына жұмсалған барлық уақыт пен күш енді одан да жақсырақ пайдаланушы тәжірибесін жасауға бағытталуы мүмкін. Нені сүюге болмайды?


Біз құрастыруға қатысты қателердің басқа орталар үшін қолданбаға еніп кетпеуін қамтамасыз етеміз. Құрастыру жүйелеріндегі кемшіліктерге байланысты пайда болатын фантомдық қателер болуы мүмкін. Мүмкіндіктер аз, бірақ олар бар.



L O A D I N G
. . . comments & more!

About Author

Egor Grushin HackerNoon profile picture
Egor Grushin@egorgrushin
11+ years of experience both in software development and architecture for highload B2B and B2C projects.

ТЕГТЕРДІ АЛУ

БҰЛ МАҚАЛА БАСҚАРҒАН...