@silexlabs/silex 3.0.0-alpha.30 → 3.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.silex/default/.silex.data.json +1 -0
  2. package/.silex.js +1 -8
  3. package/CONTRIBUTING.md +48 -25
  4. package/README.md +96 -0
  5. package/dist/client/css/admin.css +4 -66
  6. package/dist/client/js/main.js +53 -103
  7. package/dist/client/js/main.js.LICENSE.txt +3 -19
  8. package/dist/constants.js +4 -0
  9. package/dist/page.js +15 -0
  10. package/dist/server/cli.js +9 -0
  11. package/dist/server/config.js +31 -11
  12. package/dist/server/{start.js → express.js} +1 -1
  13. package/dist/server/index.js +9 -3
  14. package/dist/types.js +34 -0
  15. package/package.json +35 -34
  16. package/public/silex.js +25 -0
  17. package/src/example-client-config.js +47 -0
  18. package/src/plugins/DefaultBackend.js +40 -4
  19. package/src/plugins/ExpressPlugin.js +9 -0
  20. package/src/plugins/PublishPlugin.js +4 -4
  21. package/src/plugins/WebsitePlugin.js +77 -18
  22. package/src/ts/client/config.ts +20 -2
  23. package/src/ts/client/grapesjs/blocks.ts +18 -86
  24. package/src/ts/client/grapesjs/index.ts +27 -9
  25. package/src/ts/client/grapesjs/internal-links.test.ts +1 -0
  26. package/src/ts/client/grapesjs/publish.ts +4 -4
  27. package/src/ts/client/grapesjs/semantic.ts +1 -0
  28. package/src/ts/client/index.ts +21 -8
  29. package/src/ts/constants.ts +5 -0
  30. package/src/ts/server/cli.ts +6 -0
  31. package/src/ts/server/config.ts +45 -16
  32. package/src/ts/server/{start.ts → express.ts} +1 -1
  33. package/src/ts/server/index.ts +9 -2
  34. package/src/ts/types.ts +6 -12
  35. package/tsconfig-server-debug.json +2 -3
  36. package/tsconfig-server-release.json +2 -3
  37. package/tsconfig.json +2 -3
  38. package/webpack.config.js +0 -1
  39. package/public/example-config.js +0 -31
  40. package/readme.md +0 -51
  41. /package/dist/{server/events.js → events.js} +0 -0
  42. /package/src/ts/{server/events.ts → events.ts} +0 -0
@@ -3,9 +3,12 @@ const { resolve } = require('path')
3
3
  const formidable = require('formidable')
4
4
 
5
5
  const { noCache } = require('./Cache')
6
+ const { defaultSite } = require('@silexlabs/silex').default.types
6
7
 
7
8
  const EVENT_READ_START = 'EVENT_READ_START'
8
9
  const EVENT_READ_END = 'EVENT_READ_END'
10
+ const EVENT_DELETE_START = 'EVENT_WRITE_START'
11
+ const EVENT_DELETE_END = 'EVENT_WRITE_END'
9
12
  const EVENT_WRITE_START = 'EVENT_WRITE_START'
10
13
  const EVENT_WRITE_END = 'EVENT_WRITE_END'
11
14
  const EVENT_ASSET_READ_START = 'EVENT_ASSET_READ_START'
