Π”ΠΎΡ†ΠΊΠ΅Ρ€ слика Π·Π° Π΄ΠΈΡΡ‚Ρ€ΠΈΠ±ΡƒΡ†ΠΈΡ˜Ρƒ Π°ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π΅ Π·Π° Ρ˜Π΅Π΄Π½Ρƒ страницу

ΠΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π° Π½Π° јСдној страници (БПА) јС скуп статичких ΠˆΠ°Π²Π°Π‘Ρ†Ρ€ΠΈΠΏΡ‚ ΠΈ Π₯Π’ΠœΠ› Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°, ΠΊΠ°ΠΎ ΠΈ слика ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΡ… рСсурса. ΠŸΠΎΡˆΡ‚ΠΎ сС Π½Π΅ ΠΌΠ΅ΡšΠ°Ρ˜Ρƒ Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡ΠΊΠΈ, ΡšΠΈΡ…ΠΎΠ²ΠΎ ΠΎΠ±Ρ˜Π°Π²Ρ™ΠΈΠ²Π°ΡšΠ΅ Π½Π° ΠΌΡ€Π΅ΠΆΠΈ јС Π²Π΅ΠΎΠΌΠ° Π»Π°ΠΊΠΎ. ΠŸΠΎΡΡ‚ΠΎΡ˜ΠΈ Π²Π΅Π»ΠΈΠΊΠΈ Π±Ρ€ΠΎΡ˜ Ρ˜Π΅Ρ„Ρ‚ΠΈΠ½ΠΈΡ…, ΠΏΠ° Ρ‡Π°ΠΊ ΠΈ бСсплатних сСрвиса Π·Π° ΠΎΠ²ΠΎ, ΠΏΠΎΡ‡Π΅Π²ΡˆΠΈ ΠΎΠ΄ Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΈΡ… Π“ΠΈΡ‚Π₯ΡƒΠ± страница (Π° Π·Π° Π½Π΅ΠΊΠ΅ Ρ‡Π°ΠΊ ΠΈ са Π½Π°Ρ€ΠΎΠ΄.Ρ€Ρƒ) ΠΈ Π·Π°Π²Ρ€ΡˆΠ°Π²Π°Ρ˜ΡƒΡ›ΠΈ са ЦДН-ΠΎΠΌ ΠΊΠ°ΠΎ ΡˆΡ‚ΠΎ јС Амазон Π‘3. ΠœΠ΅Ρ’ΡƒΡ‚ΠΈΠΌ, Ρ‚Ρ€Π΅Π±Π°Π»ΠΎ ΠΌΠΈ јС Π½Π΅ΡˆΡ‚ΠΎ Π΄Ρ€ΡƒΠ³ΠΎ.

Π’Ρ€Π΅Π±Π°ΠΎ ΠΌΠΈ јС Π”ΠΎΡ†ΠΊΠ΅Ρ€ имиџ са БПА-ΠΎΠΌ Π΄Π° Π±ΠΈ сС Π»Π°ΠΊΠΎ ΠΌΠΎΠ³Π°ΠΎ ΠΏΠΎΠΊΡ€Π΅Π½ΡƒΡ‚ΠΈ ΠΈΡƒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΡšΠΈ ΠΊΠ°ΠΎ Π΄Π΅ΠΎ ΠšΡƒΠ±Π΅Ρ€Π½Π΅Ρ‚Π΅Ρ кластСра ΠΈ Π½Π° машини Π±Π°Ρ†ΠΊ-Π΅Π½Π΄ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ΅Ρ€Π° који Π½Π΅ΠΌΠ° појма ΡˆΡ‚Π° јС БПА.

Π—Π° сСбС сам ΠΎΠ΄Ρ€Π΅Π΄ΠΈΠΎ слСдСћС Π·Π°Ρ…Ρ‚Π΅Π²Π΅ Π·Π° слику:

  • Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΎΡΡ‚ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π΅ (Π°Π»ΠΈ Π½Π΅ ΠΌΠΎΠ½Ρ‚Π°ΠΆΠ΅);
  • ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π½Π° Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Π° ΠΈ Ρƒ ΠΏΠΎΠ³Π»Π΅Π΄Ρƒ диска ΠΈ РАМ-Π°;
  • ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡΠ°ΡšΠ΅ ΠΊΡ€ΠΎΠ· ΠΏΡ€ΠΎΠΌΠ΅Π½Ρ™ΠΈΠ²Π΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ° Ρ‚Π°ΠΊΠΎ Π΄Π° сС слика ΠΌΠΎΠΆΠ΅ користити Ρƒ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΡ‚ΠΈΠΌ ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠΈΠΌΠ°;
  • Π½Π°Ρ˜Π΅Ρ„ΠΈΠΊΠ°ΡΠ½ΠΈΡ˜Π° Π΄ΠΈΡΡ‚Ρ€ΠΈΠ±ΡƒΡ†ΠΈΡ˜Π° Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°.

