From 4485a1051439c2c03f43cb9719091f64b902a275 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sat, 5 Jul 2025 08:18:15 +0500 Subject: [PATCH] hot reload (#24) * container with hot reload * update readme --- .env | 11 ++ .github/workflows/build.yml | 8 +- Dockerfile | 53 +++---- Dockerfile.prod | 51 +++++++ README.md | 75 +++++----- docker-compose.prod.yml | 140 +++++++++++++++++++ docker-compose.yml | 136 +++--------------- tools/{language.patch => patches/lang.patch} | 0 tools/patches/vite.patch | 35 +++++ 9 files changed, 312 insertions(+), 197 deletions(-) create mode 100644 .env create mode 100644 Dockerfile.prod create mode 100644 docker-compose.prod.yml rename tools/{language.patch => patches/lang.patch} (100%) create mode 100644 tools/patches/vite.patch diff --git a/.env b/.env new file mode 100644 index 0000000..2557328 --- /dev/null +++ b/.env @@ -0,0 +1,11 @@ +APP_PATH=/opt/outline +SRC_PATH=./outline + +ADDRESS=localhost +PORT_OUTLINE=10240 +PORT_OIDC=10241 +PORT_REDIS=10242 +PORT_POSTGRES=10243 + +COMMON=outline +SECRET=deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3c45460..91e0bc5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,8 +9,8 @@ on: - .github/workflows/** - outline/** - tools/translation.json - - tools/language.patch - - Dockerfile + - tools/patches/** + - Dockerfile.prod workflow_dispatch: concurrency: @@ -79,6 +79,10 @@ jobs: cache-from: type=gha,scope=build-${{ matrix.arch }} cache-to: type=gha,mode=max,scope=build-${{ matrix.arch }} platforms: linux/${{ matrix.arch }} + file: Dockerfile.prod + build-args: | + APP_PATH=/opt/outline + SRC_PATH=./outline labels: ${{ steps.metadata.outputs.labels }} outputs: type=image,"name=${{ github.repository }},ghcr.io/${{ github.repository }}",push-by-digest=true,name-canonical=true,push=true diff --git a/Dockerfile b/Dockerfile index b455062..9217b90 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,14 @@ -ARG APP_PATH=/opt/outline -ARG SRC_PATH=./outline - -FROM node:20 AS deps +FROM node:20 AS base ARG APP_PATH ARG SRC_PATH WORKDIR $APP_PATH + +FROM base AS deps COPY ${SRC_PATH}/package.json ${SRC_PATH}/yarn.lock ./ RUN yarn install --production=true --frozen-lockfile --network-timeout 1000000 && \ yarn cache clean -FROM node:20 AS build -ARG APP_PATH -ARG SRC_PATH -WORKDIR $APP_PATH +FROM base AS build RUN apt-get update && \ apt-get install -y patch cmake && \ rm -rf /var/lib/apt/lists/* @@ -22,35 +18,18 @@ ENV NODE_OPTIONS="--max-old-space-size=24000" RUN yarn install --no-optional --frozen-lockfile --network-timeout 1000000 && \ yarn cache clean COPY ${SRC_PATH} . -COPY ./tools/language.patch . -RUN patch -p1 < language.patch -COPY ./tools/translation.json ./shared/i18n/locales/ru_RU/translation.json +COPY --from=deps $APP_PATH/node_modules ./node_modules +COPY ./tools/patches/* . +RUN for patch in $(ls *.patch); do patch -p1 < $patch; done +RUN cat < /entrypoint.sh +npx yarn concurrently -n "dev,i18n" \ + "yarn dev:watch" \ + "yarn nodemon \ + --watch './shared/i18n/locales/ru_RU' \ + --exec 'yarn build:i18n'" +EOF ARG CDN_URL -RUN yarn build && rm -rf node_modules - -FROM node:22-slim AS release -ARG APP_PATH -ARG SRC_PATH -WORKDIR $APP_PATH -RUN apt-get update && \ - apt-get install -y curl && \ - rm -rf /var/lib/apt/lists/* ARG DATA_PATH=/var/lib/outline/data -ARG USER=nodejs -RUN useradd -m -U ${USER} && \ - mkdir -p ${DATA_PATH} && \ - chown -R ${USER}:${USER} ${APP_PATH} ${DATA_PATH}/.. && \ - chmod 1777 ${DATA_PATH} -COPY --chown=${USER} --from=deps $APP_PATH/node_modules ./node_modules -COPY --chown=${USER} --from=build $APP_PATH/build ./build -COPY --chown=${USER} --from=build $APP_PATH/server ./server -COPY --chown=${USER} --from=build $APP_PATH/public ./public -COPY --chown=${USER} --from=build $APP_PATH/.sequelizerc . -COPY --chown=${USER} --from=build $APP_PATH/package.json . -ENV NODE_ENV=production -ENV PORT=3000 -USER ${USER} -EXPOSE ${PORT} VOLUME ${DATA_PATH} -HEALTHCHECK --interval=1m CMD curl -fs localhost:${PORT}/_health | grep -q OK || exit 1 -CMD ["yarn", "start"] +STOPSIGNAL SIGKILL +ENTRYPOINT ["bash", "/entrypoint.sh"] diff --git a/Dockerfile.prod b/Dockerfile.prod new file mode 100644 index 0000000..05e8a1f --- /dev/null +++ b/Dockerfile.prod @@ -0,0 +1,51 @@ +FROM node:20 AS base +ARG APP_PATH +ARG SRC_PATH +WORKDIR $APP_PATH + +FROM base AS deps +COPY ${SRC_PATH}/package.json ${SRC_PATH}/yarn.lock ./ +RUN yarn install --production=true --frozen-lockfile --network-timeout 1000000 && \ + yarn cache clean + +FROM base AS build +RUN apt-get update && \ + apt-get install -y patch cmake && \ + rm -rf /var/lib/apt/lists/* +COPY ${SRC_PATH}/patches ./patches +COPY ${SRC_PATH}/package.json ${SRC_PATH}/yarn.lock ./ +ENV NODE_OPTIONS="--max-old-space-size=24000" +RUN yarn install --no-optional --frozen-lockfile --network-timeout 1000000 && \ + yarn cache clean +COPY ${SRC_PATH} . +COPY ./tools/patches/lang.patch . +RUN for patch in $(ls *.patch); do patch -p1 < $patch; done +COPY ./tools/translation.json ./shared/i18n/locales/ru_RU/translation.json +ARG CDN_URL +RUN yarn build && rm -rf node_modules + +FROM node:22-slim AS release +RUN apt-get update && \ + apt-get install -y curl && \ + rm -rf /var/lib/apt/lists/* +ARG DATA_PATH=/var/lib/outline/data +ARG USER=nodejs +ARG APP_PATH +WORKDIR $APP_PATH +RUN useradd -m -U ${USER} && \ + mkdir -p ${DATA_PATH} && \ + chown -R ${USER}:${USER} ${APP_PATH} ${DATA_PATH}/.. && \ + chmod 1777 ${DATA_PATH} +COPY --chown=${USER} --from=deps $APP_PATH/node_modules ./node_modules +COPY --chown=${USER} --from=build $APP_PATH/build ./build +COPY --chown=${USER} --from=build $APP_PATH/server ./server +COPY --chown=${USER} --from=build $APP_PATH/public ./public +COPY --chown=${USER} --from=build $APP_PATH/.sequelizerc . +COPY --chown=${USER} --from=build $APP_PATH/package.json . +ENV NODE_ENV=production +ENV PORT=3000 +USER ${USER} +EXPOSE ${PORT} +VOLUME ${DATA_PATH} +HEALTHCHECK --interval=1m CMD curl -fs localhost:${PORT}/_health | grep -q OK || exit 1 +CMD ["yarn", "start"] diff --git a/README.md b/README.md index 3e04913..6e7de83 100644 --- a/README.md +++ b/README.md @@ -35,23 +35,48 @@ services: ## πŸ› οΈ Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° +### ΠšΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ + +- русский ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ β€” [tools/translation.json](./tools/translation.json) +- английский ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ β€” [outline/shared/i18n/locales/en_US/translation.json](https://github.com/outline/outline/blob/main/shared/i18n/locales/en_US/translation.json) +- Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» β€” [tools/translation.tmp.json]() (сущСствуСт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ локально) + +### Быстрый старт + +0. ΠšΠ»ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ рСпозитория с ΠΏΠΎΠ΄ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ: + ```sh + git clone --recurse-submodules git@github.com:flameshikari/outline-ru.git + ``` + +1. ΠŸΡƒΠ»Π» ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² ΠΏΠΎΠ΄ΠΌΠΎΠ΄ΡƒΠ»Π΅ ΠΈ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π½Π° ΠΊΠΎΠΌΠΌΠΈΡ‚ с Ρ†Π΅Π»Π΅Π²ΠΎΠΉ вСрсиСй: + ```sh + cd outline + git pull --rebase --tags + git checkout v0.85.0 + cd - + ``` + +2. Запуск ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠ²: + ```sh + docker compose up -d --build + ``` + Π’Π΅Π±-интСрфСйс Outline Π±ΡƒΠ΄Π΅Ρ‚ доступСн ΠΏΠΎ [этой ссылкС](http://localhost:10240). + +3. Π€ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ [tools/diff.py](./tools/diff.py): + ```sh + python tools/diff.py + ``` + ПослС ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΈΡΡ‚ΡƒΠΏΠΈΡ‚ΡŒ ΠΊ ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Ρƒ сфомированного Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π°. Π›ΡŽΠ±Ρ‹Π΅ измСнСния Π² русском ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π΅ обновят [ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡƒΡŽ Π²Π΅Π±-страницу](http://localhost:10240) Ρ‡Π΅Ρ€Π΅Π· ΠΏΠ°Ρ€Ρƒ сСкунд. + ### ОписаниС -ΠšΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ Outline описан Π² ΠΎΠ΄Π½ΠΎΠΌ [Dockerfile](./Dockerfile) Π½Π° основС Π΄Π²ΡƒΡ… ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹Ρ… с ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ΠΌ [ΠΏΠ°Ρ‚Ρ‡Π°](./tools/language.patch) ΠΏΠΎΠ²Π΅Ρ€Ρ… исходного ΠΊΠΎΠ΄Π° Outline (ΠΎΠ½ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ ΠΊ этому Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΡŽ Π² качСствС подмодуля) ΠΈ ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ [Ρ„Π°ΠΉΠ»Π° ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π°](./tools/translation.json). ΠŸΠ°Ρ‚Ρ‡, ΠΏΠΎΠΌΠΈΠΌΠΎ добавлСния ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΡ… строк Π² ΠΊΠΎΠ΄, мСняСт Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ upstream-ссылки, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Outline ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ» этот ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ Π½Π° Π½Π°Π»ΠΈΡ‡ΠΈΠ΅ Π½ΠΎΠ²Ρ‹Ρ… вСрсий, Π° Π½Π΅ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ. - -Π’ [docker-compose.yml](./docker-compose.yml) описаны Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° (ΠΊΠ»ΠΈΠΊΠ°Π±Π΅Π»ΡŒΠ½Ρ‹Π΅ названия Π΄Π°Π»Π΅Π΅ β€” это localhost-ссылки): [Outline](http://localhost:10240), Redis, Postgres ΠΈ [тСстовый OIDC-сСрвСр](http://localhost:10241) (Π»ΠΎΠ³ΠΈΠ½/ΠΏΠ°Ρ€ΠΎΠ»ΡŒ: `outline`). Π’Π°ΠΊΠΆΠ΅ Ρ‚Π°ΠΌ описана вся конфигурация ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠ²; настраивайтС ΠΏΠΎΠ΄ сСбя ΠΏΠΎ ТСланию. ПослС ΠΏΠ΅Ρ€Π²ΠΎΠΉ сборки ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ слоёв бСрётся ΠΈΠ· кэша, сам Outline послС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ пСрСсобираСтся ΠΎΠΊΠΎΠ»ΠΎ ΠΏΠΎΠ»ΠΌΠΈΠ½ΡƒΡ‚Ρ‹-ΠΌΠΈΠ½ΡƒΡ‚Ρ‹ (Ρ‚ΡƒΡ‚ зависит ΠΎΡ‚ ΠΆΠ΅Π»Π΅Π·Π°). Пайплайн ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊΠΎΠΉ: ΠΏΠ΅Ρ€Π΅Π²Ρ‘Π» β†’ собрал β†’ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠ». - -Π‘ΠΊΡ€ΠΈΠΏΡ‚ [diff.py](./tools/diff.py) ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для объСдинСния ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΎΠ² [английского](https://github.com/outline/outline/blob/main/shared/i18n/locales/en_US/translation.json) с [русским](./tools/translation.json) Π²ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» `./tools/translation.tmp.json`. Π‘ΠΊΡ€ΠΈΠΏΡ‚ Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ° ΠΈ ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²/ΠΎΠΏΡ†ΠΈΠΉ, ΠΎΠ½ просто запускаСтся (с Π²Ρ‹Π²ΠΎΠ΄ΠΎΠΌ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ) ΠΈ Π΄Π΅Π»Π°Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅: +Π‘ΠΊΡ€ΠΈΠΏΡ‚ [tools/diff.py](./tools/diff.py) ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для объСдинСния английского ΠΈ русского ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΎΠ² Π²ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ». Π‘ΠΊΡ€ΠΈΠΏΡ‚ Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ° ΠΈ ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²/ΠΎΠΏΡ†ΠΈΠΉ, ΠΎΠ½ просто запускаСтся (с Π²Ρ‹Π²ΠΎΠ΄ΠΎΠΌ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ) ΠΈ Π΄Π΅Π»Π°Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅: - сохраняСт Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅Π²Π΅Π΄Ρ‘Π½Π½Ρ‹Π΅ строки - удаляСт Π½Π΅Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅Π²Π΅Π΄Ρ‘Π½Π½Ρ‹Π΅ строки -- Ссли Π² Ρ„Π°ΠΉΠ»Π΅ ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° Π΅ΡΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Π΅ key/value ΠΏΠ°Ρ€Ρ‹, Ρ‚ΠΎ ΠΎΠ½ΠΈ ΡΡ‡ΠΈΡ‚Π°ΡŽΡ‚ΡΡ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡΠΌΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, `HTML` ΠΈΠ»ΠΈ `API`) ΠΈ пСрСносятся ΠΊΠ°ΠΊ Π΅ΡΡ‚ΡŒ +- Ссли Π² русском ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π΅ Π΅ΡΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Π΅ key/value ΠΏΠ°Ρ€Ρ‹, Ρ‚ΠΎ ΠΎΠ½ΠΈ ΡΡ‡ΠΈΡ‚Π°ΡŽΡ‚ΡΡ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡΠΌΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, `HTML` ΠΈΠ»ΠΈ `API`) ΠΈ пСрСносятся ΠΊΠ°ΠΊ Π΅ΡΡ‚ΡŒ - Π½ΠΎΠ²Ρ‹Π΅ Π½Π΅ΠΏΠ΅Ρ€Π΅Π²Π΅Π΄Ρ‘Π½Π½Ρ‹Π΅ строки Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ Π² ΠΊΠΎΠ½Π΅Ρ† -> Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, для ΠΊΠΎΠ»Π»Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° стоило ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ [Crowdin](https://crowdin.com), Π½ΠΎ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Ρ€ΡƒΠΊΠΈ Π½Π΅ дошли Β―\\_(ツ)_/Β― - -Π’ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ дСлаСтся ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ Π½ΠΎΠ²Ρ‹Ρ… строк, Π° Π·Π°Ρ‚Π΅ΠΌ [Ρ„Π°ΠΉΠ» ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π°](./tools/translation.json) Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ замСняСтся Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌ Ρ„Π°ΠΉΠ»ΠΎΠΌ. - > Если Π²ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ ΠΏΡ€ΠΈΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‚ Π΄Π²Π΅ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Π΅ Π½Π΅ΠΏΠ΅Ρ€Π΅Π²Π΅Π΄Ρ‘Π½Π½Ρ‹Π΅ строки, Π½ΠΎ ΠΎΠ΄Π½Π° ΠΈΠ· Π½ΠΈΡ… с суффиксом `_plural` (мноТСствСнноС число), Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€: > > ```json @@ -69,33 +94,3 @@ services: > "{{ count }} comment_2": "{{ count }} ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠ΅Π²" > } > ``` - -### ΠšΠΎΠΌΠ°Π½Π΄Ρ‹ - -0. ΠšΠ»ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ рСпозитория с ΠΏΠΎΠ΄ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ - ```sh - git clone --recurse-submodules git@github.com:flameshikari/outline-ru.git - ``` - -1. ΠŸΡƒΠ»Π» ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² ΠΏΠΎΠ΄ΠΌΠΎΠ΄ΡƒΠ»Π΅ ΠΈ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π½Π° ΠΊΠΎΠΌΠΌΠΈΡ‚ с Ρ†Π΅Π»Π΅Π²ΠΎΠΉ вСрсиСй - ```sh - cd outline - git pull --rebase --tags - git checkout v0.85.0 - cd - - ``` - -2. Π€ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ [diff.py](./tools/diff.py) - ```sh - python ./tools/diff.py - ``` - -3. Π—Π°ΠΌΠ΅Π½Π° [Ρ„Π°ΠΉΠ»Π° ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π°](./tools/translation.json) послС ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Π° строк Π²ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ - ``` - cp ./tools/translation.tmp.json ./tools/translation.json - ``` - -4. Π‘Π±ΠΎΡ€ΠΊΠ° ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° - ```sh - docker compose up -d --build - ``` \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..b562f83 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,140 @@ +volumes: + outline: + name: outline + outline-postgres: + name: outline-postgres + +networks: + default: + name: outline + +services: + outline: + container_name: outline + image: flameshikari/outline-ru:nightly + build: + context: . + dockerfile: Dockerfile.prod + args: + - APP_PATH=${APP_PATH} + - SRC_PATH=${SRC_PATH} + network_mode: host + pull_policy: always + volumes: + - outline:/var/lib/outline/data + depends_on: + - outline-postgres + - outline-redis + - outline-oidc + environment: + FILE_STORAGE: local + FORCE_HTTPS: false + PORT: ${PORT_OUTLINE} + URL: http://${ADDRESS}:${PORT_OUTLINE} + SECRET_KEY: ${SECRET} + UTILS_SECRET: ${SECRET} + REDIS_URL: redis://${ADDRESS}:${PORT_REDIS} + DATABASE_URL: postgres://${COMMON}:${COMMON}@${ADDRESS}:${PORT_POSTGRES}/${COMMON} + PGSSLMODE: disable + OIDC_ISSUER_URL: http://${ADDRESS}:${PORT_OIDC} + OIDC_CLIENT_ID: ${COMMON} + OIDC_CLIENT_SECRET: ${COMMON} + + outline-oidc: + container_name: outline-oidc + image: ghcr.io/soluto/oidc-server-mock:0.11.0 + ports: + - ${PORT_OIDC}:80 + healthcheck: + test: curl -fs ${ADDRESS}/health || exit 1 + start_period: 2s + interval: 1s + timeout: 100ms + retries: 10 + environment: + ASPNETCORE_URLS: http://+:80 + ASPNETCORE_ENVIRONMENT: Development + CLIENTS_CONFIGURATION_INLINE: | + [ + { + "ClientId": "${COMMON}", + "ClientSecrets": ["${COMMON}"], + "RedirectUris": ["http://${ADDRESS}:${PORT_OUTLINE}/auth/oidc.callback"], + "AllowedGrantTypes": ["authorization_code"], + "AllowedScopes": ["openid", "profile", "email"], + "RequirePkce": false + } + ] + USERS_CONFIGURATION_INLINE: | + [ + { + "SubjectId": "1", + "Username": "${COMMON}", + "Password": "${COMMON}", + "Claims": [ + { + "Type": "email", + "Value": "mail@example.com", + "ValueType": "string" + }, + { + "Type": "name", + "Value": "Outline", + "ValueType": "string" + } + ] + } + ] + SERVER_OPTIONS_INLINE: | + { + "AccessTokenJwtType": "JWT", + "Discovery": { + "ShowKeySet": true + }, + "Authentication": { + "CookieSameSiteMode": "Lax", + "CheckSessionCookieSameSiteMode": "Lax" + } + } + LOGIN_OPTIONS_INLINE: | + { + "AllowRememberLogin": false + } + LOGOUT_OPTIONS_INLINE: | + { + "AutomaticRedirectAfterSignOut": true + } + ASPNET_SERVICES_OPTIONS_INLINE: | + { + "ForwardedHeadersOptions": { + "ForwardedHeaders" : "All" + } + } + + outline-redis: + container_name: outline-redis + image: redis:7 + ports: + - ${PORT_REDIS}:6379 + healthcheck: + test: redis-cli ping + interval: 10s + timeout: 30s + retries: 3 + + outline-postgres: + container_name: outline-postgres + image: postgres:17 + ports: + - ${PORT_POSTGRES}:5432 + volumes: + - outline-postgres:/var/lib/postgresql/data + healthcheck: + test: pg_isready + interval: 30s + timeout: 20s + retries: 3 + environment: + POSTGRES_USER: ${COMMON} + POSTGRES_PASSWORD: ${COMMON} + POSTGRES_DB: ${COMMON} diff --git a/docker-compose.yml b/docker-compose.yml index 9b70612..423e4af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,131 +10,31 @@ networks: services: outline: - container_name: outline - image: flameshikari/outline-ru:nightly - build: . - network_mode: host - pull_policy: always - volumes: - - outline:/var/lib/outline/data + extends: + file: docker-compose.prod.yml + service: outline + image: !reset + pull_policy: !reset + build: + dockerfile: !reset depends_on: - outline-postgres - outline-redis - outline-oidc - environment: - FILE_STORAGE: local - FORCE_HTTPS: false - PORT: 10240 - URL: http://localhost:10240 - SECRET_KEY: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef - UTILS_SECRET: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef - REDIS_URL: redis://localhost:10242 - DATABASE_URL: postgres://outline:outline@localhost:10243/outline - PGSSLMODE: disable - OIDC_ISSUER_URL: http://localhost:10241 - OIDC_CLIENT_ID: outline - OIDC_CLIENT_SECRET: outline - # OIDC_AUTH_URI: http://localhost:10241/connect/authorize - # OIDC_TOKEN_URI: http://localhost:10241/connect/token - # OIDC_USERINFO_URI: http://localhost:10241/connect/userinfo - # OIDC_SCOPES: openid profile email - # OIDC_USERNAME_CLAIM: username + volumes: + - ./tools/translation.json:/opt/outline/shared/i18n/locales/ru_RU/translation.json outline-oidc: - container_name: outline-oidc - image: ghcr.io/soluto/oidc-server-mock:0.11.0 - ports: - - 10241:80 - healthcheck: - test: curl -fs localhost/health || exit 1 - start_period: 2s - interval: 1s - timeout: 100ms - retries: 10 - environment: - ASPNETCORE_URLS: http://+:80 - ASPNETCORE_ENVIRONMENT: Development - CLIENTS_CONFIGURATION_INLINE: | - [ - { - "ClientId": "outline", - "ClientSecrets": ["outline"], - "RedirectUris": ["http://localhost:10240/auth/oidc.callback"], - "AllowedGrantTypes": ["authorization_code"], - "AllowedScopes": ["openid", "profile", "email"], - "RequirePkce": false - } - ] - USERS_CONFIGURATION_INLINE: | - [ - { - "SubjectId": "1", - "Username": "outline", - "Password": "outline", - "Claims": [ - { - "Type": "email", - "Value": "mail@example.com", - "ValueType": "string" - }, - { - "Type": "name", - "Value": "Outline", - "ValueType": "string" - } - ] - } - ] - SERVER_OPTIONS_INLINE: | - { - "AccessTokenJwtType": "JWT", - "Discovery": { - "ShowKeySet": true - }, - "Authentication": { - "CookieSameSiteMode": "Lax", - "CheckSessionCookieSameSiteMode": "Lax" - } - } - LOGIN_OPTIONS_INLINE: | - { - "AllowRememberLogin": false - } - LOGOUT_OPTIONS_INLINE: | - { - "AutomaticRedirectAfterSignOut": true - } - ASPNET_SERVICES_OPTIONS_INLINE: | - { - "ForwardedHeadersOptions": { - "ForwardedHeaders" : "All" - } - } + extends: + file: docker-compose.prod.yml + service: outline-oidc outline-redis: - container_name: outline-redis - image: redis:7 - ports: - - 10242:6379 - healthcheck: - test: redis-cli ping - interval: 10s - timeout: 30s - retries: 3 + extends: + file: docker-compose.prod.yml + service: outline-redis outline-postgres: - container_name: outline-postgres - image: postgres:17 - ports: - - 10243:5432 - volumes: - - outline-postgres:/var/lib/postgresql/data - healthcheck: - test: pg_isready - interval: 30s - timeout: 20s - retries: 3 - environment: - POSTGRES_USER: outline - POSTGRES_PASSWORD: outline - POSTGRES_DB: outline + extends: + file: docker-compose.prod.yml + service: outline-postgres diff --git a/tools/language.patch b/tools/patches/lang.patch similarity index 100% rename from tools/language.patch rename to tools/patches/lang.patch diff --git a/tools/patches/vite.patch b/tools/patches/vite.patch new file mode 100644 index 0000000..e05eb32 --- /dev/null +++ b/tools/patches/vite.patch @@ -0,0 +1,35 @@ +diff --git a/server/routes/index.ts b/server/routes/index.ts +index 26fbded27..478de1922 100644 +--- a/server/routes/index.ts ++++ b/server/routes/index.ts +@@ -103,7 +103,7 @@ router.get("/locales/:lng.json", async (ctx) => { + await send(ctx, path.join(lng, "translation.json"), { + setHeaders: (res, _, stats) => { + res.setHeader("Last-Modified", formatRFC7231(stats.mtime)); +- res.setHeader("Cache-Control", `public, max-age=${7 * Day.seconds}`); ++ res.setHeader("Cache-Control", "no-store"); + res.setHeader( + "ETag", + crypto.createHash("md5").update(stats.mtime.toISOString()).digest("hex") +diff --git a/vite.config.ts b/vite.config.ts +index 32b52d44e..26d611fee 100644 +--- a/vite.config.ts ++++ b/vite.config.ts +@@ -45,6 +45,17 @@ export default () => + : { strict: true }, + }, + plugins: [ ++ { ++ name: 'reload', ++ configureServer(server) { ++ const { ws, watcher } = server; ++ watcher.on('change', file => { ++ if (file.endsWith('build/shared/i18n/locales/ru_RU/translation.json')) { ++ ws.send({ type: 'full-reload' }); ++ } ++ }); ++ }, ++ }, + // https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme + react({ + babel: {