Skip to content

Commit

Permalink
added: last page
Browse files Browse the repository at this point in the history
  • Loading branch information
Viktor Pasynok committed Nov 5, 2024
1 parent be87090 commit 3315047
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 3 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@grlt-hub/app-compose",
"version": "1.0.0-next.3",
"version": "1.0.0-next.4",
"type": "module",
"private": false,
"main": "dist/index.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,43 @@ title: Dynamically Load Features
sidebar:
order: 7
---

In some cases, certain features in your application may be disabled, either by configuration or based on user interaction. With `app-compose`, you can use dynamic imports to load the code for these features only when their containers are enabled. This approach helps reduce the initial bundle size and optimize application performance by loading code only when it’s needed.

## Example

Here, the `featureModuleContainer` container uses a dynamic `import()` to load `FeatureComponent` only when `enable` returns `true`. This approach ensures that `FeatureComponent` is loaded only if the feature is enabled.

```ts title="featureModuleContainer.ts"
import { createContainer } from '@grlt-hub/app-compose';

const featureModuleContainer = createContainer({
id: 'featureModule',
start: async () => {
const { FeatureComponent } = await import('./FeatureComponent');
return { api: { ui: FeatureComponent } };
},
enable: () => process.env.FEATURE_MODULE_ENABLED === 'true',
});

export { featureModuleContainer };
```

In `main.ts`, `compose.up` initializes the `featureModuleContainer`. If `FEATURE_MODULE_ENABLED` is set to `true`, `FeatureComponent` is dynamically loaded and made available in the container’s API.

```ts title="main.ts"
import { compose } from '@grlt-hub/app-compose';
import { featureModuleContainer } from './featureModuleContainer';

await compose.up([featureModuleContainer]);
```

## Explanation

- **Dynamic Import**: The `import()` statement inside the `start` function loads `FeatureComponent` only when the container is enabled.
- **Conditional Enablement**: The `enable` function checks the environment variable `FEATURE_MODULE_ENABLED`, which controls whether the feature should be loaded.
- **Optimized Loading**: This approach ensures that code for disabled features isn’t bundled or loaded until explicitly needed.

## Conclusion

Using dynamic imports with `app-compose` allows you to load code only for enabled features, optimizing resource usage and improving application load time. This approach is especially beneficial for larger applications with features that may be conditionally enabled or disabled.
97 changes: 97 additions & 0 deletions website/src/content/docs/how-to-guides/use-with-react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,100 @@ await compose.up([logoContainer, layoutContainer]);
This approach works well for pages with a relatively simple component structure and minimal nesting. However, for more complex setups with deeply nested components, you might need a higher level of flexibility. To achieve this, you can use a slot-based concept, which is not natively available in React but is supported by the `grlt-hub` ecosystem through the [@grlt-hub/react-slots](https://github.com/grlt-hub/react-slots) package.

## Example Using Slots

This example demonstrates how to use `app-compose` with React by incorporating slots for flexible component positioning. Using the `@grlt-hub/react-slots` package, we create a layout that includes a footer component inserted dynamically into a predefined slot.

Here, we create the `copyrightContainer` with a simple component that displays a copyright message. This component will be dynamically inserted into the layout.

```tsx title="copyright.tsx"
import { createContainer } from '@grlt-hub/app-compose';

const Component = () => <code>All rights reserved.</code>;

const copyrightContainer = createContainer({
id: 'copyright',
start: () => ({
api: { ui: Component },
}),
});

export { copyrightContainer };
```

In `layoutContainer`, we define a layout with a `Bottom` slot, into which other components can be inserted. The slot `Slots.Bottom` serves as a placeholder in the layout for dynamically added components.

```tsx title="layout.tsx"
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { createContainer } from '@grlt-hub/app-compose';
import { createSlotIdentifier, createSlots } from '@grlt-hub/react-slots';

const layoutContainer = createContainer({
id: 'layout',
start: () => {
const { slotsApi, Slots } = createSlots({ Bottom: createSlotIdentifier() } as const);

createRoot(document.getElementById('root')!).render(
<StrictMode>
<div>
Hello
<Slots.Bottom />
</div>
</StrictMode>,
);

return {
api: { slotsApi },
};
},
});

export { layoutContainer };
```

In `footerContainer`, we create a footer component that depends on `layoutContainer` and optionally on `copyrightContainer`. If the copyright component is available, it will be rendered within the footer. The footer itself is dynamically inserted into the `Bottom` slot of the layout.

```tsx title="footer.tsx"
import { type PropsWithChildren, type FC } from 'react';
import { layoutContainer } from './layout';
import { copyrightContainer } from './copyright';
import { createContainer } from '@grlt-hub/app-compose';

const Component: FC<PropsWithChildren> = ({ children }) => <footer>{children}</footer>;

const footerContainer = createContainer({
id: 'footer',
dependsOn: [layoutContainer],
optionalDependsOn: [copyrightContainer],
start: (deps, optDeps) => {
deps.layout.slotsApi.insert.into.Bottom({
component: () => <Component>{optDeps.copyright?.ui ? <optDeps.copyright.ui /> : 'No copyright'}</Component>,
});

return { api: null };
},
});

export { footerContainer };
```

And up 'em all

```ts
import { compose } from '@grlt-hub/app-compose';

import { layoutContainer } from './layout';
import { copyrightContainer } from './copyright';
import { footerContainer } from './footer';

await compose.up([layoutContainer, copyrightContainer, footerContainer]);
```

### Explanation

- **Slot-Based Layout**: The layout defines a `Bottom` slot that serves as a placeholder for dynamically inserted components.
- **Dynamic Footer**: The footer component is created in a separate container and inserted into the `Bottom` slot of the layout.
- **Optional Dependencies**: The footer component conditionally depends on `copyrightContainer`. If the copyright component is available, it is rendered inside the footer.
- **Initialization with** `compose.up`: All containers are initialized using `compose.up`, ensuring that dependencies are resolved and components are rendered in the correct order.

This example demonstrates how to achieve a flexible, slot-based structure in React using `app-compose` and [@grlt-hub/react-slots](https://github.com/grlt-hub/react-slots), enabling more complex and modular component arrangements.

0 comments on commit 3315047

Please sign in to comment.