From 4e1d124154c4dc60552fbcda4ce385af884f68d8 Mon Sep 17 00:00:00 2001 From: Vladlen Fedosov Date: Mon, 18 May 2020 13:36:58 +0300 Subject: [PATCH 1/3] feat!: initProps concept removed from ILC --- ilc/client.js | 2 +- ilc/server/tailor/configs-injector.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ilc/client.js b/ilc/client.js index 9669b77f..195a4ed6 100644 --- a/ilc/client.js +++ b/ilc/client.js @@ -49,7 +49,7 @@ selectSlotsToRegister([...registryConf.routes, registryConf.specialRoutes['404'] } return Promise.all(waitTill) - .then(v => v[0].mainSpa !== undefined ? v[0].mainSpa(appConf.initProps || {}) : v[0]); + .then(v => v[0].mainSpa !== undefined ? v[0].mainSpa(appConf.props || {}) : v[0]); }, isActiveFactory(router, appName, slotName), { diff --git a/ilc/server/tailor/configs-injector.js b/ilc/server/tailor/configs-injector.js index f226e5a1..69f29779 100644 --- a/ilc/server/tailor/configs-injector.js +++ b/ilc/server/tailor/configs-injector.js @@ -140,7 +140,7 @@ module.exports = class ConfigsInjector { #getPolyfillUrl = () => this.#cdnUrl === null ? '/_ilc/polyfill.min.js' : urljoin(this.#cdnUrl, '/polyfill.min.js'); #getSPAConfig = (registryConfig) => { - const apps = _.mapValues(registryConfig.apps, v => _.pick(v, ['spaBundle', 'cssBundle', 'dependencies', 'props', 'initProps', 'kind'])); + const apps = _.mapValues(registryConfig.apps, v => _.pick(v, ['spaBundle', 'cssBundle', 'dependencies', 'props', 'kind'])); const spaConfig = JSON.stringify(_.omit({...registryConfig, apps}, ['templates'])); return ``; From 22f13b560ebe58955708cf023bbcdf43c1dd07ae Mon Sep 17 00:00:00 2001 From: Vladlen Fedosov Date: Mon, 18 May 2020 13:50:36 +0300 Subject: [PATCH 2/3] feat!: initProps concept removed from ILC Registry --- registry/client/src/appRoutes/Edit.js | 2 +- registry/client/src/apps/Edit.js | 3 +-- registry/client/src/apps/dataTransform.js | 6 ------ registry/server/apps/interfaces/index.ts | 2 -- registry/server/apps/routes/createApp.ts | 2 +- registry/server/apps/routes/updateApp.ts | 2 +- .../20200518134531_apps_initProps_removal.ts | 16 ++++++++++++++++ registry/server/routes/config.ts | 1 - registry/server/seeds/01_apps.ts | 8 -------- registry/tests/apps.spec.ts | 8 -------- 10 files changed, 20 insertions(+), 30 deletions(-) create mode 100644 registry/server/migrations/20200518134531_apps_initProps_removal.ts diff --git a/registry/client/src/appRoutes/Edit.js b/registry/client/src/appRoutes/Edit.js index 6a2dc1c0..7562c9f5 100755 --- a/registry/client/src/appRoutes/Edit.js +++ b/registry/client/src/appRoutes/Edit.js @@ -65,7 +65,7 @@ const InputForm = ({mode = 'edit', ...props}) => { { id: 'essential', name: 'Essential' }, { id: 'regular', name: 'Regular' }, ]} /> - + diff --git a/registry/client/src/apps/Edit.js b/registry/client/src/apps/Edit.js index 99982f54..bc6409db 100755 --- a/registry/client/src/apps/Edit.js +++ b/registry/client/src/apps/Edit.js @@ -54,8 +54,7 @@ const InputForm = ({mode = 'edit', ...props}) => { - - + ); diff --git a/registry/client/src/apps/dataTransform.js b/registry/client/src/apps/dataTransform.js index 4fc36215..1b99fe33 100644 --- a/registry/client/src/apps/dataTransform.js +++ b/registry/client/src/apps/dataTransform.js @@ -9,18 +9,12 @@ export function transformGet(app) { if (app.props) { app.props = JSON.stringify(app.props); } - if (app.initProps) { - app.initProps = JSON.stringify(app.initProps); - } } export function transformSet(app) { if (app.props) { app.props = JSON.parse(app.props); } - if (app.initProps) { - app.initProps = JSON.parse(app.initProps); - } if (app.dependencies) { app.dependencies = app.dependencies.reduce((acc, v) => { acc[v.key] = v.value; diff --git a/registry/server/apps/interfaces/index.ts b/registry/server/apps/interfaces/index.ts index 2038ecbc..ac60bb47 100644 --- a/registry/server/apps/interfaces/index.ts +++ b/registry/server/apps/interfaces/index.ts @@ -9,7 +9,6 @@ export default interface App { props?: string, // JSON({ [propName: string]: any }) configSelector?: string, ssr: string, // JSON({ src: string, timeout: number }) - initProps?: string, // JSON({ [propName: string]: any }) } export const appNameSchema = Joi.string().trim().min(1); @@ -25,7 +24,6 @@ const commonApp = { src: Joi.string().trim().uri().required(), timeout: Joi.number().required(), }), - initProps: Joi.object().default({}), kind: Joi.string().valid('primary', 'essential', 'regular'), }; diff --git a/registry/server/apps/routes/createApp.ts b/registry/server/apps/routes/createApp.ts index 2bedf44b..aaac2995 100644 --- a/registry/server/apps/routes/createApp.ts +++ b/registry/server/apps/routes/createApp.ts @@ -22,7 +22,7 @@ const validateRequestBeforeCreateApp = validateRequestFactory([{ const createApp = async (req: Request, res: Response): Promise => { const app = req.body; - await db('apps').insert(stringifyJSON(['dependencies', 'props', 'ssr', 'initProps', 'configSelector'], app)); + await db('apps').insert(stringifyJSON(['dependencies', 'props', 'ssr', 'configSelector'], app)); const [savedApp] = await db.select().from('apps').where('name', app.name); diff --git a/registry/server/apps/routes/updateApp.ts b/registry/server/apps/routes/updateApp.ts index 8f4a21ba..b8ddf281 100644 --- a/registry/server/apps/routes/updateApp.ts +++ b/registry/server/apps/routes/updateApp.ts @@ -43,7 +43,7 @@ const updateApp = async (req: Request, res: Response): P return; } - await db('apps').where({ name: appName }).update(stringifyJSON(['dependencies', 'props', 'ssr', 'initProps', 'configSelector'], app)); + await db('apps').where({ name: appName }).update(stringifyJSON(['dependencies', 'props', 'ssr', 'configSelector'], app)); const [updatedApp] = await db.select().from('apps').where('name', appName); diff --git a/registry/server/migrations/20200518134531_apps_initProps_removal.ts b/registry/server/migrations/20200518134531_apps_initProps_removal.ts new file mode 100644 index 00000000..77e39e7f --- /dev/null +++ b/registry/server/migrations/20200518134531_apps_initProps_removal.ts @@ -0,0 +1,16 @@ +import * as Knex from "knex"; + + +export async function up(knex: Knex): Promise { + return knex.schema.table('apps', function (table) { + table.dropColumn('initProps'); + }) +} + + +export async function down(knex: Knex): Promise { + return knex.schema.createTable('apps', table => { + table.json('initProps'); + }); +} + diff --git a/registry/server/routes/config.ts b/registry/server/routes/config.ts index 47171480..ae21cca9 100644 --- a/registry/server/routes/config.ts +++ b/registry/server/routes/config.ts @@ -25,7 +25,6 @@ router.get('/', async (req, res) => { data.apps = apps.reduce((acc, v) => { v.ssr = JSON.parse(v.ssr); v.dependencies = JSON.parse(v.dependencies); - v.initProps = JSON.parse(v.initProps); v.props = JSON.parse(v.props); if (sharedProps.length && v.configSelector !== null) { JSON.parse(v.configSelector).forEach((configSelectorName: string) => { diff --git a/registry/server/seeds/01_apps.ts b/registry/server/seeds/01_apps.ts index ab4e28d5..acb0497c 100644 --- a/registry/server/seeds/01_apps.ts +++ b/registry/server/seeds/01_apps.ts @@ -15,7 +15,6 @@ export async function seed(knex: Knex): Promise { src: 'http://localhost:8235/', timeout: 1000, }), - initProps: '{}', props: '{}', kind: 'essential', }, { @@ -27,7 +26,6 @@ export async function seed(knex: Knex): Promise { rxjs: 'https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.js', '@portal/fetchWithCache': `http://${publicHost}:8238/fetchWithCache.js`, }), - initProps: '{}', props: JSON.stringify({ publicPath: `http://${publicHost}:8236/` }), @@ -38,7 +36,6 @@ export async function seed(knex: Knex): Promise { dependencies: JSON.stringify({ '@portal/fetchWithCache': `http://${publicHost}:8238/fetchWithCache.js`, }), - initProps: '{}', props: '{}', kind: 'primary', }, { @@ -51,9 +48,6 @@ export async function seed(knex: Knex): Promise { }), assetsDiscoveryUrl: 'http://127.0.0.1:8239/_spa/dev/assets-discovery', dependencies: '{}', - initProps: JSON.stringify({ - publicPath: `http://${publicHost}:8239/dist/` - }), props: JSON.stringify({ publicPath: `http://${publicHost}:8239/dist/` }), @@ -66,14 +60,12 @@ export async function seed(knex: Knex): Promise { timeout: 1000, }), dependencies: '{}', - initProps: '{}', props: '{}', kind: 'primary', }, { name: '@portal/fetchWithCache', spaBundle: `http://${publicHost}:8238/fetchWithCache.js`, dependencies: '{}', - initProps: '{}', props: '{}', kind: 'essential', }, diff --git a/registry/tests/apps.spec.ts b/registry/tests/apps.spec.ts index d591b372..6c11c25c 100644 --- a/registry/tests/apps.spec.ts +++ b/registry/tests/apps.spec.ts @@ -16,7 +16,6 @@ const example = { kind: 'primary', // dependencies: {}, // props: {}, - // initProps: {}, }), updated: Object.freeze({ name: '@portal/ncTestAppReactssr', @@ -38,9 +37,6 @@ const example = { assetsPath: 'http://127.0.0.1:3001/uisamplereactUpdated', locationStrategy: 'browserHistoryUpdated', }, - initProps: { - assetsPath: 'http://127.0.0.1:3001/uisamplereact', - }, }), }; example.encodedName = encodeURIComponent(example.correct.name); @@ -65,7 +61,6 @@ describe(`Tests ${example.url}`, () => { assetsDiscoveryUrl: 789, dependencies: 456, props: 789, - initProps: 456, }; let response = await request.post(example.url) @@ -82,7 +77,6 @@ describe(`Tests ${example.url}`, () => { '"props" must be of type object\n' + '"configSelector" must be an array\n' + '"ssr" must be of type object\n' + - '"initProps" must be of type object\n' + '"name" must be a string' ); @@ -193,7 +187,6 @@ describe(`Tests ${example.url}`, () => { assetsDiscoveryUrl: 789, dependencies: 456, props: 789, - initProps: 456, kind: 'origin', }; @@ -211,7 +204,6 @@ describe(`Tests ${example.url}`, () => { '"props" must be of type object\n' + '"configSelector" must be an array\n' + '"ssr" must be of type object\n' + - '"initProps" must be of type object\n' + '"kind" must be one of [primary, essential, regular]' ); expect(response.body).deep.equal({}); From b4622ee06f6c3e52a045d156ba346eeb90b51237 Mon Sep 17 00:00:00 2001 From: Vladlen Fedosov Date: Mon, 18 May 2020 14:04:42 +0300 Subject: [PATCH 3/3] doc: documentation added --- docs/ilc_app_interface.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/ilc_app_interface.md b/docs/ilc_app_interface.md index 82861def..470a1d94 100644 --- a/docs/ilc_app_interface.md +++ b/docs/ilc_app_interface.md @@ -16,7 +16,7 @@ ILC also supports apps that have client side rendering only. During the course of a single-spa page, registered applications are loaded, bootstrapped (initialized), mounted, unmounted, and unloaded. ILC (with the help of the [single-spa](https://single-spa.js.org/)) provides hooks into each phase via `lifecycles`. -See more information about the [lifecycle functions here](https://single-spa.js.org/docs/building-applications#lifecyle-props). +See more information about the [lifecycle functions here](https://single-spa.js.org/docs/building-applications/#lifecyle-props). ### Custom props that are passed to every app @@ -25,3 +25,27 @@ See more information about the [lifecycle functions here](https://single-spa.js. * `getCurrentBasePath(): string` - returns same value as `basePath` param in `routerProps` query parameter * `errorHandler(error, errorInfo = {}): void` - app MUST use it to propagate all unhandled errors * `appId` - Unique application ID, if same app will be rendered twice on a page - it will get different IDs + + +### Init code during app bundle loading + +Sometimes you need to run some initialization code right after app bundle will be loaded in the browser and usually you +want to be able to pass some configuration properties to that code. + +ILC allows you to export a function called `mainSpa(props)` that will receive application properties that were defined in +_Registry_ in it's first argument. +This function should return an object with "single-spa" [lifecycle functions](https://single-spa.js.org/docs/building-applications/#lifecyle-props). + +**Example of possible use case:** +```javascript +// File specified as Webpack entry point +export const mainSpa = (props) => { + if (props.publicPath) { + __webpack_public_path__ = props.publicPath; + } else { + console.warn(`Can't determine value of the "__webpack_public_path__", falling back to default one...`); + } + + return require('./app-bootstrap'); // Returns: {bootstrap: () => {}, mount: () => {}, unmount: () => {}} +}; +``` \ No newline at end of file