Данас Ρ›Ρƒ Π²Π°ΠΌ Ρ€Π΅Ρ›ΠΈ ΠΊΠ°ΠΊΠΎ:

  • Π³ΡƒΡ‚ Π½Π³ΠΈΠ½ΠΊ;
  • ΠΈΠ·Π³Ρ€Π°Π΄ΠΈ Π±Ρ€ΠΎΡ‚Π»ΠΈ ΠΈΠ· ΠΈΠ·Π²ΠΎΡ€Π°;
  • Π½Π°ΡƒΡ‡ΠΈΡ‚ΠΈ статичкС Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ Π΄Π° Ρ€Π°Π·ΡƒΠΌΠ΅Ρ˜Ρƒ ΠΏΡ€ΠΎΠΌΠ΅Π½Ρ™ΠΈΠ²Π΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ°;
  • ΠΈ Π½Π°Ρ€Π°Π²Π½ΠΎ ΠΊΠ°ΠΊΠΎ саставити Π”ΠΎΡ†ΠΊΠ΅Ρ€ слику ΠΎΠ΄ свСга ΠΎΠ²ΠΎΠ³Π°.

Π‘Π²Ρ€Ρ…Π° ΠΎΠ²ΠΎΠ³ Ρ‡Π»Π°Π½ΠΊΠ° јС Π΄Π° ΠΏΠΎΠ΄Π΅Π»ΠΈΠΌ својС искуство ΠΈ испровоцирам искуснС Ρ‡Π»Π°Π½ΠΎΠ²Π΅ Π·Π°Ρ˜Π΅Π΄Π½ΠΈΡ†Π΅ Π½Π° конструктивну ΠΊΡ€ΠΈΡ‚ΠΈΠΊΡƒ.

Π˜Π·Π³Ρ€Π°Π΄ΡšΠ° сликС Π·Π° склапањС

Π”Π° Π±ΠΈ ΠΊΠΎΠ½Π°Ρ‡Π½Π° Π”ΠΎΡ†ΠΊΠ΅Ρ€ слика Π±ΠΈΠ»Π° ΠΌΠ°Π»Π°, ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ јС Π΄Π° сС ΠΏΡ€ΠΈΠ΄Ρ€ΠΆΠ°Π²Π°Ρ‚Π΅ Π΄Π²Π° ΠΏΡ€Π°Π²ΠΈΠ»Π°: ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ слојСва ΠΈ минималистичку основну слику. ЈСдна ΠΎΠ΄ Π½Π°Ρ˜ΠΌΠ°ΡšΠΈΡ… основних слика јС слика АлпинС Π›ΠΈΠ½ΡƒΠΊ-Π°, Ρ‚Π°ΠΊΠΎ Π΄Π° Ρ›Ρƒ Ρ‚ΠΎ ΠΈΠ·Π°Π±Ρ€Π°Ρ‚ΠΈ. НСки Π±ΠΈ ΠΌΠΎΠ³Π»ΠΈ Ρ‚Π²Ρ€Π΄ΠΈΡ‚ΠΈ Π΄Π° АлпинС нијС ΠΏΠΎΠ³ΠΎΠ΄Π°Π½ Π·Π° ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΡšΡƒ, ΠΈ ΠΌΠΎΠΆΠ΄Π° су Ρƒ ΠΏΡ€Π°Π²Ρƒ. Али Π»ΠΈΡ‡Π½ΠΎ, Π½ΠΈΠΊΠ°Π΄Π° нисам ΠΈΠΌΠ°ΠΎ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° са њим ΠΈ Π½Π΅ΠΌΠ° Π½ΠΈΠΊΠ°ΠΊΠ²ΠΈΡ… Π°Ρ€Π³ΡƒΠΌΠ΅Π½Π°Ρ‚Π° ΠΏΡ€ΠΎΡ‚ΠΈΠ² њСга.

Π”Π° ΠΈΠΌΠ°ΠΌ мањС слојСва, саставићу слику Ρƒ 2 Ρ„Π°Π·Π΅. ΠŸΡ€Π²ΠΈ јС Π½Π°Ρ†Ρ€Ρ‚, Ρƒ ΡšΠ΅ΠΌΡƒ Ρ›Π΅ остати сви ΠΏΠΎΠΌΠΎΡ›Π½ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ ΠΈ ΠΏΡ€ΠΈΠ²Ρ€Π΅ΠΌΠ΅Π½ΠΈ Ρ„Π°Ρ˜Π»ΠΎΠ²ΠΈ. И Ρƒ Π·Π°Π²Ρ€ΡˆΠ½ΠΎΡ˜ Ρ„Π°Π·ΠΈ Ρ›Ρƒ само написати ΠΊΠΎΠ½Π°Ρ‡Π½Ρƒ Π²Π΅Ρ€Π·ΠΈΡ˜Ρƒ Π°ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π΅.

ΠŸΠΎΡ‡Π½ΠΈΠΌΠΎ са ΠΏΠΎΠΌΠΎΡ›Π½ΠΎΠΌ сликом.

