Combining Hugo and React

Re-designing my portfolio site

Why Hugo?

As I document my development journey Hugo offers a wonderful opportunity for a fully fledged blog feature. Generating a new post is as easy as running hugo new blog posts/title which then creates all the correct routing and with the layouts markdown can even handle things like tags, author, date created, pagination and order.

//index.html
<div>
<a href="https://dashboard.featurepeek.com/peek/k5zh70zl#/">
<div class="beatjuice portfolio-proj zoom bottom-margin_10">
</div>
</a>
<p class="text-center port-desc_mw bottom-margin_10">A beat machine made with React and Howler.js
</p>
</div>

<div>
<a href="https://fork-it-all.herokuapp.com/">
<div class="forkitall portfolio-proj zoom bottom-margin_10">
</div>
</a>
<p class="text-center port-desc_mw bottom-margin_10">Forkitall - A single page React app that allows users
to share
their twists on various recipes. Pulls data from <a
href="https://www.themealdb.com/api.php">TheMealDB.com</a>
</p>
</div>

<div>
<a href="https://github.com/AndrewRLloyd88/jungle-rails">
<div class="jungle portfolio-proj zoom bottom-margin_10"></div>
</a>
<p class="text-center port-desc_mw bottom-margin_10">Jungle - A mini e-commerce application built with
Rails 4.2
</p>
</div>
//style.css

/* Portfolio Elements */

.listkeeper {
background-image: url('./images/listkeeper.jpg');
background-size: cover;
}

.beatjuice {
background-image: url('./images/beatjuice.jpg');
background-size: cover;
}

.phaserpong {
background-image: url('./images/pong.jpg');
background-size: cover;
}

.jeopardy {
background-image: url('./images/jeopardy.jpeg');
background-size: cover;
}

.forkitall {
background-image: url('./images/cookdinosaur.svg');
background-size: cover;
}
"build": "npm-run-all webpack hugo-build",
"hugo-build": "hugo --cleanDestinationDir",
"hugo-server": "hugo server --disableFastRender",
"webpack": "webpack",
"webpack-watch": "webpack --watch",
"dev": "npm-run-all webpack --parallel webpack-watch hugo-server"
const path = require('path');

module.exports = {
entry: './themes/arlmediaTheme/assets/js/index.js',
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'themes', 'arlmediaTheme', 'assets', 'js'),
},
};
import axios from 'axios';
import lunr from 'lunr';

axios.get('https://api.kanye.rest').then((res) => {
console.log(res.data);
});
module.exports = function (api) {
api.cache(true);
const presets = [['@babel/preset-react']];
const plugins = [];
return {
presets,
plugins,
};
};
const path = require('path');

module.exports = {
entry: './themes/arlmediaTheme/assets/js/index.js',
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'themes', 'arlmediaTheme', 'assets', 'js'),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
},
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
include: /flexboxgrid/,
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader'],
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
},
};
import React, { useState, useEffect } from 'react';
import { projectData } from './projectData';

export default function main() {
return (
<div className="project">
{projectData.map((project, i) => (
<div className="project-inner">
<div className="project-container">
<div className="project-description">
<div className="project-desc-text">
<p className="desc">{project.description}</p>
{project.frontend && (
<p className="stack-type">
<span className="stack-type-title">Frontend:</span>
<div className="stack-row">
{project.frontend.map((icon, i) => (
<span className="stack-icon">
<img
className="stack-image"
src={icon}
title={project.frontendNames[i]}
></img>
</span>
))}
</div>
</p>
)}
{project.backend && (
<p className="stack-type">
<span className="stack-type-title">Backend:</span>
<div className="stack-row">
{project.backend.map((icon, i) => (
<span className="stack-icon">
<img
className="stack-image"
src={icon}
title={project.backendNames[i]}
></img>
</span>
))}
</div>
</p>
)}
{project.test && (
<p className="stack-type">
<span className="stack-type-title">Test:</span>
<div className="stack-row">
{project.test.map((icon, i) => (
<span className="stack-icon">
<img
className="stack-image"
src={icon}
title={project.testNames[i]}
></img>
</span>
))}
</div>
</p>
)}
{project.deployment && (
<p className="stack-type">
<span className="stack-type-title">Deployment:</span>
<div className="stack-row">
{project.deployment.map((icon, i) => (
<span className="stack-icon">
<img
className="stack-image"
src={icon}
title={project.deploymentNames[i]}
></img>
</span>
))}
</div>
</p>
)}
</div>
</div>
<img className="project-image" src={project.image}></img>
</div>
<div className="project-control-panel">
<p className="project-name">{project.name}</p>
<div className="project-buttons">
{project.github !== '' && (
<button
onClick={() => {
window.location.href = `${project.github}`;
}}
>
Code
</button>
)}
{project.demo !== '' && (
<button
onClick={() => {
window.location.href = `${project.demo}`;
}}
>
Demo
</button>
)}
</div>
</div>
</div>
))}
</div>
);
}
export const projectData = [
{
name: 'MB-WYSIWYG Text Editor',
description:
'A Rich Text Editor built for Mintbean’s Build Your Own Text Editor hackathon.',
image: '/images/projects/wysiwyg.png',
github: 'https://github.com/AndrewRLloyd88/mb-text-editor',
demo: 'https://mb-wysiwyg-text-editor.netlify.app/',
frontend: [react, typescript, css3, materialui],
backend: null,
test: null,
deployment: [netlify],
frontendNames: ['React', 'TypeScript', 'CSS3', 'MaterialUI'],
backendNames: null,
testNames: null,
deploymentNames: ['Netlify'],
},
//more projects are below in the array

How to add more than one React Style Entry File

I needed to run two React scripts one for my projects and one for my skills to map out in a similar way as the above. With the setup I currently had no way to define two entry and output files. After doing a bit of researching I came across this useful post:

module.exports = {
entry: {
index: './themes/arlmediaTheme/assets/js/modulea/index.js',
projects: './themes/arlmediaTheme/assets/js/moduleb/projects.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'themes', 'arlmediaTheme', 'assets', 'js'),
},
//...

SVG Limit errors

I also encountered some issues whilst using SVGs at first due to the custom setup with webpack. Initially all of my SVG resources were coming back 404 despite having the correct path. At one point a lot of .SVG files were being generated with a minified name and the browser was clearly not recieving the correct files:

{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {
limit: 10000,
},
},
],
},
{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {
limit: 1000000,
},
},
],
},

About The Author

  • HTML5
  • TypeScript
  • JavaScript
  • Ruby on Rails
  • CSS3
  • MySQL/PostgreSQL
  • Bootstrap
  • MaterialUI
  • React
  • Redux

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store