Git Product home page Git Product logo

single-spa-portal-example's Introduction

single-spa-portal-example

The goal of this project is to provide an example of how to build a portal like app which consists of multiple single page applications (SPA's). Each SPA should be self contained with its own build process. It should be individually deployable without the need to deploy the whole application if there are changes to any individual app.

This example is based on simple-single-spa-webpack-example but will provide further features like:

  • Isolate SPA's with their own build process
  • Load SPA's on demand with SystemJS
  • Provide a way to communicate between each SPA
  • Get assets (like images, fonts, css, etc.) coming from different servers to work
  • Support multiple Angular versions without zone.js conflicts. For details see Multiple Angular Apps
  • Support Angular AOT Builds

How to run this project

  1. Clone this project
  2. Jump into each app folder and do:
    • npm install
    • npm run watch:portal
  3. Then start the portal with:
    • npm install
    • npm run watch
  4. Open up http://localhost:9000 in a web browser.

npm tasks

watch:portal: Builds the app as UMD module with singleSPA as middleware to consume the app by the portal. Changes are automatically detected.

build:portal: Releases the app as UMD module and outputs all contents to a folder. You can upload the produced file in production to your webserver. Hint: The Angular 6 example is being build with AOT. You can use npm run build:portal -- --env.analyzeBundle to see that there is no compiler.js inside the bundle.

watch:standalone: If you just want to develop the single app without the whole portal, you can use this task. Check the console log to see which port the app is being served from. This task is OPTIONAL! For now this task only exists on the Vue project to serve as an example.

build:standalone: As with the watch:standlone taks, this builds the app as stand alone version (no portal needed). This task is OPTIONAL! For now this task only exists on the Vue project to serve as an example.

inter-app-communication

This topic has been discussed multiple times (i.e. here or here). There may be many solutions to solve this problem. In this repository I want you to show a solution that meets the following requirements:

  • Each app is a self contained system. No app knows the internal state of another app or their data model. In short, each app is treated as a black box and can be maintained by a different team.
  • Each app must be able to have a complex state.
  • When you navigate between apps, the state must not be lost (because of mount/unmount).

To meet these requirements I have decided for an event system where each app can or can not listen to events that other apps send. This enables each app to keep their isolated state and modify only their own state based on events from other apps (and probably resend other events). No app needs direct access to the state of another app.

Furthermore I needed to split the apps into two parts. One is the normal app itself (GUI, Framework, etc.), the other is a "communication layer" which is exported as separate module and loaded/instantiated by the portal regardless of the app state. This allows each app to listen and react to events even if they aren't mounted.

Each app can process these events in whatever way they like. The only requirement is that all apps agree on one event format to send and receive these events.

For this example I have decided to just go with redux since it basically does exactly what I need. Throw events and process events. But this system works with whatever technic you like.

Here is a graphic which illustrates what actually happens:

inter-app-communication

The main parts are:

StoreApps: Contains state + business logic. Implements a dispatch method which can be called by the GlobalEventDistributor if an global event occurs.

GUIApps: singleSPA middleware + UI code like HTML, CSS, Controller, etc. + Framework like React or Angular

GlobalEventDistributor: Can be used to register stores. Sends dispatch events to all stores. (Observer pattern)

How it works:

  1. The root-application boots and loads all stores and instantiates them. This is necessary since we need the communication layer (store) to be active at all times. Even if the whole application is not mounted yet. Otherwise no app specific events getting processed.
  2. When an app is being mounted, the root-application passes the already instantiated store belonging to the individual app down. The root-application also passes a reference to the GlobalEventDistributor to the app.
  3. Now you can happily send all your global events to the GlobalEventDistributor with the dispatch() method and all other events to the local store.

Cons:

As already mentioned, the biggest disadvantage is that all stores have to be loaded when the root-application loads. The reason for this is that we are building a project that will have a huge application state being entirely in the browser. The user will likely input 1h of data without any server communication and once he is done, he will save everything with one click. This must not necessarily be your use-case. For example if you are only interested in inter-app-communication with any currently active app, you may not need to load all states beforehand but rather load them while the apps mount.

Multiple Angular Apps

The big issue with Angular 2+ is, that it (or third party libraries which Angular depends on) pollute the global window object. One such library is Zone.js. Zone.js monkey patches all async events and add its reference to the window object. If you have multiple Angular apps running, Angular will complain that Zone.js is already loaded.

One possible solution is to separate Zone.js from all Angular apps and load Zone.js only once in the portal. This may not be the best solution because as soon as you have multiple different Angular versions as apps in the portal, it may be possible that some of them require different Zone.js versions. Which may break everything at that point. Even though it is not a great solution, it may be the best solution we have with the current state of angular.

The other solution I found is to load every Angular app in its own iframe. Doing that, every Angular app runs completely isolated. You can then set the render target for Angular to the parent window. With this solution Angular runs in a complete isolated context but renders all content to the main DOM. Sadly this is also not the perfect solution since you open up many other issues you have to deal with. A few examples are:

  • You need to manually put all CSS styles from the iframe to the parent window
  • The angular router can no longer access the browser URL to update it according to the app routing
  • You can't use third party UI libraries that depent on document events. (i.e. a dropdown component that wants to know when you click on the document to close it.)

In the future we may have better solutions like Angular elements to deal with this issue, until then our best bet is to put a single Zone.js instance into the portal app. Which is exactly what I did in this example project.

Forks

single-spa-portal-example's People

Contributors

joeldenning avatar me-12 avatar themcmurder 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

single-spa-portal-example's Issues

webpack is building the child applications as single main.js file

Hi,
Thanks for this repo. I was straggling to configure webpack. You saved me. Your sample project's webpack is building the child applications as single main.js file. Is this is the correct way .

If I want to create it as a single application, I need to load it to other single-spa root application

Error at final step 3 while running portal watch command "npm run watch"

I am following the instructions provided in section "How to run this project". Successfully completed steps 1, 2 and first part of step 3. However, I am getting the following error while running the final part of step 3 i.e npm run watch. I could not figure out the issue, any help is appreciated! Thank you so much.

Error copied from LOG file:

0 info it worked if it ends with ok
1 verbose cli [ 'C:\Program Files\nodejs\node.exe',
1 verbose cli 'C:\Users\user1\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js',
1 verbose cli 'run',
1 verbose cli 'watch' ]
2 info using [email protected]
3 info using [email protected]

4 verbose run-script [ 'prewatch', 'watch', 'postwatch' ]
5 info lifecycle [email protected]prewatch: [email protected]
6 info lifecycle [email protected]
watch: [email protected]
7 verbose lifecycle [email protected]watch: unsafe-perm in lifecycle true
8 verbose lifecycle [email protected]
watch: PATH: C:\Users\user1\AppData\Roaming\npm\node_modules\npm\node_modules\npm-lifecycle\node-gyp-bin;C:\Users\user1\playground\single-spa\single-spa-portal-example-master\portal\node_modules.bin;
9 verbose lifecycle [email protected]watch: CWD: C:\Users\user1\playground\single-spa\single-spa-portal-example-master\portal
10 silly lifecycle [email protected]
watch: Args: [ '/d /s /c', 'webpack-dev-server --port 9000' ]
11 silly lifecycle [email protected]watch: Returned: code: 1 signal: null
12 info lifecycle [email protected]
watch: Failed to exec watch script
13 verbose stack Error: [email protected] watch: webpack-dev-server --port 9000
13 verbose stack Exit status 1
13 verbose stack at EventEmitter. (C:\Users\user1\AppData\Roaming\npm\node_modules\npm\node_modules\npm-lifecycle\index.js:285:16)
13 verbose stack at emitTwo (events.js:126:13)
13 verbose stack at EventEmitter.emit (events.js:214:7)
13 verbose stack at ChildProcess. (C:\Users\user1\AppData\Roaming\npm\node_modules\npm\node_modules\npm-lifecycle\lib\spawn.js:55:14)
13 verbose stack at emitTwo (events.js:126:13)
13 verbose stack at ChildProcess.emit (events.js:214:7)
13 verbose stack at maybeClose (internal/child_process.js:925:16)
13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:209:5)

