GithubHelp home page GithubHelp logo

microsoft / redux-micro-frontend Goto Github PK

View Code? Open in Web Editor NEW
340.0 15.0 61.0 264 KB

This is a library for using Redux to manage state for self-contained apps in a Micro-Frontend architecture. Each self-contained isolated app can have its own isolated and decoupled Redux store. The componentized stores interact with a global store for enabling cross-application communication.

License: MIT License

TypeScript 94.08% JavaScript 5.92%
redux microfrontends microfrontend statemanagement react-redux

redux-micro-frontend's People

Contributors

datajoy-eric avatar deepakparamesh avatar enk0de avatar harunsmrkovic avatar iswar7892 avatar jaapaurelio avatar microsoft-github-operations[bot] avatar microsoftopensource avatar patrickcode avatar rotty3000 avatar siva-i avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redux-micro-frontend's Issues

Adding custom logger is throwing unhandled exception

Describe the bug
When adding a custom logger to the existing loggers, an unhandled exception is getting thrown

To Reproduce
Add a custom logger to the Global Store
globalStore.SetLogger(actionLoggerAdaptor);

Expected behavior
Custom logger should get added

Screenshots
image

Desktop (please complete the following information):

  • OS: Windows
  • Browser Chrome

Using redux-micro-frontend for shared history

At the moment, my organisation is looking into the whole instance of microfrontends.

We have several applications (React + Redux + React Router) that we have developed - and are developing - separately. However, we are interested in having them integrated as microfrontends in another application (the 'container'), which would contain common functionality like the navigation bars. Otherwise, the microfrontends would generally do their own thing. Users can navigate to Microfrontend App 1 at address /mfeapp1, Microfrontend App 2 at address /mfeapp2, and so on. (If the applications are running as microfrontends, we can engineer it so that the different apps are running on different paths.)

Each app has Redux, but there is no shared state between the apps... with one exception: router history. And this is one area where it would be a good idea to have shared state, so that both the container and the microfrontends know what URL the user has navigated to.

What I am looking for is some guidance on whether redux-micro-frontend is suitable for this situation. In the container app, we have:

const reducers = (history: History<unknown>) => combineReducers({
  router: connectRouter(history), // From connected-react-router
});

And the container store is:

  store = createReduxStore(reducers(history), compose(
    applyMiddleware(
      thunk,
      routerMiddleware(history),
    ),
    /* eslint-disable-next-line no-underscore-dangle */
    process.env.NODE_ENV === 'development' && window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : (f: unknown) => f,
  ));

Microfrontends may be interacting with the history

import { push } from 'connected-react-router';
/* ... */
dispatch(push(path)); // The user has pressed a button.

I looked at your sample app, but I noticed that both the microfrontends are running on the same page. This seems a different situation from where my organisations finds itself.

Doesn't work with Jest

I'm trying to test my application using Jest lib and getting the following error:

image

I've tryed common solutions like babel-jest and other configurations mentioned on docs. but have no result. Can you check?

Error related to RXJS when using Webpack 5 Module Federation

** Context **
I am currently in the process of experimenting with a microfrontend architecture with Webpack 5 and the Module Federation plugin. I have integrate this library to communicate with microfrontends based on web-components.

Describe the bug
When i integrate the "redux-micro-frontend" library inside my shell or microfrontend separatly based on Angular, all it is fine. But when i unite the shell and microfrontends AND i use an othe library who use RXJS like angular material. An error occured :
image

At first I didn't notice the error because I had the Redux dev tools chrome extension enabled. This extension obviously made it possible to resolve this conflict between the versions of RXJS.

But when i threw my application in production and the clients try to use some features of the application, they notice some bugs with some components from Angular Material.

To Reproduce
Steps to reproduce the behavior:

  1. Use webpack 5 module federation
  2. Create a basic shell and a basic microfrontend
  3. Integrate @angular/material inside your shell or your microfrontend
  4. Integrate "redux-micro-frontend"
  5. You will note that when you try to do : "GlobalStore.Get()" the error above will appear.

Solution
So I investigated and noted that when the "redux-micro-frotnend" library was not integrated no problems occurred. And I quickly came to the conclusion that there was a conflict between the redux library used and rxjs in my application. To solve this problem, I was able to observe two solutions:

  • Grab redux and redux-devtools-extension inside peerDependencies (in package.json)
  • Upgrade the redux version to 4.1.1

I hope i was clear with my explications :)

add option to get-or-set a store instance

Is your feature request related to a problem? Please describe.
I'm having a hard time integrating redux-developer tools. I can do it, but it's not elegant. In doing so I find that we have to forgo the get-or-set behaviour of the GlobalStore.

