build(docker): minimize production docker image size by using ubuntu:focal
This commit is contained in:
parent
c738f311da
commit
b0a295d8bb
12
.env.example
12
.env.example
|
@ -1,10 +1,10 @@
|
|||
# Reactive Resume
|
||||
# App
|
||||
TZ=UTC
|
||||
SECRET_KEY=change-me
|
||||
|
||||
# URLs
|
||||
APP_URL=http://localhost:3000
|
||||
SERVER_URL=http://localhost:3100
|
||||
PUBLIC_APP_URL=https://localhost:3000
|
||||
PUBLIC_SERVER_URL=https://localhost:3100
|
||||
|
||||
# Database
|
||||
POSTGRES_HOST=localhost
|
||||
|
@ -25,9 +25,7 @@ MAIL_PORT=
|
|||
MAIL_USERNAME=
|
||||
MAIL_PASSWORD=
|
||||
|
||||
# Google OAuth
|
||||
GOOGLE_CLIENT_ID=change-me
|
||||
# Google
|
||||
PUBLIC_GOOGLE_CLIENT_ID=change-me
|
||||
GOOGLE_CLIENT_SECRET=change-me
|
||||
|
||||
# Google Web Fonts
|
||||
GOOGLE_API_KEY=change-me
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
{
|
||||
"extends": ["../.eslintrc.json", "next/core-web-vitals"],
|
||||
"ignorePatterns": [".next"],
|
||||
"extends": [
|
||||
"../.eslintrc.json",
|
||||
"next/core-web-vitals"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
".next",
|
||||
"__ENV.js"
|
||||
],
|
||||
"rules": {
|
||||
"@next/next/no-img-element": "off"
|
||||
"@next/next/no-img-element": "off",
|
||||
"@next/next/no-sync-scripts": "off"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,3 +34,6 @@ yarn-error.log*
|
|||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
|
||||
# react-env
|
||||
__ENV.js
|
|
@ -24,8 +24,6 @@ COPY --from=dependencies /app/node_modules ./node_modules
|
|||
COPY --from=dependencies /app/schema/node_modules ./schema/node_modules
|
||||
COPY --from=dependencies /app/client/node_modules ./client/node_modules
|
||||
|
||||
RUN [[ -e .env ]] && cp .env ./client/.env
|
||||
|
||||
RUN pnpm run build:schema
|
||||
RUN pnpm run build:client
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import env from '@beam-australia/react-env';
|
||||
import { joiResolver } from '@hookform/resolvers/joi';
|
||||
import { Google, Login, Visibility, VisibilityOff } from '@mui/icons-material';
|
||||
import { Button, IconButton, InputAdornment, TextField } from '@mui/material';
|
||||
|
@ -54,7 +55,7 @@ const LoginModal: React.FC = () => {
|
|||
);
|
||||
|
||||
const { signIn } = useGoogleLogin({
|
||||
clientId: process.env.googleClientId as string,
|
||||
clientId: env('GOOGLE_CLIENT_ID'),
|
||||
onSuccess: async (response: GoogleLoginResponse | GoogleLoginResponseOffline) => {
|
||||
await loginWithGoogleMutation({ accessToken: (response as GoogleLoginResponse).accessToken });
|
||||
|
||||
|
|
|
@ -7,15 +7,12 @@ const nextConfig = {
|
|||
|
||||
i18n,
|
||||
|
||||
images: {
|
||||
domains: ['www.gravatar.com'],
|
||||
},
|
||||
|
||||
env: {
|
||||
appVersion: version,
|
||||
appUrl: process.env.APP_URL,
|
||||
serverUrl: process.env.SERVER_URL,
|
||||
googleClientId: process.env.GOOGLE_CLIENT_ID,
|
||||
},
|
||||
|
||||
images: {
|
||||
domains: ['www.gravatar.com'],
|
||||
},
|
||||
|
||||
// Hack to make Tailwind darkMode 'class' strategy with CSS Modules
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"name": "@reactive-resume/client",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "react-env --prefix PUBLIC -- next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"start": "react-env --prefix PUBLIC -- next start",
|
||||
"lint": "next lint --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@beam-australia/react-env": "^3.1.1",
|
||||
"@emotion/css": "^11.7.1",
|
||||
"@emotion/react": "^11.8.1",
|
||||
"@emotion/styled": "^11.8.1",
|
||||
|
@ -52,6 +53,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"@reactive-resume/schema": "workspace:*",
|
||||
"@types/downloadjs": "^1.4.3",
|
||||
"@types/lodash": "^4.14.179",
|
||||
"@types/node": "17.0.21",
|
||||
|
@ -68,7 +70,6 @@
|
|||
"prettier": "^2.5.1",
|
||||
"sass": "^1.49.9",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"typescript": "<4.6.0",
|
||||
"@reactive-resume/schema": "workspace:*"
|
||||
"typescript": "<4.6.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,13 +21,15 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
|
|||
<>
|
||||
<Head>
|
||||
<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" />
|
||||
|
||||
<script src="/__ENV.js" />
|
||||
</Head>
|
||||
|
||||
<ReduxProvider store={store}>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import env from '@beam-australia/react-env';
|
||||
import _axios, { AxiosError } from 'axios';
|
||||
import Router from 'next/router';
|
||||
|
||||
|
@ -13,11 +14,11 @@ export type ServerError = {
|
|||
};
|
||||
|
||||
const axios = _axios.create({
|
||||
baseURL: `${process.env.serverUrl}/api`,
|
||||
baseURL: `${env('SERVER_URL')}/api`,
|
||||
});
|
||||
|
||||
export const uninterceptedAxios = _axios.create({
|
||||
baseURL: `${process.env.serverUrl}/api`,
|
||||
baseURL: `${env('SERVER_URL')}/api`,
|
||||
});
|
||||
|
||||
axios.interceptors.request.use((config) => {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"build:client": "pnpm -F client build",
|
||||
"build": "env-cmd concurrently \"pnpm run build:*\"",
|
||||
"start:server": "pnpm -F server start:prod",
|
||||
"start:client": "pnpm -F client start",
|
||||
"start:client": "env-cmd pnpm -F client start",
|
||||
"start": "env-cmd concurrently --kill-others \"pnpm run start:*\""
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
@ -38,6 +38,7 @@ importers:
|
|||
client:
|
||||
specifiers:
|
||||
'@babel/core': ^7.17.5
|
||||
'@beam-australia/react-env': ^3.1.1
|
||||
'@emotion/css': ^11.7.1
|
||||
'@emotion/react': ^11.8.1
|
||||
'@emotion/styled': ^11.8.1
|
||||
|
@ -99,6 +100,7 @@ importers:
|
|||
uuid: ^8.3.2
|
||||
webfontloader: ^1.6.28
|
||||
dependencies:
|
||||
'@beam-australia/react-env': 3.1.1
|
||||
'@emotion/css': 11.7.1_@babel+core@7.17.5
|
||||
'@emotion/react': 11.8.1_7c3ecd89bd75b61b41f2029715ea2305
|
||||
'@emotion/styled': 11.8.1_c697ad3c4ddb0545c7a1d619984abba5
|
||||
|
@ -614,6 +616,16 @@ packages:
|
|||
'@babel/helper-validator-identifier': 7.16.7
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
/@beam-australia/react-env/3.1.1:
|
||||
resolution: {integrity: sha512-LdWzgqmu116t9+sOvONyB21bBmI8dm8g8s3KhnJVzCcK93GrdSisuIOtOkQPMYgenmVGTWQwWnbLAgoka/jAFw==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
cross-spawn: 6.0.5
|
||||
dotenv: 8.6.0
|
||||
dotenv-expand: 5.1.0
|
||||
minimist: 1.2.5
|
||||
dev: false
|
||||
|
||||
/@changesets/apply-release-plan/5.0.5:
|
||||
resolution: {integrity: sha512-CxL9dkhzjHiVmXCyHgsLCQj7i/coFTMv/Yy0v6BC5cIWZkQml+lf7zvQqAcFXwY7b54HxRWZPku02XFB53Q0Uw==}
|
||||
dependencies:
|
||||
|
@ -3320,6 +3332,17 @@ packages:
|
|||
which: 1.3.1
|
||||
dev: true
|
||||
|
||||
/cross-spawn/6.0.5:
|
||||
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
|
||||
engines: {node: '>=4.8'}
|
||||
dependencies:
|
||||
nice-try: 1.0.5
|
||||
path-key: 2.0.1
|
||||
semver: 5.7.1
|
||||
shebang-command: 1.2.0
|
||||
which: 1.3.1
|
||||
dev: false
|
||||
|
||||
/cross-spawn/7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
@ -3625,6 +3648,10 @@ packages:
|
|||
csstype: 3.0.11
|
||||
dev: false
|
||||
|
||||
/dotenv-expand/5.1.0:
|
||||
resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==}
|
||||
dev: false
|
||||
|
||||
/dotenv-expand/8.0.1:
|
||||
resolution: {integrity: sha512-j/Ih7bIERDR5PzI89Zu8ayd3tXZ6E3dbY0ljQ9Db0K87qBO8zdLsi2dIvDHMWtjC3Yxb8XixOTHAtia0fDHRpg==}
|
||||
engines: {node: '>=12'}
|
||||
|
@ -6220,6 +6247,10 @@ packages:
|
|||
- babel-plugin-macros
|
||||
dev: false
|
||||
|
||||
/nice-try/1.0.5:
|
||||
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
|
||||
dev: false
|
||||
|
||||
/node-abi/3.8.0:
|
||||
resolution: {integrity: sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -6628,6 +6659,11 @@ packages:
|
|||
resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
/path-key/2.0.1:
|
||||
resolution: {integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=}
|
||||
engines: {node: '>=4'}
|
||||
dev: false
|
||||
|
||||
/path-key/3.1.1:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -7717,7 +7753,6 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
shebang-regex: 1.0.0
|
||||
dev: true
|
||||
|
||||
/shebang-command/2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
|
@ -7728,7 +7763,6 @@ packages:
|
|||
/shebang-regex/1.0.0:
|
||||
resolution: {integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/shebang-regex/3.0.0:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
|
@ -8937,7 +8971,6 @@ packages:
|
|||
hasBin: true
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
dev: true
|
||||
|
||||
/which/2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
|
|
|
@ -24,15 +24,19 @@ COPY --from=dependencies /app/node_modules ./node_modules
|
|||
COPY --from=dependencies /app/schema/node_modules ./schema/node_modules
|
||||
COPY --from=dependencies /app/server/node_modules ./server/node_modules
|
||||
|
||||
RUN [[ -e .env ]] && cp .env ./server/.env
|
||||
|
||||
RUN pnpm run build:schema
|
||||
RUN pnpm run build:server
|
||||
|
||||
FROM mcr.microsoft.com/playwright:focal as production
|
||||
FROM ubuntu:focal as production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y curl g++ make \
|
||||
&& curl -sL https://deb.nodesource.com/setup_16.x | bash \
|
||||
&& apt-get install -y nodejs \
|
||||
&& npx playwright install-deps chromium
|
||||
|
||||
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
|
||||
COPY --from=builder /app/pnpm-*.yaml .
|
||||
|
|
|
@ -5,6 +5,6 @@ export default registerAs('app', () => ({
|
|||
environment: process.env.NODE_ENV,
|
||||
secretKey: process.env.SECRET_KEY,
|
||||
port: parseInt(process.env.SERVER_PORT, 10) || 3100,
|
||||
url: process.env.APP_URL || 'http://localhost:3000',
|
||||
serverUrl: process.env.SERVER_URL || 'http://localhost:3100',
|
||||
url: process.env.PUBLIC_APP_URL || 'http://localhost:3000',
|
||||
serverUrl: process.env.PUBLIC_SERVER_URL || 'http://localhost:3100',
|
||||
}));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule as NestConfigModule } from '@nestjs/config';
|
||||
import * as Joi from 'joi';
|
||||
import Joi from 'joi';
|
||||
|
||||
import appConfig from './app.config';
|
||||
import authConfig from './auth.config';
|
||||
|
@ -16,8 +16,8 @@ const validationSchema = Joi.object({
|
|||
NODE_ENV: Joi.string().valid('development', 'production').default('development'),
|
||||
|
||||
// URLs
|
||||
APP_URL: Joi.string().default('http://localhost:3000'),
|
||||
SERVER_URL: Joi.string().default('http://localhost:3100'),
|
||||
PUBLIC_APP_URL: Joi.string().default('http://localhost:3000'),
|
||||
PUBLIC_SERVER_URL: Joi.string().default('http://localhost:3100'),
|
||||
|
||||
// Database
|
||||
POSTGRES_HOST: Joi.string().required(),
|
||||
|
@ -31,14 +31,16 @@ const validationSchema = Joi.object({
|
|||
JWT_SECRET: Joi.string().required(),
|
||||
JWT_EXPIRY_TIME: Joi.number().required(),
|
||||
|
||||
// Google
|
||||
GOOGLE_API_KEY: Joi.string().allow(''),
|
||||
|
||||
// Mail
|
||||
MAIL_HOST: Joi.string().allow(''),
|
||||
MAIL_PORT: Joi.number().default(465),
|
||||
MAIL_USERNAME: Joi.string().allow(''),
|
||||
MAIL_PASSWORD: Joi.string().allow(''),
|
||||
|
||||
// Google
|
||||
GOOGLE_API_KEY: Joi.string().allow(''),
|
||||
GOOGLE_CLIENT_SECRET: Joi.string().allow(''),
|
||||
PUBLIC_GOOGLE_CLIENT_ID: Joi.string().allow(''),
|
||||
});
|
||||
|
||||
@Module({
|
||||
|
|
|
@ -2,6 +2,6 @@ import { registerAs } from '@nestjs/config';
|
|||
|
||||
export default registerAs('google', () => ({
|
||||
apiKey: process.env.GOOGLE_API_KEY,
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientId: process.env.PUBLIC_GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
}));
|
||||
|
|
Loading…
Reference in New Issue