Skip to content

Build awesome configuration

Customize the static site generator that builds your Silex websites.

Overview

Silex uses build awesome (powered by Eleventy) to compile website source files (from GrapesJS) into static HTML, CSS, and assets. The build awesome build process is triggered when a user publishes, running the .eleventy.js config file and any data files.

You can customize: - Directory structure (input, output, includes) - Plugins and filters - Data files (.json, .js) - Template languages - Build transforms and passes

Prerequisites

CMS configuration (EleventyPluginOptions)

The Silex CMS plugin exposes a configuration object that controls build awesome behavior:

interface EleventyPluginOptions {
  enabled: boolean // Enable/disable 11ty build
  enable11ty: boolean // Actually run 11ty (vs just passing files through)
  cacheBuster: boolean // Add timestamps to asset URLs
  dataSources: DataSource[] // GraphQL APIs for CMS
  dir: {
    input: string // Where website files come from
    html: string // Where HTML files go (relative to input)
    assets: string // Assets directory
    css: string // CSS directory
  }
  urls: {
    css: string // Public URL prefix for CSS
    assets: string // Public URL prefix for assets
  }
}

Configuring in client config

Set CMS options in your client config file:

// client-config.js
export default async function (config) {
  config.cmsConfig = {
    enabled: true,
    enable11ty: true,
    cacheBuster: false,
    dataSources: [
      {
        id: 'wordpress',
        type: 'graphql',
        url: 'https://my-wordpress.com/graphql',
      },
    ],
    dir: {
      input: '',
      html: '',
      assets: 'assets',
      css: 'css',
    },
    urls: {
      css: '/css',
      assets: '/assets',
    },
  }
}

Directory structure

When published, Silex creates this structure:

.
├── .eleventy.js           — 11ty config
├── .eleventyignore        — Files to exclude
├── _data/                 — Global data files
│   ├── site.json          — Site settings
│   └── (CMS data)         — From GraphQL APIs
├── css/                   — Stylesheets
│   ├── page-name.css
│   └── global.css
├── assets/                — Images, fonts, etc.
│   ├── logo.png
│   └── hero.jpg
├── _includes/             — Reusable templates
│   └── page-layout.liquid
├── index.html             — Home page
├── about.html             — Other pages
└── blog/
    ├── index.html         — Collection page
    └── post-1.html        — Generated pages

Customizing directories

Change where input comes from and where output goes:

// In your .eleventy.js
module.exports = function(eleventyConfig) {
  return {
    dir: {
      input: 'content',      // Input directory (default: '.')
      output: '_site',       // Output directory (default: '_site')
      includes: '_layouts',  // Includes directory
      layouts: '_layouts',   // Layouts directory
      data: '_data_custom',  // Data files directory
    },
  }
}

In Silex client config, the dir.input option affects relative paths:

config.cmsConfig.dir = {
  input: 'src',
  html: 'pages',
  assets: 'static/assets',
  css: 'static/css',
}

Customizing the build

Create a .eleventy.js file in your published site's root to extend Silex's default config:

// .eleventy.js
module.exports = function(eleventyConfig) {
  // Add custom filters
  eleventyConfig.addFilter('uppercase', (value) => {
    return value.toUpperCase()
  })

  // Add a plugin
  const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight')
  eleventyConfig.addPlugin(syntaxHighlight)

  // Add a custom collection
  eleventyConfig.addCollection('posts', (collection) => {
    return collection.getFilteredByGlob('posts/*.md').sort((a, b) => {
      return b.date - a.date
    })
  })

  // Passthrough copy (don't process these files)
  eleventyConfig.addPassthroughCopy('fonts/')

  // Return config options
  return {
    pathPrefix: '/',
    htmlTemplateEngine: 'liquid',
  }
}

Data files

Create .json or .js files in _data/ to make data available to all templates:

// _data/site.json
{
  "title": "My Website",
  "description": "A great website",
  "socialImage": "/assets/og-image.jpg"
}

In any HTML template:

<title>{{ site.title }}</title>
<meta name="description" content="{{ site.description }}">

Dynamic data files

Use .js files to fetch data at build time:

// _data/posts.js
module.exports = async () => {
  const response = await fetch('https://api.example.com/posts')
  return response.json()
}

Then use in templates:

{% for post in posts %}
  <h2>{{ post.title }}</h2>
{% endfor %}

CMS data

When Silex data sources are enabled, their data is available in _data/:

// Silex fetches from WordPress and makes it available
// _data/wordpress.json (generated)
{
  "posts": [
    { "id": 1, "title": "First Post", "content": "..." },
    { "id": 2, "title": "Second Post", "content": "..." }
  ]
}

Use in templates:

{% for post in wordpress.posts %}
  <article>
    <h2>{{ post.title }}</h2>
    <p>{{ post.content }}</p>
  </article>
{% endfor %}

Plugins

Add build awesome plugins to extend functionality:

// .eleventy.js
const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight')
const image = require('@11ty/eleventy-img')

