Skip to content

Commit a04cc67

Browse files
committed
refactor: workflow, frontend app, and frontend build
* fixes create react app bug: facebook/create-react-app#8688 * adds styling to frontend app * improves frontend dockerfile * adds additional commands to makefile and README
1 parent 6af7142 commit a04cc67

File tree

11 files changed

+118
-108
lines changed

11 files changed

+118
-108
lines changed

README.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## The Ultimate Go and React Development Setup with Docker (Part 2)
44

5-
### Building A Complete Example
5+
### Building A Complete API Example
66

7-
This repository is paired with a [blog post](https://blog.ivorscott.com/ultimate-go-react-development-setup-with-docker-part2). If you follow along, the project starter is available under the `part2_starter` branch. Part 2 is heavily influenced by [Ardan labs service training](https://github.com/ardanlabs/service-training). I highly recommend their [courses](https://education.ardanlabs.com/).
7+
This repository is paired with a [blog post](https://blog.ivorscott.com/ultimate-go-react-development-setup-with-docker-part2). Part 2 is heavily influenced by [Ardan labs service training](https://github.com/ardanlabs/service-training). I highly recommend their [courses](https://education.ardanlabs.com/).
88

99
[Previous blog post](https://blog.ivorscott.com/ultimate-go-react-development-setup-with-docker)
1010

@@ -379,9 +379,19 @@ make api # develop the api with live reloading
379379
make client # develop the client app in a separate terminal
380380
```
381381

382+
![Minion](docs/run.png)
383+
384+
6 - Navigate to https://localhost:4000/v1/products and https://localhost:3000 in two separate tabs.
385+
386+
Note:
387+
388+
To replicate the production environment as much as possible locally, we use self-signed certificates.
389+
390+
In your browser, you may see a warning and need to click a link to proceed to the requested page. This is common when using self-signed certificates.
391+
382392
This approach to development uses containers entirely.
383393

384-
6 - **Idiomatic Go development** (container free go api)
394+
7 - **Idiomatic Go development** (container free go api)
385395

386396
Another option is to only containerize the client and database. This approach
387397
allows you to work with the go api in an idiomatic fashion, with command line flags
@@ -445,6 +455,10 @@ make debug-api # use delve on the same api in a separate container (no live relo
445455

446456
make debug-db # use pgcli to inspect postgres db
447457

458+
make rm # remove all containers
459+
460+
make rmi # remove all images
461+
448462
make exec user="..." service="..." cmd="..." # execute command in running container
449463

450464
make tidy # clean up unused api dependencies
@@ -453,6 +467,8 @@ make test-api # run api tests
453467

454468
make test-client # run client tests
455469

470+
make test-client-watch # run client tests and watch
471+
456472
make migration <name> # create a migration
457473

458474
make version # print current migration version
@@ -519,7 +535,7 @@ Run the debuggable api. Set a break point on a route handler. Click 'Launch remo
519535

520536
</details>
521537

522-
### Building A Complete Example
538+
### Building A Complete API Example
523539

524540
The Ultimate Go and React Development Setup with Docker (Part 2)
525541

client/Dockerfile

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,74 +7,69 @@ WORKDIR /client
77
# 3. Copy both package.json and package-lock.json into /client in the image's filesystem
88
COPY package*.json ./
99

10-
# 4. Install only the production node_modules and clean up the cache
11-
RUN npm ci \
12-
&& npm cache clean --force
13-
14-
# 5. Extend the base stage and create a new stage named dev
10+
# 4. Extend the base stage and create a new stage named dev
1511
FROM base as dev
1612

17-
# 6. Set the NODE_ENV and PATH Environment variables
13+
# 5. Set the NODE_ENV and PATH Environment variables
1814
ENV NODE_ENV=development
1915
ENV PATH /client/node_modules/.bin:$PATH
2016

21-
# 7. Provide meta data about the port the container must expose
17+
# 6. Provide meta data about the port the container must expose
2218
EXPOSE 3000
2319

24-
# 8. Create a new /app directory in /client
20+
# 7. Create a new /app directory in /client
2521
RUN mkdir /client/app
2622

27-
# 9. Install development dependencies
28-
RUN npm i --only=development \
29-
&& npm cache clean --force
23+
# 8. Install development dependencies
24+
RUN npm install && npm cache clean --force
3025

31-
# 10. Print npm configuration for debugging purposes
26+
# 9. Print npm configuration for debugging purposes
3227
RUN npm config list
3328

34-
# 11. Set the working directory to /client/app
29+
# 10. Set the working directory to /client/app
3530
WORKDIR /client/app
3631

37-
# 12. Provide the default command for the development container
32+
# 11. Provide the default command for the development container
3833
CMD ["npm", "run", "start"]
3934

40-
# 13. Extend the dev stage and create a new stage called test
35+
# 12. Extend the dev stage and create a new stage called test
4136
FROM dev as test
4237

43-
# 14. Copy the remainder of the client folder source code into the image's filesystem
38+
# 13. Copy the remainder of the client folder source code into the image's filesystem
4439
COPY . .
4540

46-
# 15. Run node_module vulnerability checks
41+
# 14. Run node_module vulnerability checks
4742
RUN npm audit
4843

49-
# 16. Run unit tests in CI
44+
# 15. Run unit tests in CI
5045
RUN CI=true npm test --env=jsdom
5146

52-
# 17. Extend the test stage and create a new stage named build-stage
47+
# 16. Extend the test stage and create a new stage named build-stage
5348
FROM test as build-stage
5449

55-
# 18. Build the production static assets
50+
# 17. Build the production static assets
5651
RUN npm run build
5752

58-
# 19. Install aquasecurity's trivy for robust image scanning
59-
FROM aquasec/trivy:0.4.3 as trivy
53+
# 18. Install aquasecurity's trivy for robust image scanning
54+
FROM aquasec/trivy:0.4.4 as trivy
6055

61-
# 20. Scan the nginx alpine image before production use
56+
# 19. Scan the nginx alpine image before production use
6257
RUN trivy nginx:1.17-alpine && \
6358
echo "No image vulnerabilities" > result
6459

65-
# 21. Extend the nginx apline image and create a new stage named prod
60+
# 20. Extend the nginx apline image and create a new stage named prod
6661
FROM nginx:1.17-alpine as prod
6762

68-
# 22. Copy only the files we want from a few stages into the prod stage
63+
# 21. Copy only the files we want from a few stages into the prod stage
6964
COPY --from=trivy result secure
7065
COPY --from=build-stage /client/app/build /usr/share/nginx/html
7166

72-
# 23. Copy non-root user nginx configuration
67+
# 22. Copy non-root user nginx configuration
7368
# https://hub.docker.com/_/nginx
7469
COPY --from=build-stage /client/app/nginx /etc/nginx/
7570

76-
# 24. Provide meta data about the port the container must expose
71+
# 23. Provide meta data about the port the container must expose
7772
EXPOSE 80
7873

79-
# 25. Define how Docker should test the container to check that it is still working
74+
# 24. Define how Docker should test the container to check that it is still working
8075
HEALTHCHECK CMD [ "wget", "-q", "0.0.0.0:80" ]

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"workbox-webpack-plugin": "4.3.1"
6969
},
7070
"scripts": {
71-
"start": "node scripts/start.js",
71+
"start": "HTTPS=true REACT_APP_API_URL=https://localhost:4000/v1 node scripts/start.js",
7272
"build": "node scripts/build.js",
7373
"test": "node scripts/test.js"
7474
},

client/src/App/App.scss

Lines changed: 7 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,16 @@ body {
1010
box-sizing: border-box;
1111
// https://css-tricks.com/snippets/css/font-shorthand/
1212
font: normal 400 24px/1.7 "Lato", Helvetica, sans-serif;
13-
background: #000;
1413
color: #777;
15-
padding: 30px;
1614
}
1715

1816
.header {
1917
position: relative;
2018
height: 85vh;
2119
background-image: linear-gradient(
2220
to right bottom,
23-
rgba(126, 2123, 111, 0.8),
24-
rgba(209, 73, 31, 0.6)
21+
rgba(126, 212, 111, 0.8),
22+
rgba(209, 73, 31, 0.8)
2523
),
2624
url("http://getwallpapers.com/wallpaper/full/d/3/a/547521.jpg");
2725
background-size: cover;
@@ -133,54 +131,13 @@ body {
133131
}
134132
}
135133

136-
.products-feature {
134+
.main {
137135
position: relative;
138-
top: -650px;
139-
margin: 100px;
136+
top: -500px;
137+
text-align: center;
140138
color: #fff;
141-
142-
header {
143-
font-size: 36px;
144-
font-weight: 700;
145-
text-align: center;
146-
margin-bottom: 46px;
147-
}
148-
149-
.products {
150-
display: flex;
151-
flex: 1;
152-
justify-content: center;
153-
&__card {
154-
width: 100%;
155-
min-height: 300px;
156-
max-width: 300px;
157-
margin: 10px;
158-
padding: 12px;
159-
background-color: #fff;
160-
border-radius: 8px;
161-
color: #444;
162-
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25),
163-
0 10px 10px rgba(0, 0, 0, 0.22);
164-
}
165-
.a {
166-
position: relative;
167-
top: 0px;
168-
animation: moveInBottom 0.65s ease-out 1s;
169-
animation-fill-mode: backwards;
170-
}
171-
.b {
172-
position: relative;
173-
top: 40px;
174-
animation: moveInBottom 0.65s ease-out 1.2s;
175-
animation-fill-mode: backwards;
176-
}
177-
.c {
178-
position: relative;
179-
top: 80px;
180-
animation: moveInBottom 0.65s ease-out 1.4s;
181-
animation-fill-mode: backwards;
182-
}
183-
}
139+
animation: moveInBottom 0.65s ease-out 1.4s;
140+
animation-fill-mode: backwards;
184141
}
185142

186143
@keyframes moveInLeft {

client/src/App/App.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import React from 'react';
2-
import { render } from '@testing-library/react';
3-
import App from './App';
1+
import React from "react";
2+
import { render } from "@testing-library/react";
3+
import App from "./App";
44

5-
test('renders learn react link', () => {
5+
test("renders learn react link", () => {
66
const { getByText } = render(<App />);
7-
const linkElement = getByText(/learn react/i);
8-
expect(linkElement).toBeInTheDocument();
7+
const button = getByText(/Sign Up/i);
8+
expect(button).toBeInTheDocument();
99
});

client/src/App/App.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ class App extends React.Component<{}, State> {
2727
subtitle="Second hand games"
2828
callToActionText="Sign Up"
2929
/>
30-
<Products products={this.state.products} />
30+
<div className="main">
31+
<h1>The Best Prices</h1>
32+
<h3>Gaming Is Our Passion. Get 20% Off Any 2nd Purchase!</h3>
33+
<Products products={this.state.products} />
34+
</div>
3135
</div>
3236
);
3337
}

client/src/App/Products/Products.scss

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.products-feature {
2+
color: #fff;
3+
margin-top: 40px;
4+
5+
.products {
6+
display: flex;
7+
flex: 1;
8+
justify-content: center;
9+
&__card {
10+
display: flex;
11+
flex: 1;
12+
flex-direction: column;
13+
justify-content: center;
14+
width: 100%;
15+
min-height: 300px;
16+
max-width: 300px;
17+
margin: 10px;
18+
padding: 12px;
19+
background-color: #fff;
20+
border-radius: 8px;
21+
color: #444;
22+
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25),
23+
0 10px 10px rgba(0, 0, 0, 0.22);
24+
}
25+
}
26+
}

client/src/App/Products/Products.tsx

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
import React from "react";
22
import { IProduct } from "./types";
3-
4-
const classes = ["a", "b", "c"];
3+
import "./Products.scss";
54

65
const Products: React.FC<{ products: IProduct[] }> = ({ products }) => (
76
<main className="products-feature">
8-
<header>Store</header>
97
<div className="products">
10-
{products.map((product, index) => {
8+
{products.map(product => {
119
return (
12-
index < 3 && (
13-
<div
14-
key={product.id}
15-
className={`products__card ${classes[index]}`}
16-
>
17-
<b className="products__card-name">{product.name}</b>
18-
<p className="products__card-description">
19-
{product.description}
20-
</p>
21-
<p className="products__card-price">{product.price}</p>
22-
</div>
23-
)
10+
<div key={product.id} className="products__card">
11+
<b className="products__card-name">{product.name}</b>
12+
<p className="products__card-price">{product.price}</p>
13+
</div>
2414
);
2515
})}
2616
</div>

docker-compose.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ services:
2222
- ./api:/api
2323
networks:
2424
- postgres-net
25+
# swap commands to disable live reload
2526
# command: go run ./cmd/api
2627
command: CompileDaemon --build="go build -o main ./cmd/api" -log-prefix=false --command=./main
2728

@@ -33,9 +34,13 @@ services:
3334
environment:
3435
HTTPS: "true"
3536
REACT_APP_API_URL: https://localhost:$API_PORT/v1
37+
CHOKIDAR_USEPOLLING: "true"
3638
ports:
3739
- $CLIENT_PORT:$CLIENT_PORT
40+
# fixes bug in react-scripts/start.js found in latest create react app release
41+
# https://github.com/facebook/create-react-app/issues/8688
3842
tty: true
43+
stdin_open: true
3944
volumes:
4045
- ./client:/client/app
4146
- /client/app/node_modules
@@ -63,7 +68,7 @@ services:
6368
networks:
6469
- postgres-net
6570
# run a container without the default seccomp profile
66-
# https://github.com/go-delve/delve/issues/515
71+
# https://github.com/go-delve/delve/issues/515#issuecomment-214911481
6772
security_opt:
6873
- "seccomp:unconfined"
6974
tty: true

docs/run.png

351 KB
Loading

0 commit comments

Comments
 (0)