14 verbose pkgid [email protected]
15 verbose cwd C:\Users\user1\playground\single-spa\single-spa-portal-example-master\portal
16 verbose Windows_NT 10.0.16299
17 verbose argv "C:\Program Files\nodejs\node.exe" "C:\Users\user1\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js" "run" "watch"
18 verbose node v8.9.0
19 verbose npm v5.6.0
20 error code ELIFECYCLE
21 error errno 1
22 error [email protected] watch: webpack-dev-server --port 9000
22 error Exit status 1
23 error Failed at the [email protected] watch script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 1, true ]

Possible to work with a laravel-vue app ?

Perhaps is there a way to make this integration work with a laravel-vue app? My goal is to have a centered app/portal that can give access to multiple apps, and some of them are made on laravel-vue. I'm open to new ideas. Thank you.

Loading angular apps (different versions) inside root appliatin with singleSpaEntry exposed inside each app

I am working to build an app to load different version angular apps using loader (root application) approach.

app1 -> angular 1.x
app2 -> angular 4 (using angular-cli)
app3 -> angular 6 (using angular-cli)

Each app will have singleSpaEntry.ts with mount, unmount (lifecyle methods). All these apps are managed and implemented by different teams.

Registering application

singleSpa.registerApplication(name, () => SystemJS.import(appURL), hashPrefix(hash));
   
 appURL -> http://<hostname>:port//singleSpaEntry.js

