To work on the website you'll need to have either node.js or Docker installed. In your development environment npm run preview
will start up a webpack-dev-server on port 3000 for development which will hot-reload the site as file changes are detected.
The suggested setup for development is using the Docker.
# Build image
docker build -t zaproxy-website .
# Start container with image of zaproxy-website
docker run -it -v "$(pwd)/site:/app/site" \
-v "$(pwd)/src:/app/src" -p 3000:3000 zaproxy-website npm run preview
For development, the site heavily depends on node.js for utilities that build the front-end CSS & JavaScript. The entrypoint for modifying the site JavaScript is src/index.js
which gets transpiled using babel & packed up with webpack packages.
# Check for associated vulns
npm audit
# Check for packages
npm outdated
# Update a package
npm update @babel/core
./bin/build.sh
cp -r ./dist/ ../zaproxy-website-builds
cd ../zaproxy-website-builds
git push origin staging
Generically speaking, the term post & page can be used interchangeably, the exception is when content types are defined (type: post
)
https://gohugo.io/getting-started/directory-structure/
|--site // Everything in here will be built with hugo
| |--content // Posts and collections - ask if you need extra posts
| |--data // YAML data files with any data for use in examples
| |--layouts // This is where all templates go
| | |--_default // This is where the default layouts live
| | |--partials // This is where includes live
| | |--index.html // The index page
| |--static // Files in here ends up in the public folder
|--src // Files that will pass through the asset pipeline
| |--css // Webpack will bundle imported css seperately
| |--index.js // index.js is the webpack entry for your css & js assets
For adding & modifying content the place to be is site/content/
. Content is written in the form of markdown files with YAML headers including details about the post such as title, date & layout. The name of the file is tranformed into a url when the site is generated. A file named site/content/download.md
becomes /download
. Additionally, any folder structure you create in that directory will be reflected in the sites' url heirarchy. That means site/content/blog/2017-08-22-zap-browser-launch.md
becomes /blog/2017-08-22-zap-browser-launch
.
Sample
---
type: page
title: Get Involved
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus et dui ligula.
Donec semper ex at molestie scelerisque. In sodales bibendum leo, vitae porttitor
est viverra at. Phasellus tincidunt enim ac rutrum convallis. Duis at tellus a
erat consequat fringilla. Ut augue leo, blandit vel d
## Mauris
You can also use hugo
commands to create the yaml content files.
# Move to site directory
cd site/
# Create generic content file
hugo new contributing.md
# Create a content file using the site/archetypes/blog.md template
hugo new blog/$(date -v +7d '+%Y-%m-%d')-learning-zap-api/index.md
For keeping content organized you also have the option of encapsulating the content of a post in a directory. If a post has a number of images or other assets related to it, it is much cleaner to include those assets with the post instead of putting them all in the assets directory. For example instead of having site/content/download.md
, you could have site/content/download/index.md
& all the post's related images would also live in that same download
directory.
For adding new categories of content such as addons or wiki entries follow the pattern below using addons as an example
mkdir -p site/content/addons/{images,icons}
site/content/addons/active-scan-rules/images/
site/content/addons/access-control/context-options/_index.md
site/content/addons/access-control/context-options.md
site/content/addons/active-scan-rules.md
---
title: "Active Scan Rules"
type: addon
status: alpha
icon:
---
For controlling what HTML is rendered, you need to work with the site templates. In the directory, site/layouts/
, you'll find a number of HTML files with various template tags. The first file to check out is site/layouts/_default/baseof.html
- this is the base layout Hugo uses to build your site that templates extend. Hugo has a lookup order for associating a content entry to a template. A single entry whose type is post (type: post
), Hugo will look for a layout in site/layouts/post/single.html
, and if that does not exist, it will fallback to site/layouts/_default/single.html
.
For generic posts, the lookup resolution works great, but sometimes you have posts that requires custom layouts, such as the downloads page. In those cases, you can specifiy the layout in the content markdown file & it will lookup the template.
This is what site/content/download.md
currently looks like which resolves to the template found site/layouts/page/download.html
.
type: page
layout: download
---
Data that is shared across the site lives in site/data/
. For example, a list of all the site authors is an example of a piece of data you would reference across numerous places on the site. You can create site/data/authors.yaml
.
---
- name: 'Simon Bennets'
picture: 'https://pbs.twimg.com/profile_images/2186782633/simonbennetts2_400x400.jpg'
twitter: '@psiinon'
is_core: true
- name: 'David Scrobonia'
picture: 'https://pbs.twimg.com/profile_images/1132029219876347904/FYA3rHRq_400x400.png'
twitter: '@david_scrobonia'
is_core: true
Later, in the templates, you would reference that data & the template would render.
{{ range $author := $.Site.Data.authors }}
<section class="post-author-single flex p-10">
<div class="col-1-5">
<img class="author-picture" src="https://github.com/zaproxy/zaproxy-website/raw/main/{{ $author.picture }}" />
</div>
<div class="author-name col-4-5">
{{ $author.name }}
<a class="author-twitter" href="https://twitter.com/{{ $author.twitter }}">{{ $author.twitter }}</a>
</div>
</section>
{{ end }}
https://gohugo.io/templates/data-templates/
For assets that are completely static and don't need to go through the asset pipeline,
use the site/static
folder. Images, font-files, etc, all go there. Files in the static folder end up in the web root. So a file called site/static/favicon.ico
will end up being available as /favicon.ico
and so on...
All the CSS is written in SCSS ("Sassy CSS") with all the files in src/css/
with src/css/main.css
being the entrypoint, defining main variables & importing the needed styles.
Styles are separated by broad category, component and post specific styles. For example, if you need to change the typography across the entire site, src/css/_type.scss
is the file to edit.
https://sass-lang.com/documentation/syntax
The src/index.js
file is the entrypoint for webpack and will be built to /dist/main.js
You can use ES6 and use both relative imports or import libraries from npm. Any CSS file imported into the index.js
will be run through Webpack, compiled with PostCSS Next, and minified to /dist/[name].[hash:5].css
. Import statements will be resolved as part of the build.
You can read more about Hugo's template language in their documentation below. The most useful page there is the one about the available functions.
To separate the development and production - aka build - stages, all gulp tasks run with a node environment variable named either development
or production
.
You can access the environment variable inside the theme files with getenv "NODE_ENV"
. See the following example for a conditional statement:
{{ if eq (getenv "NODE_ENV") "development" }}You're in development!{{ end }}
All tasks starting with build set the environment variable to production
- the other will set it to development
.