Skip to content

Commit

Permalink
Merge pull request #165 from namecheap/feature/initProps_removal
Browse files Browse the repository at this point in the history
Feature/init props removal
  • Loading branch information
StyleT authored May 18, 2020
2 parents 5589af9 + b4622ee commit 02fa70d
Show file tree
Hide file tree
Showing 13 changed files with 47 additions and 33 deletions.
26 changes: 25 additions & 1 deletion docs/ilc_app_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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: () => {}}
};
```
2 changes: 1 addition & 1 deletion ilc/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
{
Expand Down
2 changes: 1 addition & 1 deletion ilc/server/tailor/configs-injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<script type="spa-config">${spaConfig}</script>`;
Expand Down
2 changes: 1 addition & 1 deletion registry/client/src/appRoutes/Edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const InputForm = ({mode = 'edit', ...props}) => {
{ id: 'essential', name: 'Essential' },
{ id: 'regular', name: 'Regular' },
]} />
<JsonField source="props" label="App props"/>
<JsonField source="props" label="Properties that will be passed to application at current route"/>
</SimpleFormIterator>
</ArrayInput>
</FormTab>
Expand Down
3 changes: 1 addition & 2 deletions registry/client/src/apps/Edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ const InputForm = ({mode = 'edit', ...props}) => {
<NumberInput source="ssr.timeout" label="Request timeout, in ms" />
</FormTab>
<FormTab label="Props">
<JsonField source="props"/>
<JsonField source="initProps"/>
<JsonField source="props" label="Properties that will be passed to application"/>
</FormTab>
</TabbedForm>
);
Expand Down
6 changes: 0 additions & 6 deletions registry/client/src/apps/dataTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions registry/server/apps/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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'),
};

Expand Down
2 changes: 1 addition & 1 deletion registry/server/apps/routes/createApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const validateRequestBeforeCreateApp = validateRequestFactory([{
const createApp = async (req: Request, res: Response): Promise<void> => {
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<App>('apps').where('name', app.name);

Expand Down
2 changes: 1 addition & 1 deletion registry/server/apps/routes/updateApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const updateApp = async (req: Request<UpdateAppRequestParams>, 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<App>('apps').where('name', appName);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as Knex from "knex";


export async function up(knex: Knex): Promise<any> {
return knex.schema.table('apps', function (table) {
table.dropColumn('initProps');
})
}


export async function down(knex: Knex): Promise<any> {
return knex.schema.createTable('apps', table => {
table.json('initProps');
});
}

1 change: 0 additions & 1 deletion registry/server/routes/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
8 changes: 0 additions & 8 deletions registry/server/seeds/01_apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export async function seed(knex: Knex): Promise<any> {
src: 'http://localhost:8235/',
timeout: 1000,
}),
initProps: '{}',
props: '{}',
kind: 'essential',
}, {
Expand All @@ -27,7 +26,6 @@ export async function seed(knex: Knex): Promise<any> {
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/`
}),
Expand All @@ -38,7 +36,6 @@ export async function seed(knex: Knex): Promise<any> {
dependencies: JSON.stringify({
'@portal/fetchWithCache': `http://${publicHost}:8238/fetchWithCache.js`,
}),
initProps: '{}',
props: '{}',
kind: 'primary',
}, {
Expand All @@ -51,9 +48,6 @@ export async function seed(knex: Knex): Promise<any> {
}),
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/`
}),
Expand All @@ -66,14 +60,12 @@ export async function seed(knex: Knex): Promise<any> {
timeout: 1000,
}),
dependencies: '{}',
initProps: '{}',
props: '{}',
kind: 'primary',
}, {
name: '@portal/fetchWithCache',
spaBundle: `http://${publicHost}:8238/fetchWithCache.js`,
dependencies: '{}',
initProps: '{}',
props: '{}',
kind: 'essential',
},
Expand Down
8 changes: 0 additions & 8 deletions registry/tests/apps.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const example = <any>{
kind: 'primary',
// dependencies: {},
// props: {},
// initProps: {},
}),
updated: Object.freeze({
name: '@portal/ncTestAppReactssr',
Expand All @@ -38,9 +37,6 @@ const example = <any>{
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);
Expand All @@ -65,7 +61,6 @@ describe(`Tests ${example.url}`, () => {
assetsDiscoveryUrl: 789,
dependencies: 456,
props: 789,
initProps: 456,
};

let response = await request.post(example.url)
Expand All @@ -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'
);

Expand Down Expand Up @@ -193,7 +187,6 @@ describe(`Tests ${example.url}`, () => {
assetsDiscoveryUrl: 789,
dependencies: 456,
props: 789,
initProps: 456,
kind: 'origin',
};

Expand All @@ -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({});
Expand Down

0 comments on commit 02fa70d

Please sign in to comment.