-
Notifications
You must be signed in to change notification settings - Fork 86
docs(articles): getting started #354
Changes from 5 commits
8cfdbad
a6ba1ff
9e7ff87
821a619
890a3ba
bf555a9
262ce0d
554125e
d851005
6bc91df
e32575a
bca0f9f
3894600
091561d
a036763
713f169
789f657
3d357fe
77e7c6a
0cbb872
5888063
b9ef49e
bf13507
c6536d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,387 @@ | ||||||||||||||||||||||
Getting Started | ||||||||||||||||||||||
--------------- | ||||||||||||||||||||||
|
||||||||||||||||||||||
One App is a web application that combines together multiple experiences into a single, | ||||||||||||||||||||||
cohesive runtime. These experiences, or Holocron modules as we call them empower teams | ||||||||||||||||||||||
to craft a rich user experience that can be used to compose parts of a web page or as | ||||||||||||||||||||||
route destinations all on their own. One App was built from the ground up with Holocron | ||||||||||||||||||||||
and its micro frontend architecture, allowing engineers to seamlessly update each module | ||||||||||||||||||||||
independently and collaborate across teams working together to create a product. While | ||||||||||||||||||||||
One App comes with a security standard in practice, progressive web app capability and | ||||||||||||||||||||||
many other features, its feature set can be configured by Holocron modules to your | ||||||||||||||||||||||
exact specification. | ||||||||||||||||||||||
|
||||||||||||||||||||||
This guide will get us started with One App and will go over some of the | ||||||||||||||||||||||
fundamental concepts of the framework. We will start from the beginning | ||||||||||||||||||||||
by creating our first Holocron module, then we will go through a few | ||||||||||||||||||||||
One App essentials to get up and running quickly. | ||||||||||||||||||||||
|
||||||||||||||||||||||
## 📖 Table of Contents | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have seen the CSP is a common pitfall... What about adding a section for a basic CSP configuration at least explaining that one-app Blocks everything by default and that you won't be able to make any api calls unless you configure your CSP. This should be explained as one of the main advantages of using one app as a best practice security feature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with you however CSP is an advanced topic that deserves an article or a set of reference documentation on its own. Another concern with adding a section is it starts to make the document heavy for a getting started guide, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah we should add it to separate PR and maybe mention the article here once we have the CSP content |
||||||||||||||||||||||
* [Generating a Module](#generating-a-module) | ||||||||||||||||||||||
* [Running One App](#running-one-app) | ||||||||||||||||||||||
* [Adding CSS Styles](#adding-css-styles) | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i really like how you've broken this down into different sections There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you! |
||||||||||||||||||||||
* [Creating Routes](#creating-routes) | ||||||||||||||||||||||
* [Module State & Data](#module-state-&-data) | ||||||||||||||||||||||
* [Configuring One App](#configuring-one-app) | ||||||||||||||||||||||
* [Development](#development) | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should be more specific about this, what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I totally agree that this section is bare compared to the rest, I'll update it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||||||||||||||||||||||
|
||||||||||||||||||||||
### Generating a Module | ||||||||||||||||||||||
|
||||||||||||||||||||||
The first step to get started with One App is to generate a Holocron module. | ||||||||||||||||||||||
There are two different Holocron module types, root and child module. Let us | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should explain what the difference is between root and child module There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'd love if we could add images to describe this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can plan to add images later, I agree would be so helpful! |
||||||||||||||||||||||
start by creating a root Holocron module, the entry point to our micro frontend. | ||||||||||||||||||||||
|
||||||||||||||||||||||
```bash | ||||||||||||||||||||||
export NODE_ENV=development | ||||||||||||||||||||||
|
||||||||||||||||||||||
npx -p yo -p @americanexpress/generator-one-app-module \\ | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why break this onto a separate line? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a pretty long command and breaks flex positioning in mobile devices. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤔 but when it gets put to the docs it isn't a simple copy and paste There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly, breaking it up like this is a little confusing. I suspect many would think these 2 lines are separate commands There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If putting it on one line would make it less confusing, I'm all for it. Will update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated in 789f657 |
||||||||||||||||||||||
-- yo @americanexpress/one-app-module | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
Once the command is executed, you will be prompted to fill out a few questions | ||||||||||||||||||||||
about your new module before it is generated. Starting off, we will want to name | ||||||||||||||||||||||
our module and make sure that it is a root module; feel free to answer as you | ||||||||||||||||||||||
wish for the other questions. Once the root module is generated we will be able | ||||||||||||||||||||||
to start developing with One App. | ||||||||||||||||||||||
Francois-Esquire marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
|
||||||||||||||||||||||
> #### More Info | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [One App](https://github.com/americanexpress/one-app) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> ##### Packages | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`react`](https://reactjs.org/) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`react-dom`](https://reactjs.org/docs/react-dom.html) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`holocron`](https://github.com/americanexpress/holocron/tree/main/packages/holocron) | ||||||||||||||||||||||
|
||||||||||||||||||||||
### Running One App | ||||||||||||||||||||||
|
||||||||||||||||||||||
Every Holocron module that is generated comes with pre-installed scripts that can | ||||||||||||||||||||||
be run afterwards. One of these scripts is the `npm start` script that starts up | ||||||||||||||||||||||
`one-app-runner`, which is our primary tool for local development. | ||||||||||||||||||||||
Francois-Esquire marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
|
||||||||||||||||||||||
```bash | ||||||||||||||||||||||
npm start | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
When `one-app-runner` is fully loaded and running, we can navigate to `http://localhost:3000` | ||||||||||||||||||||||
and view our Holocron module in the browser. In another terminal window you can run | ||||||||||||||||||||||
|
||||||||||||||||||||||
```bash | ||||||||||||||||||||||
npm run watch:build | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Open another terminal window and run: npm run watch:build There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good. suggestion, I will be adding this manually. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated 789f657 |
||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
and this will watch for any changes made to your module, then update `one-app-runner` | ||||||||||||||||||||||
with the rebuilt module bundle. The command above uses `one-app-bundler` which can | ||||||||||||||||||||||
also be used to bundle our Holocron module. | ||||||||||||||||||||||
Francois-Esquire marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
|
||||||||||||||||||||||
```bash | ||||||||||||||||||||||
npm run build | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will add this manually. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added these |
||||||||||||||||||||||
|
||||||||||||||||||||||
When ready to publish to production, make sure to set `NODE_ENV=production` before building. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we mention why here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this should be in a blockquote There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good points, I will update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||||||||||||||||||||||
|
||||||||||||||||||||||
**Local Configuration** | ||||||||||||||||||||||
|
||||||||||||||||||||||
Inside the `package.json` of your Holocron module, you can | ||||||||||||||||||||||
include a `"one-amex": {}` property to configure some of the | ||||||||||||||||||||||
tools in our ecosystem. | ||||||||||||||||||||||
|
||||||||||||||||||||||
```json | ||||||||||||||||||||||
{ | ||||||||||||||||||||||
"name": "my-module", | ||||||||||||||||||||||
"one-amex": { | ||||||||||||||||||||||
"bundler": { | ||||||||||||||||||||||
"webpackConfigPath": "webpack.config.js" | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we recommend There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nellyk Agree.. a custom webpack config is usually a feature for advanced users and not necessarily required when you are just getting started There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point on that, I wanted readers to know that it is possible, however as you both mentioned, it is an advanced feature. |
||||||||||||||||||||||
}, | ||||||||||||||||||||||
"runner": { | ||||||||||||||||||||||
"rootModuleName": "my-module", | ||||||||||||||||||||||
"modules": [ | ||||||||||||||||||||||
".", | ||||||||||||||||||||||
"../my-adjacent-child-module" | ||||||||||||||||||||||
] | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
When you start using child modules, `one-app-runner` can include | ||||||||||||||||||||||
multiple local modules when it's configured to accept them. | ||||||||||||||||||||||
`one-app-bundler` can have it's `webpack` config extended along | ||||||||||||||||||||||
with other options. | ||||||||||||||||||||||
|
||||||||||||||||||||||
> #### More Info | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> **Recipes** | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Run One App Locally](../recipes/running-one-app-locally) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Running In Production](../recipes/running-in-production) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Publishing Modules](../recipes/publishing-modules) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> ##### Packages | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`@americanexpress/one-app-runner`](https://github.com/americanexpress/one-app-cli/tree/main/packages/one-app-runner) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`@americanexpress/one-app-bundler`](https://github.com/americanexpress/one-app-cli/tree/main/packages/one-app-bundler) | ||||||||||||||||||||||
|
||||||||||||||||||||||
### Adding CSS Styles | ||||||||||||||||||||||
|
||||||||||||||||||||||
Styling a Holocron module with `CSS` or `SCSS` can be accomplished by creating a | ||||||||||||||||||||||
separate file that is used with the markup we write in our module. | ||||||||||||||||||||||
|
||||||||||||||||||||||
`src/components/styles.scss` | ||||||||||||||||||||||
|
||||||||||||||||||||||
```css | ||||||||||||||||||||||
.myButton { | ||||||||||||||||||||||
background-color: green; | ||||||||||||||||||||||
|
||||||||||||||||||||||
&:active, | ||||||||||||||||||||||
&:focus, | ||||||||||||||||||||||
&:hover { | ||||||||||||||||||||||
background-color: blue; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
We can import the stylesheet into our module and use CSS modules to access the class name | ||||||||||||||||||||||
for each selector by its name. The class names are unique when they are generated which | ||||||||||||||||||||||
avoids unwanted cascading of styles in our document. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could expand a bit more here to explain that the reason we use cssModules is because modules should be independent and we don't want css from other modules to affect them... hence the unique class name / avoiding collision There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will add a bit to this sentence |
||||||||||||||||||||||
|
||||||||||||||||||||||
`src/components/MyModule.jsx` | ||||||||||||||||||||||
|
||||||||||||||||||||||
```jsx | ||||||||||||||||||||||
import React from 'react'; | ||||||||||||||||||||||
import styles from './styles.scss'; | ||||||||||||||||||||||
|
||||||||||||||||||||||
export default function MyModule() { | ||||||||||||||||||||||
return ( | ||||||||||||||||||||||
<div> | ||||||||||||||||||||||
<button type="button" className={styles.myButton}> | ||||||||||||||||||||||
Click Me | ||||||||||||||||||||||
</button> | ||||||||||||||||||||||
</div> | ||||||||||||||||||||||
); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
> #### More Info | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> **Recipes** | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Adding Styles Recipe](../recipes/adding-styles) | ||||||||||||||||||||||
|
||||||||||||||||||||||
### Creating Routes | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should adjust the order of this section to be before adding styles... it would be ideal if you could continue from the previous step, then show developers how to add a second module locally and load it using Additionally we could also show how to load modules with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually did want to talk about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. About ordering sections, I get where you are coming from when switching the two sections.. the reason I'd want to keep the CSS as the first activity in the module is the ease to set up, a core part of web development (CSS) and direct visual feedback will give readers (especially new to One App or JavaScript) a soft start for the first thing they do in a module. I feel that would segway into more JavaScript heavy sections that follow. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree with your take @Francois-Esquire since users can still load the webpage from the root, afterwards they can look at adding routes |
||||||||||||||||||||||
|
||||||||||||||||||||||
One App has built in dynamic routing that uses each Holocron module to | ||||||||||||||||||||||
build out the router. There is a special property that we can assign to | ||||||||||||||||||||||
our module `Module.childRoutes` which would allow us to add routes to | ||||||||||||||||||||||
One App. `childRoutes` should be assigned a function that is given | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It only needs to be a function when you need to use the store for something, otherwise it can be an array or just a route with or without nested routes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TIL, thank you for sharing that 😄 I'll update the wording. |
||||||||||||||||||||||
the Redux `store` used by the app, which can be useful when using | ||||||||||||||||||||||
route hooks like `onEnter`. | ||||||||||||||||||||||
|
||||||||||||||||||||||
`src/components/MyModule.jsx` | ||||||||||||||||||||||
|
||||||||||||||||||||||
```jsx | ||||||||||||||||||||||
import React from 'react'; | ||||||||||||||||||||||
import { Route } from '@americanexpress/one-app-router'; | ||||||||||||||||||||||
import ModuleRoute from 'holocron-module-route'; | ||||||||||||||||||||||
|
||||||||||||||||||||||
export default function MyModule({ children }) { | ||||||||||||||||||||||
return ( | ||||||||||||||||||||||
<div> | ||||||||||||||||||||||
{children} | ||||||||||||||||||||||
</div> | ||||||||||||||||||||||
); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
MyModule.childRoutes = () => [ | ||||||||||||||||||||||
<ModuleRoute path="home" moduleName="home-module" />, | ||||||||||||||||||||||
<Route | ||||||||||||||||||||||
path="about" | ||||||||||||||||||||||
component={() => ( | ||||||||||||||||||||||
<p> | ||||||||||||||||||||||
About Page | ||||||||||||||||||||||
</p> | ||||||||||||||||||||||
)} | ||||||||||||||||||||||
/>, | ||||||||||||||||||||||
]; | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
> #### More Info | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> **API** | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Routing](../api/modules/routing) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Loading Modules](../api/modules/loading-modules) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> **Recipes** | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Code Splitting Using Holocron](../recipes/code-splitting-using-holocron) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> ##### Packages | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`@americanexpress/one-app-router`](https://github.com/americanexpress/one-app-router/tree/master) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`holocron-module-route`](https://github.com/americanexpress/holocron/tree/main/packages/holocron-module-route) | ||||||||||||||||||||||
|
||||||||||||||||||||||
### Module State & Data | ||||||||||||||||||||||
|
||||||||||||||||||||||
Holocron modules have another special property `Module.holocron` we can be added to allow us | ||||||||||||||||||||||
to configure the module. Within `holocron`, we can set keys like `reducer` to include a module | ||||||||||||||||||||||
Francois-Esquire marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
reducer with the Redux `store` used by One App. There is also `loadModuleData` that is called | ||||||||||||||||||||||
during server side render and when a Holocron module is loaded by One App. When we combine the | ||||||||||||||||||||||
two, we can asynchronously load all the data needed for a module and add it to the `store` when | ||||||||||||||||||||||
a `reducer` is supplied to the `holocron` configuration. | ||||||||||||||||||||||
|
||||||||||||||||||||||
`src/components/MyModule.jsx` | ||||||||||||||||||||||
|
||||||||||||||||||||||
```jsx | ||||||||||||||||||||||
import React from 'react'; | ||||||||||||||||||||||
import { fromJS } from 'immutable'; | ||||||||||||||||||||||
|
||||||||||||||||||||||
function DataVisualizer({ data, loaded }) { | ||||||||||||||||||||||
return ( | ||||||||||||||||||||||
<div> | ||||||||||||||||||||||
{/* do something with the data when it loads */} | ||||||||||||||||||||||
</div> | ||||||||||||||||||||||
); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
export default function MyModule({ moduleState = {}, moduleLoadStatus = 'loading' }) { | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should recommend There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i agree on this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair point, will update this |
||||||||||||||||||||||
return ( | ||||||||||||||||||||||
<DataVisualizer data={moduleState} loaded={moduleLoadStatus === 'loaded'} /> | ||||||||||||||||||||||
); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
MyModule.holocron = { | ||||||||||||||||||||||
name: 'my-module', | ||||||||||||||||||||||
reducer: (moduleState = fromJS({}), action) => { | ||||||||||||||||||||||
if (action.type === 'my-action') return fromJS(action.data); | ||||||||||||||||||||||
return moduleState; | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
loadModuleData: async ({ store: { dispatch }, fetchClient }) => { | ||||||||||||||||||||||
const response = await fetchClient('url/to/data.json'); | ||||||||||||||||||||||
const data = await response.json(); | ||||||||||||||||||||||
dispatch({ type: 'my-action', data }); | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
Both `moduleState` and `moduleLoadStatus` are props given to each Holocron module. | ||||||||||||||||||||||
All state is `immutable` and the `reducer` provided will be expected to return | ||||||||||||||||||||||
Immutable compliant types (which includes JavaScript primitives). `loadModuleData` | ||||||||||||||||||||||
is passed the Redux `store`, along with the `fetchClient`, `ownProps` and the | ||||||||||||||||||||||
`module` itself. `fetchClient` can be configured with `appConfig` which will | ||||||||||||||||||||||
learn about in the next section. | ||||||||||||||||||||||
|
||||||||||||||||||||||
> #### More Info | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> **API** | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Loading Data](../api/modules/loading-data) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [State Management](../api/modules/state-management) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> **Recipes** | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Enabling Server Side Render](../recipes/enabling-serverside-rendering) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Internationalization](../recipes/internationalizing-your-module) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> ##### Packages | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`immutable`](https://immutable-js.github.io/immutable-js/) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`redux`](https://redux.js.org/) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`react-redux`](https://react-redux.js.org/) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`reselect`](https://github.com/reduxjs/reselect) | ||||||||||||||||||||||
|
||||||||||||||||||||||
### Configuring One App | ||||||||||||||||||||||
|
||||||||||||||||||||||
When One App first starts up on the server, it loads in all the modules | ||||||||||||||||||||||
and looks for `Module.appConfig` in each module to configure the app runtime. | ||||||||||||||||||||||
The root module is used to configure many aspects of One App, including the | ||||||||||||||||||||||
state configuration that is available for every module to use when rendering. | ||||||||||||||||||||||
|
||||||||||||||||||||||
`src/appConfig.js` | ||||||||||||||||||||||
|
||||||||||||||||||||||
```js | ||||||||||||||||||||||
export default { | ||||||||||||||||||||||
csp: "default-src 'self';", | ||||||||||||||||||||||
providedStateConfig: { | ||||||||||||||||||||||
theme: { | ||||||||||||||||||||||
client: 'my-theme-name', | ||||||||||||||||||||||
server: 'my-theme-name', | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
The `appConfig` property is meant strictly for the server side, | ||||||||||||||||||||||
take advantage of `global.BROWSER` to ensure that the `appConfig` | ||||||||||||||||||||||
is only bundled with the server side build. | ||||||||||||||||||||||
|
||||||||||||||||||||||
`src/components/MyModule.jsx` | ||||||||||||||||||||||
|
||||||||||||||||||||||
```jsx | ||||||||||||||||||||||
import React from 'react'; | ||||||||||||||||||||||
import { useSelector } from 'react-redux'; | ||||||||||||||||||||||
|
||||||||||||||||||||||
export default function MyModule() { | ||||||||||||||||||||||
const { theme } = useSelector( | ||||||||||||||||||||||
(state) => state.get('config'), | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe consider this example to load a single config value from the state? for best practices and performance we should recommend avoiding |
||||||||||||||||||||||
(state) => state.toJS() | ||||||||||||||||||||||
); | ||||||||||||||||||||||
Francois-Esquire marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
|
||||||||||||||||||||||
return ( | ||||||||||||||||||||||
<p> | ||||||||||||||||||||||
Theme Configuration: | ||||||||||||||||||||||
{theme} | ||||||||||||||||||||||
</p> | ||||||||||||||||||||||
); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
if (!global.BROWSER) { | ||||||||||||||||||||||
// eslint-disable-next-line global-require | ||||||||||||||||||||||
MyModule.appConfig = require('../appConfig.js'); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
> #### More Info | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> **API** | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [App Configuration](../api/modules/app-configuration) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Environment Variables](../api/server/environment-variables) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Module Map Schema](../api/server/module-map-schema) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> **Recipes** | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Partial Rendering](../recipes/partial-rendering) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [Progressive Web App](../recipes/PWA.md) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> ##### Packages | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`@americanexpress/one-app-ducks`](https://github.com/americanexpress/one-app-ducks) | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> [`@americanexpress/one-service-worker`](https://github.com/americanexpress/one-service-worker) | ||||||||||||||||||||||
|
||||||||||||||||||||||
### Development | ||||||||||||||||||||||
|
||||||||||||||||||||||
**Recipes** | ||||||||||||||||||||||
|
||||||||||||||||||||||
* [Mocking API Calls](../recipes/mocking-api-calls) | ||||||||||||||||||||||
|
||||||||||||||||||||||
**API** | ||||||||||||||||||||||
|
||||||||||||||||||||||
* [CLI Commands](../api/server/cli-commands) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that "micro frontends" would make more sense here than "experiences". Is it really an accurate description to say Holocron modules are experiences? They are more versatile than that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with you, I'll update