Client configuration and plugins¶
Customize the Silex editor with plugins, publication transformers, and settings sections.
Overview¶
The client config file runs in the browser when the editor loads. It lets you add plugins (from GrapesJS or custom), define how websites are published, and extend the settings UI. Like the server config, it's a plugin that receives a ClientConfig object.
Prerequisites¶
- Server configured with
SILEX_CLIENT_CONFIGenvironment variable pointing to your config file - Understanding of publication transformers
- Basic JavaScript knowledge
Setup¶
1. Create a client config file¶
Create client-config.js in your Silex instance directory:
// client-config.js
export default async function (config) {
console.log('Client config loading')
// Add plugins, transformers, settings here
}
2. Configure the server to serve it¶
Set the environment variable:
Or in Docker:
Mount the file into the container:
3. The file is loaded at startup¶
When users open the editor, Silex fetches your client config from http://your-silex.com/client-config.js?version and executes it. Changes are picked up on page reload.
ClientConfig API¶
class ClientConfig extends Config {
// Properties
websiteId: WebsiteId
storageId: ConnectorId
lang: string
rootUrl: string
debug: boolean
addHashInCssFileName: boolean
replacedElements: string[]
grapesJsConfig: EditorConfig
clientConfigUrl: string
fontsApiKey: string
fontsServerUrl: string
fontsApiUrl: string
cmsConfig: Partial<EleventyPluginOptions> & { enabled?: boolean }
publicationTransformers: Array<PublicationTransformer>
// Methods
getEditor(): Editor
initGrapesConfig(): void
addPlugin(plugin: Plugin | Plugin[], options?: any): Promise<void>
addPublicationTransformers(
transformers: PublicationTransformer | PublicationTransformer[]
): void
resetPublicationTransformers(): void
addDefaultPlugins(): Promise<void>
addSettings( // deprecated
section: SettingsSection,
siteOrPage: 'site' | 'page',
position?: 'first' | 'last' | number
): void
removeSettings(id: string, siteOrPage: 'site' | 'page'): void
}
Adding plugins¶
GrapesJS plugins¶
Load any GrapesJS plugin via npm:
// client-config.js
import grapesJsCustomCode from 'grapesjs-custom-code'
import grapesJsTooltip from 'grapesjs-tooltip'
export default async function (config) {
// Add plugins to the GrapesJS editor
config.grapesJsConfig.plugins = [
...config.grapesJsConfig.plugins,
grapesJsCustomCode,
grapesJsTooltip,
]
// Plugin options (optional)
config.grapesJsConfig.pluginsOpts = {
...config.grapesJsConfig.pluginsOpts,
[grapesJsCustomCode]: { /* options */ },
[grapesJsTooltip]: { /* options */ },
}
}
Custom plugins¶
Create your own plugin module:
// plugins/my-plugin.js
export default {
name: 'MyPlugin',
async init(editor, options) {
console.log('My plugin initialized', options)
// Add a custom block
editor.Blocks.add('my-block', {
label: 'My Block',
content: '<div>Custom block</div>',
category: 'Basic',
media: '<svg>...</svg>',
})
// Listen to editor events
editor.on('canvas:render', () => {
console.log('Canvas rendered')
})
},
}
Then load it in your config:
// client-config.js
import myPlugin from './plugins/my-plugin.js'
export default async function (config) {
config.grapesJsConfig.plugins = [
...config.grapesJsConfig.plugins,
myPlugin,
]
config.grapesJsConfig.pluginsOpts = {
...config.grapesJsConfig.pluginsOpts,
MyPlugin: {
someOption: 'value',
},
}
}
Adding publication transformers¶
Publication transformers control how websites are rendered and published. See Publication transformers for details.
Example: Transform file paths for a CDN:
export default async function (config) {
config.addPublicationTransformers({
transformPath(path, type) {
// Rewrite CSS paths to a CDN
if (type === 'css') {
return path.replace(/\.css$/, '.min.css')
}
return path
},
transformPermalink(link, type, initiator) {
// Point all assets to a CDN
if (!link.startsWith('http')) {
return 'https://cdn.example.com/' + link
}
return link
},
transformFile(file) {
// Minify HTML (example using a hypothetical lib)
if (file.type === 'html') {
file.content = minifyHtml(file.content)
}
return file
},
})
}
Multiple transformers¶
Chain multiple transformers:
export default async function (config) {
// Transformer 1: Rewrite paths
config.addPublicationTransformers({
transformPath(path, type) {
return path.startsWith('/') ? path : '/' + path
},
})
// Transformer 2: Add cache busting
config.addPublicationTransformers({
transformFile(file) {
const now = Date.now()
file.name = file.name.replace(/\.(\w+)$/, `.${now}.$1`)
return file
},
})
}
Transformers run in order, each one receiving the output of the previous.
Listening to client events¶
Access the editor and listen to its events:
const { ClientEvent } = require('@silexlabs/silex/dist/client/events')
export default async function (config) {
// Wait for GrapesJS to load
config.on(ClientEvent.GRAPESJS_END, (editor) => {
console.log('Editor is ready', editor)
// Listen to publication events
editor.on(ClientEvent.PUBLISH_START, (data) => {
console.log('Publishing website:', data.siteSettings.name)
})
editor.on(ClientEvent.PUBLISH_END, (result) => {
console.log('Publication result:', result)
})
editor.on(ClientEvent.SETTINGS_SAVE_START, (data) => {
console.log('Saving settings')
})
})
}
Client events¶
| Event | Fired on | Purpose |
|---|---|---|
STARTUP_START |
config | Silex is starting (page loading) |
STARTUP_END |
config | Silex is ready |
GRAPESJS_START |
config | GrapesJS is about to initialize |
GRAPESJS_END |
editor | GrapesJS is ready |
PUBLICATION_UI_OPEN |
editor | Publish dialog opened |
PUBLICATION_UI_CLOSE |
editor | Publish dialog closed |
PUBLISH_BEFORE |
editor | Before publication starts |
PUBLISH_START |
editor | Publication starts |
PUBLISH_PAGE |
editor | Publishing a single page |
PUBLISH_DATA |
editor | Before sending data to server |
PUBLISH_END |
editor | Publication complete |
PUBLISH_ERROR |
editor | Publication failed |
PUBLISH_LOGIN_START |
editor | Before connector login |
PUBLISH_LOGIN_END |
editor | After connector login |
SETTINGS_OPEN |
editor | Settings dialog opened |
SETTINGS_CLOSE |
editor | Settings dialog closed |
SETTINGS_SAVE_START |
editor | Settings about to save |
SETTINGS_SAVE_END |
editor | Settings saved |
Configuring GrapesJS¶
Modify editor behavior before it loads:
export default async function (config) {
// Customize GrapesJS config
config.grapesJsConfig = {
...config.grapesJsConfig,
canvas: {
styles: ['https://fonts.googleapis.com/css?family=Roboto'],
scripts: [],
},
allowScripts: 0, // Disable script tags in canvas
blockManager: {
blocks: [], // Clear default blocks
},
}
}
Configuring CMS¶
The CMS is built into Silex and enabled by default. Customize it:
export default async function (config) {
config.cmsConfig = {
enabled: true,
enable11ty: true,
cacheBuster: false,
dataSources: [],
dir: {
input: '',
html: '',
assets: 'assets',
css: 'css',
},
urls: {
css: '/css',
assets: '/assets',
},
}
}
For CMS configuration details, see Build awesome configuration.
Complete example¶
// client-config.js
import grapesJsCustomCode from 'grapesjs-custom-code'
import myPlugin from './plugins/my-plugin.js'
import { ClientEvent } = require('@silexlabs/silex/dist/client/events')
export default async function (config) {
// Add plugins
config.grapesJsConfig.plugins = [
...config.grapesJsConfig.plugins,
grapesJsCustomCode,
myPlugin,
]
config.grapesJsConfig.pluginsOpts = {
...config.grapesJsConfig.pluginsOpts,
[grapesJsCustomCode]: { languages: ['javascript', 'css'] },
MyPlugin: { apiKey: process.env.MY_API_KEY },
}
// Add publication transformers
config.addPublicationTransformers({
transformPath(path, type) {
return path.replace(/\.html$/, '')
},
transformPermalink(link) {
if (!link.startsWith('http') && !link.startsWith('/')) {
return '/' + link
}
return link
},
})
// Listen to events
config.on(ClientEvent.GRAPESJS_END, (editor) => {
editor.on(ClientEvent.PUBLISH_END, (result) => {
if (result.success) {
console.log(`Published to ${result.url}`)
} else {
console.error(`Publication failed: ${result.message}`)
}
})
})
// Customize CMS
config.cmsConfig.dataSources = [
{
id: 'wordpress',
type: 'graphql',
url: 'https://my-wordpress.com/graphql',
},
]
}
Troubleshooting¶
Config file not loading¶
Check the browser console for fetch errors:
- Open DevTools (F12)
- Check Console tab for 404 or syntax errors
- Check Network tab:
client-config.js?versionshould return 200
Ensure SILEX_CLIENT_CONFIG is set:
Plugins not loaded¶
Add debug logging:
export default async function (config) {
console.log('Client config is running')
console.log('GrapesJS config:', config.grapesJsConfig)
// ... add plugins
}
Check the browser console for errors during plugin initialization.
Publication transformers not applied¶
Verify they're added before the default transformer:
export default async function (config) {
// Add custom transformer FIRST
config.resetPublicationTransformers()
config.addPublicationTransformers(myTransformer)
}
See also¶
- Server-side config
- Publication transformers — Publication transformers
- Creating plugins — Creating plugins