module.exports = function(eleventyConfig) {
  // Add a plugin
  eleventyConfig.addPlugin(syntaxHighlight)

  // Add image optimization
  eleventyConfig.addNunjucksAsyncShortcode('image', async (src, alt) => {
    const metadata = await image(src, {
      widths: [300, 600, 1200],
      formats: ['webp', 'jpeg'],
      outputDir: '_site/img/',
    })

    const imageMarkup = Object.values(metadata)
      .map(imageFormat => imageFormat[imageFormat.length - 1])
      .map(image => `<source srcset="${image.srcset}" type="${image.sourceType}">`)
      .join('')

    return `<picture>${imageMarkup}</picture>`
  })

  return {
    dir: {
      input: '.',
      output: '_site',
    },
  }
}

Popular plugins:

Plugin Purpose
@11ty/eleventy-plugin-syntaxhighlight Code highlighting with Prism
@11ty/eleventy-img Image optimization and responsive pictures
@11ty/eleventy-plugin-rss RSS feed generation
@11ty/eleventy-navigation Navigation menu management
@11ty/eleventy-plugin-bundle Asset bundling and inline optimization

Shortcodes

Shortcodes are custom template tags. Define them in .eleventy.js:

eleventyConfig.addShortcode('year', () => {
  return new Date().getFullYear()
})

eleventyConfig.addPairedShortcode('callout', (content, type = 'info') => {
  return `<div class="callout callout-${type}">${content}</div>`
})

Use in templates:

<footer>
  <p>Copyright &copy; {% year %}</p>
</footer>

{% callout "warning" %}
This is important!
{% endcallout %}

In Silex, editors can insert shortcodes via a shortcode block.

Filters

Create custom filters for transforming data:

eleventyConfig.addFilter('readableDate', (dateObj) => {
  return new Date(dateObj).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  })
})

eleventyConfig.addFilter('limit', (array, limit) => {
  return array.slice(0, limit)
})

Use in templates:

<time>{{ date | readableDate }}</time>

{% for post in posts | limit(5) %}
  <h2>{{ post.title }}</h2>
{% endfor %}

Collections

Create collections to group and sort content:

eleventyConfig.addCollection('posts', (collection) => {
  return collection
    .getFilteredByGlob('posts/**/*.html')
    .sort((a, b) => b.date - a.date)
})

eleventyConfig.addCollection('recent', (collection) => {
  const now = new Date()
  return collection
    .getAll()
    .filter(item => item.date < now)
    .reverse()
    .slice(0, 5)
})

Use in templates:

{% for post in collections.posts %}
  <article>{{ post.data.title }}</article>
{% endfor %}

Transforms and passes

Process the entire HTML output during the build:

// Minify HTML in production
if (process.env.NODE_ENV === 'production') {
  eleventyConfig.addTransform('minify', (content) => {
    if (!content.includes('<!doctype html>')) return content

    const minifyHtml = require('minify-html')
    return minifyHtml.minify(Buffer.from(content), {
      do_not_minify_doctype: true,
      minify_css: true,
      minify_js: true,
    }).toString()
  })
}

Cache busting

Enable cache busting to append timestamps to asset URLs:

config.cmsConfig.cacheBuster = true

This rewrites:

/css/style.css → /css/style.1234567890.css
/assets/logo.png → /assets/logo.1234567890.png

Great for avoiding browser caching issues on updates.

Example: Full .eleventy.js

// .eleventy.js
const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight')
const image = require('@11ty/eleventy-img')
const { EleventyHtmlBasePlugin } = require('@11ty/eleventy')

module.exports = function(eleventyConfig) {
  // Plugins
  eleventyConfig.addPlugin(syntaxHighlight)
  eleventyConfig.addPlugin(EleventyHtmlBasePlugin)

  // Filters
  eleventyConfig.addFilter('date', (dateObj) => {
    return new Date(dateObj).toISOString().split('T')[0]
  })

  // Collections
  eleventyConfig.addCollection('sortedPosts', (collection) => {
    return collection
      .getFilteredByGlob('posts/**/*.html')
      .sort((a, b) => b.date - a.date)
  })

  // Shortcodes
  eleventyConfig.addShortcode('year', () => new Date().getFullYear())

  // Transforms
  eleventyConfig.addTransform('minify', (content, outputPath) => {
    if (outputPath && outputPath.endsWith('.html')) {
      const minify = require('html-minifier')
      return minify.minify(content, { useShortDoctype: true })
    }
    return content
  })

  // Passthrough
  eleventyConfig.addPassthroughCopy('fonts/')
  eleventyConfig.addPassthroughCopy('vendor/')

  return {
    dir: {
      input: '.',
      output: '_site',
      includes: '_includes',
      data: '_data',
    },
    htmlTemplateEngine: 'liquid',
    pathPrefix: '/',
  }
}

Troubleshooting

Build is too slow

Build awesome can be slow if: - Fetching data from external APIs on each build - Processing many large images - Complex filters or transforms

Optimize:

  1. Cache data files between builds
  2. Use a CDN for images instead of local processing
  3. Simplify filters or move logic to the client

Data not available in templates

Check: - File is in _data/ directory - Filename matches the variable name (e.g., site.json{{ site }}) - No syntax errors in .js files - Build awesome log shows "Writing X files"

Shortcodes not working

Ensure: - Defined in .eleventy.js before returning config - Used with correct syntax (paired vs unpaired) - File is in the published site root (not in node_modules)

See also

Edit this page on GitLab