experiments with docker packaging, figuring out deploy plan

This commit is contained in:
Amruth Pillai
2022-03-03 12:24:32 +01:00
parent 2aa3786f5f
commit 58160b2b6e
20 changed files with 1068 additions and 372 deletions

View File

@ -1,2 +1,8 @@
NEXT_PUBLIC_APP_VERSION=$npm_package_version
# App & Server URLs
NEXT_PUBLIC_APP_URL=$APP_URL
NEXT_PUBLIC_SERVER_URL=$SERVER_URL
# Google OAuth
NEXT_PUBLIC_GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID

18
apps/client/i18n/index.ts Normal file
View File

@ -0,0 +1,18 @@
import HttpBackend from 'i18next-http-backend';
const i18nConfig = {
i18n: {
defaultLocale: 'en',
locales: ['en'],
},
debug: false,
nsSeparator: '.',
ns: ['common', 'modals', 'landing', 'dashboard', 'builder'],
serializeConfig: false,
use: [HttpBackend],
backend: {
loadPath: `${process.env.NEXT_PUBLIC_APP_URL}/locales/{{lng}}/{{ns}}.json`,
},
};
export default i18nConfig;

View File

@ -1,14 +0,0 @@
/**
* @type {import('next-i18next').UserConfig}
**/
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en'],
},
debug: false,
nsSeparator: '.',
initImmediate: false,
localePath: './apps/client/public/locales',
ns: ['common', 'modals', 'landing', 'dashboard', 'builder'],
};

View File

