1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | const fsEx = require('fs-extra')
|
8 | const path = require('path')
|
9 | const inquirer = require('inquirer')
|
10 | const logger = require('../logger')
|
11 | const UserSettings = require('../user/UserSettings')
|
12 | const AppSettings = require('../app/AppSettings')
|
13 | const FrontendProcess = require('../app/frontend/FrontendProcess')
|
14 | const FrontendSetup = require('../app/frontend/FrontendSetup')
|
15 | const DcHttpClient = require('../DcHttpClient')
|
16 | const utils = require('../utils/utils')
|
17 | const ExtensionConfigWatcher = require('../app/ExtensionConfigWatcher')
|
18 |
|
19 | const { SETTINGS_FOLDER, THEMES_FOLDER } = require('../app/Constants')
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | class FrontendAction {
|
25 | constructor () {
|
26 | this.appSettings = new AppSettings().validate()
|
27 | this.userSettings = new UserSettings().validate()
|
28 | this.settingsFolder = path.join(this.appSettings.getApplicationFolder(), SETTINGS_FOLDER)
|
29 | this.dcClient = new DcHttpClient(this.userSettings, logger)
|
30 | this.frontendSetup = new FrontendSetup(this.dcClient, this.appSettings)
|
31 | this.extensionConfigWatcher = new ExtensionConfigWatcher(this.appSettings)
|
32 | }
|
33 |
|
34 | |
35 |
|
36 |
|
37 |
|
38 | static register (caporal) {
|
39 | caporal
|
40 | .command('frontend start')
|
41 | .description('Starts the webpack dev server for the frontend development')
|
42 | .option('-t, --theme [value]', 'The name of the theme that you want to be compiled by webpack.')
|
43 | .option('-h, --host [value]', 'The URL or IP address of your local development environment.')
|
44 | .option('-p, --port [value]', 'The port to use for accessing the output via browser.')
|
45 | .action((args, options) => { new FrontendAction().run('start', args, options) })
|
46 |
|
47 | caporal
|
48 | .command('frontend setup')
|
49 | .description('Changes the settings for the frontend development')
|
50 | .action((args, options) => { new FrontendAction().run('setup', args, options) })
|
51 | }
|
52 |
|
53 | |
54 |
|
55 |
|
56 |
|
57 | async findThemes () {
|
58 |
|
59 | const source = path.resolve(this.appSettings.getApplicationFolder(), THEMES_FOLDER)
|
60 |
|
61 |
|
62 | const folders = await fsEx.readdir(source)
|
63 |
|
64 | const promises = folders.map(folder => fsEx.lstat(path.join(source, folder)))
|
65 | const results = await Promise.all(promises)
|
66 |
|
67 | return folders.filter((folder, index) => results[index].isDirectory())
|
68 | }
|
69 |
|
70 | |
71 |
|
72 |
|
73 |
|
74 | requestThemeOption () {
|
75 | return new Promise(async (resolve, reject) => {
|
76 | const themes = await this.findThemes()
|
77 | if (themes.length === 1) return resolve(themes[0])
|
78 |
|
79 | inquirer
|
80 | .prompt([{
|
81 | type: 'list',
|
82 | name: 'theme',
|
83 | message: 'Please choose a theme to use',
|
84 | choices: themes
|
85 | }])
|
86 | .then(answers => resolve(answers.theme))
|
87 | .catch(error => reject(error))
|
88 | })
|
89 | }
|
90 |
|
91 | |
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | async run (action, args, options = {}) {
|
98 | this.userSettings = new UserSettings().validate()
|
99 | this.appSettings = new AppSettings().validate()
|
100 |
|
101 | const pid = await utils.previousProcess('frontend', this.settingsFolder)
|
102 | if (pid) throw new Error(`Frontend process is already running with pid: ${pid}. Please quit this process first.`)
|
103 |
|
104 | switch (action) {
|
105 | default:
|
106 | case 'start': {
|
107 | utils.generateComponentsJson(this.appSettings)
|
108 | let theme = options.theme
|
109 | if (!theme) theme = await this.requestThemeOption()
|
110 | await this.start({...options, theme}, await this.buildThemePath(theme))
|
111 | break
|
112 | }
|
113 | case 'setup': {
|
114 | await this.frontendSetup.run()
|
115 | break
|
116 | }
|
117 | }
|
118 |
|
119 | process.on('SIGINT', async () => {
|
120 | await this.extensionConfigWatcher.stop()
|
121 | await utils.deleteProcessFile('frontend', this.settingsFolder)
|
122 | })
|
123 | }
|
124 |
|
125 | |
126 |
|
127 |
|
128 |
|
129 |
|
130 | async buildThemePath (theme) {
|
131 | const themePath = path.join(this.appSettings.getApplicationFolder(), THEMES_FOLDER, theme)
|
132 | if (!await fsEx.exists(themePath)) {
|
133 | throw new Error(`Can't find theme '${theme}'. Please make sure you passed the right theme.`)
|
134 | }
|
135 | return themePath
|
136 | }
|
137 |
|
138 | |
139 |
|
140 |
|
141 |
|
142 |
|
143 | async start (options, themeFolder) {
|
144 | const frontend = new FrontendProcess(options, this.frontendSetup, this.appSettings)
|
145 |
|
146 | await this.extensionConfigWatcher.start()
|
147 | this.extensionConfigWatcher.on('configChange', (config) => {
|
148 |
|
149 | utils.generateComponentsJson(this.appSettings)
|
150 | })
|
151 |
|
152 | await this.updateThemeConfig(themeFolder)
|
153 | await frontend.run()
|
154 | await utils.setProcessFile('frontend', this.settingsFolder, process.pid)
|
155 | }
|
156 |
|
157 | async updateThemeConfig (templateFolder) {
|
158 | logger.info(`Generating theme config`)
|
159 | const extensionConfigFile = await fsEx.readJSON(path.join(templateFolder, 'extension-config.json'))
|
160 |
|
161 | return this.dcClient.generateExtensionConfig(extensionConfigFile, this.appSettings.getId())
|
162 | .then((extConfig) => {
|
163 | if (!extConfig.frontend) return logger.warn('No config with the destination \'frontend\' found')
|
164 | const appJsonFile = path.join(templateFolder, 'config', 'app.json')
|
165 | return fsEx.outputJson(appJsonFile, extConfig.frontend, {spaces: 2})
|
166 | })
|
167 | .then(() => {
|
168 | logger.info(`Updated theme config`)
|
169 | })
|
170 | .catch(err => {
|
171 | throw new Error('Could not generate config: ' + err.message)
|
172 | })
|
173 | }
|
174 | }
|
175 |
|
176 | module.exports = FrontendAction
|