Ideas?
I started with GlobalStore.Get().CreateStore(...) which behaves as get-or-set like I wish however it does not allow me to use the enhancer parameter of Redux.createStore which means I cannot easily apply the redex developer tools plugin (which is wired via enhancer function) while preserving the get-or-set approach.

Describe the solution you'd like
I would like to apply the redux developer tools plugin to stores via the get-or-set methods of the globalStore.

Describe alternatives you've considered
I've directly create stores that use the plugin and wired them into the global store. This works just fine but I can't do the same with the GlobalStore.CreateStore

(it's quite possible I'm just not knowledgable enough to do it.)

PS: is there a forum or mail list for this project for usability questions?

Issue with start-component

I get following error while using npm run start start-component

$ npm run start start-component

> [email protected] start C:\Users\HOME\Documents\projects\redux-micro-frontend\sample\todoApp
> webpack serve "start-component"

`resolve/lib/core` is deprecated; please use `is-core-module` directly
[webpack-cli] Unknown argument: start-component
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! [email protected] start: `webpack serve "start-component"`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\HOME\AppData\Roaming\npm-cache\_logs\2020-12-03T13_24_20_148Z-debug.log

How to apply redux-micro-frontend with nextjs

Your library is very well but i don't know how to apply it in my project
I am building a project by micro-front-end with nextjs. But in progress, we see an issue about managing redux of each shared component: Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>. I think , they can't able to see the state of other apps, need to set up to share state between components

Can you guide me how to apply your library in micro-front-end with nextjs?

Security Issues in y18n

Describe the bug
Security dependabot alert

To Reproduce
Steps to reproduce the behavior:

  1. Go to any of the same projects
  2. Run npm i
  3. Run npm audit

Expected behavior
0 Securutiry Vulnerabilities

Additional context
Package - y18n

Re-open old issue with JEST testing

[Related]
#8

This is the message I get

Details:

    ~/Project/node_modules/redux-micro-frontend/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export * from './src/actions';
                                                                                             ^^^^^^

    SyntaxError: Unexpected token 'export'

      1 | /* eslint-disable @typescript-eslint/no-explicit-any */
    > 2 | import { GlobalStore, IAction } from 'redux-micro-frontend'
        | ^
      3 |
      4 | export interface Action<T = any> {
      5 |   type: T

      at Runtime.createScriptFromCode (../../node_modules/jest-runtime/build/index.js:1350:14)
      at Object.<anonymous> (src/services/globalState/index.tsx:2:1)

Test Suites: 1 failed, 1 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        6.445 s
Ran all test suites.

package.json

{
  "name": "@tools",
  "version": "1.0.311",
  "main": "index.ts",
  "private": true,
  "babel": {
    "presets": [
      "@babel/preset-react"
    ]
  },
  "dependencies": {
    "@react-keycloak/web": "^3.4.0",
    "axios": "^0.21.1",
    "axios-hooks": "^2.3.0",
    "i18next": "^20.3.4",
    "i18next-browser-languagedetector": "^6.1.2",
    "i18next-resources-to-backend": "^1.0.0",
    "jsbi": "^3.1.6",
    "keycloak-js": "^12.0.3",
    "react": "^17.0.1",
    "react-error-boundary": "^3.1.1",
    "react-i18next": "^11.11.3",
    "react-use": "^17.2.4",
    "redux-micro-frontend": "^1.2.0",
    "rollbar": "^2.21.1",
    "ulid": "^2.3.0",
    "uuid": "^8.3.2"
  },
  "devDependencies": {
    "@testing-library/react-hooks": "^5.0.3",
    "@types/jest": "^26.0.20",
    "@types/node": "^16.11.6",
    "@types/uuid": "^8.3.1",
    "@typescript-eslint/eslint-plugin": "^4.29.0",
    "@typescript-eslint/eslint-plugin-tslint": "^5.0.0",
    "@typescript-eslint/parser": "^4.29.0",
    "axios-mock-adapter": "^1.19.0",
    "babel-jest": "^26.6.3",
    "eslint": "^7.32.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-import": "^2.24.2",
    "eslint-plugin-prettier": "^3.4.0",
    "eslint-plugin-react": "^7.24.0",
    "eslint-plugin-react-hooks": "^4.2.0",
    "eslint-webpack-plugin": "^3.0.1",
    "jest": "^26.6.3",
    "react-test-renderer": "^16.9.0",
    "ts-jest": "^26.5.1",
    "ts-node": "^9.1.1"
  },
  "scripts": {
    "test": "REF_URL=localhost:50000 jest",
    "lint": "eslint . --quiet",
    "clean": "rm -rf dist"
  }
}

jest.config.js

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'jsdom',
  modulePathIgnorePatterns: ['<rootDir>/dist/'],
}