@ -1,12 +1,13 @@
const withNx = require('@nrwl/next/plugins/with-nx');
const { i18n } = require('./next-i18next.config');
/**
* @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
**/
const nextConfig = {
i18n,
i18n: {
defaultLocale: 'en',
locales: ['en'],
},
nx: {
svgr: false,

View File

@ -4,11 +4,11 @@ import { GetServerSideProps, NextPage } from 'next';
import dynamic from 'next/dynamic';
import Head from 'next/head';
import { useTranslation } from 'next-i18next';
import i18nConfig from 'next-i18next.config';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { useEffect } from 'react';
import { useQuery } from 'react-query';
import i18nConfig from '@/i18n/index';
import { fetchResumeByIdentifier } from '@/services/resume';
import { useAppDispatch } from '@/store/hooks';
import { setResume } from '@/store/resume/resumeSlice';

View File

@ -9,12 +9,12 @@ import { GetServerSideProps, NextPage } from 'next';
import dynamic from 'next/dynamic';
import Link from 'next/link';
import { useRouter } from 'next/router';
import i18nConfig from 'next-i18next.config';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { useEffect } from 'react';
import toast from 'react-hot-toast';
import { useMutation, useQuery } from 'react-query';
import i18nConfig from '@/i18n/index';
import { ServerError } from '@/services/axios';
import { printResumeAsPdf, PrintResumeAsPdfParams } from '@/services/printer';
import { fetchResumeByIdentifier } from '@/services/resume';
@ -39,7 +39,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async ({ query, loc
const { username, slug } = query as QueryParams;
try {
const resume = await fetchResumeByIdentifier({ username, slug, options: { withHost: true } });
const resume = await fetchResumeByIdentifier({ username, slug });
return {
props: { username, slug, resume, ...(await serverSideTranslations(locale, ['common'], i18nConfig)) },

View File

@ -31,7 +31,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async ({ query }) =
try {
if (isEmpty(secretKey)) throw new Error('There is no secret key!');
const resume = await fetchResumeByIdentifier({ username, slug, options: { secretKey, withHost: true } });
const resume = await fetchResumeByIdentifier({ username, slug, options: { secretKey } });
return { props: { resume } };
} catch (error) {

View File

@ -4,36 +4,28 @@ import DateAdapter from '@mui/lab/AdapterDayjs';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import { appWithTranslation, useTranslation } from 'next-i18next';
import i18nConfig from 'next-i18next.config';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { appWithTranslation } from 'next-i18next';
import { Toaster } from 'react-hot-toast';
import { QueryClientProvider } from 'react-query';
import { Provider as ReduxProvider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import Loading from '@/components/shared/Loading';
import i18nConfig from '@/i18n/index';
import ModalWrapper from '@/modals/index';
import queryClient from '@/services/react-query';
import store, { persistor } from '@/store/index';
import WrapperRegistry from '@/wrappers/index';
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, ['common', 'modals'], i18nConfig)),
},
};
}
const App: React.FC<AppProps> = ({ Component, pageProps }) => {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t('common.title')}</title>
<meta name="description" content={t('common.description')} />
<title>Reactive Resume</title>
<meta
name="description"
content="Reactive Resume is a free and open source resume builder that's built to make the mundane tasks of creating, updating and sharing your resume as easy as 1, 2, 3."
/>
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="initial-scale=1, width=device-width" />

View File

@ -4,11 +4,11 @@ import dynamic from 'next/dynamic';
import Head from 'next/head';
import Link from 'next/link';
import { useTranslation } from 'next-i18next';
import i18nConfig from 'next-i18next.config';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { useQuery } from 'react-query';
import { RESUMES_QUERY } from '@/constants/index';
import i18nConfig from '@/i18n/index';
import { fetchResumes } from '@/services/resume';
import styles from '@/styles/pages/Dashboard.module.scss';

View File

@ -1,14 +1,14 @@
import { Link as LinkIcon } from '@mui/icons-material';
import { Button } from '@mui/material';
import type { NextPage } from 'next';
import type { GetServerSideProps, NextPage } from 'next';
import dynamic from 'next/dynamic';
import Image from 'next/image';
import Link from 'next/link';
import { Trans, useTranslation } from 'next-i18next';
import i18nConfig from 'next-i18next.config';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { screenshots } from '@/config/screenshots';
import i18nConfig from '@/i18n/index';
import { logout } from '@/store/auth/authSlice';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
@ -20,13 +20,13 @@ const Footer = dynamic(() => import('@/components/shared/Footer'));
const Logo = dynamic(() => import('@/components/shared/Logo'));
const NoSSR = dynamic(() => import('@/components/shared/NoSSR'));
export async function getStaticProps({ locale }) {
export const getServerSideProps: GetServerSideProps = async ({ locale }) => {
return {
props: {
...(await serverSideTranslations(locale, ['common', 'modals', 'landing'], i18nConfig)),
},
};
}
};
const Home: NextPage = () => {
const { t } = useTranslation();

View File

@ -8,12 +8,12 @@ import isEmpty from 'lodash/isEmpty';
import { GetServerSideProps, NextPage } from 'next';
import dynamic from 'next/dynamic';
import Link from 'next/link';
import i18nConfig from 'next-i18next.config';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { useEffect } from 'react';
import toast from 'react-hot-toast';
import { useMutation, useQuery } from 'react-query';
import i18nConfig from '@/i18n/index';
import { ServerError } from '@/services/axios';
import { printResumeAsPdf, PrintResumeAsPdfParams } from '@/services/printer';
import { fetchResumeByShortId } from '@/services/resume';
@ -36,7 +36,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async ({ query, loc
const { shortId } = query as QueryParams;
try {
const resume = await fetchResumeByShortId({ shortId, options: { withHost: true } });
const resume = await fetchResumeByShortId({ shortId });
return { props: { shortId, resume, ...(await serverSideTranslations(locale, ['common'], i18nConfig)) } };
} catch {

View File

@ -1,6 +0,0 @@
{
"/api": {
"target": "http://localhost:3100",
"secure": false
}
}

View File

@ -13,11 +13,11 @@ export type ServerError = {
};
const axios = _axios.create({
baseURL: '/api',
baseURL: `${process.env.NEXT_PUBLIC_SERVER_URL}/api`,
});
export const uninterceptedAxios = _axios.create({
baseURL: '/api',
baseURL: `${process.env.NEXT_PUBLIC_SERVER_URL}/api`,
});
axios.interceptors.request.use((config) => {

View File

@ -14,7 +14,6 @@ export type FetchResumeByIdentifierParams = {
username: string;
slug: string;
options?: {
withHost?: boolean;
secretKey?: string;
};
};
@ -22,7 +21,6 @@ export type FetchResumeByIdentifierParams = {
export type FetchResumeByShortIdParams = {
shortId: string;
options?: {
withHost?: boolean;
secretKey?: string;
};
};
@ -60,25 +58,20 @@ export type DeleteResumeParams = {
export const fetchResumes = () => axios.get<Resume[]>('/resume').then((res) => res.data);
export const fetchResumeByShortId = async ({
shortId,
options = { secretKey: '', withHost: false },
}: FetchResumeByShortIdParams) => {
const hostname = options.withHost ? `${process.env.SERVER_URL}/api` : '';
export const fetchResumeByShortId = async ({ shortId, options = { secretKey: '' } }: FetchResumeByShortIdParams) => {
const requestOptions = isEmpty(options.secretKey) ? {} : { params: { secretKey: options.secretKey } };
return axios.get<Resume>(`${hostname}/resume/short/${shortId}`, requestOptions).then((res) => res.data);
return axios.get<Resume>(`/resume/short/${shortId}`, requestOptions).then((res) => res.data);
};
export const fetchResumeByIdentifier = async ({
username,
slug,
options = { secretKey: '', withHost: false },
options = { secretKey: '' },
}: FetchResumeByIdentifierParams) => {
const hostname = options.withHost ? `${process.env.SERVER_URL}/api` : '';
const requestOptions = isEmpty(options.secretKey) ? {} : { params: { secretKey: options.secretKey } };
return axios.get<Resume>(`${hostname}/resume/${username}/${slug}`, requestOptions).then((res) => res.data);
return axios.get<Resume>(`/resume/${username}/${slug}`, requestOptions).then((res) => res.data);
};
export const createResume = (createResumeParams: CreateResumeParams) =>

View File

@ -16,12 +16,13 @@
"paths": {
"@/components/*": ["components/*"],
"@/config/*": ["config/*"],
"@/constants/*": ["constants/*"],
"@/i18n/*": ["i18n/*"],
"@/modals/*": ["modals/*"],
"@/pages/*": ["pages/*"],
"@/public/*": ["public/*"],
"@/services/*": ["services/*"],
"@/store/*": ["store/*"],
"@/constants/*": ["constants/*"],
"@/styles/*": ["styles/*"],
"@/templates/*": ["templates/*"],
"@/types/*": ["types/*"],