Π”Π° бистС саставили БПА Π°ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Ρƒ, ΠΎΠ±ΠΈΡ‡Π½ΠΎ Π²Π°ΠΌ јС ΠΏΠΎΡ‚Ρ€Π΅Π±Π°Π½ Π½ΠΎΠ΄Π΅.јс. Π£Π·Π΅Ρ›Ρƒ Π·Π²Π°Π½ΠΈΡ‡Π½Ρƒ слику, која Ρ‚Π°ΠΊΠΎΡ’Π΅ Π΄ΠΎΠ»Π°Π·ΠΈ са Π½ΠΏΠΌ ΠΈ ΠΈΠ°Ρ€Π½ ΠΏΠ°ΠΊΠ΅Ρ‚ ΠΌΠ΅Π½Π°ΡŸΠ΅Ρ€ΠΈΠΌΠ°. Π£ својС Π»ΠΈΡ‡Π½ΠΎ ΠΈΠΌΠ΅ Π΄ΠΎΠ΄Π°Ρ›Ρƒ Π½ΠΎΠ΄Π΅-Π³ΠΈΠΏ, који јС ΠΏΠΎΡ‚Ρ€Π΅Π±Π°Π½ Π·Π° ΠΏΡ€Π°Π²Ρ™Π΅ΡšΠ΅ Π½Π΅ΠΊΠΈΡ… Π½ΠΏΠΌ ΠΏΠ°ΠΊΠ΅Ρ‚Π°, ΠΈ Π‘Ρ€ΠΎΡ‚Π»ΠΈ компрСсор ΠΈΠ· Π“ΡƒΠ³Π»Π°, који Ρ›Π΅ Π½Π°ΠΌ каснијС Π±ΠΈΡ‚ΠΈ ΠΎΠ΄ користи.

Π”ΠΎΡ†ΠΊΠ΅Ρ€Ρ„ΠΈΠ»Π΅ са ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΌΠ°.

# Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π·
FROM node:12-alpine
LABEL maintainer="Aleksey Maydokin <[email protected]>"
ENV BROTLI_VERSION 1.0.7
# ΠŸΠ°ΠΊΠ΅Ρ‚Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½ΡƒΠΆΠ½Ρ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ ΠΈΠ· исходников Brotli
RUN apk add --no-cache --virtual .build-deps 
        bash 
        gcc 
        libc-dev 
        make 
        linux-headers 
        cmake 
        curl 
    && mkdir -p /usr/src 
    # Π˜ΡΡ…ΠΎΠ΄Π½ΠΈΠΊΠΈ Brotli скачиваСм ΠΈΠ· ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ рСпозитория
    && curl -LSs https://github.com/google/brotli/archive/v$BROTLI_VERSION.tar.gz | tar xzf - -C /usr/src 
    && cd /usr/src/brotli-$BROTLI_VERSION 
    # ΠšΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅ΠΌ Brotli
    && ./configure-cmake --disable-debug && make -j$(getconf _NPROCESSORS_ONLN) && make install 
    # ДобавляСм node-gyp
    && yarn global add node-gyp 
    # Π£Π±ΠΈΡ€Π°Π΅ΠΌ Π·Π° собой мусор
    && apk del .build-deps && yarn cache clean && rm -rf /usr/src

Π’Π΅Ρ› ΠΎΠ²Π΄Π΅ сС Π±ΠΎΡ€ΠΈΠΌ Π·Π° ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΠΈΠ·Π°ΠΌ, Ρ‚Π°ΠΊΠΎ Π΄Π° имиџ склапа јСдан Π²Π΅Π»ΠΈΠΊΠΈ Ρ‚ΠΈΠΌ.

Π“ΠΎΡ‚ΠΎΠ²Ρƒ слику ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΎΠ½Π°Ρ›ΠΈ ΠΎΠ²Π΄Π΅: https://hub.docker.com/r/alexxxnf/spa-builder. Иако ΠΏΡ€Π΅ΠΏΠΎΡ€ΡƒΡ‡ΡƒΡ˜Π΅ΠΌ Π΄Π° сС Π½Π΅ ΠΎΡΠ»Π°ΡšΠ°Ρ‚Π΅ Π½Π° Ρ‚ΡƒΡ’Π΅ сликС ΠΈ Π΄Π° сакупљатС својС.

АпацхС

ΠœΠΎΠΆΠ΅Ρ‚Π΅ користити Π±ΠΈΠ»ΠΎ који Π²Π΅Π± сСрвСр Π·Π° Π΄ΠΈΡΡ‚Ρ€ΠΈΠ±ΡƒΡ†ΠΈΡ˜Ρƒ статичког ΡΠ°Π΄Ρ€ΠΆΠ°Ρ˜Π°. Навикао сам Π΄Π° Ρ€Π°Π΄ΠΈΠΌ са Π½Π³ΠΈΠ½ΠΊ-ΠΎΠΌ, ΠΏΠ° Ρ›Ρƒ Π³Π° сада користити.