@@ -18,13 +21,15 @@ module.exports = async function(config, opts = {}) {
18
21
  const options = {
19
22
  // Defaults
20
23
  backend: 'src/plugins/DefaultBackend.js',
24
+ // Default data for new websites
25
+ defaultSite,
21
26
  // Options
22
27
  ...opts
23
28
  }
24
29
 
25
30
  // Link to the desired backend
26
31
  const backend = resolve(__dirname, '../..', options.backend)
27
- const { assetsDir, assetUrl, init, writeData, readData } = require(backend)
32
+ const { assetsDir, assetUrl, init, writeData, readData, list, del } = require(backend)
28
33
 
29
34
  config.on('silex:startup:start', ({app}) => {
30
35
  const router = Router()
@@ -32,6 +37,7 @@ module.exports = async function(config, opts = {}) {
32
37
  // website specials
33
38
  router.get('/website', readWebsite)
34
39
  router.post('/website', writeWebsite)
40
+ router.delete('/website', deleteWebsite)
35
41
  router.get(/\/assets\/(.*)/, readAsset)
36
42
  router.post('/assets', writeAsset)
37
43
 
@@ -39,21 +45,40 @@ module.exports = async function(config, opts = {}) {
39
45
  })
40
46
 
41
47
  async function readWebsite(req, res) {
42
- const id = req.query.id
43
- config.emit(EVENT_READ_START, { req, id })
44
- try {
45
- const data = await readData(id)
46
- config.emit(EVENT_READ_END, { req, res, data, id })
47
- res
48
- .type('application/json')
49
- .send(data)
50
- } catch (err) {
51
- if(err.code === 'ENOENT') {
52
- console.error('Read file error, website does not exist', err)
53
- res.status(404).json({ message: 'Read file error, website does not exist: ' + err.message, code: err.code})
54
- } else {
55
- console.error('Read file error', err)
56
- res.status(400).json({ message: 'Read file error: ' + err.message, code: err.code})
48
+ const { id } = req.query
49
+ if(id) {
50
+ // Returns a website data
51
+ try {
52
+ config.emit(EVENT_READ_START, { req, id })
53
+ const data = await readData(id)
54
+ config.emit(EVENT_READ_END, { req, res, data, id })
55
+ res
56
+ .type('application/json')
57
+ .send({
58
+ ...options.defaultSite,
59
+ ...data,
60
+ })
61
+ } catch (err) {
62
+ if(err.code === 'ENOENT') {
63
+ console.error('Read file error, website does not exist', err)
64
+ res.status(404).json({ message: 'Read file error, website does not exist: ' + err.message, code: err.code})
65
+ } else {
66
+ console.error('Read file error', err)
67
+ res.status(400).json({ message: err.message, code: err.code})
68
+ }
69
+ }
70
+ } else {
71
+ // list websites
72
+ try {
73
+ config.emit(EVENT_READ_START, { req, id })
74
+ const data = await list()
75
+ config.emit(EVENT_READ_END, { req, res, data, id })
76
+ res
77
+ .type('application/json')
78
+ .send(data)
79
+ } catch (err) {
80
+ console.error('List sites error', err)
81
+ res.status(400).json({ message: err.message, code: err.code })
57
82
  }
58
83
  }
59
84
  }
@@ -79,8 +104,6 @@ module.exports = async function(config, opts = {}) {
79
104
 
80
105
  async function writeWebsite(req, res) {
81
106
  const id = req.query.id
82
- await init(id)
83
-
84
107
  const [data, err] = fromBody(req.body)
85
108
  if(err) {
86
109
  res.status(400).json({ message: 'Error writing data file, could not parse the provided body: ' + err.message, code: err.code})
@@ -88,6 +111,7 @@ module.exports = async function(config, opts = {}) {
88
111
  }
89
112
  config.emit(EVENT_WRITE_START, { req, id, data })
90
113
  try {
114
+ await init(id)
91
115
  await writeData(id, data)
92
116
  } catch (err) {
93
117
  console.error('Error writing data file', err)
@@ -102,6 +126,41 @@ module.exports = async function(config, opts = {}) {
102
126
  })
103
127
  }
104
128
 
129
+ async function deleteWebsite(req, res) {
130
+ const { id } = req.query
131
+ if(id) {
132
+ try {
133
+ config.emit(EVENT_DELETE_START, { req, id })
134
+ const data = await del(id)
135
+ config.emit(EVENT_DELETE_END, { req, res, data, id })
136
+ res
137
+ .type('application/json')
138
+ .send(data)
139
+ } catch (err) {
140
+ if(err.code === 'ENOENT') {
141
+ console.error('Delete file error, website does not exist', err)
142
+ res.status(404).json({ message: 'Delete file error, website does not exist: ' + err.message, code: err.code})
143
+ } else {
144
+ console.error('Delete file error', err)
145
+ res.status(400).json({ message: err.message, code: err.code})
146
+ }
147
+ }
148
+ } else {
149
+ // list websites
150
+ try {
151
+ config.emit(EVENT_DELETE_START, { req, id })
152
+ const data = await list()
153
+ config.emit(EVENT_DELETE_END, { req, res, data, id })
154
+ res
155
+ .type('application/json')
156
+ .send(data)
157
+ } catch (err) {
158
+ console.error('List sites error', err)
159
+ res.status(400).json({ message: err.message, code: err.code })
160
+ }
161
+ }
162
+ }
163
+
105
164
  async function readAsset(req, res) {
106
165
  const id = req.query.id
107
166
  const fileName = req.params[0]
@@ -1,12 +1,14 @@
1
- import { Config } from '@silexlabs/silex-plugins'
1
+ import { Config, Plugin } from '@silexlabs/silex-plugins'
2
2
  import { getEditorConfig } from './grapesjs'
3
+ import { CLIENT_CONFIG_FILE_NAME } from '../constants'
3
4
 
4
5
  /**
5
6
  * @fileoverview Silex client side config
6
7
  */
7
8
 
8
9
  const id = new URL(location.href).searchParams.get('id') || 'default'
9
- const rootUrl = '.'
10
+ const lang = new URL(location.href).searchParams.get('lang') || 'en'
11
+ const rootUrl = `${location.protocol}//${location.host}${location.pathname}`
10
12
 
11
13
  export class SilexConfig extends Config {
12
14
  /**
@@ -14,8 +16,24 @@ export class SilexConfig extends Config {
14
16
  */
15
17
  debug = false
16
18
 
19
+ /**
20
+ * language for I18n module
21
+ */
22
+ lang = lang
23
+
17
24
  /**
18
25
  * Grapesjs config
19
26
  */
20
27
  editor = getEditorConfig(id, rootUrl)
28
+
29
+ /**
30
+ * Client config url
31
+ * This is the url of the config file which is a plugin
32
+ */
33
+ clientConfigUrl = `${rootUrl}${CLIENT_CONFIG_FILE_NAME}`
34
+
35
+ /**
36
+ * GrapesJs plugins
37
+ */
38
+ grapesJsPlugins: Plugin[] = []
21
39
  }
@@ -1,88 +1,20 @@
1
- import * as grapesjs from 'grapesjs/dist/grapes.min.js'
2
-
3
- const pluginName = 'blocks'
4
- const clsContainer = 'silex-container'
5
- const clsSection = 'silex-section'
6
- const clsSectionBackground = 'silex-section-background'
7
-
8
- export const blocksPlugin = grapesjs.plugins.add(pluginName, (editor, opts) => {
9
- // Make row and column classes private
10
- const privateCls = [clsSection, clsSectionBackground, clsContainer]
11
- .map(cls => '.' + cls)
12
- editor.on(
13
- 'selector:add',
14
- selector => privateCls.indexOf(selector.getFullName()) >= 0 && selector.set('private', 1)
15
- )
16
- ;[
17
- // {
18
- // id: 'section',
19
- // def: {
20
- // label: 'Section',
21
- // category: 'Containers',
22
- // attributes: { class: 'fa fa-list-alt' },
23
- // draggable: 'body',
24
- // content: {
25
- // tagName: 'section',
26
- // styles: `
27
- // .${clsSectionBackground} {
28
- // display: flex;
29
- // justify-content: center;
30
- // }
31
- // `,
32
- // components: [
33
- // {
34
- // tagName: 'div',
35
- // name: 'Section container',
36
- // attributes: { class: ['website-width'] },
37
- // draggable: false,
38
- // removable: false,
39
- // resizable: true,
40
- // styles: `
41
- // .${clsSection} {
42
- // min-height: 100px;
43
- // width: 1200px;
44
- // }
45
- // `,
46
- // },
47
- // ],
48
- // },
49
- // },
50
- // },
51
- {
52
- id: 'container',
53
- def: {
54
- label: 'Container',
55
- category: 'Basics',
56
- attributes: { class: 'container-png' },
57
- content: {
58
- type: 'container',
59
- style: {
60
- 'min-height': '100px',
61
- },
62
- },
1
+ export const blocksPlugin = (editor, opts) => {
2
+ // Defaults
3
+ const options = {
4
+ ...opts,
5
+ }
6
+ // Container block
7
+ const containerId = 'container'
8
+ editor.BlockManager.add(containerId, {
9
+ label: 'Container',
10
+ category: 'Basics',
11
+ attributes: { class: 'container-png' },
12
+ content: {
13
+ type: containerId, // display as "Container"
14
+ style: {
15
+ 'min-height': '100px',
63
16
  },
64
17
  },
65
- // {
66
- // id: 'link-block',
67
- // def: {
68
- // category: 'Containers',
69
- // label: 'Link Block',
70
- // attributes: { class: 'fa fa-link' },
71
- // content: {
72
- // type: 'link',
73
- // editable: false,
74
- // droppable: true,
75
- // resizable: true,
76
- // style:{
77
- // display: 'inline-block',
78
- // padding: '5px',
79
- // 'min-height': '100px',
80
- // 'width': '100px'
81
- // }
82
- // },
83
- // },
84
- // },
85
- ]
86
- .forEach(block => editor.BlockManager.add(block.id, block.def))
87
- })
88
-
18
+ })
19
+ editor.DomComponents.addType(containerId, {})
20
+ }
@@ -1,4 +1,4 @@
1
- import grapesjs, { EditorConfig } from 'grapesjs'
1
+ import grapesjs from 'grapesjs'
2
2
  import openImport from './openImport'
3
3
 
4
4
  /**
@@ -14,7 +14,7 @@ import styleFilterPlugin from 'grapesjs-style-filter'
14
14
  import formPlugin from 'grapesjs-plugin-forms'
15
15
  import codePlugin from 'grapesjs-custom-code'
16
16
  import uiSuggestClasses from '@silexlabs/grapesjs-ui-suggest-classes'
17
- import symbolsPlugin from '@silexlabs/grapesjs-symbols/src'
17
+ import * as symbolsPlugin from '@silexlabs/grapesjs-symbols' // Why is this not working without *?
18
18
  import loadingPlugin from '@silexlabs/grapesjs-loading'
19
19
  import fontsDialogPlugin, { cmdOpenFonts } from '@silexlabs/grapesjs-fonts'
20
20
  import symbolDialogsPlugin, { cmdPromptAddSymbol } from './symbolDialogs'
@@ -60,8 +60,6 @@ plugins
60
60
  throw new Error(`Plugin ${p.name} could not be loaded correctly`)
61
61
  })
62
62
 
63
- export function getPlugins() { return plugins }
64
-
65
63
  // ////////////////////
66
64
  // Config
67
65
  // ////////////////////
@@ -86,7 +84,7 @@ export function getEditorConfig(id: string, rootUrl: string) {
86
84
  },
87
85
 
88
86
  assetManager: {
89
- upload: `${rootUrl}/assets/`,
87
+ upload: `${rootUrl}assets/`,
90
88
  },
91
89
 
92
90
  storageManager: {
@@ -94,8 +92,8 @@ export function getEditorConfig(id: string, rootUrl: string) {
94
92
  type: 'remote',
95
93
  options: {
96
94
  remote: {
97
- urlStore: `${rootUrl}/website/?id=${id}`,
98
- urlLoad: `${rootUrl}/website/?id=${id}`,
95
+ urlStore: `${rootUrl}website/?id=${id}`,
96
+ urlLoad: `${rootUrl}website/?id=${id}`,
99
97
  },
100
98
  },
101
99
  },
@@ -214,10 +212,16 @@ export function getEditorConfig(id: string, rootUrl: string) {
214
212
  // Keep a ref to the editor singleton
215
213
  let editor
216
214
 
217
- export function initEditor(config: EditorConfig) {
215
+ export function initEditor(config, grapesJsPlugins) {
218
216
  if(editor) throw new Error('Grapesjs editor already created')
219
217
 
220
- editor = grapesjs.init(config)
218
+ editor = grapesjs.init({
219
+ plugins: [
220
+ ...grapesJsPlugins,
221
+ ...config.plugins,
222
+ ],
223
+ ...config,
224
+ })
221
225
 
222
226
  // customize the editor
223
227
  ;['text']
@@ -253,6 +257,20 @@ export function initEditor(config: EditorConfig) {
253
257
  // use the style filter plugin
254
258
  editor.StyleManager.addProperty('extra',{ extend: 'filter' })
255
259
  })
260
+
261
+ // Handle errors
262
+ editor.on('storage:error:load', (err) => {
263
+ editor.Modal.open({
264
+ title: 'Error loading website',
265
+ content: `This website could not be loaded.<br><hr>${err}`,
266
+ })
267
+ })
268
+ editor.on('storage:error:store', (err) => {
269
+ editor.Modal.open({
270
+ title: 'Error saving website',
271
+ content: `This website could not be saved.<br><hr>${err}`,
272
+ })
273
+ })
256
274
  }
257
275
 
258
276
  export function getEditor() {
@@ -1,4 +1,5 @@
1
1
  import { internalLinksPlugin } from './internal-links'
2
+ import { expect, test, beforeEach } from '@jest/globals'
2
3
  import grapesjs from 'grapesjs'
3
4
 
4
5
  let editor
@@ -8,7 +8,7 @@ import { onAll } from '../utils'
8
8
  const pluginName = 'publish'
9
9
  export const cmdPublish = 'publish-open-dialog'
10
10
  let _token = null
11
- let projectId
11
+ let id
12
12
  let rootUrl
13
13
 
14
14
  // plugin code
@@ -19,7 +19,7 @@ export const publishPlugin = grapesjs.plugins.add(pluginName, (editor, opts) =>
19
19
  }
20
20
  // Global config
21
21
  rootUrl = opts.rootUrl
22
- projectId = opts.projectId
22
+ id = opts.id
23
23
  // Keep track of the token
24
24
  editor.on('login:success', async ({ getUser, getToken }) => {
25
25
  _token = await getToken()
@@ -248,7 +248,7 @@ export async function startPublication(editor) {
248
248
  ...projectData,
249
249
  settings: siteSettings,
250
250
  publication: publicationSettings,
251
- projectId,
251
+ id,
252
252
  files,
253
253
  }
254
254
  // Reset asset URLs
@@ -282,7 +282,7 @@ export async function startPublication(editor) {
282
282
  let res
283
283
  let json
284
284
  try {
285
- res = await fetch(`${ rootUrl }/publish`, {
285
+ res = await fetch(`${ rootUrl }publish`, {
286
286
  method: 'POST',
287
287
  body: JSON.stringify({
288
288
  data,
@@ -20,6 +20,7 @@ const tags = [
20
20
  'SECTION',
21
21
  'ADDRESS',
22
22
  'ARTICLE',
23
+ 'BUTTON',
23
24
  'NAV',
24
25
  'HEADER',
25
26
  'FOOTER',
@@ -4,11 +4,9 @@
4
4
  *
5
5
  */
6
6
 
7
- // Get env vars from webpack (see plugin in webpack.config.js)
8
- declare const CONFIG_URL: string
9
-
10
7
  import { SilexConfig } from './config'
11
8
  import { initEditor, getEditor } from './grapesjs/index'
9
+ import { EVENT_STARTUP_START, EVENT_STARTUP_END } from '../events'
12
10
 
13
11
  /**
14
12
  * Start Silex, called from host HTML page with window.silex.start()
@@ -17,22 +15,37 @@ export async function start(options = {}) {
17
15
  const config = new SilexConfig()
18
16
  Object.assign(config, options)
19
17
 
20
- // Initial config file
21
- if(CONFIG_URL) {
22
- await config.addPlugin(CONFIG_URL, {})
23
- }
18
+ // Config file in root folder which can be generated by the server
19
+ console.log('Loading config', config.clientConfigUrl)
20
+ //import(/* webpackIgnore: true */ config.clientConfigUrl)
21
+ //.then((configFile) => console.log('Config loaded', configFile))
22
+ //.catch((e) => console.error('Config error', config.clientConfigUrl, e))
23
+ await config.addPlugin(config.clientConfigUrl, {})
24
24
 
25
25
  // Debug mode
26
26
  if (config.debug) {
27
27
  console.warn('Silex starting in debug mode.', {config})
28
28
  }
29
29
 
30
+ // Notify plugins that loading is over and Silex is starting
31
+ config.emit(EVENT_STARTUP_START)
32
+
30
33
  // Start grapesjs
31
- initEditor(config.editor)
34
+ console.log('start', {config})
35
+ try{
36
+ initEditor(config.editor, config.grapesJsPlugins)
37
+ } catch(e) {
38
+ console.error('Error starting Silex', e)
39
+ }
40
+
41
+ // Init internationalization module
42
+ getEditor().I18n.setLocale(config.lang)
32
43
 
33
44
  // End of loading
34
45
  getEditor().on('load', () => {
46
+ console.log('Silex started')
35
47
  document.querySelector('.silex-loader').classList.add('silex-dialog-hide')
36
48
  document.querySelector('#gjs').classList.remove('silex-dialog-hide')
49
+ config.emit(EVENT_STARTUP_END)
37
50
  })
38
51
  }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @fileoverview define constants for Silex client and server
3
+ */
4
+
5
+ export const CLIENT_CONFIG_FILE_NAME = 'silex.js'
@@ -12,6 +12,9 @@ const options = parse({
12
12
  'ssl-certificate': [ false, 'Path to SSL certificate', 'file'],
13
13
  'force-https-trust-xfp-header': [ false, 'Sets the trustXFPHeader param of the express module "cookie-session". Use only with --force-https', 'boolean'],
14
14
  'session-secret': ['s', 'Session secret', 'string'],
15
+ 'cors-url': ['', 'Enable CORS for URL (can be "*")', 'string'],
16
+ 'client-config': ['', 'Path to client config file to be served on .silex-client.js', 'string'],
17
+ 'fs-root': ['', 'Path to the root folder where to store websites. Used by the default backend (fs).', 'string'],
15
18
  }, {})
16
19
 
17
20
  if(options.config) process.env.CONFIG = options.config
@@ -23,5 +26,8 @@ if(options['ssl-private-key']) process.env.SILEX_SSL_PRIVATE_KEY = options['ssl-
23
26
  if(options['ssl-certificate']) process.env.SILEX_SSL_CERTIFICATE = options['ssl-certificate']
24
27
  if(options['force-https-trust-xfp-header']) process.env.SILEX_FORCE_HTTPS_TRUST_XFP_HEADER = options['force-https-trust-xfp-header']
25
28
  if(options['session-secret']) process.env.SILEX_SESSION_SECRET = options['session-secret']
29
+ if(options['cors-url']) process.env.SILEX_CORS_URL = options['cors-url']
30
+ if(options['client-config']) process.env.SILEX_CLIENT_CONFIG = options['client-config']
31
+ if(options['fs-root']) process.env.FS_ROOT = options['fs-root']
26
32
 
27
33
  import './index'
@@ -9,16 +9,20 @@
9
9
 
10
10
  import { Config, Plugin } from '@silexlabs/silex-plugins'
11
11
  import { resolve } from 'path'
12
+ import { CLIENT_CONFIG_FILE_NAME } from '../constants'
13
+ import { Router } from 'express'
14
+ import { readFile } from 'fs/promises'
15
+ import { EVENT_STARTUP_START } from '../events'
12
16
 
13
17
  /**
14
18
  * Config types definitions
15
19
  */
16
20
  export class ServerConfig extends Config {
17
21
  constructor(
18
- public url: string,
19
- public debug: boolean,
20
- public port: string,
21
- public apiPath: string
22
+ public url: string,
23
+ public debug: boolean,
24
+ public port: string,
25
+ public apiPath: string,
22
26
  ) {
23
27
  super()
24
28
  }
@@ -28,13 +32,49 @@ export class ServerConfig extends Config {
28
32
  export default async function(): Promise<ServerConfig> {
29
33
  const port = process.env.PORT || '6805' // 6805 is the date of sexual revolution started in paris france 8-)
30
34
  const debug = process.env.SILEX_DEBUG === 'true'
35
+ const clientConfigPath = process.env.SILEX_CLIENT_CONFIG
31
36
 
32
37
  const url = process.env.SERVER_URL || `http://localhost:${port}`
33
38
  const config = new ServerConfig(url, debug, port, '/api')
34
39
 
40
+ // Serve the client side config file
41
+ if (clientConfigPath) {
42
+ config.on(EVENT_STARTUP_START, async ({ app }) => {
43
+ console.log(`> Serving client side config ${clientConfigPath} at ${CLIENT_CONFIG_FILE_NAME}`)
44
+ // Attach the route immediately
45
+ const router = Router()
46
+ app.use(router)
47
+ // Load the config file and serve it
48
+ let clientConfig = (await readFile(clientConfigPath as string)).toString()
49
+ router.get(`/${CLIENT_CONFIG_FILE_NAME}`, async (res, req, next) => {
50
+ // Reload each time in debug mode
51
+ if (config.debug) {
52
+ console.log('[Debug mode] Reloading config file', clientConfigPath)
53
+ clientConfig = (await readFile(clientConfigPath)).toString()
54
+ }
55
+ // Send the config file
56
+ req.header('Content-Type', 'application/javascript').send(clientConfig)
57
+ })
58
+ })
59
+ }
60
+
61
+ // Optional config file
62
+ // Load this config file before the main config file so that routes can be overriden
63
+ // Or listen for event silex:startup:end to add routes after the default ones
64
+ if (process.env.CONFIG) {
65
+ const userConfigPath: Plugin = process.env.CONFIG
66
+ console.log('> Loading user config', userConfigPath)
67
+ try {
68
+ // Initiate the process with the config file which is just another plugin
69
+ await config.addPlugin(userConfigPath, {})
70
+ } catch (e) {
71
+ throw new Error(`User config file ${userConfigPath} error: ${e.message}`)
72
+ }
73
+ }
74
+
35
75
  // Config file in root folder
36
76
  const configFilePath: Plugin = resolve(__dirname, '../../.silex.js')
37
- console.log('Loading config', configFilePath)
77
+ console.log('> Loading config', configFilePath)
38
78
  try {
39
79
  // Initiate the process with the config file which is just another plugin
40
80
  await config.addPlugin(configFilePath, {})
@@ -45,17 +85,6 @@ export default async function(): Promise<ServerConfig> {
45
85
  throw new Error(`Error in config file ${configFilePath}: ${e.message}`)
46
86
  }
47
87
  }
48
- // Optional config file
49
- if (process.env.CONFIG) {
50
- const userConfigPath: Plugin = process.env.CONFIG
51
- console.log('Loading user config', userConfigPath)
52
- try {
53
- // Initiate the process with the config file which is just another plugin
54
- await config.addPlugin(userConfigPath, {})
55
- } catch (e) {
56
- throw new Error(`User config file ${userConfigPath} not found: ${e.message}`)
57
- }
58
- }
59
88
 
60
89
  // Return the config file
61
90
  return config
@@ -1,7 +1,7 @@
1
1
  import express, { Application } from 'express'
2
2
 
3
3
  import { ServerConfig } from './config'
4
- import { EVENT_STARTUP_START, EVENT_STARTUP_END } from './events'
4
+ import { EVENT_STARTUP_START, EVENT_STARTUP_END } from '../events'
5
5
 
6
6
  export default async function(config: ServerConfig): Promise<Application> {
7
7
  // Plugins hook to create API routes
@@ -1,5 +1,12 @@
1
1
  import getConfig from './config'
2
- import start from './start'
2
+ import start from './express'
3
+
4
+ import * as config from './config'
5
+ import * as types from '../types'
6
+ import * as events from '../events'
7
+ import * as constants from '../constants'
8
+ import * as page from '../page'
9
+ export default { config, types, events, constants, page }
3
10
 
4
11
  // Main app
5
12
  async function main() {
@@ -30,7 +37,7 @@ async function startLiverReload() {
30
37
  const server = createServer({
31
38
  delay: 0,
32
39
  }, () => {
33
- console.info(`\nDebug mode\nLive reload server is running.\nWatching ${dist}`)
40
+ console.info(`\n> Debug mode\n> Live reload server is running.\n> Watching ${dist}`)
34
41
  })
35
42
  server.watch(dist)
36
43
  }