To integrate Svelte components into your Hugo website, you’ll need to set up a separate npm project within your Hugo project’s root directory. This approach allows you to manage and build your Svelte components independently, making it easier to maintain and update them over time.
Here’s the file structure you’ll be working with:
├── content
├── hugo.toml
├── package.json
├── package-lock.json
├── rollup.config.mjs
├── svelte
│ └── components
│ └── my-component
│ └── my-component.svelte
└── themes
└── yourtheme
The package.json
file contains the necessary dependencies for building your Svelte components. Let’s take a look at the contents:
{
"name": "svelte-component-library",
"version": "0.0.1",
"private": true,
"scripts": {
"build": "rollup -c",
"build:component": "rollup -c --component",
},
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"browser-sync": "^3.0.3",
"globby": "^12.0.2",
"npm-run-all": "^4.1.5",
"rollup": "^2.3.4",
"rollup-plugin-css-only": "^3.1.0",
"rollup-plugin-svelte": "^7.0.0",
"rollup-plugin-terser": "^7.0.0",
"svelte": "^5.1.3"
}
}
The rollup.config.mjs
file is responsible for configuring the Rollup build process for your Svelte components. It ensures that each component is built and optimized for inclusion in your Hugo project.
import svelte from "rollup-plugin-svelte";
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import { terser } from "rollup-plugin-terser";
import css from "rollup-plugin-css-only";
import { globbySync } from "globby";
const production = !process.env.ROLLUP_WATCH;
const formats = ["umd"];
const argIndex = process.argv.findIndex(arg => arg === '--component');
const targetComponent = argIndex !== -1 ? process.argv[argIndex + 1] : null;
// If a specific component is specified, only build that one
const components = targetComponent
? [targetComponent]
: globbySync("svelte/components/**/*.svelte").map(
(path) => path.split("/")[2]
);
export default components.map((component) => ({
input: `svelte/components/${component}/${component}.svelte`,
output: formats.map((format) => ({
name: component,
file: `static/js/${component}.min.js`,
format,
})),
plugins: [
svelte({ compilerOptions: { dev: !production, customElement: true } }),
css({ output: "bundle.css" }),
resolve({
browser: true,
dedupe: ["svelte"],
}),
commonjs(),
terser(),
],
watch: {
clearScreen: false,
},
}));
Once you’ve finished testing your Svelte components, you’ll need to add a custom HTML tag to each of them. This will allow you to easily insert the components into your Hugo content:
<svelte:options customElement="my-component" />
<script></script>
<html><html>
<style></style>
To build all of your components, run the following command:
npm run build
If you only want to build a specific component, you can use the following command:
npm run build:component -- my-component
Finally, to inject your newly built Svelte components into your Hugo content, you can create a custom HTML shortcode. Since you can’t directly inject raw HTML in Hugo, you’ll need to create a shortcode that handles the component insertion for you. Here’s an example of how you might do this:
+++
title = 'My blog'
draft = false
+++
/* raw html shortcode begin
<script src='/js/my-component.min.js'></script>
<my-component></my-component>
/* raw html shortcode end
By following this structure, you can integrate Svelte components into your Hugo-powered website, allowing you to take advantage of the power and flexibility of both technologies. Although I dont think the workflow is seamless, it still needs some refinement but it gets the job done