Нгинк ΠΈΠΌΠ° Π·Π²Π°Π½ΠΈΡ‡Π½Ρƒ Π”ΠΎΡ†ΠΊΠ΅Ρ€ слику, Π°Π»ΠΈ ΠΈΠΌΠ° ΠΏΡ€Π΅Π²ΠΈΡˆΠ΅ ΠΌΠΎΠ΄ΡƒΠ»Π° Π·Π° Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½Ρƒ статичку Π΄ΠΈΡΡ‚Ρ€ΠΈΠ±ΡƒΡ†ΠΈΡ˜Ρƒ. Који су ΡƒΠΊΡ™ΡƒΡ‡Π΅Π½ΠΈ Ρƒ испоруку ΠΌΠΎΠΆΠ΅ сС Π²ΠΈΠ΄Π΅Ρ‚ΠΈ Ρƒ ΡΠΏΠ΅Ρ†ΠΈΡ˜Π°Π»Π½ΠΎΠΌ Ρ‚ΠΈΠΌΡƒ ΠΈΠ»ΠΈ Ρƒ Π·Π²Π°Π½ΠΈΡ‡Π½ΠΎΠΌ Π”ΠΎΡ†ΠΊΠ΅Ρ€Ρ„ΠΈΠ»Π΅-Ρƒ.

$ Π΄ΠΎΡ†ΠΊΠ΅Ρ€ Ρ€ΡƒΠ½ --Ρ€ΠΌ Π½Π³ΠΈΠ½ΠΊ:1-Π°Π»ΠΏΠΈΠ½Π΅ Π½Π³ΠΈΠ½ΠΊ -Π’

nginx version: nginx/1.17.9
built by gcc 8.3.0 (Alpine 8.3.0) 
built with OpenSSL 1.1.1d  10 Sep 2019
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --with-perl_modules_path=/usr/lib/perl5/vendor_perl --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-Os -fomit-frame-pointer' --with-ld-opt=-Wl,--as-needed

ΠšΠΎΡ€ΠΈΡΡ‚ΠΈΡ›Ρƒ Π”ΠΎΡ†ΠΊΠ΅Ρ€Ρ„ΠΈΠ»Π΅ ΠΊΠ°ΠΎ основу, Π°Π»ΠΈ Ρ›Ρƒ Ρƒ ΡšΠ΅ΠΌΡƒ оставити само ΠΎΠ½ΠΎ ΡˆΡ‚ΠΎ јС ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ Π·Π° Π΄ΠΈΡΡ‚Ρ€ΠΈΠ±ΡƒΡ†ΠΈΡ˜Ρƒ статичког ΡΠ°Π΄Ρ€ΠΆΠ°Ρ˜Π°. Моја Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π½Π΅Ρ›Π΅ ΠΌΠΎΡ›ΠΈ Π΄Π° Ρ€Π°Π΄ΠΈ ΠΏΡ€Π΅ΠΊΠΎ Π₯ВВПБ-Π°, Π½Π΅Ρ›Π΅ ΠΏΠΎΠ΄Ρ€ΠΆΠ°Π²Π°Ρ‚ΠΈ Π°ΡƒΡ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Ρƒ ΠΈ још ΠΌΠ½ΠΎΠ³ΠΎ Ρ‚ΠΎΠ³Π°. Али моја Π²Π΅Ρ€Π·ΠΈΡ˜Π° Ρ›Π΅ ΠΌΠΎΡ›ΠΈ Π΄Π° дистрибуира Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ ΠΊΠΎΠΌΠΏΡ€ΠΈΠΌΠΎΠ²Π°Π½Π΅ ΠΏΠΎΠΌΠΎΡ›Ρƒ Π‘Ρ€ΠΎΡ‚Π»ΠΈ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ°, који јС ΠΌΠ°Π»ΠΎ Π΅Ρ„ΠΈΠΊΠ°ΡΠ½ΠΈΡ˜ΠΈ ΠΎΠ΄ Π³Π·ΠΈΠΏ-Π°. ΠšΠΎΠΌΠΏΡ€ΠΈΠΌΠΎΠ²Π°Ρ›Π΅ΠΌΠΎ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ јСдном; Π½Π΅ΠΌΠ° ΠΏΠΎΡ‚Ρ€Π΅Π±Π΅ Π΄Π° Ρ‚ΠΎ Ρ€Π°Π΄ΠΈΠΌΠΎ Ρƒ Ρ…ΠΎΠ΄Ρƒ.

Ово јС Π”ΠΎΡ†ΠΊΠ΅Ρ€Ρ„ΠΈΠ»Π΅ са којим сам Π·Π°Π²Ρ€ΡˆΠΈΠΎ. ΠšΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈ Π½Π° руском су моји, Π½Π° СнглСском - ΠΈΠ· ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π°.

Π”ΠΎΡ†ΠΊΠ΅Ρ€Ρ„ΠΈΠ»Π΅

# Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· снова Alpine
FROM alpine:3.9
LABEL maintainer="Aleksey Maydokin <[email protected]>"
ENV NGINX_VERSION 1.16.0
ENV NGX_BROTLI_VERSION 0.1.2
ENV BROTLI_VERSION 1.0.7
RUN set -x 
    && addgroup -S nginx 
    && adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx 