Can you please let me know, is there any format or dependencies i need to follow to compile singleSpaEntry.ts?

Getting below error while trying to access the app.

Uncaught Error: Application 'app6' died in status LOADING_SOURCE_CODE: Unexpected token <

Please find the example app created at https://github.com/naresh217/single-spa

How does all this work in production?

Hello. Amazing project you got there!

I cloned and played around with both simple-single-spa-webpack-example and single-spa-portal-example and found them awesome. For development, at least.

But the idea so far is to have a bigger macro-frontend which loads the smaller micro-frontends at runtime, right? This code is prepared to load the development builds of the micros, not the production built ones. What I am investigating is a way of, having the macro already in production, load the production micro's at runtime, and if I re-build and re-publish a micro be able to reload it transparently to the end user, as the macro is left unchanged.

So my question is, how do you make this work in production, both the macro and the micros?

Thanks in advance.

How to run this angular 4 app standalone?

First of all, a great thanks for this example!

As in this example portal is working fine with all child apps but I need to run angular app standalone as well.

Will you please provide me the solution to run angular app standalone as you did for Vue project.

Thanks again!

VueJS router project

Hello guys,

first of all have to say that single-spa seems gr8 work for me and my team needs.

However, we play a lot with VueJS and want to combine it with single-spa so we can make our project attractive for more other javascript developers such as Angular, React, etc...

The thing is, we already have monolith application written in VueJS which behave very nice but we are not experts enough to port it into single-spa. Our issue is as title says use of VueJS router.

Let's be honest and confess that application is pretty useless if we can't use router there.

Since we struggle about this few days we pushed project on this repository https://github.com/egoisticum/single-spa-vue-router so somebody can help us.

What we did is basic:

  1. Forked single-spa-portal-example repo
  2. Removed all other applications except Vue one
  3. Put some dummy content and routes into Vue project

We tried to make any VueRouter configuration possibility and tested it but without success.

Also, followed the instructions from this discussion single-spa/single-spa#228 but nothing made it work for our project.

Can't wait to see community suggestions or some commits on our repository.

BTW I mentioned you guys doesn't have to much Vue lowers in your team and that you seek for it. So, maybe this project can be cool playground for all VueJS folks which are interested in single-spa and we as a team are eager to make much more examples Vue based just after we make vue router works.

Thanks in advance.

portal webpack external useless

hello,supermans
when i set portal project's webpack external ,it is useless!!!!!
image
I load the common resource
image
image

and i try to require vue
image
it say cant find
image
anyone help me ,please

No NgModule metadata found for 'MainModule'.

After switching to prod app2 (Angular) by replacing const typescriptLoader = prodMode ? prodTypescriptLoader : devTypescriptLoader; with const typescriptLoader = prodTypescriptLoader; I get the followign error
Application 'app2' died in status NOT_MOUNTED: No NgModule metadata found for 'MainModule'.
in the portal app.

How to load a production app there?

