Hugo
Hugo it is framework for building static websites commonly based on Markdown files.
Adding React to Hugo
Method described below:
- does not create active development enviroment. It is suited for once-written-no-longer-be-changing
react
components - uses webpack as additional step, adds complexity to your build process (of course)
- assuming using
typescript
Prerequisites:
node
is installedhugo
is installed
Assuming:
- your hugo site is building corectly
- your working directory is hugo site (the place where
config.toml
orconfig.yml
lies)
Installing packages
npm init
npm install react react-dom @types/react @types/react-dom --save
npm install webpack webpack-cli webpack-merge typescript ts-loader style-loader css-loader --save-dev
Create tsconfig.json
{
"compilerOptions": {
"outDir": "./assets/react/dist/",
"sourceMap": true,
"target": "es5",
"module": "es6",
"strict": true,
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
},
"exclude": [
"./themes",
]
}
Create webpack.common.js
. This config is shared betwen developement
(debuging information), and production
(small size and performance).
Components will be stored in ./assets/react/
directory, which
const path = require('path');
module.exports = {
entry: {
coffee_ratio: './assets/react/coffee_ratio/index.tsx'
},
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: [
path.resolve(__dirname, './node_modules/'),
path.resolve(__dirname, './themes/')
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, './assets/react/dist/'),
},
};
Create webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
});
Create webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
});
Add build commands to package.json
{
//...
"scripts": {
"build": "webpack --config webpack.dev.js",
"buildprod": "webpack --config webpack.prod.js"
},
//...
}
Create layouts/shortcodes/react.html
{{ if .Get "entry" }}
<div id="{{ .Get "entry" }}"></div>
{{ else }}
<div id="app"></div>
{{ end }}
{{- $scriptName := print "react/dist/" (.Get "name") ".js" -}}
{{- $app := resources.Get $scriptName -}}
<script src="{{ $app.RelPermalink }}"></script>
Complete Dockerfile
with multi-stage
FROM node:17.6.0-alpine3.15 as node_builder
WORKDIR /app
# restoring node dependecies
ADD package-lock.json package.json ./
RUN npm install
# building assets
ADD tsconfig.json webpack.common.js webpack.prod.js ./
ADD assets ./assets
RUN npm run buildprod
FROM peaceiris/hugo as builder
COPY /app/assets/react/dist /app/assets/react/dist
WORKDIR /app
# building the rest of application
ADD . .
RUN hugo
# coping output to webserver
FROM nginx:1.21.6-alpine as server
COPY /app/public /usr/share/nginx/html