# УстанавливаСм ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½ΡƒΠΆΠ½Ρ‹ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ nginx ΠΈ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ ngx_brotli ΠΊ Π½Π΅ΠΌΡƒ
    && apk add --no-cache --virtual .build-deps 
            gcc 
            libc-dev 
            make 
            linux-headers 
            curl 
    && mkdir -p /usr/src 
# Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π΅ΠΌ исходники
    && curl -LSs https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz | tar xzf - -C /usr/src 
    && curl -LSs https://github.com/eustas/ngx_brotli/archive/v$NGX_BROTLI_VERSION.tar.gz | tar xzf - -C /usr/src 
    && curl -LSs https://github.com/google/brotli/archive/v$BROTLI_VERSION.tar.gz | tar xzf - -C /usr/src 
    && rm -rf /usr/src/ngx_brotli-$NGX_BROTLI_VERSION/deps/brotli/ 
    && ln -s /usr/src/brotli-$BROTLI_VERSION /usr/src/ngx_brotli-$NGX_BROTLI_VERSION/deps/brotli 
    && cd /usr/src/nginx-$NGINX_VERSION 
    && CNF="
            --prefix=/etc/nginx 
            --sbin-path=/usr/sbin/nginx 
            --modules-path=/usr/lib/nginx/modules 
            --conf-path=/etc/nginx/nginx.conf 
            --error-log-path=/var/log/nginx/error.log 
            --http-log-path=/var/log/nginx/access.log 
            --pid-path=/var/run/nginx.pid 
            --lock-path=/var/run/nginx.lock 
            --http-client-body-temp-path=/var/cache/nginx/client_temp 
            --http-proxy-temp-path=/var/cache/nginx/proxy_temp 
            --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp 
            --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp 
            --http-scgi-temp-path=/var/cache/nginx/scgi_temp 
            --user=nginx 
            --group=nginx 
            --without-http_ssi_module 
            --without-http_userid_module 
            --without-http_access_module 
            --without-http_auth_basic_module 
            --without-http_mirror_module 
            --without-http_autoindex_module 
            --without-http_geo_module 
            --without-http_split_clients_module 
            --without-http_referer_module 
            --without-http_rewrite_module 
            --without-http_proxy_module 
            --without-http_fastcgi_module 
            --without-http_uwsgi_module 
            --without-http_scgi_module 
            --without-http_grpc_module 
            --without-http_memcached_module 
            --without-http_limit_conn_module 
            --without-http_limit_req_module 
            --without-http_empty_gif_module 
            --without-http_browser_module 
            --without-http_upstream_hash_module 
            --without-http_upstream_ip_hash_module 
            --without-http_upstream_least_conn_module 
            --without-http_upstream_keepalive_module 
            --without-http_upstream_zone_module 
            --without-http_gzip_module 
            --with-http_gzip_static_module 
            --with-threads 
            --with-compat 
            --with-file-aio 
            --add-dynamic-module=/usr/src/ngx_brotli-$NGX_BROTLI_VERSION 
    " 
# Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ
    && ./configure $CNF 
    && make -j$(getconf _NPROCESSORS_ONLN) 
    && make install 
    && rm -rf /usr/src/ 
# УдаляСм динамичСский brotli ΠΌΠΎΠ΄ΡƒΠ»ΡŒ, оставляя Ρ‚ΠΎΠ»ΡŒΠΊΠΎ статичСский
    && rm /usr/lib/nginx/modules/ngx_http_brotli_filter_module.so 
    && sed -i '$ d' /etc/apk/repositories 
