Skip to content

Commit 589631d

Browse files
authored
Merge pull request #5323 from Shopify/01-30-refactor_devstatusmanager_from_singleton_to_injected_instance
Refactor devStatusManager from singleton to injected instance
2 parents e4e7e0f + 80c1946 commit 589631d

File tree

8 files changed

+67
-24
lines changed

8 files changed

+67
-24
lines changed

packages/app/src/cli/services/dev.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {getCachedAppInfo, setCachedAppInfo} from './local-storage.js'
2525
import {canEnablePreviewMode} from './extensions/common.js'
2626
import {fetchAppRemoteConfiguration} from './app/select-app.js'
2727
import {patchAppConfigurationFile} from './app/patch-app-configuration-file.js'
28+
import {DevSessionStatusManager} from './dev/processes/dev-session-status-manager.js'
2829
import {DeveloperPlatformClient} from '../utilities/developer-platform-client.js'
2930
import {Web, isCurrentAppSchema, getAppScopesArray, AppLinkedInterface} from '../models/app/app.js'
3031
import {Organization, OrganizationApp, OrganizationStore} from '../models/organization.js'
@@ -71,9 +72,9 @@ export interface DevOptions {
7172
export async function dev(commandOptions: DevOptions) {
7273
const config = await prepareForDev(commandOptions)
7374
await actionsBeforeSettingUpDevProcesses(config)
74-
const {processes, graphiqlUrl, previewUrl} = await setupDevProcesses(config)
75+
const {processes, graphiqlUrl, previewUrl, devSessionStatusManager} = await setupDevProcesses(config)
7576
await actionsBeforeLaunchingDevProcesses(config)
76-
await launchDevProcesses({processes, previewUrl, graphiqlUrl, config})
77+
await launchDevProcesses({processes, previewUrl, graphiqlUrl, config, devSessionStatusManager})
7778
}
7879

7980
async function prepareForDev(commandOptions: DevOptions): Promise<DevConfig> {
@@ -117,10 +118,10 @@ async function prepareForDev(commandOptions: DevOptions): Promise<DevConfig> {
117118
await installAppDependencies(app)
118119
}
119120

120-
const graphiqlPort = commandOptions.graphiqlPort || (await getAvailableTCPPort(ports.graphiql))
121+
const graphiqlPort = commandOptions.graphiqlPort ?? (await getAvailableTCPPort(ports.graphiql))
121122
const {graphiqlKey} = commandOptions
122123

123-
if (graphiqlPort !== (commandOptions.graphiqlPort || ports.graphiql)) {
124+
if (graphiqlPort !== (commandOptions.graphiqlPort ?? ports.graphiql)) {
124125
renderWarning({
125126
headline: [
126127
'A random port will be used for GraphiQL because',
@@ -224,7 +225,7 @@ export async function warnIfScopesDifferBeforeDev({
224225
scopesMessage(getAppScopesArray(localApp.configuration)),
225226
'\n',
226227
'Scopes in Partner Dashboard:',
227-
scopesMessage(remoteAccess?.scopes?.split(',') || []),
228+
scopesMessage(remoteAccess?.scopes?.split(',') ?? []),
228229
],
229230
nextSteps,
230231
})
@@ -301,7 +302,7 @@ async function setupNetworkingOptions(
301302
...frontEndOptions,
302303
tunnelClient,
303304
}),
304-
getBackendPort() || backendConfig?.configuration.port || getAvailableTCPPort(),
305+
getBackendPort() ?? backendConfig?.configuration.port ?? getAvailableTCPPort(),
305306
getURLs(remoteAppConfig),
306307
])
307308
const proxyUrl = usingLocalhost ? `${frontendUrl}:${proxyPort}` : frontendUrl
@@ -330,11 +331,13 @@ async function launchDevProcesses({
330331
previewUrl,
331332
graphiqlUrl,
332333
config,
334+
devSessionStatusManager,
333335
}: {
334336
processes: DevProcesses
335337
previewUrl: string
336338
graphiqlUrl: string | undefined
337339
config: DevConfig
340+
devSessionStatusManager: DevSessionStatusManager
338341
}) {
339342
const abortController = new AbortController()
340343
const processesForTaskRunner: OutputProcess[] = processes.map((process) => {
@@ -375,6 +378,7 @@ async function launchDevProcesses({
375378
abortController,
376379
developerPreview: developerPreviewController(apiKey, developerPlatformClient),
377380
shopFqdn: config.storeFqdn,
381+
devSessionStatusManager,
378382
})
379383
}
380384

packages/app/src/cli/services/dev/processes/dev-session-status-manager.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import {devSessionStatusManager, DevSessionStatus} from './dev-session-status-manager.js'
1+
import {DevSessionStatus, DevSessionStatusManager} from './dev-session-status-manager.js'
22
import {describe, test, expect, beforeEach, vi} from 'vitest'
33

44
describe('DevSessionStatusManager', () => {
5+
const devSessionStatusManager = new DevSessionStatusManager()
6+
57
beforeEach(() => {
68
devSessionStatusManager.removeAllListeners()
79
devSessionStatusManager.reset()

packages/app/src/cli/services/dev/processes/dev-session-status-manager.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ export class DevSessionStatusManager extends EventEmitter {
1414
graphiqlURL: undefined,
1515
}
1616

17+
constructor(defaultStatus?: DevSessionStatus) {
18+
super()
19+
if (defaultStatus) this.currentStatus = defaultStatus
20+
}
21+
1722
updateStatus(status: Partial<DevSessionStatus>) {
1823
const newStatus = {...this.currentStatus, ...status}
1924
// Only emit if status has changed
@@ -35,5 +40,3 @@ export class DevSessionStatusManager extends EventEmitter {
3540
}
3641
}
3742
}
38-
39-
export const devSessionStatusManager = new DevSessionStatusManager()

packages/app/src/cli/services/dev/processes/dev-session.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {setupDevSessionProcess, pushUpdatesForDevSession} from './dev-session.js'
2-
import {devSessionStatusManager} from './dev-session-status-manager.js'
2+
import {DevSessionStatusManager} from './dev-session-status-manager.js'
33
import {DeveloperPlatformClient} from '../../../utilities/developer-platform-client.js'
44
import {AppLinkedInterface} from '../../../models/app/app.js'
55
import {AppEventWatcher} from '../app-events/app-event-watcher.js'
@@ -39,6 +39,7 @@ describe('setupDevSessionProcess', () => {
3939
appWatcher: {} as AppEventWatcher,
4040
appPreviewURL: 'https://test.preview.url',
4141
appLocalProxyURL: 'https://test.local.url',
42+
devSessionStatusManager: new DevSessionStatusManager(),
4243
}
4344

4445
// When
@@ -60,6 +61,7 @@ describe('setupDevSessionProcess', () => {
6061
appWatcher: options.appWatcher,
6162
appPreviewURL: options.appPreviewURL,
6263
appLocalProxyURL: options.appLocalProxyURL,
64+
devSessionStatusManager: options.devSessionStatusManager,
6365
},
6466
})
6567
})
@@ -73,6 +75,7 @@ describe('pushUpdatesForDevSession', () => {
7375
let appWatcher: AppEventWatcher
7476
let app: AppLinkedInterface
7577
let abortController: AbortController
78+
let devSessionStatusManager: DevSessionStatusManager
7679

7780
beforeEach(() => {
7881
vi.mocked(formData).mockReturnValue({append: vi.fn(), getHeaders: vi.fn()} as any)
@@ -83,7 +86,7 @@ describe('pushUpdatesForDevSession', () => {
8386
app = testAppLinked()
8487
appWatcher = new AppEventWatcher(app)
8588
abortController = new AbortController()
86-
devSessionStatusManager.reset()
89+
devSessionStatusManager = new DevSessionStatusManager()
8790
options = {
8891
developerPlatformClient,
8992
appWatcher,
@@ -92,6 +95,7 @@ describe('pushUpdatesForDevSession', () => {
9295
organizationId: 'org123',
9396
appPreviewURL: 'https://test.preview.url',
9497
appLocalProxyURL: 'https://test.local.url',
98+
devSessionStatusManager,
9599
}
96100
})
97101

packages/app/src/cli/services/dev/processes/dev-session.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {BaseProcess, DevProcessFunction} from './types.js'
2-
import {devSessionStatusManager} from './dev-session-status-manager.js'
2+
import {DevSessionStatusManager} from './dev-session-status-manager.js'
33
import {DeveloperPlatformClient} from '../../../utilities/developer-platform-client.js'
44
import {AppLinkedInterface} from '../../../models/app/app.js'
55
import {getExtensionUploadURL} from '../../deploy/upload.js'
@@ -31,6 +31,7 @@ interface DevSessionOptions {
3131
appWatcher: AppEventWatcher
3232
appPreviewURL: string
3333
appLocalProxyURL: string
34+
devSessionStatusManager: DevSessionStatusManager
3435
}
3536

3637
interface DevSessionProcessOptions extends DevSessionOptions {
@@ -88,7 +89,7 @@ export const pushUpdatesForDevSession: DevProcessFunction<DevSessionOptions> = a
8889
{stderr, stdout, abortSignal: signal},
8990
options,
9091
) => {
91-
const {appWatcher} = options
92+
const {appWatcher, devSessionStatusManager} = options
9293

9394
const processOptions = {...options, stderr, stdout, signal, bundlePath: appWatcher.buildOutputPath}
9495

@@ -164,7 +165,7 @@ async function handleDevSessionResult(
164165
await printSuccess(`✅ Updated`, processOptions.stdout)
165166
await printActionRequiredMessages(processOptions, event)
166167
} else if (result.status === 'created') {
167-
devSessionStatusManager.updateStatus({isReady: true})
168+
processOptions.devSessionStatusManager.updateStatus({isReady: true})
168169
await printSuccess(`✅ Ready, watching for changes in your app `, processOptions.stdout)
169170
} else if (result.status === 'aborted') {
170171
outputDebug('❌ Session update aborted (new change detected or error in Session Update)', processOptions.stdout)
@@ -174,7 +175,7 @@ async function handleDevSessionResult(
174175

175176
// If we failed to create a session, exit the process. Don't throw an error in tests as it can't be caught due to the
176177
// async nature of the process.
177-
if (!devSessionStatusManager.status.isReady && !isUnitTest()) {
178+
if (!processOptions.devSessionStatusManager.status.isReady && !isUnitTest()) {
178179
throw new AbortError('Failed to start dev session.')
179180
}
180181
}
@@ -253,7 +254,7 @@ async function bundleExtensionsAndUpload(options: DevSessionProcessOptions): Pro
253254
// Create or update the dev session
254255
if (currentBundleController.signal.aborted) return {status: 'aborted'}
255256
try {
256-
if (devSessionStatusManager.status.isReady) {
257+
if (options.devSessionStatusManager.status.isReady) {
257258
const result = await devSessionUpdateWithRetry(payload, options.developerPlatformClient)
258259
const errors = result.devSessionUpdate?.userErrors ?? []
259260
if (errors.length) return {status: 'remote-error', error: errors}
@@ -363,5 +364,5 @@ async function printLogMessage(message: string, stdout: Writable, prefix?: strin
363364
async function updatePreviewURL(options: DevSessionProcessOptions, event: AppEvent) {
364365
const hasPreview = event.app.allExtensions.filter((ext) => ext.isPreviewable).length > 0
365366
const newPreviewURL = hasPreview ? options.appLocalProxyURL : options.appPreviewURL
366-
devSessionStatusManager.updateStatus({previewURL: newPreviewURL})
367+
options.devSessionStatusManager.updateStatus({previewURL: newPreviewURL})
367368
}

packages/app/src/cli/services/dev/processes/setup-dev-processes.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {WebProcess, setupWebProcesses} from './web.js'
88
import {DevSessionProcess, setupDevSessionProcess} from './dev-session.js'
99
import {AppLogsSubscribeProcess, setupAppLogsPollingProcess} from './app-logs-polling.js'
1010
import {AppWatcherProcess, setupAppWatcherProcess} from './app-watcher-process.js'
11-
import {devSessionStatusManager} from './dev-session-status-manager.js'
11+
import {DevSessionStatusManager} from './dev-session-status-manager.js'
1212
import {environmentVariableNames} from '../../../constants.js'
1313
import {AppLinkedInterface, getAppScopes, WebType} from '../../../models/app/app.js'
1414

@@ -79,6 +79,7 @@ export async function setupDevProcesses({
7979
processes: DevProcesses
8080
previewUrl: string
8181
graphiqlUrl: string | undefined
82+
devSessionStatusManager: DevSessionStatusManager
8283
}> {
8384
const apiKey = remoteApp.apiKey
8485
const apiSecret = remoteApp.apiSecretKeys[0]?.secret ?? ''
@@ -100,7 +101,7 @@ export async function setupDevProcesses({
100101
? `http://localhost:${graphiqlPort}/graphiql${graphiqlKey ? `?key=${graphiqlKey}` : ''}`
101102
: undefined
102103

103-
devSessionStatusManager.updateStatus({isReady: false, previewURL, graphiqlURL})
104+
const devSessionStatusManager = new DevSessionStatusManager({isReady: false, previewURL, graphiqlURL})
104105

105106
const processes = [
106107
...(await setupWebProcesses({
@@ -150,6 +151,7 @@ export async function setupDevProcesses({
150151
appWatcher,
151152
appPreviewURL: appPreviewUrl,
152153
appLocalProxyURL: devConsoleURL,
154+
devSessionStatusManager,
153155
})
154156
: await setupDraftableExtensionsProcess({
155157
localApp: reloadedApp,
@@ -198,6 +200,7 @@ export async function setupDevProcesses({
198200
processes: processesWithProxy,
199201
previewUrl: previewURL,
200202
graphiqlUrl: graphiqlURL,
203+
devSessionStatusManager,
201204
}
202205
}
203206

packages/app/src/cli/services/dev/ui.test.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {renderDev} from './ui.js'
22
import {Dev} from './ui/components/Dev.js'
33
import {DevSessionUI} from './ui/components/DevSessionUI.js'
4-
import {devSessionStatusManager} from './processes/dev-session-status-manager.js'
4+
import {DevSessionStatusManager} from './processes/dev-session-status-manager.js'
55
import {testDeveloperPlatformClient} from '../../models/app/app.test-data.js'
66
import {afterEach, describe, expect, test, vi} from 'vitest'
77
import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output'
@@ -21,6 +21,7 @@ const developerPreview = {
2121
}
2222

2323
const developerPlatformClient = testDeveloperPlatformClient()
24+
const devSessionStatusManager = new DevSessionStatusManager()
2425

2526
afterEach(() => {
2627
mockAndCaptureOutput().clear()
@@ -60,6 +61,7 @@ describe('ui', () => {
6061
abortController,
6162
developerPreview,
6263
shopFqdn,
64+
devSessionStatusManager,
6365
})
6466

6567
expect(vi.mocked(Dev)).not.toHaveBeenCalled()
@@ -103,6 +105,7 @@ describe('ui', () => {
103105
abortController,
104106
developerPreview,
105107
shopFqdn,
108+
devSessionStatusManager,
106109
})
107110
abortController.abort()
108111

@@ -142,6 +145,7 @@ describe('ui', () => {
142145
abortController,
143146
developerPreview,
144147
shopFqdn,
148+
devSessionStatusManager,
145149
})
146150
abortController.abort()
147151

@@ -173,7 +177,17 @@ describe('ui', () => {
173177
const abortController = new AbortController()
174178

175179
// eslint-disable-next-line @typescript-eslint/no-floating-promises
176-
renderDev({processes, previewUrl, graphiqlUrl, graphiqlPort, app, abortController, developerPreview, shopFqdn})
180+
renderDev({
181+
processes,
182+
previewUrl,
183+
graphiqlUrl,
184+
graphiqlPort,
185+
app,
186+
abortController,
187+
developerPreview,
188+
shopFqdn,
189+
devSessionStatusManager,
190+
})
177191

178192
await new Promise((resolve) => setTimeout(resolve, 100))
179193

@@ -209,7 +223,17 @@ describe('ui', () => {
209223
const abortController = new AbortController()
210224

211225
// eslint-disable-next-line @typescript-eslint/no-floating-promises
212-
renderDev({processes, previewUrl, graphiqlUrl, graphiqlPort, app, abortController, developerPreview, shopFqdn})
226+
renderDev({
227+
processes,
228+
previewUrl,
229+
graphiqlUrl,
230+
graphiqlPort,
231+
app,
232+
abortController,
233+
developerPreview,
234+
shopFqdn,
235+
devSessionStatusManager,
236+
})
213237

214238
await new Promise((resolve) => setTimeout(resolve, 100))
215239

@@ -258,6 +282,7 @@ describe('ui', () => {
258282
abortController,
259283
developerPreview,
260284
shopFqdn,
285+
devSessionStatusManager,
261286
})
262287

263288
await new Promise((resolve) => setTimeout(resolve, 100))

packages/app/src/cli/services/dev/ui.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {Dev, DevProps} from './ui/components/Dev.js'
22
import {DevSessionUI} from './ui/components/DevSessionUI.js'
3-
import {devSessionStatusManager} from './processes/dev-session-status-manager.js'
3+
import {DevSessionStatusManager} from './processes/dev-session-status-manager.js'
44
import React from 'react'
55
import {render} from '@shopify/cli-kit/node/ui'
66
import {terminalSupportsPrompting} from '@shopify/cli-kit/node/system'
@@ -16,7 +16,8 @@ export async function renderDev({
1616
graphiqlPort,
1717
developerPreview,
1818
shopFqdn,
19-
}: DevProps) {
19+
devSessionStatusManager,
20+
}: DevProps & {devSessionStatusManager: DevSessionStatusManager}) {
2021
if (!terminalSupportsPrompting()) {
2122
await renderDevNonInteractive({processes, app, abortController, developerPreview, shopFqdn})
2223
} else if (app.developerPlatformClient.supportsDevSessions) {

0 commit comments

Comments
 (0)