build(docker): minimize production docker image size by using ubuntu:focal

This commit is contained in:
Amruth Pillai 2022-03-07 21:43:38 +01:00
parent c738f311da
commit b0a295d8bb
No known key found for this signature in database
GPG Key ID: E3C57DF9B80855AD
15 changed files with 91 additions and 44 deletions

View File

@ -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

View File

@ -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"
}
}
}

3
client/.gitignore vendored
View File

@ -34,3 +34,6 @@ yarn-error.log*
# typescript
*.tsbuildinfo
# react-env
__ENV.js

View File

@ -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

View File

@ -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 });

View File

@ -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

View File

@ -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"
}
}

View File

@ -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}>

View File

@ -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) => {

View File

@ -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": {

View File

@ -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==}

View File

@ -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 .

View File

@ -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',
}));

View File

@ -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({

View File

@ -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,
}));