process.env['NUEVO_URL'] = 'http://localhost:50000'

Option to set instanceName to avoid confusion between multiple stores in redux extension

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Support exposing derived state from an app that partner apps can consume.

The beauty of this library is that you can combine with multiple redux states and they can be able to lazy loaded and registered when appropriate. By being able to subscribe to a partner state, we get the ability to get the latest state from a partner app but the problem is that Redux ideally saved the smallest amount of data in the store, and use libraries like reselect can do computations and compute derived state. Making getting derived state from partner apps not possible.

If the GlobalStore was able to expose derived state APIs then the partner apps could listen to state changes, but also get derived state without knowing the structure of the partner state. Otherwise, listening to partner state changes would require another partner app to grab the state and massage the data as needed - while this does work, it forces apps to be coupled and require to understand the structure of each others state, which is not desired.

I've tried chunking the selectors from partner apps, and lazy loading; however, reselect isn't meant to lazy load selectors, so it is rather difficult. Furthermore, it makes it hard to truly decouple apps.

I have submitted a PR to implement this feature here: #39

Thank you so much for such a wonderful library! :)

InvokeGlobalListeners is not called when RegisterStore is used

Describe the bug
InvokeGlobalListeners is not called when RegisterStore is used

To Reproduce
Steps to reproduce the behavior:

  1. Register a manually created store using GlobalStore.RegisterStore
  2. subscribe to global state using globalStore.SubscribeToGlobalState(..)
  3. trigger any store actions
  4. global listeners are not triggered

Expected behavior
global listeners are called for state changes in any store.

queued subscribe callbacks for missing stores

Is your feature request related to a problem? Please describe.
I get an error when subscribing to a missing store.

Describe the solution you'd like
Instead of getting an error when subscribing to a missing store, I'd rather the callback be queued up for the possible eventual arrival of the store (maybe never). Meanwhile, the unsubscribe would pull the callback out of the queue if no store ever arrived.
Of course if the store did eventually arrive the queued callback should be pulled out of the queue, applied to the store.

Describe alternatives you've considered
Not sure of any alternatives.

AppB is able to modify store in AppA that doesn't have registered global actions

Describe the bug
Hi everyone,

I'm playing arround with this library and I found out that I'm able to update state from AppA -> AppB even if AppB doesn't have registered global actions.

AppA:

            this.globalStore = GlobalStore.Get(false);
            this.globalStore.CreateStore('MFAppStore', MfReducer, []);
            this.globalStore.RegisterGlobalActions('MFAppStore', null);

AppB:

                this.globalStore = GlobalStore.Get(false);
                this.globalStore.CreateStore('GlobalAppStore', GlobalReducer, []);
                this.globalStore.RegisterGlobalActions('GlobalAppStore', [INCREMENT_GLOBAL, DECREMENT_GLOBAL]);

I'm able to dispatch action from AppB to AppA and modify the 'MFAppStore' even if there are not registered global actions.

In documentation ( readme ) it says:

this.globalStore.DispatchAction("App1", action); // This will dispatch the action to current app's store as well other stores who might have registered 'Action-1' as a global action

but it seems that it doesn't work as it is intended or I'm missing something?

Or it was always allowed?

Thanks

Verison 1.1.0 is broken

Describe the bug
Version 1.1.0 has typescript files

To Reproduce
Steps to reproduce the behavior:

  1. npm i [email protected]

Expected behavior
Only JavaScript and definition files should be present

Screenshots
image

How to get the global state change in one of the other app?

Describe the bug

(Not a Bug, it is a Question)
I have two apps built using redux and redux-micro-frontend, In this case how could I get the global state change happening in one place, to one of the other App?

Here is my code in the Main App component to subscribe the CounterApp

const globalStore = GlobalStore.Get(false);
const globalStateChanged = (stateChanged) => {
        const stateC = globalState.CounterApp;
        console.log({ stateChanged, stateC });
};
globalStore.SubscribeToGlobalState('CounterApp', globalStateChanged);

And in the other App(Counter app), a method is triggered by the button click. Below is the code for that. (we have the same reducer and actions file that is created from the samples projects under the library)

const incrementGlobal = () => {
    globalStore.DispatchAction("CounterApp", IncrementGlobalCounter());
};

But I don't see the globalStateChanged invocation and the console print in Main App method. What will be the issue here? Are we missing anything here, and if you could share the code for the right approach it would be great.

Need control on the format of the event logs this library is adding

Is your feature request related to a problem? Please describe.
The event logs in the logger is not customizable for the consumer application.

Describe the solution you'd like
Currently we have the option to pass our own logger instance but it doesn't give me control to pass what should be the source or the even name for same.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.