Skip to content

Client configuration

The client config is a JavaScript file that runs in the browser when the editor opens. Use it to add GrapesJS plugins, publication transformers and CMS options.

Set up the file

Point SILEX_CLIENT_CONFIG to your file:

SILEX_CLIENT_CONFIG=/path/to/client-config.js pnpm start

With Docker, mount the file and set the variable:

environment:
  SILEX_CLIENT_CONFIG: /silex/client-config.js
volumes:
  - ./client-config.js:/silex/client-config.js:ro

The file replaces the default client config, server/deploy/client-config.js. It loads the onboarding plugin and turns links that end in /index.html into folder links (/about/index.html becomes /about/). To keep this behavior, copy its content into your file.

The file must export a function. It receives the ClientConfig object:

export default async function (config) {
  // add plugins, transformers and options here
  return {}
}

How the file is loaded

The server reads the file once at startup and serves it at /silex.js?<version>. The editor loads it with a dynamic import() in the browser. The file is not bundled and does not run in Node. So:

  • require() and process.env do not exist.
  • Bare imports such as import x from 'grapesjs-tooltip' do not work.
  • Imports must be absolute URLs (a CDN, for example) or paths to files that the Silex server serves.
  • A relative import like ./plugins/x.js resolves to /plugins/x.js. Nothing serves this URL unless a server plugin does (see Creating plugins).

With SILEX_DEBUG=true, the server reads the file again at each request. Otherwise, restart the server after a change.

Add a GrapesJS plugin

A GrapesJS plugin is a function (editor, opts) => {}. Add it to config.grapesJsConfig.plugins. Its options go in config.grapesJsConfig.pluginsOpts, with the function as the key (GrapesJS uses plugin.toString()):

import tooltip from 'https://cdn.jsdelivr.net/npm/grapesjs-tooltip@0.1.8/+esm'

function helloBlock(editor, opts) {
  editor.Blocks.add('hello-block', {
    label: opts.label ?? 'Hello block',
    category: 'Elements',
    content: '<p class="hello">Hello</p>',
  })
}

export default async function (config) {
  config.grapesJsConfig.plugins.push(helloBlock, tooltip)
  config.grapesJsConfig.pluginsOpts[helloBlock.toString()] = { label: 'Hello' }
  return {}
}

Your plugins run before the plugins of Silex. Silex already loads grapesjs-custom-code, @silexlabs/grapesjs-css-variables, @silexlabs/grapesjs-fonts, @silexlabs/grapesjs-symbols, the data source plugin and others: do not add them again. The full list is in editor/grapesjs/index.ts.

Change the GrapesJS config

Silex builds its GrapesJS config after your file runs, and its own keys win: blockManager, assetManager, storageManager, layerManager, selectorManager, richTextEditor and others. plugins are added together. In pluginsOpts, the values of Silex win for the plugins it configures.

To change a key that Silex sets, do it in the silex:grapesjs:start event. It fires after Silex has built config.grapesJsConfig and before GrapesJS starts:

export default async function (config) {
  config.on('silex:grapesjs:start', () => {
    config.grapesJsConfig.showOffsets = false
  })
  return {}
}

Events

Listen on the config object:

Event Argument When
silex:startup:start none the client config is loaded
silex:grapesjs:start none before GrapesJS starts, edit config.grapesJsConfig here
silex:grapesjs:end { editor } GrapesJS is ready
silex:startup:end { editor, config } the website is loaded in the editor
config.on('silex:grapesjs:end', ({ editor }) => {
  editor.on('silex:publish:end', ({ success, message }) => {
    console.log('Published', success, message)
  })
})

Publication events such as silex:publish:start, silex:publish:page, silex:publish:data and silex:publish:end fire on the GrapesJS editor, not on config. All event names are in editor/events.ts. In the browser, window.silex.events.ClientEvent holds the same names.

Publication transformers

A transformer changes the files at publication time:

export default async function (config) {
  config.addPublicationTransformers({
    transformFile(file) {
      if (file.type === 'html') {
        return { ...file, content: file.content.replace('</body>', '<!-- published with Silex --></body>') }
      }
      return file
    },
  })
  return {}
}

addPublicationTransformers adds your transformers after the default ones. Do not call resetPublicationTransformers(): it removes the default transformer, which sets page links and the asset paths in CSS. See Publication transformers for the methods and their arguments.

CMS options

The CMS is on by default. Set config.cmsConfig to change it:

export default async function (config) {
  config.cmsConfig = {
    enabled: true,
    cacheBuster: false,
    dataSources: [{
      id: 'blog',
      label: 'Blog',
      type: 'graphql',
      url: 'https://example.com/graphql',
      method: 'POST',
      headers: {},
    }],
  }
  return {}
}
Option Default Effect
enabled true false turns off the CMS plugin
dataSources [] data sources added to every website
cacheBuster false adds a cache buster to the GraphQL queries
esModule true true writes the Eleventy data files as ES modules, false as CommonJS
fetchPluginSettings from the site settings options of the Eleventy fetch plugin, or false
i18nPlugin not set true turns on the i18n option for every website and locks it in the settings

ClientConfig properties

Property Use
grapesJsConfig GrapesJS config, see above
cmsConfig CMS options, see above
addPlugin(plugin, options) load a Silex plugin (config, options) => {}
addPublicationTransformers(t) add one transformer or an array
getEditor() the GrapesJS editor, after silex:grapesjs:end
websiteId, storageId, lang, rootUrl read from the editor URL
fontsServerUrl, fontsApiUrl, fontsApiKey the Google Fonts API or a compatible server
replacedElements tags that show the object-fit properties in the style panel
api functions that call the Silex server API
debug set it to true in your file to log the config in the browser console

In the browser, window.silex.config is the same object.

See also

Edit this page on GitLab