# Bring in gettext so we can get `envsubst`, then throw
# the rest away. To do this, we need to install `gettext`
# then move `envsubst` out of the way so `gettext` can
# be deleted completely, then move `envsubst` back.
    && apk add --no-cache --virtual .gettext gettext 
    && mv /usr/bin/envsubst /tmp/ 
    && runDeps="$( 
        scanelf --needed --nobanner /usr/sbin/nginx /usr/lib/nginx/modules/*.so /tmp/envsubst 
            | awk '{ gsub(/,/, "nso:", $2); print "so:" $2 }' 
            | sort -u 
            | xargs -r apk info --installed 
            | sort -u 
    )" 
    && apk add --no-cache $runDeps 
    && apk del .build-deps 
    && apk del .gettext 
    && mv /tmp/envsubst /usr/local/bin/ 
# Bring in tzdata so users could set the timezones through the environment
# variables
    && apk add --no-cache tzdata 
# forward request and error logs to docker log collector
    && ln -sf /dev/stdout /var/log/nginx/access.log 
    && ln -sf /dev/stderr /var/log/nginx/error.log
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]

ΠžΠ΄ΠΌΠ°Ρ… Ρ›Ρƒ ΠΏΠΎΠΏΡ€Π°Π²ΠΈΡ‚ΠΈ Π½Π³ΠΈΠ½ΠΊ.Ρ†ΠΎΠ½Ρ„ Ρ‚Π°ΠΊΠΎ Π΄Π° су Π³Π·ΠΈΠΏ ΠΈ Π±Ρ€ΠΎΡ‚Π»ΠΈ ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π½ΠΎ ΠΎΠΌΠΎΠ³ΡƒΡ›Π΅Π½ΠΈ. Π£ΠΊΡ™ΡƒΡ‡ΠΈΡ›Ρƒ ΠΈ Π·Π°Π³Π»Π°Π²Ρ™Π° Π·Π° ΠΊΠ΅ΡˆΠΈΡ€Π°ΡšΠ΅, Ρ˜Π΅Ρ€ Π½ΠΈΠΊΠ°Π΄Π° Π½Π΅Ρ›Π΅ΠΌΠΎ ΠΌΠ΅ΡšΠ°Ρ‚ΠΈ статичкС. И послСдњи Π΄ΠΎΠ΄ΠΈΡ€ Ρ›Π΅ Π±ΠΈΡ‚ΠΈ ΠΏΡ€Π΅ΡƒΡΠΌΠ΅Ρ€Π°Π²Π°ΡšΠ΅ свих 404 Π·Π°Ρ…Ρ‚Π΅Π²Π° Π½Π° ΠΈΠ½Π΄Π΅ΠΊ.Ρ…Ρ‚ΠΌΠ», ΠΎΠ²ΠΎ јС Π½Π΅ΠΎΠΏΡ…ΠΎΠ΄Π½ΠΎ Π·Π° Π½Π°Π²ΠΈΠ³Π°Ρ†ΠΈΡ˜Ρƒ Ρƒ БПА.

Π½Π³ΠΈΠ½ΠΊ.Ρ†ΠΎΠ½Ρ„

user nginx;
worker_processes  1;
error_log /var/log/nginx/error.log warn;
pid       /var/run/nginx.pid;
load_module /usr/lib/nginx/modules/ngx_http_brotli_static_module.so;
events {
    worker_connections 1024;
}
http {
    include      mime.types;
    default_type application/octet-stream;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log main;
    sendfile on;
    keepalive_timeout 65;
    gzip_static   on;
    brotli_static on;
    server {
        listen      80;
        server_name localhost;
        charset utf-8;
        location / {
            root html;
            try_files $uri /index.html;
            etag on;
            expires max;
            add_header Cache-Control public;
            location = /index.html {
                expires 0;
                add_header Cache-Control "no-cache, public, must-revalidate, proxy-revalidate";
            }
        }
    }
}

Π“ΠΎΡ‚ΠΎΠ²Ρƒ слику ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€Π΅ΡƒΠ·Π΅Ρ‚ΠΈ ΠΎΠ²Π΄Π΅: https://hub.docker.com/r/alexxxnf/nginx-spa. Π—Π°ΡƒΠ·ΠΈΠΌΠ° 10,5 ΠœΠ‘. ΠžΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈ Π½Π³ΠΈΠ½ΠΊ јС Π·Π°ΡƒΠ·ΠΈΠΌΠ°ΠΎ 19,7 ΠœΠ‘. Мој спортски интСрСс јС Π·Π°Π΄ΠΎΠ²ΠΎΡ™Π°Π½.

ΠŸΠΎΠ΄ΡƒΡ‡Π°Π²Π°ΡšΠ΅ статикС Π·Π° Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°ΡšΠ΅ ΠΏΡ€ΠΎΠΌΠ΅Π½Ρ™ΠΈΠ²ΠΈΡ… ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ°

Π—Π°ΡˆΡ‚ΠΎ ΠΌΠΎΠ³Ρƒ Π±ΠΈΡ‚ΠΈ ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π° подСшавања Ρƒ БПА? На ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π΄Π° бистС ΠΎΠ΄Ρ€Π΅Π΄ΠΈΠ»ΠΈ који Π Π•Π‘Π’Ρ„ΡƒΠ» АПИ Π΄Π° користитС. ΠžΠ±ΠΈΡ‡Π½ΠΎ сС подСшавања Π·Π° ΠΆΠ΅Ρ™Π΅Π½ΠΎ ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ΅ прСносС Ρƒ БПА Ρƒ Ρ„Π°Π·ΠΈ ΠΈΠ·Π³Ρ€Π°Π΄ΡšΠ΅. Ако Ρ‚Ρ€Π΅Π±Π° Π½Π΅ΡˆΡ‚ΠΎ Π΄Π° ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅, ΠΌΠΎΡ€Π°Ρ›Π΅Ρ‚Π΅ ΠΏΠΎΠ½ΠΎΠ²ΠΎ Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈΡ‚Π΅ Π°ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Ρƒ. НС ΠΆΠ΅Π»ΠΈΠΌ. Π–Π΅Π»ΠΈΠΌ Π΄Π° сС Π°ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π° јСдном Π½Π°ΠΏΡ€Π°Π²ΠΈ Ρƒ ЦИ Ρ„Π°Π·ΠΈ ΠΈ Π΄Π° сС ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡˆΠ΅ ΠΎΠ½ΠΎΠ»ΠΈΠΊΠΎ ΠΊΠΎΠ»ΠΈΠΊΠΎ јС ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ Ρƒ Π¦Π” Ρ„Π°Π·ΠΈ користСћи ΠΏΡ€ΠΎΠΌΠ΅Π½Ρ™ΠΈΠ²Π΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ°.

Наравно, самС статичкС Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ Π½Π΅ Ρ€Π°Π·ΡƒΠΌΠ΅Ρ˜Ρƒ Π½ΠΈΡ˜Π΅Π΄Π½Ρƒ ΠΏΡ€ΠΎΠΌΠ΅Π½Ρ™ΠΈΠ²Ρƒ ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ°. Π—Π±ΠΎΠ³ Ρ‚ΠΎΠ³Π° Ρ›Π΅Ρ‚Π΅ ΠΌΠΎΡ€Π°Ρ‚ΠΈ Π΄Π° користитС Ρ‚Ρ€ΠΈΠΊ. Π£ ΠΊΠΎΠ½Π°Ρ‡Π½ΠΎΡ˜ слици, Π½Π΅Ρ›Ρƒ ΠΏΠΎΠΊΡ€Π΅Π½ΡƒΡ‚ΠΈ Π½Π³ΠΈΠ½ΠΊ, Π²Π΅Ρ› ΡΠΏΠ΅Ρ†ΠΈΡ˜Π°Π»Π½Ρƒ схСлл скрипту која Ρ›Π΅ Ρ‡ΠΈΡ‚Π°Ρ‚ΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½Ρ™ΠΈΠ²Π΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ°, уписивати ΠΈΡ… Ρƒ статичкС Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅, компрСсовати ΠΈΡ… ΠΈ Ρ‚Π΅ΠΊ ΠΎΠ½Π΄Π° ΠΏΡ€Π΅Π½Π΅Ρ‚ΠΈ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Ρƒ Π½Π° Π½Π³ΠΈΠ½ΠΊ.

Π£ Ρ‚Ρƒ сврху, Π”ΠΎΡ†ΠΊΠ΅Ρ€Ρ„ΠΈΠ»Π΅ ΠΎΠ±Π΅Π·Π±Π΅Ρ’ΡƒΡ˜Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Π°Ρ€ Π•ΠΠ’Π Π˜ΠŸΠžΠ˜ΠΠ’. Π₯ајдС Π΄Π° ΠΌΡƒ Π΄Π°ΠΌΠΎ слСдСћу скрипту (користСћи Ангулар ΠΊΠ°ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€):

Π΄ΠΎΡ†ΠΊΠ΅Ρ€-Π΅Π½Ρ‚Ρ€ΠΈΠΏΠΎΠΈΠ½Ρ‚.сх

#!/bin/sh
set -e
FLAG_FILE="/configured"
TARGET_DIR="/etc/nginx/html"
replace_vars () {
  ENV_VARS='$(awk 'BEGIN{for(v in ENVIRON) print "

quot;v}')'
# Π’ Angular ΠΈΡ‰Π΅ΠΌ плСйсхолдСры Π² main-Ρ„Π°ΠΉΠ»Π°Ρ…
for f in "$TARGET_DIR"/main*.js; do
# envsubst замСняСт Π² Ρ„Π°ΠΉΠ»Π°Ρ… плСйсхолдСры Π½Π° значСния ΠΈΠ· ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… окруТСния
echo "$(envsubst "$ENV_VARS" < "$f")" > "$f"
done
}
compress () {
for i in $(find "$TARGET_DIR" | grep -E ".css$|.html$|.js$|.svg$|.txt$|.ttf


quot;); do
# Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½ΡƒΡŽ ΡΡ‚Π΅ΠΏΠ΅Π½ΡŒ сТатия
gzip -9kf "$i" && brotli -fZ "$i"
done
}
if [ "$1" = 'nginx' ]; then
# Π€Π»Π°Π³ Π½ΡƒΠΆΠ΅Π½, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ скрипт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΡ€ΠΈ самом ΠΏΠ΅Ρ€Π²ΠΎΠΌ запускС
if [ ! -e "$FLAG_FILE" ]; then
echo "Running init script"
echo "Replacing env vars"
replace_vars
echo "Compressing files"
compress
touch $FLAG_FILE
echo "Done"
fi
fi
exec "$@"

Π”Π° Π±ΠΈ скрипта Ρ€Π°Π΄ΠΈΠ»Π° свој посао, подСшавања ΠΌΠΎΡ€Π°Ρ˜Ρƒ Π±ΠΈΡ‚ΠΈ записана Ρƒ јс Ρ„Π°Ρ˜Π»ΠΎΠ²ΠΈΠΌΠ° Ρƒ ΠΎΠ²ΠΎΠΌ ΠΎΠ±Π»ΠΈΠΊΡƒ: ${API_URL}.

Π’Ρ€Π΅Π΄ΠΈ Π½Π°ΠΏΠΎΠΌΠ΅Π½ΡƒΡ‚ΠΈ Π΄Π° Π²Π΅Ρ›ΠΈΠ½Π° ΠΌΠΎΠ΄Π΅Ρ€Π½ΠΈΡ… БПА додајС Ρ…Π΅ΡˆΠΎΠ²Π΅ Ρƒ својС Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ ΠΏΡ€ΠΈΠ»ΠΈΠΊΠΎΠΌ ΠΈΠ·Π³Ρ€Π°Π΄ΡšΠ΅. Ово јС Π½Π΅ΠΎΠΏΡ…ΠΎΠ΄Π½ΠΎ ΠΊΠ°ΠΊΠΎ Π±ΠΈ ΠΏΡ€Π΅Ρ‚Ρ€Π°ΠΆΠΈΠ²Π°Ρ‡ ΠΌΠΎΠ³Π°ΠΎ Π±Π΅Π·Π±Π΅Π΄Π½ΠΎ Π΄Π° ΠΊΠ΅ΡˆΠΈΡ€Π° Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΡƒ Π΄ΡƒΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½Π°. Ако сС Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ, њСн Ρ…Π΅Ρˆ Ρ›Π΅ сС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚ΠΈ, ΡˆΡ‚ΠΎ Ρ›Π΅ Π·Π°ΡƒΠ·Π²Ρ€Π°Ρ‚ ΠΏΡ€ΠΈΠΌΠΎΡ€Π°Ρ‚ΠΈ ΠΏΡ€Π΅Π³Π»Π΅Π΄Π°Ρ‡ Π΄Π° ΠΏΠΎΠ½ΠΎΠ²ΠΎ ΠΏΡ€Π΅ΡƒΠ·ΠΌΠ΅ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΡƒ.

НаТалост, Ρƒ ΠΌΠΎΠΌ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ, ΠΏΡ€ΠΎΠΌΠ΅Π½Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ˜Π΅ ΠΏΡ€Π΅ΠΊΠΎ ΠΏΡ€ΠΎΠΌΠ΅Π½Ρ™ΠΈΠ²ΠΈΡ… ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ° Π½Π΅ Π΄ΠΎΠ²ΠΎΠ΄ΠΈ Π΄ΠΎ ΠΏΡ€ΠΎΠΌΠ΅Π½Π΅ Ρ…Π΅ΡˆΠ° Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅, ΡˆΡ‚ΠΎ Π·Π½Π°Ρ‡ΠΈ Π΄Π° кСш ΠΏΡ€Π΅Ρ‚Ρ€Π°ΠΆΠΈΠ²Π°Ρ‡Π° ΠΌΠΎΡ€Π° Π±ΠΈΡ‚ΠΈ ΠΏΠΎΠ½ΠΈΡˆΡ‚Π΅Π½ Π½Π° Π½Π΅ΠΊΠΈ Π΄Ρ€ΡƒΠ³ΠΈ Π½Π°Ρ‡ΠΈΠ½. НСмам овај ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ Ρ˜Π΅Ρ€ су Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΡ‚Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ˜Π΅ распорСђСнС Ρƒ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΡ‚ΠΈΠΌ ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠΈΠΌΠ°.

Π‘Π°ΡΡ‚Π°Π²Ρ™Π°ΡšΠ΅ ΠΊΠΎΠ½Π°Ρ‡Π½Π΅ сликС

ΠšΠΎΠ½Π°Ρ‡Π½ΠΎ.

Π”ΠΎΡ†ΠΊΠ΅Ρ€Ρ„ΠΈΠ»Π΅

# ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· для сборки
FROM alexxxnf/spa-builder as builder
# Π§Ρ‚ΠΎΠ±Ρ‹ эффктивнСС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ кэш Docker-Π°, сначала устанавливаСм Ρ‚ΠΎΠ»ΡŒΠΊΠΎ зависимости
COPY ./package.json ./package-lock.json /app/
RUN cd /app && npm ci --no-audit
# ΠŸΠΎΡ‚ΠΎΠΌ собираСм само ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
COPY . /app
RUN cd /app && npm run build -- --prod --configuration=docker

# Π’Ρ‚ΠΎΡ€ΠΎΠΉ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· для Ρ€Π°Π·Π΄Π°Ρ‡ΠΈ
FROM alexxxnf/nginx-spa
# Π—Π°Π±ΠΈΡ€Π°Π΅ΠΌ ΠΈΠ· ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΎΠ±Ρ€Π°Π·Π° сначала компрСссор
COPY --from=builder /usr/local/bin/brotli /usr/local/bin
# ΠŸΠΎΡ‚ΠΎΠΌ добавляСм Ρ‡ΡƒΠ΄ΠΎ-скрипт
COPY ./docker/docker-entrypoint.sh /docker-entrypoint.sh
# И Π² ΠΊΠΎΠ½Ρ†Π΅ Π·Π°Π±ΠΈΡ€Π°Π΅ΠΌ само ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
COPY --from=builder /app/dist/app /etc/nginx/html/
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

Π‘Π°Π΄Π° сС добијСна слика ΠΌΠΎΠΆΠ΅ саставити ΠΈ користити Π±ΠΈΠ»ΠΎ Π³Π΄Π΅.

Π˜Π·Π²ΠΎΡ€: Π²Π²Π².Ρ…Π°Π±Ρ€.Ρ†ΠΎΠΌ