Building a Single-Page App with React and Golang
October 10th, 2020
Outline
- part 1: tech stack & base framework
- installing dev env & tools
- creating folder structure
- creating "walking skeleton"
part 2: connecting database access
part 3: adding users + authentication
part 4: designing & building the UI frontend
part 5: modeling schema & building out the graphQL endpoints
part 6: connecting UI frontend to the backend
part 7: embedding assets & serving frontend in production
Hello friends!
This is a mult-part series on creating a single-page application using React & Golang. The goal for the series is to create a minimal blogging CMS that can be used for static site generators like Jekyll, Hugo, or Gatsby.
React will be used for the frontend (what users see) while Golang will be used for the API (which the frontend consumes).
Prerequisites
Before we get started, we'll need to make sure our development environment is correctly set up.
We will need:
- NodeJS 1.14+ & Yarn 1.22+
- Golang 1.15+
For the backend, we will need to install some tools:
- sqlc
- gqlgen
For the frontend, we will need:
- npx
- create-react-app
This guide also assumes decent knowledge of both Typescript, React & Golang.
What are we building?
The goal is a minimal blogging CMS that can be used to write & manage blog posts (stored as markdown files) that can be used by a static site generator.
It will also need some kind of authentication system so that only authorized users can actually manage the content.
The API will be built using GraphQL (specifically the gqlgen
tool) while the frontend
will consume the API using Apollo
.
We will also be using Typescript alongside React.
We will also be using:
- CSS-in-JSS (through
styled-components
) - GraphQL codegen (to generate Typescript types for graphql queries/mutations)
Why React?
Why Typescript?
Why Golang?
Setting up the project
We will be using a mono-repo approach to storing our code, meaning both the frontend and backend code will live in the same directory (and git repository).
Let's create some directorys as well as the base create-react-app
project.
First we will need to create a root directory, which I have chosen to call blog-cms
.
mkdir blog-cms && cd blog-cms
Now let's create the create-react-app
project.
npx create-react-app frontend --template typescript
We will be using absolute imports over relative imports in our React project.
In order to set that up, we need to edit the frontend/tsconfig.json
file
We will be adding baseUrl: "src"
to the compilerOptions which allows us to import
based on the absolute path of a file within the src
directory, rather than the relative path
of whatever file we are in.
The tsconfig.json
should now look like this:
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"baseUrl": "src"
},
"include": [
"src"
]
}
Let's also set up eslint
and prettier
:
In frontend/.eslintrc.json
{
"env": {
"browser": true,
"es6": true
},
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": ["react", "@typescript-eslint", "prettier"],
"extends": [
"plugin:react/recommended",
"airbnb",
"plugin:prettier/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"prettier/prettier": "error",
"no-restricted-syntax": ["error", "LabeledStatement", "WithStatement"],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"react/jsx-filename-extension": [2, { "extensions": [".js", ".jsx", ".ts", ".tsx"] }],
"no-case-declarations": "off",
"react/prop-types": 0,
"react/jsx-props-no-spreading": "off",
"no-param-reassign": "off",
"import/extensions": [
"error",
"ignorePackages",
{
"js": "never",
"mjs": "never",
"jsx": "never",
"ts": "never",
"tsx": "never"
}
],
},
"settings": {
"import/resolver": {
"node": {
"paths": ["src"],
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
}
}
This tells eslint to use the airbnb
rules as well as the prettier
eslint rules.
Under rules
, we disable some of the options that are not useful for us.
Next, let's configure prettier
:
Add the following to frontend/.prettierrc.js
module.exports = {
semi: true,
trailingComma: "all",
singleQuote: true,
printWidth: 120,
tabWidth: 2,
bracketSpacing: true,
};
Some of the interesting options:
trailingComma: "all"
: add a trailing comma in places where it is optionaltabWidth: 2
: two spaces for tabs