There are multiple modules with names that only differ in casing

Hi, I got the following warning when I try to build the app1React using this repo, I didn't change any config. By googling, this warning often caused by mixing cases in import, while this doesn't apply to me.
The difference here seems to be the backslash and forward-slash in the path that are being different.
Do you have any idea how this can happen/fix?

WARNING in (webpack)/buildin/global.js
There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:

  • C:\Users\yhe\Documents\GitHub\single-spa-portal-example\app1React\node_modules\webpack\buildin\global.js
    Used by 2 module(s), i. e.
    C:\Users\yhe\Documents\GitHub\single-spa-portal-example\app1React\node_modules\punycode\punycode.js
  • C:\Users\yhe\Documents\Github\single-spa-portal-example\app1React\node_modules\webpack\buildin\global.js
    Used by 2 module(s), i. e.
    C:\Users\yhe\Documents\Github\single-spa-portal-example\app1React\node_modules\symbol-observable\es\index.js @ (webpack)/buildin/global.js
    @ C:/Users/yhe/Documents/GitHub/single-spa-portal-example/app1React/node_modules/punycode/punycode.js
    @ C:/Users/yhe/Documents/GitHub/single-spa-portal-example/app1React/node_modules/url/url.js
    @ (webpack)-dev-server/client?http://localhost:9001
    @ multi (webpack)-dev-server/client?http://localhost:9001 ./src/singleSpaEntry.js

Add link to this repo from single-spa documentation

@me-12 are you okay with me adding a link to this repo in the single-spa documentation? I've already created https://github.com/CanopyTax/single-spa/pull/187/files, which does so, but wanted to ask you about it first.

Also, thank you for your work on single-spa, single-spa-portal-example, and for jumping into the issue queus and helping out there. Would you be interested in hearing about and helping out with some of the exciting new things we've got planned for with single-spa? And maybe joining in on some of the discussions we're having about the future direction of single-spa.

If so, we're using slack to coordinate some of that, along with github's projects for single-spa. You can join the slack with this link, and once you're in I will invite you to a group chat where we discuss these types of things.

Authentication/Authorization

Hi Michael,

First of all its awesome. Could you please provide some pointers for implementing authentication/authorization under portal having multiple apps involving react,angular & vue?

Thanks

React child app routing : blank content

Hello,

I'm trying to use the history api to push states from the portal and then use it in the app (React).
The mail state is correctly loaded by the child app. But when I navigate in it, the routing works but the rendering returns blank content.

Here is how I push the state from the portal in the index.html :

<a class="p-2 text-dark" onclick="history.pushState(null, 'persons', '/persons');">Persons</a>

The single spa loader runs my app perfectly and I land in the main route. Here is the React loaded app Router :

const Router = () => (
    <BrowserRouter>
        <Switch>
            <Route path="/persons" exact component={PersonsList}/>
            <Route path="/persons/:id" component={Person} />
            <Route component={Error}/>
        </Switch>
    </BrowserRouter>
);

export default Router;

The PersonsList is defined as following :

handleRedirection = (aPerson) => {
    this.props.history.push(`/persons/${aPerson.id}`);
}

...

