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 FrontendProcess = require('../app/frontend/FrontendProcess')
|
12 | const FrontendSetup = require('../app/frontend/FrontendSetup')
|
13 | const utils = require('../utils/utils')
|
14 | const ExtensionConfigWatcher = require('../app/ExtensionConfigWatcher')
|
15 | const { extensionConfigChanged } = require('../utils/EventHandler')
|
16 |
|
17 | const { SETTINGS_FOLDER, THEMES_FOLDER } = require('../app/Constants')
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | class FrontendAction {
|
23 | |
24 |
|
25 |
|
26 |
|
27 |
|
28 | constructor (appSettings, userSettings, dcHttpClient) {
|
29 | this.appSettings = appSettings
|
30 | this.userSettings = userSettings
|
31 | this.settingsFolder = path.join(this.appSettings.getApplicationFolder(), SETTINGS_FOLDER)
|
32 | this.dcHttpClient = dcHttpClient
|
33 | this.frontendSetup = new FrontendSetup(this.dcHttpClient, this.appSettings)
|
34 | this.extensionConfigWatcher = new ExtensionConfigWatcher(this.appSettings)
|
35 | }
|
36 |
|
37 | |
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | static register (caporal, appSettings, userSettings, dcHttpClient) {
|
45 | caporal
|
46 | .command('frontend start')
|
47 | .description('Starts the webpack dev server for the frontend development')
|
48 | .option('-t, --theme [value]', 'The name of the theme that you want to be compiled by webpack.')
|
49 | .option('-h, --host [value]', 'The URL or IP address of your local development environment.')
|
50 | .option('-p, --port [value]', 'The port to use for accessing the output via browser.')
|
51 | .option('-a, --analyze', 'Whether to analyze the bundle sizes.')
|
52 | .action(async (args, options) => {
|
53 | try {
|
54 | await new FrontendAction(appSettings, userSettings, dcHttpClient).run('start', args, options)
|
55 | } catch (err) {
|
56 |
|
57 | logger.error(err.message)
|
58 | process.exit(1)
|
59 | }
|
60 | })
|
61 |
|
62 | caporal
|
63 | .command('frontend setup')
|
64 | .description('Changes the settings for the frontend development')
|
65 | .action(async (args, options) => {
|
66 | try {
|
67 | await new FrontendAction(appSettings, userSettings, dcHttpClient).run('setup', args, options)
|
68 | } catch (err) {
|
69 | logger.error(err.message)
|
70 | process.exit(1)
|
71 | }
|
72 | })
|
73 | }
|
74 |
|
75 | |
76 |
|
77 |
|
78 |
|
79 | requestThemeOption () {
|
80 | return new Promise(async (resolve, reject) => {
|
81 | const themes = await utils.findThemes(this.appSettings)
|
82 | if (themes.length === 1) return resolve(themes[0])
|
83 |
|
84 | inquirer
|
85 | .prompt([{
|
86 | type: 'list',
|
87 | name: 'theme',
|
88 | message: 'Please choose a theme to use',
|
89 | choices: themes
|
90 | }])
|
91 | .then(answers => resolve(answers.theme))
|
92 | .catch(error => reject(error))
|
93 | })
|
94 | }
|
95 |
|
96 | |
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | async run (action, args, options = {}) {
|
103 | await this.userSettings.validate()
|
104 | await this.appSettings.validate()
|
105 |
|
106 | const pid = await utils.getProcessId('frontend', this.settingsFolder)
|
107 | if (pid) throw new Error(`Frontend process is already running with pid: ${pid}. Please quit this process first.`)
|
108 |
|
109 | switch (action) {
|
110 | default:
|
111 | case 'start': {
|
112 | await utils.generateComponentsJson(this.appSettings)
|
113 | await utils.writeExtensionConfigs(this.appSettings, this.dcHttpClient)
|
114 |
|
115 | let theme = options.theme
|
116 | if (!theme) theme = await this.requestThemeOption()
|
117 | const frontendSettings = this.appSettings.getFrontendSettings()
|
118 | await this.setStartPage(
|
119 | await this.appSettings.getId(),
|
120 | await frontendSettings.getIpAddress(),
|
121 | await frontendSettings.getPort()
|
122 | )
|
123 | await this.start({ ...options, theme }, await this.buildThemePath(theme))
|
124 | break
|
125 | }
|
126 | case 'setup': {
|
127 | const showMessage = process.env.INTEGRATION_TEST !== 'true'
|
128 | await this.frontendSetup.run(showMessage)
|
129 | break
|
130 | }
|
131 | }
|
132 | }
|
133 |
|
134 | |
135 |
|
136 |
|
137 |
|
138 |
|
139 | async buildThemePath (theme) {
|
140 | const themePath = path.join(this.appSettings.getApplicationFolder(), THEMES_FOLDER, theme)
|
141 | if (!await fsEx.exists(themePath)) {
|
142 | throw new Error(`Can't find theme '${theme}'. Please make sure you passed the right theme.`)
|
143 | }
|
144 | return themePath
|
145 | }
|
146 |
|
147 | |
148 |
|
149 |
|
150 |
|
151 |
|
152 | async setStartPage (appId, address, port) {
|
153 | await this.dcHttpClient.setStartPageUrl(appId, `http://${address}:${port}`)
|
154 | }
|
155 |
|
156 | |
157 |
|
158 |
|
159 | async resetStartPage (appId) {
|
160 | await this.dcHttpClient.setStartPageUrl(appId, '')
|
161 | }
|
162 |
|
163 | |
164 |
|
165 |
|
166 |
|
167 |
|
168 | async start (options, themeFolder) {
|
169 | const frontend = new FrontendProcess(options, this.frontendSetup, this.appSettings)
|
170 |
|
171 | process.on('SIGINT', async () => {
|
172 | try {
|
173 | frontend.stop()
|
174 | await this.extensionConfigWatcher.stop()
|
175 | await utils.deleteProcessFile('frontend', this.settingsFolder)
|
176 | await this.resetStartPage(await this.appSettings.getId())
|
177 | process.exit(0)
|
178 | } catch (err) {
|
179 | logger.error(err.message)
|
180 | process.exit(err.code)
|
181 | }
|
182 | })
|
183 |
|
184 | await this.extensionConfigWatcher.start('frontend')
|
185 | this.extensionConfigWatcher.on('configChange', (config) => extensionConfigChanged(config, this.appSettings, this.dcHttpClient))
|
186 | await this.updateThemeConfig(themeFolder)
|
187 | await frontend.run()
|
188 | await utils.setProcessFile('frontend', this.settingsFolder, process.pid)
|
189 | }
|
190 |
|
191 | async updateThemeConfig (templateFolder) {
|
192 | logger.info(`Generating theme config`)
|
193 | const extensionConfigFile = await fsEx.readJSON(path.join(templateFolder, 'extension-config.json'))
|
194 |
|
195 | return this.dcHttpClient.generateExtensionConfig(extensionConfigFile, await this.appSettings.getId())
|
196 | .then((extConfig) => {
|
197 | if (!extConfig.frontend) return logger.warn('No config with the destination \'frontend\' found')
|
198 | const appJsonFile = path.join(templateFolder, 'config', 'app.json')
|
199 | return fsEx.outputJson(appJsonFile, extConfig.frontend, { spaces: 2 })
|
200 | })
|
201 | .then(() => {
|
202 | logger.info(`Updated theme config`)
|
203 | })
|
204 | .catch(err => {
|
205 | throw new Error('Could not generate config: ' + err.message)
|
206 | })
|
207 | }
|
208 | }
|
209 |
|
210 | module.exports = FrontendAction
|