diff --git a/packages/flex-dev-utils/src/__tests__/fs.test.ts b/packages/flex-dev-utils/src/__tests__/fs.test.ts index c8e365331..7effc4d93 100644 --- a/packages/flex-dev-utils/src/__tests__/fs.test.ts +++ b/packages/flex-dev-utils/src/__tests__/fs.test.ts @@ -4,6 +4,7 @@ import * as globby from 'globby'; import * as fs from '../fs'; import * as inquirer from '../inquirer'; import { PackageJson } from '../fs'; +import { readJsonFile } from '../../dist/fs'; jest.mock('flex-plugins-utils-logger/dist/lib/inquirer'); jest.mock('globby'); @@ -339,6 +340,7 @@ describe('fs', () => { dir, flexDir: 'test-dir-flex', pluginsJsonPath, + localPluginsJsonPath: 'test-dir-local-run', }; let checkFilesExist = jest.spyOn(fs, 'checkFilesExist'); @@ -452,6 +454,97 @@ describe('fs', () => { }); }); + describe('checkRunPluginConfigurationExists', () => { + const localPluginsJsonPath = 'test-local-plugins'; + const localPlugins = ['plugin-one', 'plugin-two']; + const cliPath = { + dir: 'test-dir', + flexDir: 'test-dir-flex', + pluginsJsonPath: 'test-dir-plugins', + localPluginsJsonPath, + }; + + let checkFilesExist = jest.spyOn(fs, 'checkFilesExist'); + let mkdirpSync = jest.spyOn(fs, 'mkdirpSync'); + let writeFileSync = jest.spyOn(fs.default, 'writeFileSync'); + let readRunPluginsJson = jest.spyOn(fs, 'readRunPluginsJson'); + let getCliPaths = jest.spyOn(fs, 'getCliPaths'); + const readJsonFile = jest.spyOn(fs, 'readJsonFile'); + + beforeEach(() => { + checkFilesExist = jest.spyOn(fs, 'checkFilesExist'); + mkdirpSync = jest.spyOn(fs, 'mkdirpSync'); + writeFileSync = jest.spyOn(fs.default, 'writeFileSync'); + readRunPluginsJson = jest.spyOn(fs, 'readRunPluginsJson'); + getCliPaths = jest.spyOn(fs, 'getCliPaths'); + + mkdirpSync.mockReturnThis(); + writeFileSync.mockReturnThis(); + readJsonFile.mockReturnThis(); + readRunPluginsJson.mockReturnValue({ plugins: [], loadedPlugins: [] }); + + // @ts-ignore + getCliPaths.mockReturnValue(cliPath); + }); + + it('make directories if not found', async () => { + checkFilesExist.mockReturnValue(false); + + await fs.checkRunPluginConfigurationExists(localPlugins); + + expect(checkFilesExist).toHaveBeenCalledTimes(1); + expect(checkFilesExist).toHaveBeenCalledWith(localPluginsJsonPath); + expect(mkdirpSync).toHaveBeenCalledTimes(1); + expect(mkdirpSync).toHaveBeenCalledWith('test-dir-flex'); + }); + + it('do nothing if directories are found', async () => { + checkFilesExist.mockReturnValue(true); + + await fs.checkRunPluginConfigurationExists(localPlugins); + + expect(checkFilesExist).toHaveBeenCalledTimes(1); + expect(checkFilesExist).toHaveBeenCalledWith(localPluginsJsonPath); + expect(mkdirpSync).not.toHaveBeenCalled(); + }); + + it('should add the local plugins to the locallyRunningPlugins.json file', async () => { + checkFilesExist.mockReturnValue(true); + writeFileSync.mockReturnThis(); + + await fs.checkRunPluginConfigurationExists(localPlugins); + + expect(checkFilesExist).toHaveBeenCalledTimes(1); + expect(writeFileSync).toHaveBeenCalledTimes(1); + expect(writeFileSync).toHaveBeenCalledWith( + localPluginsJsonPath, + JSON.stringify({ plugins: localPlugins, loadedPlugins: [] }, null, 2), + ); + }); + }); + + describe('readRunPluginsJson', () => { + it('should run readJsonFile', () => { + const readJsonFile = jest.spyOn(fs, 'readJsonFile'); + const getCliPaths = jest.spyOn(fs, 'getCliPaths'); + const cliPath = { + dir: 'test-dir', + flexDir: 'test-dir-flex', + pluginsJsonPath: 'test-dir-plugins', + localPluginsJsonPath: 'test-local-plugins', + }; + + // @ts-ignore + getCliPaths.mockReturnValue(cliPath); + readJsonFile.mockReturnThis(); + + fs.readRunPluginsJson(); + + expect(readJsonFile).toHaveBeenCalledTimes(1); + expect(readJsonFile).toHaveBeenCalledWith('test-local-plugins'); + }); + }); + describe('_getFlexPluginScripts', () => { it('should resolve path', () => { const thePath = 'the/path'; @@ -517,6 +610,7 @@ describe('fs', () => { expect(fs.getCliPaths().dir).toMatchPathContaining('/.twilio-cli'); expect(fs.getCliPaths().flexDir).toMatchPathContaining('/.twilio-cli/flex'); expect(fs.getCliPaths().pluginsJsonPath).toEqual(expect.stringMatching('plugins.json')); + expect(fs.getCliPaths().localPluginsJsonPath).toEqual(expect.stringMatching('locallyRunningPlugins.json')); readPackageJson.mockRestore(); }); diff --git a/packages/flex-dev-utils/src/fs.ts b/packages/flex-dev-utils/src/fs.ts index bcd38d0d6..8096e6794 100644 --- a/packages/flex-dev-utils/src/fs.ts +++ b/packages/flex-dev-utils/src/fs.ts @@ -39,6 +39,11 @@ export interface CLIFlexConfiguration { plugins: FlexConfigurationPlugin[]; } +export interface LocallyRunningPluginsConfiguration { + plugins: string[]; + loadedPlugins: string[]; +} + export type JsonObject = { [K in keyof T]: T[K] }; export default fs; @@ -176,6 +181,7 @@ export const getCliPaths = () => { nodeModulesDir: coreNodeModulesDir, flexDir, pluginsJsonPath: resolveRelative(flexDir, 'plugins.json'), + localPluginsJsonPath: resolveRelative(flexDir, 'locallyRunningPlugins.json'), }; }; @@ -183,6 +189,10 @@ export const getCliPaths = () => { export const readPluginsJson = (): CLIFlexConfiguration => readJsonFile(getCliPaths().pluginsJsonPath); +// Read plugins.json from Twilio CLI +export const readRunPluginsJson = (): LocallyRunningPluginsConfiguration => + readJsonFile(getCliPaths().localPluginsJsonPath); + /** * Writes string to file */ @@ -389,6 +399,26 @@ export const checkPluginConfigurationExists = async ( return false; }; +/** + * Touch ~/.twilio-cli/flex/locallyRunningPlugins.json if it does not exist, + * and if it does exist, clear the file so it is ready for a new run + */ +export const checkRunPluginConfigurationExists = async (localPlugins: string[]): Promise => { + const cliPaths = getCliPaths(); + + if (!checkFilesExist(cliPaths.localPluginsJsonPath)) { + mkdirpSync(cliPaths.flexDir); + } + + const runConfig: LocallyRunningPluginsConfiguration = { plugins: [], loadedPlugins: [] }; + + for (const plugin of localPlugins) { + runConfig.plugins.push(plugin); + } + + writeJSONFile(runConfig, cliPaths.localPluginsJsonPath); +}; + /** * Adds the node_modules to the app module. * This is needed because we spawn different scripts when running start/build/test and so we lose diff --git a/packages/flex-plugin-scripts/src/scripts/__tests__/pre-localrun-check.test.ts b/packages/flex-plugin-scripts/src/scripts/__tests__/pre-localrun-check.test.ts new file mode 100644 index 000000000..740592327 --- /dev/null +++ b/packages/flex-plugin-scripts/src/scripts/__tests__/pre-localrun-check.test.ts @@ -0,0 +1,30 @@ +import * as fsScripts from 'flex-dev-utils/dist/fs'; + +import * as preLocalRunCheck from '../pre-localrun-check'; + +describe('PreLocalRunCheck', () => { + beforeEach(() => { + jest.resetAllMocks(); + jest.resetModules(); + }); + + describe('main', () => { + const _checkRunPluginConfigurationExists = jest.spyOn(fsScripts, 'checkRunPluginConfigurationExists'); + + beforeEach(() => { + _checkRunPluginConfigurationExists.mockReset(); + + _checkRunPluginConfigurationExists.mockReturnThis(); + }); + + afterAll(() => { + _checkRunPluginConfigurationExists.mockRestore(); + }); + + it('should call all methods', async () => { + await preLocalRunCheck.default(); + + expect(_checkRunPluginConfigurationExists).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/packages/flex-plugin-scripts/src/scripts/__tests__/start.test.ts b/packages/flex-plugin-scripts/src/scripts/__tests__/start.test.ts index 5d0777898..2a0644306 100644 --- a/packages/flex-plugin-scripts/src/scripts/__tests__/start.test.ts +++ b/packages/flex-plugin-scripts/src/scripts/__tests__/start.test.ts @@ -6,7 +6,7 @@ import * as pluginServerScripts from 'flex-plugin-webpack/dist/devServer/pluginS import * as devServerScripts from 'flex-plugin-webpack/dist/devServer/webpackDevServer'; import * as ipcServerScripts from 'flex-plugin-webpack/dist/devServer/ipcServer'; import * as compilerScripts from 'flex-plugin-webpack/dist/compiler'; -import { PluginsConfig } from 'flex-plugin-webpack'; +import { PluginsConfig, DelayRenderStaticPlugin } from 'flex-plugin-webpack'; import * as parserUtils from '../../utils/parser'; import * as startScripts from '../start'; @@ -316,7 +316,7 @@ describe('StartScript', () => { await startScripts._startDevServer([plugin], { ...opts, type: configScripts.WebpackType.JavaScript }, {}); expect(compiler).toHaveBeenCalledTimes(1); // eslint-disable-next-line @typescript-eslint/no-explicit-any - expect(compiler).toHaveBeenCalledWith(expect.any(Object), true, emitCompileComplete as any); + expect(compiler).toHaveBeenCalledWith(expect.any(Object), true, true, emitCompileComplete as any); }); it('should use default compiler for static/complete', async () => { @@ -326,7 +326,7 @@ describe('StartScript', () => { pluginsConfig, ); expect(compiler).toHaveBeenCalledTimes(1); - expect(compiler).toHaveBeenCalledWith(expect.any(Object), true, defaultOnCompile); + expect(compiler).toHaveBeenCalledWith(expect.any(Object), true, false, defaultOnCompile); compiler.mockReset(); await startScripts._startDevServer( @@ -335,7 +335,7 @@ describe('StartScript', () => { pluginsConfig, ); expect(compiler).toHaveBeenCalledTimes(1); - expect(compiler).toHaveBeenCalledWith(expect.any(Object), true, defaultOnCompile); + expect(compiler).toHaveBeenCalledWith(expect.any(Object), true, false, defaultOnCompile); }); }); diff --git a/packages/flex-plugin-scripts/src/scripts/pre-localrun-check.ts b/packages/flex-plugin-scripts/src/scripts/pre-localrun-check.ts new file mode 100644 index 000000000..a17bfc654 --- /dev/null +++ b/packages/flex-plugin-scripts/src/scripts/pre-localrun-check.ts @@ -0,0 +1,17 @@ +import { logger } from 'flex-dev-utils'; +import { checkRunPluginConfigurationExists } from 'flex-dev-utils/dist/fs'; + +import run from '../utils/run'; + +const preLocalRunCheck = async (...args: string[]): Promise => { + logger.debug('Checking users environment is ready to run plugins locally'); + + // Slice the args to get rid of last two elements ('--core-cwd' and the 'cwd') + await checkRunPluginConfigurationExists(args.slice(0, -2)); +}; + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +run(preLocalRunCheck); + +// eslint-disable-next-line import/no-unused-modules +export default preLocalRunCheck; diff --git a/packages/flex-plugin-scripts/src/scripts/start.ts b/packages/flex-plugin-scripts/src/scripts/start.ts index b2e380528..081531b32 100644 --- a/packages/flex-plugin-scripts/src/scripts/start.ts +++ b/packages/flex-plugin-scripts/src/scripts/start.ts @@ -17,6 +17,7 @@ import { webpackDevServer, OnDevServerCrashedPayload, PluginsConfig, + DelayRenderStaticPlugin, } from 'flex-plugin-webpack'; import getConfiguration, { ConfigurationType, WebpackType } from '../config'; @@ -118,6 +119,7 @@ export const _startDevServer = async ( // Start IPC Server if (isStaticServer) { + config?.plugins?.push(new DelayRenderStaticPlugin()); startIPCServer(); // start-flex will be listening to compilation errors emitted by start-plugin onIPCServerMessage(IPCType.onCompileComplete, onCompile); @@ -131,7 +133,12 @@ export const _startDevServer = async ( try { // Pass either the default onCompile (for start-flex) or the event-emitter (for start-plugin) - const devCompiler = compiler(config, true, isJavaScriptServer ? emitCompileComplete : onCompile); + const devCompiler = compiler( + config, + true, + isJavaScriptServer, + isJavaScriptServer ? emitCompileComplete : onCompile, + ); webpackDevServer(devCompiler, devConfig, type); } catch (err) { await emitDevServerCrashed(err); diff --git a/packages/flex-plugin-webpack/src/compiler.ts b/packages/flex-plugin-webpack/src/compiler.ts index 9f3c2ca39..404d3f6d2 100644 --- a/packages/flex-plugin-webpack/src/compiler.ts +++ b/packages/flex-plugin-webpack/src/compiler.ts @@ -6,7 +6,7 @@ import { SyncHook } from 'tapable'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import typescriptFormatter, { Issue } from '@k88/typescript-compile-error-formatter'; import webpack, { Compiler as WebpackCompiler, Configuration } from 'webpack'; -import { getPaths } from 'flex-dev-utils/dist/fs'; +import { getCliPaths, getPaths, readRunPluginsJson, writeJSONFile } from 'flex-dev-utils/dist/fs'; import webpackFormatMessages from '@k88/format-webpack-messages'; import { getLocalAndNetworkUrls } from 'flex-dev-utils/dist/urls'; @@ -48,7 +48,12 @@ const results: OnCompileResult = {}; * @param localPlugins the names of plugins to run locally */ /* istanbul ignore next */ -export default (config: Configuration, devServer: boolean, onCompile: OnCompile): Compiler => { +export default ( + config: Configuration, + devServer: boolean, + isJavaScriptServer: boolean, + onCompile: OnCompile, +): Compiler => { logger.debug('Creating webpack compiler'); try { @@ -107,7 +112,20 @@ export default (config: Configuration, devServer: boolean, onCompile: OnCompile) compiler.hooks.tsCompiled.call(messages.warnings, messages.errors); } - onCompile({ result, appName: getPaths().app.name }); + const config = readRunPluginsJson(); + + // Add the plugin to the loaded plugins configuration file + if (isJavaScriptServer) { + config.loadedPlugins.push(getPaths().app.name); + writeJSONFile(config, getCliPaths().localPluginsJsonPath); + } + + // Check to see if the plugin is the last bundle to be loaded + onCompile({ + result, + appName: getPaths().app.name, + lastPluginBundle: config.plugins.length === config.loadedPlugins.length, + }); }); return compiler; diff --git a/packages/flex-plugin-webpack/src/devServer/__tests__/ipcServer.test.ts b/packages/flex-plugin-webpack/src/devServer/__tests__/ipcServer.test.ts index 73733c644..1430bd356 100644 --- a/packages/flex-plugin-webpack/src/devServer/__tests__/ipcServer.test.ts +++ b/packages/flex-plugin-webpack/src/devServer/__tests__/ipcServer.test.ts @@ -17,14 +17,28 @@ describe('ipcServer', () => { expect(_processEmitQueue).toHaveBeenCalledTimes(1); }); - it('should test emitCompileComplete', async () => { + it('should test emitCompileComplete for a plugin that is not the last to load', async () => { + const _emitAllCompilesComplete = jest.spyOn(ipcServerScripts, 'emitAllCompilesComplete').mockReturnThis(); const _emitToServer = jest.spyOn(ipcServerScripts, '_emitToServer').mockReturnThis(); - const payload = { result: {} as ToJsonOutput, appName: 'test' }; + const payload = { result: {} as ToJsonOutput, appName: 'test', lastPluginBundle: false }; await ipcServerScripts.emitCompileComplete(payload); expect(_emitToServer).toHaveBeenCalledTimes(1); expect(_emitToServer).toHaveBeenCalledWith(ipcServerScripts.IPCType.onCompileComplete, payload); + expect(_emitAllCompilesComplete).not.toHaveBeenCalled(); + }); + + it('should test emitCompileComplete for a plugin that is the last to load', async () => { + const _emitAllCompilesComplete = jest.spyOn(ipcServerScripts, 'emitAllCompilesComplete').mockReturnThis(); + const _emitToServer = jest.spyOn(ipcServerScripts, '_emitToServer').mockReturnThis(); + + const payload = { result: {} as ToJsonOutput, appName: 'test', lastPluginBundle: true }; + await ipcServerScripts.emitCompileComplete(payload); + + expect(_emitToServer).toHaveBeenCalledTimes(1); + expect(_emitToServer).toHaveBeenCalledWith(ipcServerScripts.IPCType.onCompileComplete, payload); + expect(_emitAllCompilesComplete).toHaveBeenCalledTimes(1); }); it('should test emitDevServerCrashed', async () => { diff --git a/packages/flex-plugin-webpack/src/devServer/ipcServer.ts b/packages/flex-plugin-webpack/src/devServer/ipcServer.ts index a478f389f..840e7c911 100644 --- a/packages/flex-plugin-webpack/src/devServer/ipcServer.ts +++ b/packages/flex-plugin-webpack/src/devServer/ipcServer.ts @@ -12,11 +12,13 @@ interface Client { export enum IPCType { onCompileComplete = 'onCompileComplete', onDevServerCrashed = 'onDevServerCrashed', + onEmitAllCompilesComplete = 'onEmitAllCompilesComplete', } export interface OnCompileCompletePayload { result: ToJsonOutput; appName: string; + lastPluginBundle: boolean; } export interface OnDevServerCrashedPayload { @@ -29,6 +31,7 @@ export interface OnDevServerCrashedPayload { export interface IPCPayload { onCompileComplete: OnCompileCompletePayload; onDevServerCrashed: OnDevServerCrashedPayload; + onEmitAllCompilesComplete: unknown; } type MessageCallback = (payload: IPCPayload[T]) => void; @@ -153,12 +156,23 @@ export const onIPCServerMessage = (type: T, callback: Message messageCallbacks[type].push(callback); }; +/** + * Emits to the server that all of the JS Bundles have completed compiling + * @param payload + * @returns + */ +export const emitAllCompilesComplete = async (): Promise => _emitToServer(IPCType.onEmitAllCompilesComplete, {}); + /** * Emits a compilation complete event * @param payload */ -export const emitCompileComplete = async (payload: OnCompileCompletePayload): Promise => - _emitToServer(IPCType.onCompileComplete, payload); +export const emitCompileComplete = async (payload: OnCompileCompletePayload): Promise => { + await _emitToServer(IPCType.onCompileComplete, payload); + if (payload.lastPluginBundle) { + await emitAllCompilesComplete(); + } +}; /** * Emits a dev-server failed event diff --git a/packages/flex-plugin-webpack/src/index.ts b/packages/flex-plugin-webpack/src/index.ts index 81c2e554f..3d17aa035 100644 --- a/packages/flex-plugin-webpack/src/index.ts +++ b/packages/flex-plugin-webpack/src/index.ts @@ -21,9 +21,11 @@ export { default as pluginServer, Plugin, PluginsConfig, PLUGIN_INPUT_PARSER_REG export { emitCompileComplete, emitDevServerCrashed, + emitAllCompilesComplete, IPCType, onIPCServerMessage, OnDevServerCrashedPayload, startIPCClient, startIPCServer, } from './devServer/ipcServer'; +export { default as DelayRenderStaticPlugin } from './plugins/DelayRenderStaticPlugin'; diff --git a/packages/flex-plugin-webpack/src/plugins/DelayRenderStaticPlugin.ts b/packages/flex-plugin-webpack/src/plugins/DelayRenderStaticPlugin.ts new file mode 100644 index 000000000..3c43f5fc3 --- /dev/null +++ b/packages/flex-plugin-webpack/src/plugins/DelayRenderStaticPlugin.ts @@ -0,0 +1,20 @@ +/* istanbul ignore file */ + +import { Compiler } from '../compiler'; +import { onIPCServerMessage, IPCType } from '../devServer/ipcServer'; + +let isCalled = false; + +export default class DelayRenderStaticPlugin { + apply(compiler: Compiler): void { + compiler.hooks.beforeCompile.tapAsync('DelayPlugin', async (_, done) => { + if (isCalled) { + done(); + } + onIPCServerMessage(IPCType.onEmitAllCompilesComplete, () => { + isCalled = true; + done(); + }); + }); + } +} diff --git a/packages/plugin-flex/src/__tests__/commands/flex/plugins/start.test.ts b/packages/plugin-flex/src/__tests__/commands/flex/plugins/start.test.ts index bcbe20b49..4bcf950b7 100644 --- a/packages/plugin-flex/src/__tests__/commands/flex/plugins/start.test.ts +++ b/packages/plugin-flex/src/__tests__/commands/flex/plugins/start.test.ts @@ -16,6 +16,7 @@ describe('Commands/FlexPluginsStart', () => { const name = 'plugin-test'; const goodVersion = '2.0.0'; const badVersion = 'a.b.c'; + const preLocalRunCheck = 'pre-localrun-check'; const preStartCheck = 'pre-start-check'; const preScriptCheck = 'pre-script-check'; const pluginNameSample = 'plugin-sample'; @@ -85,7 +86,8 @@ describe('Commands/FlexPluginsStart', () => { await cmd.doRun(); expect(cmd.pluginsConfig).toEqual(config); - expect(cmd.runScript).toHaveBeenCalledTimes(3); + expect(cmd.runScript).toHaveBeenCalledTimes(4); + expect(cmd.runScript).toHaveBeenCalledWith(preLocalRunCheck, [pkg.name]); expect(cmd.runScript).toHaveBeenCalledWith('start', [ 'flex', '--name', @@ -120,7 +122,8 @@ describe('Commands/FlexPluginsStart', () => { expect(cmd._flags.name).toBeUndefined(); expect(cmd._flags[includeRemote]).toBeUndefined(); expect(cmd._flags[flexUiSource]).toBeUndefined(); - expect(cmd.runScript).toHaveBeenCalledTimes(2); + expect(cmd.runScript).toHaveBeenCalledTimes(3); + expect(cmd.runScript).toHaveBeenCalledWith(preLocalRunCheck, [badVersionPkg.name]); expect(cmd.runScript).toHaveBeenCalledWith(preStartCheck, ['--name', badVersionPkg.name]); expect(cmd.runScript).toHaveBeenCalledWith(preScriptCheck, ['--name', badVersionPkg.name]); expect(cmd.spawnScript).not.toHaveBeenCalled(); @@ -146,7 +149,8 @@ describe('Commands/FlexPluginsStart', () => { expect(cmd._flags.name).toBeUndefined(); expect(cmd._flags[includeRemote]).toBeUndefined(); expect(cmd._flags[flexUiSource]).toBeUndefined(); - expect(cmd.runScript).toHaveBeenCalledTimes(2); + expect(cmd.runScript).toHaveBeenCalledTimes(3); + expect(cmd.runScript).toHaveBeenCalledWith(preLocalRunCheck, [badPluginsPkg.name]); expect(cmd.runScript).toHaveBeenCalledWith(preStartCheck, ['--name', badPluginsPkg.name]); expect(cmd.runScript).toHaveBeenCalledWith(preScriptCheck, ['--name', badPluginsPkg.name]); expect(cmd.spawnScript).not.toHaveBeenCalled(); @@ -218,7 +222,8 @@ describe('Commands/FlexPluginsStart', () => { await cmd.run(); expect(cmd.pluginsConfig).toEqual(config); - expect(cmd.runScript).toHaveBeenCalledTimes(3); + expect(cmd.runScript).toHaveBeenCalledTimes(4); + expect(cmd.runScript).toHaveBeenCalledWith(preLocalRunCheck, [pkg.name]); expect(cmd.runScript).toHaveBeenCalledWith('start', [ 'flex', '--name', diff --git a/packages/plugin-flex/src/commands/flex/plugins/start.ts b/packages/plugin-flex/src/commands/flex/plugins/start.ts index 933901973..8241662b8 100644 --- a/packages/plugin-flex/src/commands/flex/plugins/start.ts +++ b/packages/plugin-flex/src/commands/flex/plugins/start.ts @@ -110,6 +110,9 @@ export default class FlexPluginsStart extends FlexPlugin { flexArgs.push('--port', flexPort.toString()); if (flexArgs.length && localPluginNames.length) { + // Verify the users environment is ready to run plugins locally + await this.checkLocalEnvironment(localPluginNames); + // Verify all plugins are correct for (let i = 0; localPluginNames && i < localPluginNames.length; i++) { await this.checkPlugin(localPluginNames[i]); @@ -164,6 +167,13 @@ export default class FlexPluginsStart extends FlexPlugin { } } + /** + * Checks that the user's environment is ready to run plugins locally + */ + async checkLocalEnvironment(args: string[]): Promise { + await this.runScript('pre-localrun-check', args); + } + /** * Checks the plugin version exists * @param name the inputted plugin name w/ @ version