In this post we will focus on the website four our small family business. I decided to go with React as I recently learned more about it and I think it is a good opportunity to put the knowledge into practice.
What we will need to do in order to get a website up and running:
- a domain and hosting space (already registered over the weekend, so this should be ready)
- a git repository (I’m going to host it on GitLab)
- a simple CI/CD pipeline that builds and publishes the website
- a bit of Java Script and HTML to make it look like a website (the goal is to just get something up, we will finalize the website later)
I ususally use hosting services that come with a CLI like firebase etc. I decided to go with a Swiss hosting provider and I’m not sure yet what options they provide me to automate my deployment. Worst case it is going to be a manual upload. Let’s see. 🙂
Setup GitLab Repository & React App
First we created a new Git repository on GitLab. Tha’t s straight forward if you have an account already. Then we created a new React app and added the respective remotes, so that we are able to push our commits to the remote GitLab repository.
We decided to go with the simple create-react-app to get our app up and running quickly.
npx create-react-app usmalbilder
cd usmalbilder
npm usmalbilder
Note that usmalbilder is the name of the project / website.
Coding
Our website will be very simple in its first iteration. It is basically a list of images you can scroll through and download the ones you like for printing. Nevertheless we wanted it to look modern (in a way ;-)) and not start from zero. We found that Chakra UI offers a nice set of components and good documentation to get something nice quickly.
So the first thing we actually did was adding the library:
npm install --save @chakra-ui/react @emotion/react @emotion/styled framer-motion
And then do the required ChakraProvider setup. This is our index.js after the setup:
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { ChakraProvider } from "@chakra-ui/react";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<ChakraProvider>
<App />
</ChakraProvider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
That’s it for the general setup. Now we just added a bit of code for the content. In our App component we do:
- create a state containing our list of images that we know about
- fech the list from a local resource (json packaged with the website)
- render the list in a grid
All other interactions for downloading etc. we will build later. This is really the first step to get something out. To be honest we could have done even less, but you will see it is so few lines of code, which we put into App.js
import "./App.css";
import {
Card,
CardBody,
CardFooter,
Image,
Stack,
Divider,
Button,
} from "@chakra-ui/react";
import { Text } from "@chakra-ui/react";
import { Grid, Heading, VStack } from "@chakra-ui/react";
import { Box, SimpleGrid } from "@chakra-ui/react";
import { useEffect, useState } from "react";
function App() {
const [data, setData] = useState({});
useEffect(() => {
const fetchData = async () => {
const response = await fetch("db.json");
const json = await response.json();
setData(json);
};
fetchData();
}, []);
return (
<div className="App">
<VStack>
<Heading m={10}>usmalbilder.ch</Heading>
<SimpleGrid columns={4} spacing={10}>
{data.images &&
data.images.map((image) => (
<Box>
<Card maxW="sm">
<CardBody>
<Image src={image.url} borderRadius="lg" />
<Stack mt="6" spacing="3">
<Heading size="md">{image.name}</Heading>
<Text>{image.description}</Text>
</Stack>
</CardBody>
<Divider />
<CardFooter>
<Button variant="solid" colorScheme="blue" w={'100%'}>
Download & Print
</Button>
</CardFooter>
</Card>
</Box>
))}
</SimpleGrid>
</VStack>
</div>
);
}
export default App;
It is worth mentioning that the generate app comes with some initial content and we cleared the App.css and index.css.
That’s it, this gives us a simple website that looks almost like what we want.
Chakra UI
I’d like to mention that I really liked the experience with Chakra UI so far. Mostly the simple grid system and the styling system allowed us to come up with something very quickly. Kudos to the team!
Build & Deploy
Having a simple React app it is time to automate the build and publish process. For this we will need a GitLab pipeline. I have some hosting space on hosttech.ch and they provided me with some access to an FTP server. This will be an interesting challenge. 🙂
Or maybe not, let’s check if ChatGTP can help us out.
Looks quite promising. We will change it a bit as we don’t want the username and password in the pipeline but as variables managed in GitLab. Also I’m not sure why I need a Python image to get lftp and using the latest image is generally bad practice if you want to have stable builds!
Another thing to mention (and I just realize myself how lazy I usually am if you got the resouces paid for you) is to think early how to optimize the build. For instance npm install is usally a rather expensive operation, so we should cache the results and use the optimized npm ci to install our dependencies.
Here is the complete pipeline we use:
image: node:14-alpine
stages:
- build
- deploy
variables:
FTP_USER: "$_FTP_USER"
FTP_PASSWORD: "$_FTP_PASSWORD"
FTP_SERVER: "xxxxx"
FTP_PORT: "21"
cache:
paths:
- node_modules/
build:
stage: build
script:
- npm ci
- npm run build
artifacts:
paths:
- build/
deploy:
stage: deploy
image: ubuntu:20.04
script:
- apt-get update && apt-get install -y lftp
- lftp -c "set ssl:verify-certificate no; open -u $FTP_USER,$FTP_PASSWORD ftp://$FTP_SERVER:$FTP_PORT; mirror -R build /httpdocs"
It really is important to understand content generated by ChatGPT. It helps getting a quicker start for sure, but you still should evaluate the result and understand it. Please, don’t just copy code or commands blindly. ChatGPT would like to disable SSL for the communication with the FTP server. You don’t really want clear text communication from a random GitLab runner to your hosting provider.
I changed it to disable the certificate validation. Also not really good, but at least it uses a secured channel. I will see later how we can import the hosting provider certificate into our trust store, should be doable.
We are online!
You can find our first version online on www.usmalbilder.ch. It is a first iteration, but we have almost everything we need. You may notice the certificate is not properly configured yet, we will take care of that soon – and then finalize the application and then finally add content using generative AI!