diff --git a/config/webpack.dev.js b/config/webpack.dev.js index 972ea2752..ea0a709a1 100644 --- a/config/webpack.dev.js +++ b/config/webpack.dev.js @@ -1,4 +1,5 @@ const Dotenv = require("dotenv-webpack"); +const CopyPlugin = require('copy-webpack-plugin'); const Webpack = require("webpack"); const { GenerateSW } = require("workbox-webpack-plugin"); const fs = require("fs"); @@ -13,12 +14,12 @@ module.exports = { open: true, port: "3000", historyApiFallback: true, - // https: { + //https: { // DEV.NOTE: uncomment and change names of files according to your generated ones - // key: fs.readFileSync("cert\\localhost+1-key.pem"), - // cert: fs.readFileSync("cert\\localhost+1.pem"), - // }, + //key: fs.readFileSync("cert\\localhost+1-key.pem"), + //cert: fs.readFileSync("cert\\localhost+1.pem"), + //}, }, module: { rules: require("./webpack.rules"), @@ -38,53 +39,57 @@ module.exports = { new Dotenv({ path: `./.env`, }), - // new GenerateSW({ - // skipWaiting: true, - // clientsClaim: true, - // maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, - // runtimeCaching: [ - // { - // urlPattern: /\.(?:js|css)$/, - // handler: 'CacheFirst', - // options: { - // cacheName: 'static-resources', - // expiration: { - // maxAgeSeconds: 60 * 60 * 24 * 7, // 1 week - // }, - // }, - // }, - // { - // urlPattern: /\.(?:png|jpg|jpeg|svg|gif)$/, - // handler: 'CacheFirst', - // options: { - // cacheName: 'image-resources', - // expiration: { - // maxAgeSeconds: 60 * 60 * 24 * 7, // 1 week - // }, - // }, - // }, - // { - // urlPattern: /\.(?:woff|woff2|ttf|otf)$/, - // handler:'CacheFirst', - // options: { - // cacheName: 'font-resources', - // expiration: { - // maxAgeSeconds: 60 * 60 * 24 * 90, // 3 months - // }, - // }, - // }, - // { - // urlPattern: /^https?.*/, - // handler: 'NetworkFirst', - // options: { - // cacheName: 'external-resources', - // expiration: { - // maxEntries: 260 - // }, - // }, - // }, - // ], - // }), + new GenerateSW({ + skipWaiting: true, + clientsClaim: true, + maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, + runtimeCaching: [ + { + urlPattern: /env-config\.js$/, + handler: 'NetworkOnly' + }, + { + urlPattern: /\.(?:js|css)$/, + handler: 'CacheFirst', + options: { + cacheName: 'static-resources', + expiration: { + maxAgeSeconds: 60 * 60 * 24 * 7, // 1 week + }, + }, + }, + { + urlPattern: /\.(?:png|jpg|jpeg|svg|gif)$/, + handler: 'CacheFirst', + options: { + cacheName: 'image-resources', + expiration: { + maxAgeSeconds: 60 * 60 * 24 * 7, // 1 week + }, + }, + }, + { + urlPattern: /\.(?:woff|woff2|ttf|otf)$/, + handler:'CacheFirst', + options: { + cacheName: 'font-resources', + expiration: { + maxAgeSeconds: 60 * 60 * 24 * 90, // 3 months + }, + }, + }, + { + urlPattern: /^https?.*/, + handler: 'NetworkFirst', + options: { + cacheName: 'external-resources', + expiration: { + maxEntries: 260 + }, + }, + }, + ], + }), ], optimization: { splitChunks: { diff --git a/config/webpack.prod.js b/config/webpack.prod.js index 7063db33d..c39d6c22b 100644 --- a/config/webpack.prod.js +++ b/config/webpack.prod.js @@ -52,6 +52,10 @@ module.exports = { clientsClaim: true, maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, runtimeCaching: [ + { + urlPattern: /env-config\.js$/, + handler: 'NetworkOnly' + }, { urlPattern: /\.(?:js|css)$/, handler: 'NetworkFirst', diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 7d0eeeb47..000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,99 +0,0 @@ -services: - certbot: - restart: always - image: certbot/certbot:latest - volumes: - - /etc/certbot/www/:/var/www/certbot/:rw - - /etc/certbot/conf/:/etc/letsencrypt/:rw - - nginx: - restart: always - image: nginx:latest - ports: - - "80:80" - - "443:443" - environment: - FRONTEND_SERVER_NAME: ${FRONTEND_SERVER_NAME} - BACKEND_SERVER_NAME: ${BACKEND_SERVER_NAME} - volumes: - - ./templates:/etc/nginx/templates - - /etc/certbot/www:/var/www/certbot/:ro - - /etc/certbot/conf:/etc/nginx/ssl/:ro - - - loki: - restart: always - container_name: loki - image: grafana/loki:latest - ports: - - "3100:3100" - command: -config.file=/etc/loki/local-config.yaml - volumes: - - ./loki/config:/etc/loki - - frontend: - restart: always - image: streetcodeua/streetcode_client:${DOCKER_TAG_FRONTEND} - pull_policy: always - expose: - - "80" - healthcheck: - test: curl --fail http://localhost || exit 1 - interval: 30s - timeout: 10s - retries: 5 - environment: - API_URL: ${ENV_API_BACKEND} - REACT_APP_GOOGLE_ANALYTICS: ${ENV_GOOGLE_ANALYTICS} - RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY} - logging: - driver: loki - options: - loki-url: "http://localhost:3100/loki/api/v1/push" - - backend: - restart: always - image: streetcodeua/streetcode:${DOCKER_TAG_BACKEND} - pull_policy: always - expose: - - "80" - environment: - STREETCODE_ConnectionStrings__DefaultConnection: ${DB_CONNECTION_STRING} - STREETCODE_Blob__BlobStoreKey: ${BLOB_STORAGE_KEY} - STREETCODE_Blob__BlobStorePath: /mnt/data/ - STREETCODE_Instagram__InstagramID: ${INSTAGRAM_ID} - STREETCODE_Instagram__InstagramToken: ${INSTAGRAM_TOKEN} - STREETCODE_Payment__Token: ${PAYMENT_TOKEN} - STREETCODE_EMAILCONFIGURATION__PASSWORD: ${EMAIL_PASSWORD} - STREETCODE_RECAPTCHA__SECRETKEY: ${RECAPTCHA_SECRET_KEY} - STREETCODE_CORS__AllowedOrigins: ${CORS_ALLOWED_ORIGINS} - STREETCODE_CORS__AllowedHeaders: ${CORS_ALLOWED_HEADERS} - STREETCODE_CORS__AllowedMethods: ${CORS_ALLOWED_METHODS} - STREETCODE_CORS__ExposedHeaders: ${CORS_EXPOSED_HEADERS} - STREETCODE_CORS__PreflightMaxAge: "600" - STREETCODE_IPRATELIMITING__GENERALRULES__0__LIMIT: 500 - ASPNETCORE_ENVIRONMENT: ${SWAGGER_APP_ENVIRONMENT} - volumes: - - type: bind - source: /imagestorage - target: /mnt/data - healthcheck: - test: curl --fail http://localhost/api/partners/getAll || exit 1 - interval: 30s - timeout: 10s - retries: 5 - extra_hosts: - - "host.docker.internal:host-gateway" - logging: - driver: loki - options: - loki-url: "http://localhost:3100/loki/api/v1/push" -volumes: - backend: -networks: - backend: - external: - name: backend - frontend: - external: - name: frontend diff --git a/public/env-config.js b/public/env-config.js index 111a97b97..fbd5c3254 100644 --- a/public/env-config.js +++ b/public/env-config.js @@ -3,4 +3,5 @@ window._env_ = { API_URL: "https://stageback.streetcode.com.ua/api", REACT_APP_GOOGLE_ANALYTICS: "REACT_APP_GOOGLE_ANALYTICS_VALUE", RECAPTCHA_SITE_KEY: "6LeUO3ApAAAAAOC7F4v0qTsSwIR9mZu33SWjAAtM", + VERSION: "1.0.0" } diff --git a/src/app/common/components/withClearCache.tsx b/src/app/common/components/withClearCache.tsx new file mode 100644 index 000000000..84f3fe966 --- /dev/null +++ b/src/app/common/components/withClearCache.tsx @@ -0,0 +1,35 @@ +/* eslint-disable no-underscore-dangle */ +import { Component, useEffect, useState } from 'react'; + +const WithClearCache: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [isLatestBuildDate, setIsLatestBuildDate] = useState(false); + + const refreshCacheAndReload = () => { + if (caches) { + caches.keys().then((names) => { + for (const name of names) { + caches.delete(name); + } + }); + console.log("Cache is cleared") + } + window.location.reload(); + }; + + useEffect(() => { + const localVersion = localStorage.getItem('VERSION'); + const isVersionMatches = localVersion === window._env_.VERSION; + setIsLatestBuildDate(isVersionMatches); + if (!isVersionMatches) { + localStorage.setItem('VERSION', window._env_.VERSION); + refreshCacheAndReload(); + } + }, []); + + if (isLatestBuildDate) { + return children; + } + return null; +}; + +export default WithClearCache; diff --git a/src/index.tsx b/src/index.tsx index c3bf711c2..a1524593b 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,6 +8,7 @@ import { RouterProvider } from 'react-router-dom'; import router from '@app/router/Routes'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import WithClearCache from './app/common/components/withClearCache'; declare global { interface Window { @@ -16,6 +17,7 @@ declare global { SERVER_API_URL: string; REACT_APP_GOOGLE_ANALYTICS: string; RECAPTCHA_SITE_KEY: string; + VERSION: string; }; } } @@ -39,10 +41,12 @@ const root = ReactDOM.createRoot( const queryClient = new QueryClient(); root.render( - - - - - - , + + + + + + + + , );