diff --git a/.env b/.env index c305002..a5fd32f 100644 --- a/.env +++ b/.env @@ -1,2 +1,12 @@ ####### USERS ######## USERS_SUPER=["akalinina","vchikalkin"] + +####### Colors ######## +NEXT_PUBLIC_COLOR_PRIMARY= +NEXT_PUBLIC_COLOR_SECONDARY= +NEXT_PUBLIC_COLOR_TERTIARTY= + +####### URLS ######## +NEXT_PUBLIC_URL_GET_USER_DIRECT= +NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT= +NEXT_PUBLIC_URL_CORE_FINGAP_DIRECT= \ No newline at end of file diff --git a/@packages/tools/common.ts b/@packages/tools/common.ts new file mode 100644 index 0000000..421f808 --- /dev/null +++ b/@packages/tools/common.ts @@ -0,0 +1,4 @@ +/* eslint-disable import/prefer-default-export */ +export function isServer() { + return typeof window === 'undefined'; +} diff --git a/Dockerfile b/Dockerfile index ebd73d8..18c781e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,23 +16,10 @@ WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . -ARG NEXT_PUBLIC_BASE_PATH -ARG NEXT_PUBLIC_COLOR_PRIMARY -ARG NEXT_PUBLIC_COLOR_SECONDARY -ARG NEXT_PUBLIC_COLOR_TERTIARTY -ARG NEXT_PUBLIC_FAVICON -ARG NEXT_TELEMETRY_DISABLED -ARG NEXT_PUBLIC_URL_CRM_GRAPHQL_PROXY -ARG NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT -ARG NEXT_PUBLIC_URL_GET_USER_PROXY -ARG NEXT_PUBLIC_URL_GET_USER_DIRECT -ARG NEXT_PUBLIC_URL_CORE_FINGAP_PROXY -ARG NEXT_PUBLIC_URL_CORE_FINGAP_DIRECT - # Next.js collects completely anonymous telemetry data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the build. -# ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_TELEMETRY_DISABLED 1 RUN yarn build @@ -45,7 +32,7 @@ WORKDIR /app ENV NODE_ENV production # Uncomment the following line in case you want to disable telemetry during runtime. -# ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_TELEMETRY_DISABLED 1 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs diff --git a/api/core/query.ts b/api/core/query.ts index 4f42c02..5c39f17 100644 --- a/api/core/query.ts +++ b/api/core/query.ts @@ -1,16 +1,15 @@ /* eslint-disable import/prefer-default-export */ import type { QueryFunctionContext } from '@tanstack/react-query'; import axios from 'axios'; +import getUrls from 'config/urls'; import type { RequestFinGAP, ResponseFinGAP } from './types'; +const { URL_CORE_FINGAP } = getUrls(); + export async function calculateFinGAP(payload: RequestFinGAP, { signal }: QueryFunctionContext) { - const { data } = await axios.post( - process.env.NEXT_PUBLIC_URL_CORE_FINGAP_PROXY!, - payload, - { - signal, - } - ); + const { data } = await axios.post(URL_CORE_FINGAP, payload, { + signal, + }); return data; } diff --git a/api/user/query.ts b/api/user/query.ts index 5605a83..40d89af 100644 --- a/api/user/query.ts +++ b/api/user/query.ts @@ -1,16 +1,14 @@ /* eslint-disable import/prefer-default-export */ import type { AxiosRequestConfig } from 'axios'; import axios from 'axios'; +import getUrls from 'config/urls'; import { love } from './tools'; import type { User } from './types'; -// prettier-ignore -const uri = typeof window === 'undefined' - ? process.env.NEXT_PUBLIC_URL_GET_USER_DIRECT - : process.env.NEXT_PUBLIC_URL_GET_USER_PROXY; +const { URL_GET_USER } = getUrls(); export async function getUser(config: AxiosRequestConfig) { - const user = await axios.get(uri!, config).then((res) => love(res.data)); + const user = await axios.get(URL_GET_USER, config).then((res) => love(res.data)); return user; } diff --git a/apollo/client.js b/apollo/client.js index 1fb0e6d..ef8319b 100644 --- a/apollo/client.js +++ b/apollo/client.js @@ -1,19 +1,18 @@ /* eslint-disable no-underscore-dangle */ /* eslint-disable @typescript-eslint/naming-convention */ import { ApolloClient, InMemoryCache } from '@apollo/client'; +import getUrls from 'config/urls'; +import { isServer } from 'tools/common'; /** @type {import('@apollo/client').ApolloClient} */ let apolloClient; -// prettier-ignore -const uri = typeof window === 'undefined' - ? process.env.NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT - : process.env.NEXT_PUBLIC_URL_CRM_GRAPHQL_PROXY; +const { URL_CRM_GRAPHQL } = getUrls(); function createApolloClient() { return new ApolloClient({ - ssrMode: typeof window === 'undefined', - uri, + ssrMode: isServer(), + uri: URL_CRM_GRAPHQL, cache: new InMemoryCache(), }); } @@ -27,7 +26,7 @@ export default function initializeApollo(initialState = null) { _apolloClient.cache.restore(initialState); } // For SSG and SSR always create a new Apollo Client - if (typeof window === 'undefined') return _apolloClient; + if (isServer()) return _apolloClient; // Create the Apollo Client once in the client if (!apolloClient) apolloClient = _apolloClient; diff --git a/config/schema/env.js b/config/schema/env.js new file mode 100644 index 0000000..72fbfe8 --- /dev/null +++ b/config/schema/env.js @@ -0,0 +1,14 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { z } = require('zod'); + +const envSchema = z.object({ + NEXT_PUBLIC_BASE_PATH: z.string().optional(), + NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT: z.string(), + NEXT_PUBLIC_URL_GET_USER_DIRECT: z.string(), + NEXT_PUBLIC_URL_CORE_FINGAP_DIRECT: z.string(), + NEXT_PUBLIC_COLOR_PRIMARY: z.string(), + NEXT_PUBLIC_COLOR_SECONDARY: z.string(), + NEXT_PUBLIC_COLOR_TERTIARTY: z.string(), +}); + +module.exports = envSchema; diff --git a/config/schema/runtime-config.js b/config/schema/runtime-config.js new file mode 100644 index 0000000..0dbb9bb --- /dev/null +++ b/config/schema/runtime-config.js @@ -0,0 +1,20 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const envSchema = require('./env'); + +const publicRuntimeConfigSchema = envSchema.pick({ + NEXT_PUBLIC_BASE_PATH: true, + NEXT_PUBLIC_COLOR_PRIMARY: true, + NEXT_PUBLIC_COLOR_SECONDARY: true, + NEXT_PUBLIC_COLOR_TERTIARTY: true, +}); + +const serverRuntimeConfigSchema = envSchema.pick({ + NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT: true, + NEXT_PUBLIC_URL_GET_USER_DIRECT: true, + NEXT_PUBLIC_URL_CORE_FINGAP_DIRECT: true, +}); + +module.exports = { + publicRuntimeConfigSchema, + serverRuntimeConfigSchema, +}; diff --git a/config/urls.ts b/config/urls.ts new file mode 100644 index 0000000..89403e8 --- /dev/null +++ b/config/urls.ts @@ -0,0 +1,36 @@ +import urls from 'constants/urls'; +import getConfig from 'next/config'; +import { isServer } from 'tools/common'; +import { publicRuntimeConfigSchema, serverRuntimeConfigSchema } from './schema/runtime-config'; + +const { serverRuntimeConfig, publicRuntimeConfig } = getConfig(); + +function getUrls() { + if (isServer()) { + const { + NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT, + NEXT_PUBLIC_URL_GET_USER_DIRECT, + NEXT_PUBLIC_URL_CORE_FINGAP_DIRECT, + } = serverRuntimeConfigSchema.parse(serverRuntimeConfig); + + return { + URL_CRM_GRAPHQL: NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT, + URL_GET_USER: NEXT_PUBLIC_URL_GET_USER_DIRECT, + URL_CORE_FINGAP: NEXT_PUBLIC_URL_CORE_FINGAP_DIRECT, + }; + } + + const { NEXT_PUBLIC_BASE_PATH = '' } = publicRuntimeConfigSchema.parse(publicRuntimeConfig); + + function withBasePath(url: string) { + return NEXT_PUBLIC_BASE_PATH + url; + } + + return { + URL_CRM_GRAPHQL: withBasePath(urls.URL_CRM_GRAPHQL_PROXY), + URL_GET_USER: withBasePath(urls.URL_GET_USER_PROXY), + URL_CORE_FINGAP: withBasePath(urls.URL_CORE_FINGAP_PROXY), + }; +} + +export default getUrls; diff --git a/constants/urls.js b/constants/urls.js new file mode 100644 index 0000000..ff1491a --- /dev/null +++ b/constants/urls.js @@ -0,0 +1,5 @@ +module.exports = { + URL_GET_USER_PROXY: '/api/auth/user', + URL_CRM_GRAPHQL_PROXY: '/api/graphql/crm', + URL_CORE_FINGAP_PROXY: '/api/core/fingap', +}; diff --git a/mocks/handlers.js b/mocks/handlers.js index 1940b91..15a2b83 100644 --- a/mocks/handlers.js +++ b/mocks/handlers.js @@ -1,3 +1,4 @@ +import getUrls from 'config/urls'; import { rest } from 'msw'; const _ = require('radash'); @@ -22,11 +23,13 @@ const users = { }, }; +const { URL_GET_USER, URL_CORE_FINGAP, URL_CRM_GRAPHQL } = getUrls(); + export const handlers = [ - rest.get(process.env.NEXT_PUBLIC_URL_GET_USER_DIRECT, (req, res, ctx) => { + rest.get(URL_GET_USER, (req, res, ctx) => { return res(ctx.json(users.vchikalkin)); }), - rest.post(process.env.NEXT_PUBLIC_URL_CORE_FINGAP_PROXY, (req, res, ctx) => { + rest.post(URL_CORE_FINGAP, (req, res, ctx) => { return res( ctx.json({ sum: _.random(100000, 200000), @@ -34,7 +37,7 @@ export const handlers = [ }) ); }), - // rest.post(process.env.NEXT_PUBLIC_URL_CRM_GRAPHQL_PROXY, (req, res, ctx) => { + // rest.post(URL_CRM_GRAPHQL, (req, res, ctx) => { // return res(ctx.status(503)); // }), ]; diff --git a/mocks/index.js b/mocks/index.js index 6f36a3f..b3d8372 100644 --- a/mocks/index.js +++ b/mocks/index.js @@ -1,4 +1,6 @@ -if (typeof window === 'undefined') { +const { isServer } = require('tools/common'); + +if (isServer()) { const { server } = require('./server'); server.listen(); } else { diff --git a/next.config.js b/next.config.js index 5285a2e..ec0b7fe 100644 --- a/next.config.js +++ b/next.config.js @@ -3,7 +3,13 @@ const { withPlugins } = require('next-composed-plugins'); const withLess = require('next-with-less'); const withGraphQL = require('next-plugin-graphql'); +const envSchema = require('./config/schema/env'); +const urls = require('./constants/urls'); const { devices } = require('./@packages/ui/screens'); +const { publicRuntimeConfigSchema } = require('./config/schema/runtime-config'); +const { serverRuntimeConfigSchema } = require('./config/schema/runtime-config'); + +const env = envSchema.parse(process.env); /** @type {import('next').NextConfig} */ const nextConfig = { @@ -20,24 +26,24 @@ const nextConfig = { images: { deviceSizes: devices, }, - rewrites: - process.env.NODE_ENV === 'development' && - async function rewrites() { - return [ - { - source: process.env.NEXT_PUBLIC_URL_CRM_GRAPHQL_PROXY, - destination: process.env.NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT, - }, - { - source: process.env.NEXT_PUBLIC_URL_GET_USER_PROXY, - destination: process.env.NEXT_PUBLIC_URL_GET_USER_DIRECT, - }, - { - source: process.env.NEXT_PUBLIC_URL_CORE_FINGAP_PROXY, - destination: process.env.NEXT_PUBLIC_URL_CORE_FINGAP_DIRECT, - }, - ]; - }, + async rewrites() { + return [ + { + source: urls.URL_CRM_GRAPHQL_PROXY, + destination: env.NEXT_PUBLIC_URL_CRM_GRAPHQL_DIRECT, + }, + { + source: urls.URL_GET_USER_PROXY, + destination: env.NEXT_PUBLIC_URL_GET_USER_DIRECT, + }, + { + source: urls.URL_CORE_FINGAP_PROXY, + destination: env.NEXT_PUBLIC_URL_CORE_FINGAP_DIRECT, + }, + ]; + }, + publicRuntimeConfig: publicRuntimeConfigSchema.parse(env), + serverRuntimeConfig: serverRuntimeConfigSchema.parse(env), }; const plugins = [withLess, withGraphQL]; @@ -47,7 +53,7 @@ const config = { lessLoaderOptions: { lessOptions: { modifyVars: { - 'primary-color': process.env.NEXT_PUBLIC_COLOR_PRIMARY, + 'primary-color': env.NEXT_PUBLIC_COLOR_PRIMARY, }, }, }, diff --git a/stores/index.js b/stores/index.js index d732c6c..a795796 100644 --- a/stores/index.js +++ b/stores/index.js @@ -2,6 +2,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable no-underscore-dangle */ import { createContext } from 'react'; +import { isServer } from 'tools/common'; import RootStore from './root'; /** @type{RootStore} */ @@ -27,7 +28,7 @@ export function initializeStore(initialData) { } } - if (typeof window === 'undefined') return _store; + if (isServer()) return _store; if (!store) store = _store; return _store; diff --git a/stores/root.ts b/stores/root.ts index a5f372e..0c49ab8 100644 --- a/stores/root.ts +++ b/stores/root.ts @@ -1,12 +1,13 @@ /* eslint-disable import/no-cycle */ import { enableStaticRendering } from 'mobx-react-lite'; +import { isServer } from 'tools/common'; import CalculationStore from './calculation'; import type { ProcessStore } from './process'; import createProcessStore from './process'; import ResultsStore from './results'; import TablesStore from './tables'; -enableStaticRendering(typeof window === 'undefined'); +enableStaticRendering(isServer()); export default class RootStore { $calculation: CalculationStore;