Skip to content

Commit

Permalink
chore: add @ui-kitten/metro-config package
Browse files Browse the repository at this point in the history
  • Loading branch information
artyorsh authored Feb 24, 2020
1 parent b0b85b8 commit 12230c6
Show file tree
Hide file tree
Showing 17 changed files with 1,188 additions and 192 deletions.
5 changes: 1 addition & 4 deletions docs/src/articles/guides/configure-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,7 @@ UI Kitten includes much more components that can be used with React Navigation:
## Note on the other navigation libraries

Since React Navigation is not the only solution to perform routing within the React Native app, you might be interested
in other navigation libraries like React Native Navigation by Wix. Currently, UI Kitten is not well-adopted to be used
with this library and might have some performance issues.

Consider using React Navigation since UI Kitten has better API support with it.
in other navigation libraries like React Native Navigation by Wix. By default, UI Kitten is not well adopted to work with this library, and you may need to [improve it's performance](guides/improving-performance).

<hr>

Expand Down
57 changes: 57 additions & 0 deletions docs/src/articles/guides/improving-performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Improving Performance

By default, UI Kitten is configured with processing Eva mapping packages during the runtime. This may lead to performance issues when using [mapping customization](design-system/customize-mapping) or React Native Navigation by Wix. By following this guide, you will know how to get rid of this and save time your application takes on loading.

## Configuration

Install the additional metro configuration:

```bash
npm i -D @ui-kitten/metro-config
```

Create **metro.config.js** at the root of your project if you don't have this file yet and place the following code:

```js
const MetroConfig = require('@ui-kitten/metro-config');

const evaConfig = {
evaPackage: '@eva-design/eva',
// Optional, but may be useful when using mapping customization feature.
// customMappingPath: './custom-mapping.json',
};

module.exports = MetroConfig.create(evaConfig, {
// Whatever was previously specified
});
```

Modify props passed to ApplicationProvider:

```jsx
import React from 'react';
import { ApplicationProvider } from '@ui-kitten/components';
import * as eva from '@eva-design/eva';

export default () => (
<ApplicationProvider {...eva} theme={eva.light}>
// ...
</ApplicationProvider>
);
```
Restart Metro Bundler if it is running to apply the changes.

<hr>

## Definition

Let's take a look on the **evaConfig** we define:

**evaPackage** represents the name of Eva Design System package installed.

In this example, we use `@eva-design/eva`.
It may be one of the valid Eva Design System packages.

**customMappingPath** represents a path to custom mapping if you use [mapping customization](design-system/customize-mapping) feature. You may omit it if you do not customize Eva.

The second argument of `create` function is a standard configuration of Metro Bundler. In case you had `metro.config.js` previously, pass the object you had to merge it with UI Kitten configuration.
11 changes: 11 additions & 0 deletions docs/src/structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ export const structure = [
},
],
},
{
type: 'page',
name: 'Improving Performance',
children: [
{
type: 'block',
block: 'markdown',
source: 'guides/improving-performance.md',
},
],
},
],
},
{
Expand Down
1 change: 1 addition & 0 deletions scripts/bump-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const PACKAGES: string[] = [
'components',
'date-fns',
'eva-icons',
'metro-config',
'moment',
'template-js',
'template-ts',
Expand Down
3 changes: 2 additions & 1 deletion scripts/publish-packages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ function rebuild(done: GulpCompletionCallback): void {

function publish(done: GulpCompletionCallback): void {
execSync(`npm publish ${PACKAGES_BUILD_DIR}/components`, { cwd: ROOT_DIR });
execSync(`npm publish ${PACKAGES_BUILD_DIR}/eva-icons`, { cwd: ROOT_DIR });
execSync(`npm publish ${PACKAGES_BUILD_DIR}/date-fns`, { cwd: ROOT_DIR });
execSync(`npm publish ${PACKAGES_BUILD_DIR}/eva-icons`, { cwd: ROOT_DIR });
execSync(`npm publish ${PACKAGES_BUILD_DIR}/metro-config`, { cwd: ROOT_DIR });
execSync(`npm publish ${PACKAGES_BUILD_DIR}/moment`, { cwd: ROOT_DIR });
execSync(`npm publish ${PACKAGES_DIR}/template-js`, { cwd: ROOT_DIR });
execSync(`npm publish ${PACKAGES_DIR}/template-ts`, { cwd: ROOT_DIR });
Expand Down
55 changes: 31 additions & 24 deletions src/components/theme/application/applicationProvider.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@ import { StyleProvider } from '../style/styleProvider.component';
import { ThemeProviderProps } from '../theme/themeProvider.component';
import { ModalPanel } from '../modal/modalPanel.component';

interface ComponentProps {
interface EvaRuntimeProcessingProps {
mapping: SchemaType;
customMapping?: CustomSchemaType;
}

export type ApplicationProviderProps = ComponentProps & ThemeProviderProps;
interface EvaBuildtimeProcessingProps {
styles: ThemeStyleType;
}

type EvaProcessingProps = EvaRuntimeProcessingProps | EvaBuildtimeProcessingProps;

export type ApplicationProviderProps = EvaProcessingProps & ThemeProviderProps;
export type ApplicationProviderElement = React.ReactElement<ApplicationProviderProps>;

interface State {
Expand All @@ -38,55 +44,56 @@ interface State {
* @extends React.Component
*
* @property {SchemaType} mapping - Determines the mapping for basic components.
* This is designed to be provided by developers team and can be imported from npm package (e.g. `@eva-design/eva`).
* This is designed to be provided from any `@eva-design/*` package (e.g. `@eva-design/eva`)
* If provided, will be merged with customMapping to bootstrap eva during the runtime.
*
* @property {CustomSchemaType} customMapping - Determines the customization mapping.
* @property {CustomSchemaType} customMapping - Determines the customized mapping.
* This is merged with `mapping` property and designed to be used components customization.
*
* @property {ThemeType} theme - Determines the theme for basic components.
* This is designed to be provided by developers team and can be imported from npm package (e.g. `@eva-design/eva`).
*
* @property {ThemeStyleType} styles - Determines the styles compiled by bootstrapping eva.
* If provided, will replace runtime styles calculation.
* Should be used with `@ui-kitten/metro-config` package.
*
* @property {ReactNode} children - Determines application root component.
*
* @overview-example Simple Usage
*
* ```
* import React from 'react';
* import { ApplicationProvider, Layout, Text } from '@ui-kitten/components';
* import { mapping, light as lightTheme } from '@eva-design/eva';
* import * as eva from '@eva-design/eva';
*
* export default class App extends React.Component {
*
* render() {
* return (
* <ApplicationProvider
* mapping={mapping}
* theme={lightTheme}>
* <Layout style={{ flex: 1 }}>
* <Text>Welcome to UI Kitten</Text>
* </Layout>
* </ApplicationProvider>
* );
* }
* }
* export default () => (
* <ApplicationProvider {...eva} theme={eva.light}>
* <Layout style={{ flex: 1 }}>
* <Text>Welcome to UI Kitten</Text>
* </Layout>
* </ApplicationProvider>
* );
* ```
*/
export class ApplicationProvider extends React.Component<ApplicationProviderProps, State> {

public state: State = {
styles: (this.props as EvaBuildtimeProcessingProps).styles,
};

private schemaProcessor: SchemaProcessor = new SchemaProcessor();

constructor(props: ApplicationProviderProps) {
super(props);
const { mapping, customMapping } = this.props;

const styles: ThemeStyleType = this.createStyles(mapping, customMapping);

this.state = { styles };
if (!this.state.styles) {
const { mapping, customMapping } = this.props as EvaRuntimeProcessingProps;
this.state.styles = this.createStyles(mapping, customMapping);
}
}

private createStyles = (mapping: SchemaType, custom: CustomSchemaType): ThemeStyleType => {
const customizedMapping: SchemaType = merge({}, mapping, custom);

return this.schemaProcessor.process(customizedMapping);
};

Expand Down
75 changes: 75 additions & 0 deletions src/metro-config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Fs from 'fs';
import LodashMerge from 'lodash.merge';
import MetroConfig from 'metro-config/src/defaults';
import BootstrapService from './services/bootstrap.service';
import { EvaConfig } from './services/eva-config.service';
import ProjectService from './services/project.service';

// TS definitions for metro config?
type MetroConfigType = any;

const defaultMetroConfig = MetroConfig.getDefaultValues();
const customMappingWatchOptions = {
/*
* How often the custom mapping should be polled in milliseconds
*/
interval: 100,
};

/**
* Creates custom Metro config for bootstrapping Eva packages.
*
* @param {EvaConfig} evaConfig - configuration of Eva Design System used in project.
* @see {EvaConfig}
*
* @param metroConfig - configuration of Metro Bundler used in project.
* @link https://facebook.github.io/metro/docs/configuration
*
* @returns a combination of two metro configurations.
*
* @example Usage
*
* ```metro.config.js
* const MetroConfig = require('@ui-kitten/metro-config');
*
* const evaConfig = {
* evaPackage: '@eva-design/eva', // Required.
* customMappingPath: './custom-mapping.json', // Optional.
* };
*
* module.exports = MetroConfig.create(evaConfig, {
* // Whatever was previously specified
* });
* ```
*/
export const create = (evaConfig: EvaConfig, metroConfig?: MetroConfigType): MetroConfigType => {

const handleMetroEvent = (event): void => {
const reporter = metroConfig && metroConfig.reporter || defaultMetroConfig.reporter;

if (reporter && reporter.update) {
reporter.update(event);
}

if (event.type === 'initialize_started') {
BootstrapService.run(evaConfig);

const customMappingPath: string = ProjectService.resolvePath(evaConfig.customMappingPath);
const customMappingExists: boolean = Fs.existsSync(customMappingPath);

if (customMappingExists) {
Fs.watchFile(customMappingPath, customMappingWatchOptions, () => {
BootstrapService.run(evaConfig);
});
}
}
};

const libConfig: MetroConfigType = {
reporter: {
update: handleMetroEvent,
},
};

return LodashMerge({}, libConfig, metroConfig);
};
28 changes: 28 additions & 0 deletions src/metro-config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@ui-kitten/metro-config",
"description": "UI Kitten config for Metro Bundler",
"version": "4.4.0",
"author": "akveo <contact@akveo.com>",
"license": "MIT",
"homepage": "https://github.com/akveo/react-native-ui-kitten#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/akveo/react-native-ui-kitten.git"
},
"bugs": {
"url": "https://github.com/akveo/react-native-ui-kitten/issues"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@eva-design/dss": "^1.4.0",
"@eva-design/processor": "^1.4.0",
"@types/lodash.merge": "ts3.7",
"chalk": "^3.0.0",
"lodash.merge": "^4.6.1"
},
"peerDependencies": {
"metro-config": "^0.58.0"
}
}
Loading

0 comments on commit 12230c6

Please sign in to comment.