{this.state.persons.map(aPerson => (
    <React.Fragment key={aPerson.id}>
        <div className="row" onClick={this.handleRedirection.bind(this,aPerson)}>

The problem is that when I click on an element, even if the redirection works and the Person component's constructor is called, the rendering doesn't work.
Here is the Person component definition :

import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';

class Person extends React.Component {
    static propTypes = {
        match: PropTypes.object 
    };

    constructor(props){
        super(props);
        console.log('the selected person : ' + this.props.match.params.id);
    }

    render(){
        return(
            <div>A person</div>
        )
    }
}
export default withRouter(Person);

Question : Why the console.log is called but not the rendering ? is there a conflict with the single-spa lib ?

Regards

Proxy configuration for production environment.

Hi,

Firstly, realy thanks for this amazing work!
It's runing smoothly in the development environment.

There is a only dev environment server proxy and a comment for production purposes in "Webpack.config.js".
https://github.com/me-12/single-spa-portal-example/blob/master/portal/webpack.config.js
// Proxy config for development purposes. In production, you would configure you webserver to do something similar.
proxy: {
"/app1": {
target: "http://localhost:9001",
pathRewrite: {"^/app1" : ""}
},.....................................................

Can you give an idea about how can i configure web server to do something similar?

Or is there another way?

Thanks,
Türenç.

Cannot find module '../assets/angular-logo.png'.

Hi Michael,

Awesome repo, especially stand alone and separate build and deploy. I got an error on below. But app works fine.
import angularImg = require("../assets/angular-logo.png");

./src/app2.component.ts
(5,29): error TS2307: Cannot find module '../assets/angular-logo.png'.

This is not an issue

image

Unable to provide styleUrl for the Angular component

I have downloaded this github application and able to run successfully by loading all single spa applications. But I am facing one problem when specify the style url in Angular component.


@Component({
    selector: 'app5',
    styleUrls:["./app5.component.scss"],_
	template: `
		<div style="margin-top: 100px;">
            <img [src]="angularImg" style="width: 100px;"/> <br />
			This was rendered by App5 which is written in Angular 6
		</div>
        <br />

I have installed all the dependencies required for style loader ,scss loader , post css loader but finally I am getting the below error .

ERROR in ./src/app5.component.scss
Module build failed (from ./node_modules/postcss-loader/src/index.js):
Error: No PostCSS Config found in: C:\MyCave\jStudio\LinqIndepth\CSharp.Linq\MicrofrontEndResearch\SingleSpaPortal\Application\app5Angular\src
    at config.load.then (C:\MyCave\jStudio\LinqIndepth\CSharp.Linq\MicrofrontEndResearch\SingleSpaPortal\Application\app5Angular\node_modules\postcss-load-config\src\index.js:55:15)
 @ ./src/app5.component.ts 46:21-53
 @ ./src/main-module.ts
 @ ./src/singleSpaEntry.ts
 @ multi (webpack)-dev-server/client?http://localhost:9005 src/singleSpaEntry.ts
i 「wdm」: Failed to compile.

for resolving this error I have installed postconfig package also , but still I am getting the same error
is there any workaround for this??

Understanding routing for a prod release

Hi there! First and foremost wow I love what you guys are doing over there at CanopyTax. This is so elegant. I have read through all your documentation at single-spa and all of the open and closed issues but I’m still confused by something in particular. If I understand correctly, each application can be separated out into their own repo and publish themselves independently, to their own URL. I’ve got everything downloaded and running locally.

I am trying to separate out my applications and getting them all built and published to azure through docker containers for a prod build. I can get it done locally by adding “—host 0.0.0.0” to the package.json for the portal but it only works if all the packages are in a shared container. So now the watch looks like this.

webpack-dev-server –host 0.0.0.0 –port 9000

My issue is really that I’m not understanding how the exposed ports in the webpack-dev-server proxy would translate to dynamic URLS in runtime.
If I publish each child application to their own dynamic URL how can I get my prod webpack config for the portal to pick up each application?
How exactly does the routing work in the portal?
Do I have it wrong and they have to be bundled together into the same URL?
How does CanopyTax deploy to prod?

In Portal.js there is the loadApp function call.
await loadApp('test', '/test', '/test/singleSpaEntry.js', '/test/store.js', globalEventDistributor);
Is this where I would need SystemJS.import()?

I know there are a lot of questions here. sorry! Honestly any advice you can give would be super helpful.
Thanks in advance!

SystemJS 3.0.0 issue

The app when compiled with updated lib of systemjs to 3.0.0 wont work.
https://www.npmjs.com/package/systemjs

I am using VueCli 3 to build the package which works perfectly with SystemJs 0.21.6 dev verison.

It gives following error
Uncaught TypeError: Application 'app-dwfs' died in status LOADING_SOURCE_CODE: Cannot read property 'call' of undefined
at Module.i.import (system.js:564)
at Object.loadImpl (helper.js:36)
at single-spa.js:1
at t.invoke (zone.js:391)
at e.run (zone.js:150)
at zone.js:889
at t.invokeTask (zone.js:423)
at e.runTask (zone.js:195)
at m (zone.js:601)
at e.invokeTask [as invoke] (zone.js:502)

Error while loading single-spa-vue app from portal

This is my fork https://github.com/markuman/single-spa-portal-example/

I simply did

  • npx vue create app4vue

and attache single-spa-vue, but when I try to load the portal and click app4, I got the following error.
I've absolutly no idea what's wrong with that.

Error: 'app4' died in status LOADING_SOURCE_CODE: Module http://localhost:9000/app4/app.js detected as amd but didn't execute correctly.
  Instantiating http://localhost:9000/app4/app.js
  Loading /app4/app.js

As far as I understand, the idea is to have multiple teams that work independent on single app. Later they are merged by the portal. But none of the single apps is usable standalone. E.g. wenn doing npm run watch in the reactapp, I just receive Cannot GET /. So the teams can only their result when deploying it over the portal?

Inter app communication layer - distrobute auth info?

Hi there.

Im wondering with the store app layer, could this be used to store some authz info?

Say i have 2 child apps, 1 that is open and 1 that is restricted to users with a certain role, Can i feed authz into the store and have this consumed by all the child apps as they bootstrap/mount?

I cant see any reason why not. Im just trying to get an understanding how global config and shared info like this can feed into the solution as a whole.

I think this sample shows how, but im asking to get your expert point of view on how cross cutting concerns like authz etc would be handled?

single SPA portal synchronously loads Store

async function init() {
    const globalEventDistributor = new GlobalEventDistributor();

    // app1: The URL "/app1/..." is being redirected to "http://localhost:9001/..." this is done by the webpack proxy (webpack.config.js)
    await loadApp('app1', '/app1', '/app1/singleSpaEntry.js', '/app1/store.js', globalEventDistributor);

    // app2: The URL "/app2/..." is being redirected to "http://localhost:9002/..." this is done by the webpack proxy (webpack.config.js)
    await loadApp('app2', '/app2', '/app2/singleSpaEntry.js', '/app2/store.js', globalEventDistributor);

    // app3: The URL "/app3/..." is being redirected to "http://localhost:9003/..." this is done by the webpack proxy (webpack.config.js)
    await loadApp('app3', '/app3', '/app3/singleSpaEntry.js', null, null); // does not have a store, so we pass null

    // app3: The URL "/app4/..." is being redirected to "http://localhost:9004/..." this is done by the webpack proxy (webpack.config.js)
    await loadApp('app4', '/app4', '/app4/singleSpaEntry.js', null, null); // does not have a store, so we pass null

    // app5: The URL "/app5/..." is being redirected to "http://localhost:9005/..." this is done by the webpack proxy (webpack.config.js)
    await loadApp('app5', '/app5', '/app5/singleSpaEntry.js', '/app5/store.js', globalEventDistributor);

    singleSpa.start();
}

Is it synchronously loading the stores? Can I load these with non-blocking way?

Frameworks

Is it possible to integrate with Rails?

Angular1 UI router incompatibility with Portal Routing

Hello,

First off, thanks so much for this example. This speeds up the development of the portal architecture significantly. So far you have solved a lot of the problems we would have faced had we started from scratch with.

However we have one issue, we are using angular-1 single spa portal library with UI router. Once the angular1 app is loaded, all other routes / apps cease to load. Guessing this is due to an incompatibility between portal routing and angular1 routing

any ideas?

VueJS with Vuex

Firstly I'd like to say this is a great repo! you've done some amazing work.

I'm currently reading through the forks people have done and I've noticed none of them tend to use Vuex which for vue is the default state management tool. When I add a store.js with vuex to the portal.js I get a 404 from app4. Please see the screenshot attached.

Do you have any ideas, or could you point me towards the right direction for the introduction of vuex into this type of project.

Thank you.

screen shot 2018-12-05 at 15 04 53

Adding middleware with globalEventDistributer as an argument

How would you pass the globalEventDistributer into middleware as an argument given that the portal gets the store from a store file and the globalEventDistributer is seen first as a prop on root.component? I would really prefer not to have to pass the globalEventDistributer around through the entire component tree... :)

Routing when using react-router-redux

I'm playing around with the single-spa-portal-example and while adapting my existing React app to be used with the portal example I ran into this routing issue where I have a few Redux actions that triggers a push action to get the user to a new page. Unfortunately push does not accept, by design I think, relative URLs, so all paths must be absolute. This is a bit disturbing since applications will need to know where they fit in the routing mechanism of the portal. I was just wondering if anyone has already stumble around this problem and what are some best practices to fix it?

I guess one could always pass down the path where the application is mounted and have actions/components use this as an starting point.

Here is some code for better understanding:

import {push} from "react-router-redux";

let myAction = (dispatch, value) => {
        dispatch(push(`/path/to/${value}`); # NOTE: This path must be absolute
};

How to use Vue cli3.0 as a portal?

I want to use single-spa-vue to complete the portal and application functions, but the documentation seems to be very little about VUE, and DEMO portals are based on webpack, and do not use VUE as the portal DEMO.

Production build in angular

Hello,

I've just tried the build and it seems it is too big for angular apps.(500kb).
Could you add an example how to run the built version on node.js for example?

Thank you for your help

Norbert

Unable to define templateUrl App components file.

I would like to move the html content into .html file and use the templateUrl instead of template. I am getting 404 error. Can you please help me, am i missing anything?

@component({
selector: 'app5',
template: `


<img [src]="angularImg" style="width: 100px;"/>

This was rendered by App5 which is written in Angular 6


    <div>
        <b> Count: {{ count }}</b><br/><br/>
        <button (click)="increment()">local increment</button>&nbsp;Send a <b>local</b> increment event. This will
        only increase the counter for the current app. <br/>
        
        <button (click)="decrement()">local decrement</button>&nbsp;Send a <b>local</b> decrement event. This will
        only decrement the counter for the current app. <br/>

        
        <button (click)="globalIncrement()">global increment</button>&nbsp;Send a <b>global</b> increment event.
        This will increase the counter for the current app and all other apps that listen to this event. <br/>
        
        <button (click)="globalDecrement()">global decrement</button>&nbsp;Send a <b>global</b> decrement event.
        This will increase the counter for the current app and all other apps that listen to this event. <br/>
    </div>
	
    <br />
	<a [routerLink]="['/subroute1']" routerLinkActive="active">Angular route 1</a>&nbsp;
	<a [routerLink]="['/subroute2']" routerLinkActive="active">Angular route 2</a>

	<router-outlet></router-outlet>
`,

})

Mono Repo version created (need some help for react) FIXED

@me-12 Thanks for creating this example. It was exactly what I was looking for.
One issue with running this sample is the process of going into each app and building / running it separately. To improve on that I have created a monorepo version of the same using lerna + yarn workspaces. The process of running it is just a two step process a defined in the README. I was planning to submit this as a PR but have run into one issue with the react app. I think I am missing something very basic here , but not able to figure it out. It would be great if you can provide me some incites.
Here is the project
https://github.com/tsukhu/single-spa-portal-example

Also once fixed , if you think it is ok , then I will submit this as a PR (after some fine tuning and getting the React app working)

Example uses webpack-dev-server which is presently in a maintenance-only mode

Please note that webpack-dev-server is presently in a maintenance-only mode and will not be accepting any additional features in the near term. Most new feature requests can be accomplished with Express middleware; please look into using the before and after hooks in the documentation.

For reference https://github.com/webpack/webpack-dev-server

Mostly I created this issue because I want to have a discussion on what the alternative "Express middleware" would be

Does Vue router work at all with single-spa?

None of the examples seem to use the Vue router and I'm struggling to get it working.
I've tried history mode and hash mode, and different "base" URLs.

const router = new Router({
  base: '/vue-spa/',
  mode: 'history',
  routes,
});

Does some sort of a wrapper need to be written to make the Vue router compatible? Do we need to run Vue in an iframe(puke) to make the router work?

extract common node modules among sub apps

Thanks for creating this awesome example.
After analyzing the bundle file, I found there are a lot of redundancies among sub-apps, because they have many intersection of dependencies.

Is there a way to extract the common dependencies?

Illustrate how to handle images in child apps

First off, I just want to say thank you. This repo is the only example I've found for module loading child applications using single-spa.

Something I would love to see is how to have the child applications load images. So far, I have noticed child applications try to load images, but they are requested from the parent server.

If you have any ideas of how to do this, I would love to see it added to your example.

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.