squido
is a dead simple static website builder which can be hosted anywhere for super fast websites and very little effort.
The idea is to be a no-code
setup and have everything you need to run and host a website. You simply do the writing and customization of style and layout.
Simply install the squido
cli module globally in order to build and manage your static site.
From Github (preferred for latest version)
$ npm i -g https://github.com/mrvautin/squido.git
From npm
$ npm install -g squido
With Yarn
$ yarn global add squido
Make your squido
website directory:
$ mkdir my-squido-website
Enter your new squido
website directory:
$ cd my-squido-website
Setup a new squido
website from defaults
$ squido new
Make your squido
website directory:
$ mkdir my-squido-website
Enter your new squido
website directory:
$ cd my-squido-website
Get started building your squido
website structure.
The example we will use below is our blog example. There is also a documentation website example you can use.
$ git clone https://github.com/mrvautin/squido-blog-example my-squido-website
Replace my-squido-website
with your new website directory name
Enter your new squido
website directory:
$ cd my-squido-website
Run the following command to build, clean, serve and watch for changes:
$ squido serve -b -w -c
You can then visit your website here:
http://localhost:4965
Clean
= removes everything in your/build
directory.
Serve
= starts a web server so you can view your website.
Whilst it's best and easiest (depending on the user) to use squido
with Git to manage deployment and source control. If you don't want to use Git you can use our Post Build tasks to easily deploy and manage your website.
$ git remote add origin https://github.com/user/repo.git
$ git remote -v
# Verify new remote
> origin https://github.com/user/repo.git (fetch)
> origin https://github.com/user/repo.git (push)
/source/posts/hello-world.markdown
---
title: Hello World
permalink: hello-world
description: Hello World
date: '2021-03-10 01:59:00'
---
$ git add .
$ git commit -m "First commit"
$ git push
Setup the deploy/hosting.
Blog style: https://squido-blog.markmoffat.com
Documentation style: This website
Traditional website: https://squido.markmoffat.com
]]>/source
directory of here.
The structure will look something like:
The /<source_dir>
directory is the default directory for all the source files. You can change by adding another directory in the sourceDir
of the config.js
file.
File name | Usage |
---|---|
index.hbs |
The root of your website. The first page which will be rendered. |
post.hbs |
Will render the contents of the .markdown files in /<source_dir>/posts |
page.hbs |
Displayed at /page/x for the pagination of posts |
tag.hbs |
Displayed at /tag/x for the collection of posts by tag |
Your posts go in the /<source_dir>/posts
directory. You will have .markdown
files for each post/page you want.
The content
directory contains the files used for your website. Eg: Stylesheets, images, javascript files etc.
Usage: cli [options] [command]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
build [options] Builds your website
clean Clean your website build
serve [options] Serves website
The build
command has the following options:
Usage: build [options]
Builds your website
Options:
-c --clean Cleans build directory
-h, --help output usage information
The import
command allows you to import content from external sources. It has the following options:
Usage: import [options]
Import from external sources
Options:
-f, --file <path> Specify file to import
-t, --type <type> Specify the type of file to import. Eg: wordpress or ghost
-h, --help output usage information
The clean
command has the following options:
Usage: clean [options]
Clean your website build
Options:
-h, --help output usage information
The serve
command has the following options:
Usage: serve [options]
Serves website
Options:
-w --watch Watches for changes
-b --build Builds on start
-c --clean Cleans build directory
-h, --help output usage information
This command sets up a new website from our blog template.
The new
command has the following options:
Usage: new [options]
Sets up a new website
Options:
-h, --help output usage information
]]>development
and production
are examples but they need to match up with whatever NODE_ENV
is set. If one is not set, the default is development
.
const config = {
development: {
name: 'squido',
description: 'This is the blog description',
twitterHandle: '@mrvautin',
baseUrl: 'http://localhost:4965',
sourcesExt: 'markdown',
templateEngine: 'hbs',
templateConfig: {},
sourceDir: 'source',
contentDir: 'content',
buildDir: 'build',
summaryLength: 250,
port: 4965,
pagination: true,
postPerPage: 8
},
production: {
name: 'squido',
description: 'This is the blog description',
twitterHandle: '@mrvautin',
baseUrl: 'http://example.com',
sourcesExt: 'markdown',
templateEngine: 'hbs',
templateConfig: {},
sourceDir: 'source',
contentDir: 'content',
buildDir: 'build',
summaryLength: 250,
port: 4965,
pagination: true,
postPerPage: 8,
postBuild: [
{
name: 'zip',
options: {}
}
]
}
};
module.exports = config;
Config | Usage |
---|---|
name |
Used in default templates for <title> and meta tags for homepage |
description |
Used in default templates for meta tags for homepage |
baseUrl |
Used for URL building purposes. Would set this to https://example.com |
sourcesExt |
The file extension for your markdown posts |
templateEngine |
The template engine to use. Possible values are: hbs , ejs or pug |
sourceDir |
The directory where your markdown posts reside |
contentDir |
The directory where your Javascript, CSS, images and other assets reside |
buildDir |
The directory where the static HTML files and assets are placed after building |
summaryLength |
The length of the post summary which is available in the meta data of the post |
port |
The port used when running squido serve |
pagination |
This controls whether you want squido to paginate your posts |
postPerPage |
This controls how many posts appear per page |
postBuild |
Controls any post build tasks you wish to run. See here |
You can use any of the config values in your template files using {{config.<option>}}
. Eg: For example {{config.baseUrl}}
.
The templateEngine
config allows for the setting of which template engine to use - either: hbs
, ejs
or pug
is allowed. The templateConfig
object allows for the passing of configurations and is used when ejs
or pug
is set for the templateEngine
. See here for available ejs
options and here or pug
.
/source/posts
folder. The post markdown or contents is rendered using the post.hbs
template file. You can edit this any which way your want. See templates for more information.
Posts have a meta data component at the top of the file which directs how the file is built. The meta data is yaml
formatted and sits between two ---
tags. Eg:
---
title: Caede virides oculos armentis
permalink: caede-virides-oculos-armentis
description: Caede virides oculos armentis
date: '2021-03-11 19:17:00'
template: post.hbs
ignore: true
hidden: false
tags:
- alter
- tradere
---
Required fields are: 'title', 'permalink', 'description' and 'date'
You can add any data values your like but the example layouts uses the title
and description
for SEO for page title.
New meta data values can be access in the layouts using {{meta.<new value>}}
.
The permalink is required. Its used to build the URL for your website: Eg. The above will output a post at: https://example.com/caede-virides-oculos-armentis
The visible
and hidden
are optional tags for controlling the visibility of posts. Defaults is "true"
or visible.
visible
: If set to false
, the post will not be in the pagination and won't show on the index page.hidden
: If set to true
, the post will not be in the sitemap and RSS feeds.The default template file name for posts is post.hbs
but this can be overwritten per post by adding a template
meta value to your post. Eg:
---
template: template-name.hbs
---
]]>squido
uses CommonMark spec to process the markdown formatted posts.
A quick syntax summary to get your started:
Type | Renders |
---|---|
Italic or _Italic_ | Italic |
*Bold* or _Bold_ | Bold |
# Heading 1 | Heading 1 |
# Heading 2 | Heading 2 |
# Heading 3 | Heading 3 |
[Link](https://a.com) | Link |
[Image](https://url/a.png) | |
> Blockquote | Blockquote |
* List * List * List or - List - List - List |
|
1. List 2. List or 1) List 2) List 3) List |
|
Horizontal rule: --- or *** |
Horizontal rule: |
`Inline code` with backticks | Inline code with backticks |
``` javascript const test = () => { console.log('test'); }; ``` |
const test = () => { |
You can play around with the Markdown Playground here.
squido
uses Highlight.js for code highlighting. This means you can use the code block example above with code wrapped in ``` backticks. You can specify the language by adding the language for your code block.
For example, adding this:
``` javascript
function test(p1, p2) {
console.log('test');
};
```
Renders this:
function test(p1, p2) {
console.log('test');
};
You can add any HTML attributes including ID's and classes by adding {attribute}
to your Markdown syntax.
Adding a class to a header (style-me
is the class):
# header {.style-me}
Adding a data-toggle
attribute to a paragraph:
paragraph {data-toggle=modal}
You can also use this on tables with multiple classes. Eg (note the empty line under the table):
My table | Header
-------------- | ----------
Table | Contents
{.table .table-hover .table-bordered}
Renders this:
My table | Header |
---|---|
Table | Contents |
All headings are automatically rendered as # anchors to hyperlink (skip) to sections within a page / post. This means you add the /#heading-name
to the URL to automatically jump to that heading.
For example: https://squido-docs.markmoffat.com/markdown/#playground
]]>{{}}
syntax, EJS or pug. This guide will show Handlebars
formatting. Documentation on changing the templateEngine
can be found here.
Handlebars
formatting.
Documentation on changing the templateEngine
can be found here.
The template files needed by default are:
index.hbs
post.hbs
page.hbs
tag.hbs
404.hbs
Also needed is a layout file called layout.hbs
located here: /source/layouts/layout.hbs
. This file drives the main layout of the page including the <html>
, <head>
, <body>
etc tags.
Accessible on all layout and templates files is your post meta using {{meta.<property>}}
and your config.js
object. You can access that using {{config.<propery>}}
.
This is the entry point of your website, the index.html
in the root of your build directory.
You will have access to a list of posts which you may want to display if building a blog or you may want to manually create a landing page for your website. The choice is yours.
If you were to render your posts you may want to do something like where {{#each posts}}
is looping our list of posts:
<div class="row">
{{#each posts}}
<div class="article">
<h2>
<a href="/{{this.permalink}}/">{{this.title}}</a>
</h2>
{{this.summary}}
</div>
{{/each}}
</div>
Depending on if you have pagination
set to true
in your config, you will either get a full list of articles or a paginated list. See pagination for more info.
This is the rendering of the post or the markdown content at the permalink
set. Eg: mydomain.com/permalink-value
.
To render the body of the markdown file you will need to add the following tag to your template: {{{body}}}
You will have access to the full meta values of the page but can also access the title using {{title}}
. Depending on whether you included tags in the meta data of the markdown file, you will also get a tags
object you can loop through to display tags. See tags for more info.
A simple post page could be:
<div class="row">
<div class="col-md-8 offset-md-2 mb-5">
<div class="mt-5">
<h1>{{title}}</h1>
{{{body}}}
</div>
</div>
</div>
This is the pagination aspect of your website. This template is used at /page/x
(where x
is the page number). If you are creating a blog which will have pagination this could look very similar to the index.hbs
which shows all your articles/posts. Similar to the index.hbs
you will get a post
object with the posts you should render if you are doing pagination.
A simple template could look like:
<div class="row">
{{#each posts}}
<div class="col-xs-12 col-sm-3 mb-4 d-flex align-items-stretch">
<div class="card shadow-sm">
<div class="card-body">
<p class="card-text">
<h2>
<a href="/{{this.permalink}}/">{{this.title}}</a>
</h2>
{{this.summary}}
</p>
<div class="d-flex justify-content-between align-items-center">
<a class="btn btn-outline-secondary" href="/{{this.permalink}}/">Read more..</a>
</div>
</div>
</div>
</div>
{{/each}}
</div>
This is the tag page which is generated from the tags set in your post markdown. A page is create for each tag you use in your markdown files and is accessible at: /tag/<tag-value>
. Keep this in mind when setting tag values where you will want to give permalink type values for pretty URLs.
A simple template could look like:
<div class="row">
<h1>Tag: {{tag}}</h1>
{{#each posts}}
<div class="col-xs-12 col-sm-3 mb-4 d-flex align-items-stretch">
<div class="card shadow-sm">
<div class="card-body">
<p class="card-text">
<h2>
<a href="/{{this.permalink}}">{{this.title}}</a>
</h2>
{{this.summary}}
</p>
<div class="d-flex justify-content-between align-items-center">
<a class="btn btn-outline-secondary" href="/{{this.permalink}}/">Read more..</a>
</div>
</div>
</div>
</div>
{{/each}}
</div>
Hopefully this one is obvious. If at any point a page isn't found or a URL is mistyped this 404 page will be rendered.
A simple template:
<div class="row">
<div class="col-md-6 offset-md-3 mt-5 mb-3">
<div class="text-center">
<img src="/content/images/squido.svg" alt="" width="200" height="200" alt="squido logo" class="img-fluid">
</div>
<h1 class="mt-5 text-center">404 - Page not found</h1>
</div>
</div>
You can include local Stylesheets and Javascript files in the layout.hbs
file by using path starting with /content
and then wherever you have placed the file. Eg: /content/stylesheets/<myfile>.css
.
The layout.hbs
also includes a config
property named fileEnv
({{config.fileEnv}}
) which will return either nothing or .min
if you have set the NODE_ENV
to production
. This is useful if you are wanting to use the un-minified CSS or JS file when troubleshooting/developing your website and using the minified version when in production.
Example usage:
<link rel="stylesheet" href="/content/stylesheets/style{{config.fileEnv}}.css">
<script src="/content/javascripts/site{{config.fileEnv}}.js"></script>
Within a post you have access to a tag
array which contains all the tags for that post. You may want to iterate through that array to link to the /tag/<tag-value>
URL. For example:
{{#if tags}}
<div class="row">
<div class="col-md-8 offset-md-2 mb-5">
<h5 class="text-muted">Tags:</h5>
{{#each tags}}
<a href="/tag/{{this}}/">{{this}}</a> |
{{/each}}
</div>
</div>
{{/if}}
If pagination
is set to true in your config.js
file, the post
object available on all templates will be paginated to the postPerPage
value you set in your config.js
. Eg: 10 posts and postPerPage
set to 5 will create 2 pages. 1, the index page and /page/1
as the first paginated page.
You will also get a shouldPaginate
variable which will return true
or false
depending on whether there is more posts than can be displayed - eg: you should paginate.
An example displaying the pagination might look like:
{{!-- Pagination --}}
{{#if config.pagination}}
{{#if shouldPaginate}}
<div class="row">
<div class="col-xs-12 col-sm-12 mb-4 text-center">
<p class="text-muted">Page {{page}} of {{pages}}</p>
<div class="btn-group" role="group">
{{#if prevPage }}
<a href="/page/{{prevPage}}/" class="btn btn-outline-secondary">« Prev Page</a>
{{/if}}
{{#if nextPage }}
<a href="/page/{{nextPage}}/" class="btn btn-outline-secondary">Next Page »</a>
{{/if}}
</div>
</div>
</div>
{{/if}}
{{/if}}
squido
supports the adding of custom data to your website. This function allows for yaml
, json
or text
formatted files to be parsed and added to the data available in your templates.
Adding custom data is as simple as adding the following Array of Objects to your config.js
file. You will need to have the following properties:
name
= The name which is accessible in your template. Eg: A name
of swagger
will mean the contents of the file is accessible at data.swagger
.type
= Supported types are: yaml
, json
or text
file
= The file path in relation to your sourceDir
. In the example below the file is located: source/swagger.yaml
A full example below:
const config = {
development: {
name: 'squido',
description: 'This is the blog description',
twitterHandle: '@mrvautin',
baseUrl: 'http://localhost:4965',
sourcesExt: 'markdown',
templateEngine: 'hbs',
data: [
{
name: 'swagger',
type: 'yaml',
file: 'swagger.yaml'
}
],
sourceDir: 'source',
buildDir: 'build',
...
}
}
squido
supports Swagger using our custom data functionality. You can use this to setup super fast static API documentation. Simply grab our demo swagger.hbs template and setup a post like the following where template: swagger.hbs
is the path to the Swagger template file in your sourceDir
:
---
title: Swagger API docs
permalink: api
description: Swagger API Docs
date: '2021-05-11 19:17:00'
template: swagger.hbs
visible: false
hidden: false
---
Then setup your config.js
to include the Swagger data like:
const config = {
development: {
name: 'squido',
description: 'This is the blog description',
twitterHandle: '@mrvautin',
baseUrl: 'http://localhost:4965',
sourcesExt: 'markdown',
templateEngine: 'hbs',
data: [
{
name: 'swagger',
type: 'yaml',
file: 'swagger.yaml'
}
],
sourceDir: 'source',
buildDir: 'build',
...
}
}
Where
swaggerFile
is the name of yourswagger.yaml
file in relation to yoursourceDir
. Note: thetype
can also be set tojson
for a JSON formatted Swagger file.
Partials can be created in /source/partials
and can be used in layout and other template files.
Once a file is created you can add it to your template using:
{{> header}}
Where
header
is the name of the fileheader.hbs
located:/source/partials/header.hbs
ejs
handling of partials is a little more flexible. You can setup your config using the templateConfig.views
option with the directory where the partials will exist. Eg:
const config = {
development: {
name: 'squido',
description: 'This is the blog description',
twitterHandle: '@mrvautin',
baseUrl: 'http://localhost:4965',
sourcesExt: 'markdown',
templateEngine: 'ejs',
templateConfig: {
views: ['source/partials']
},
sourceDir: 'source',
buildDir: 'build',
...
}
}
Note: The
templateConfig.views
takes an array of paths
Pug partials is super easy. You need to setup the root by setting the templateConfig.basedir
to __dirname
. Eg:
const config = {
development: {
name: 'squido',
description: 'This is the blog description',
twitterHandle: '@mrvautin',
baseUrl: 'http://localhost:4965',
sourcesExt: 'markdown',
templateEngine: 'pug',
templateConfig: {
basedir: __dirname
},
sourceDir: 'source',
buildDir: 'build',
...
}
}
Then in a template you can include a partial by adding the following: include /source/partials/header.pug
/sitemap.xml
. Eg: example.com/sitemap.xml
RSS/Atom/JSON feeds are also automatically built and can be found at:
/rss
. Eg: example.com/rss
/atom
. Eg: example.com/atom
/json
. Eg: example.com/json
Plugins are Javascript files within /<source dir>/plugins/<plugin name>.js
.
The plugin file needs to export a function named run
. For example:
const run = (opts) => {
/* code in here */
console.log('opts', opts);
};
module.exports = {
run
};
Adding plugins to your /config.js
file is simple by adding the plugin to the plugins array:
const config = {
development: {
...
plugins: [
{
name: 'search',
options: {}
}
]
}
}
name
: the name of the plugin. This also needs to match the name of the file. Eg: /source/plugins/search.js
options
: An arg object passed into the plugin.
You can access environment variables in your plugins using the process.squido.envVars
object.
You might want to do something different in your plugin based on a environment variable you've set with you hosting provider.
An example plugin:
const run = (opts) => {
const config = process.squido;
let toPrint = 'Hello squido';
if(config.envVars.helloMessage){
toPrint = config.envVars.helloMessage;
}
console.log(`Hello ${toPrint}`);
};
module.exports = {
run
};
Eg: For Netlify you would set a variable named helloMessage
to World
(for example above) and the plugin would then console.log Hello World
if the environment variable is set and Hello squido
when nothing is set.
squido
allows the importing of content from Ghost and Wordpress.
We will use the import command.
To import data, you first need to export your data from your Ghost site:
cog
icon at the bottom of the sidebarLabs
Export your content
To import that data into squido
you need to run this command from the root of your squido
website:
$ squido import -f /path/to/file/ghost.json -t ghost
You will see a new folder with all your posts in Markdown format here: /imported
.
You can check your files are imported correctly then move your newly imported Markdown files here: /<source dir>/posts
.
To import data, you first need to export your data from your Wordpress site:
Tools
Export
Export all
To import that data into squido
you need to run this command from the root of your squido
website:
$ squido import -f /path/to/file/wordpress.xml -t wordpress
You will see a new folder with all your posts in Markdown format here: /imported
.
You can check your files are imported correctly then move your newly imported Markdown files here: /<source dir>/posts
.
You can host this website anywhere static websites are supported. Some options are https://www.netlify.com as the deployments are just dead simple.
Simply connect your Git repo and set the Build settings
settings like below:
And set the Environment variable to align with your config.js
file:
You are done. Now each push to your Git repo will trigger the build and deploy on Netlify.
Publishing to Github pages is easy. Simply set your config buildDir
to docs
and the correct baseUrl
. Eg:
production: {
name: 'squido',
description: 'This is the blog description',
twitterHandle: '@mrvautin',
baseUrl: 'https://<github-username>.github.io',
sourcesExt: 'markdown',
sourceDir: 'source',
buildDir: 'docs',
summaryLength: 250,
port: 4965,
pagination: true,
postPerPage: 8
}
Then simply build your website with squido build -c
and push to your Github repo.
You then need to set Source
to /docs
as shown here and may need to change the branch.
You can then either access at your Repo URL (https://<github-username>.github.io
) or a custom domain
It's very easy to publish your squido
website to AWS Amplify.
New App
Host web app
Edit
on the build commands and ensure baseDirectory
is set to /build
. Eg Yaml file will look like:version: 1
frontend:
phases:
preBuild:
commands:
- npm ci
build:
commands:
- npm run build
artifacts:
baseDirectory: /build
files:
- '**/*'
cache:
paths:
- node_modules/**/*
Save and deploy
and wait for your website to be built!It's very easy to publish your squido
website for FREE
using Cloudflare pages. Free SSL, custom domain, global CDN and more and just super simple to setup.
Create new project
Begin setup
Save and deploy
Custom domains
and you are doneDigitalocean Apps makes hosting your static HTML squido
website for FREE
just so bloody easy. Digitalocean Apps offers free SSL, custom domain, global CDN and more.
Github
as source and choose your squido
Repository:Next
Next
.Next
once moreStarter
for FREE
hostingLaunch Starter App
View logs
buttonSettings
and configure your domain and moreYou are done. Enjoy your super fast hosting on the awesome Digitalocean platform!
Publishing your squido
website to Azure Static Web Apps is very easy and low cost.
Other
under Deployment details
.Manage Deployment Token
. Copy this token somewhere safe. It will be used later.Repos
and clone the Azure repo to your local machine. Either move your existing squido
site into this local repo, or create a new squido
site. Commit and push code to this Azure DevOps repoPipelines
and create a new Pipeline for the project. Select Starter Pipeline
and paste in the yaml template belowtrigger:
- main
pool:
vmImage: ubuntu-latest
variables:
- name: NODE_ENV
value: production
steps:
- checkout: self
submodules: true
- task: AzureStaticWebApp@0
inputs:
app_location: '/'
output_location: '/build'
azure_static_web_apps_api_token: $(deployment_token)
Variables
then New Variable
deployment_token
and paste in the Deployment Token
from Step 1c. abovesquido
admin panel is accessible after running the serve.
Running serve:
$ squido serve -b -c -w
Open the following in a browser: http://localhost:4965/squido
You should see:
Here you can create, edit and delete any posts for you website. Once you have completed you simply need to deploy or Git commit and push to your repo.
]]>The zip
postBuild
task simply zips all the files in your /build
directory into a file called build.zip
located here: /build/build.zip
. You can then send/upload this file to your website host, FTP it or back it up.
An example config.js
configuration is below. There are no options for this task.
production: {
name: 'squido docs',
description: 'Squido documentation - A dead simple static website generator',
...
postBuild: [
{
name: 'zip',
options: {}
}
]
...
}
The netlify
postBuild
deploys your website to Netlify without the use of Git. This task requires the zip
task to also be configured before this task (see below config) as this task will upload the zip file containing your website direct to Netlify using their file upload API.
An example netlify
task configuration is below. You can see the zip
task is configured first:
production: {
name: 'squido docs',
description: 'Squido documentation - A dead simple static website generator',
...
postBuild: [
{
name: 'zip',
options: {}
},
{
name: 'netlify',
options: {
siteName: 'squido test website'
apiToken: 'my-netlify-api-token'
}
}
]
...
}
To use this task you will need to obtain your apiToken
from Netlify
by:
Netlify
here https://app.netlify.com/user/applicationsPersonal access tokens
, click New access token
config.js
file under apiToken
After you run:
$ squido build -c
The build files of your website will first be added to a zip file, then that file is uploaded to Netlify to be built and served. You can then view your Netlify websites under the Sites
tab and can control your custom domain and other settings.