This article explains how to introduce TypeScript and React when creating a custom Hugo theme. For the basic Hugo setup, please refer to Creating a Free Blog with Markdown (GitHub Pages + Hugo) .
1. Initializing the Hugo Theme
You can easily create a theme scaffold using the hugo new theme command.
hugo new theme tomatohugo
Running this command creates a directory named tomatohugo with the basic file and directory structure needed for theme development.
tomatohugo git:(main) tree .
.
├── LICENSE
├── README.md
├── archetypes/
│ └── default.md
├── assets/
│ ├── css/
│ │ └── main.css
│ └── js/
│ └── main.js
├── content/
│ ├── _index.md
│ └── posts/
│ ├── _index.md
│ ├── post-1.md
│ ├── post-2.md
│ └── post-3/
│ ├── bryce-canyon.jpg
│ └── index.md
├── data/
├── hugo.toml
├── i18n/
├── layouts/
│ ├── _default/
│ │ ├── baseof.html
│ │ ├── home.html
│ │ ├── list.html
│ │ └── single.html
│ └── partials/
│ ├── footer.html
│ ├── head/
│ │ ├── css.html
│ │ └── js.html
│ ├── head.html
│ ├── header.html
│ ├── menu.html
│ └── terms.html
├── static/
│ └── favicon.ico
└── theme.toml
15 directories, 25 files
LICENSE: Theme license information.README.md: Theme description and usage instructions.archetypes/: Templates for content creation.assets/: Frontend resources such as CSS and JavaScript. Processed by Hugo Pipes.content/: Sample content.data/: Data files used by the theme.hugo.toml: Site-wide configuration file (Hugo 0.112.0+).i18n/: Translation files for multilingual support.layouts/: HTML template files.static/: Static files (images, favicon, etc.). Copied as-is during build.theme.toml: File defining theme settings.
After initialization, you can start a local server with the hugo server command to verify that the simple theme works correctly.
hugo server
2. Introducing TypeScript
Set up the Node.js environment and configure Webpack and the TypeScript compiler to use TypeScript within the theme.
Initialize
package.json: Run thenpm initcommand at the root of the theme directory to create apackage.jsonfile.```bashnpm init -y
Install TypeScript and
ts-loader: Install the TypeScript compiler and the loader for processing TypeScript files with Webpack.```bashnpm install –save-dev typescript ts-loader webpack webpack-cli
Create
tsconfig.json: Create the TypeScript configuration filetsconfig.json.```json{ “compilerOptions”: { “target”: “es5”, // JavaScript output version “module”: “commonjs”, // Module system “outDir”: “./assets/js/”, // Output directory for compiled JS files “strict”: true // Enable strict type checking }, “include”: [ “./assets/ts/**/*.ts” // TypeScript files to compile ], “exclude”: [ “node_modules” // Directories to exclude ] }
Create a TypeScript file: Create a TypeScript file (e.g.,
main.ts) in the./assets/ts/directory.```typescript:assets/ts/main.tsconst message: string = “Hello, TypeScript!”; console.log(message);
Create
webpack.config.js: Create the Webpack configuration file. Webpack is a module bundler for JavaScript applications, used here to bundle TypeScript files.```javascript:webpack.config.jsconst path = require(‘path’);
module.exports = { mode: ‘development’, // or ‘production’ entry: ‘./assets/ts/main.ts’, // Entry point module: { rules: [ { test: /\.ts$/, // Target .ts files use: ’ts-loader’, // Use ts-loader exclude: /node_modules/, }, ], }, resolve: { extensions: [’.ts’, ‘.js’], // Extensions to resolve during import }, output: { filename: ‘bundle.js’, // Output file name path: path.resolve(__dirname, ‘assets/js’), // Output directory }, };
6. **Run the build**:
Run Webpack to compile TypeScript files into JavaScript and bundle them.
```bash
npx webpack
``` This creates`./assets/js/bundle.js`.
7. **Integration into Hugo templates**:
To incorporate the generated JavaScript file into Hugo templates, add code like the following in an appropriate location such as `layouts/partials/head/js.html`.
```html:layouts/partials/head/js.html
<!-- layouts/partials/head/js.html -->
{{- with resources.Get "js/bundle.js" }}
<script src="{{ .RelPermalink }}"></script>
{{- end }}
```
PR example for TypeScript introduction: [https://github.com/yuhi-sa/tomatohugo/pull/1](https://github.com/yuhi-sa/tomatohugo/pull/1)
## 3. Introducing React
Add React to the TypeScript environment.
1. **Install React-related libraries**:
Install React itself, the DOM manipulation library, and their type definition files.
```bash
npm install --save react react-dom
npm install --save-dev @types/react @types/react-dom
```
2. **Writing a React component**:
Since React uses JSX (JavaScript XML) syntax for writing components, change the TypeScript file extension to `assets/ts/main.tsx`.
```typescript:assets/ts/main.tsx
import React from 'react';
import { createRoot } from 'react-dom/client'; // Recommended API for React 18+
const App = () => {
return (
<div>
<h1>Hello, React!</h1>
</div>
);
};
// Get the mount point element in HTML
const appElement = document.getElementById('app-root'); // Example: id is 'app-root'
if (appElement) {
const root = createRoot(appElement); // Create root with createRoot
root.render(<App />); // Render the component
}
``` **Note**: From React 18 onwards, using`createRoot`instead of`ReactDOM.render`is recommended. Also change the mount point ID in the HTML to`app-root` or similar.
3. **Integration into Hugo templates**:
Add an HTML element for calling the React component to the appropriate Hugo template file (e.g., `layouts/_default/single.html` or `layouts/_default/home.html`).
```html
<main>
<div id="app-root"></div> <!-- React component mount point -->
</main>
<!-- Load JavaScript -->
{{- partial "head/js.html" . -}}
Update Webpack configuration: Update the Webpack configuration to bundle React components (.tsx files).
```javascript:webpack.config.jsconst path = require(‘path’);
module.exports = { mode: ‘development’, entry: ‘./assets/ts/main.tsx’, // Change entry point to .tsx module: { rules: [ { test: /\.tsx?$/, // Target .ts or .tsx files use: ’ts-loader’, exclude: /node_modules/, }, ], }, resolve: { extensions: [’.ts’, ‘.tsx’, ‘.js’], // Add .tsx to extensions }, output: { filename: ‘bundle.js’, path: path.resolve(__dirname, ‘assets/js’), }, };
5. **Verification**:
Verify the setup by starting the local server and confirming that "Hello, React!" is displayed.
```bash
hugo server
```
PR example for React introduction: [https://github.com/yuhi-sa/tomatohugo/pull/2](https://github.com/yuhi-sa/tomatohugo/pull/2)