single-spa / single-spa-examples

Examples of single-spa applications.
https://single-spa.surge.sh
MIT License
359 stars 128 forks source link

Build process #52

Open sharpcoder28 opened 6 years ago

sharpcoder28 commented 6 years ago

How would this work in production? If I have apps in different repos, I need to build (i.e. ng build --prod) which produces bundled files with random names, and then dump the output into respective folders. Also what's up with the reference to .ts files?

joeldenning commented 6 years ago

Hey sharpcoder28, good question! The docs here hopefully explain some of the problems and solutions for creating a large, microserviced frontend with single-spa. Let me know if they help, or if they could be improved!

About your specific questions, though:

If I have apps in different repos, I need to build (i.e. ng build --prod) which produces bundled files with random names, and then dump the output into respective folders

It sounds like you're using angular-cli to build at least one of the single-spa applications? The example here in single-spa-examples actually does not use angular-cli, which is why you can't find it in this repo. You can check out single-spa-angular-cli, which is a library that helps you get things set up with angular-cli apps. It also explains how they fit into the single-spa world. The basic approach taken in that project is that ng build produces a bundle that creates a global variable for your single-spa application. Your singleSpa.registerApplication calls go through the library and lazily download the bundles for each of the applications that were built by angular-cli.

Also what's up with the reference to .ts files?

I'm not sure what you mean here, could you clarify? Are you talking about the .ts files like this one in the repo? Or maybe how the code has the .ts extension in its imports?

sharpcoder28 commented 6 years ago

I tried single-spa-angular-cli, all kinds of issues. From the start it says "In the child application" what child application? And then in the app entry file? What file? I'm guessing you mean for us to create one. That link is a 404.

The if I follow to run examples locally, first of all the git clone is a bad url. Running npm start throws an error. Npm start in the /src/menu throws an error, have to install @angular/dev something. Same thing for the other folders. The it says to add an angular cli apps, app1, but that already exists. How do I run the root application with all of the components working?

sharpcoder28 commented 6 years ago

I get this error when running npm run start in the root folder:

screen shot 2018-02-25 at 1 19 32 pm
joeldenning commented 6 years ago

@robinComa could you comment on this one, since you maintain single-spa-angular-cli? (Also, THANK YOU for being so great at helping me field some of these questions. It's a huge help for me, since I'm not an expert in Angular)

robinComa commented 6 years ago

Hello @sharpcoder28 and @joeldenning

To use an ng cli apps with single spas, it is really simple. You have to generate you projet with angular cli (if not already create : not existing app) : ng new app1 --prefix=app1

And after you have to change somethings inside your angular app :

// src/apps/app1/src/main.ts

import { enableProdMode } from '@angular/core';
import { Router } from '@angular/router';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { singleSpaAngularCliPlatform } from 'single-spa-angular-cli/lib/single-spa-angular-cli-platform';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

// Router is not mandatory, only if you use a router for your app1
singleSpaAngularCliPlatform.mount('app1-root', Router).subscribe((attachUnmount) => {
  platformBrowserDynamic().bootstrapModule(AppModule).then(attachUnmount);
});

And remove zone.js :

// src/app1/src/polyfills.ts

// Comment zone.js, it is globaly imported by the portal
// import 'zone.js/dist/zone';  // Included with Angular CLI.

And add zone.js only for your cli app (to run it outside the portal :

// src/app1/src/index.html

  <app1-root></app1-root>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.8.19/zone.js"></script>
</body>

After it, you can use the ng build --prod to build your cli app, I recommend for the moment to use : ng build --prod --output-hashing=media

Now you can use single spa all usual :

// src/main.js

import { registerApplication, start } from 'single-spa';
import { singleSpaAngularCliRouter } from 'single-spa-angular-cli/lib/utils';
import 'babel-polyfill';
import 'zone.js';

const LOADER = {
    menu: import('./loaders/menu.js'),
    home: import('./loaders/home.js'),
    app1: import('./loaders/app1.js'),
    help: import('./loaders/help.js')
};

registerApplication('menu', () => LOADER.menu, singleSpaAngularCliRouter.hashPrefix('/**', true));
registerApplication('home', () => LOADER.home, singleSpaAngularCliRouter.hashPrefix('/home', true));
registerApplication('app1', () => LOADER.app1, singleSpaAngularCliRouter.hashPrefix('/app1'));
registerApplication('help', () => LOADER.help, singleSpaAngularCliRouter.hashPrefix('/app1'));
start();
// src/loaders/app1.js

import singleSpaAngularCli from 'single-spa-angular-cli';

const lifecycles = singleSpaAngularCli({
    name: 'app1',
    selector: 'app1-root',
    baseScriptUrl: '/src/apps/app1/dist',
    css: [
        'styles.bundle.css',
    ],
    scripts: [
        'inline.bundle.js',
        'polyfills.bundle.js',
        'vendor.bundle.js',
        'main.bundle.js'
    ]
});

export const bootstrap = [
    lifecycles.bootstrap
];

export const mount = [
    lifecycles.mount
];

export const unmount = [
    lifecycles.unmount
];

export const unload = [
    lifecycles.unload
];

The only tricks to run your app on cli and single spa is to add this on your single spa index.html:

// src/app1/src/index.html

  <app1-root></app1-root>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.8.19/zone.js"></script>
</body>

For more information, see the doc : https://github.com/PlaceMe-SAS/single-spa-angular-cli-examples

Is it more clear?

@joeldenning no problem to help you when I can!

sharpcoder28 commented 6 years ago

First error I get when trying to follow examples:

image

sharpcoder28 commented 6 years ago

Did a normal git clone, and I still get that error above about build/common.js. Are you missing a webpack build in the tutorial? Ran npm run preinstall and it still didn't help

sharpcoder28 commented 6 years ago

more errors:

image

joeldenning commented 6 years ago

@sharpcoder28 I tried to run single-spa-angular-cli-examples as well a couple days ago and ran into issues as well. The error that you screenshotted above is the same one that I saw because the locally install angular-cli wasn't working correctly. I submitted https://github.com/PlaceMe-SAS/single-spa-angular-cli-examples/pull/2 to fix the issues that I saw. Here were some of the things I had to do to get things working:

I also ran into issues using the local version of angular-cli for each of the builds. So I changed it to use the globally installed version of angular-cli and that seemed to work better. If you have trouble getting any of the builds to work, try running ng build --prod --output-hashing=media in each application directory manually and diagnosing the errors one by one. I had to install @angular-devkit/core in each of the directories to get things fixed.

Can you try doing a git pull and following the steps above to see if that fixes things. I also updated the readme so that others don't run into these issues.

sharpcoder28 commented 6 years ago

Thanks! I got it working. I'm going to prototype a build process soon, but I'm pretty confident. Do you see any issue in having the apps build and just drop into the dist folder of the main running app? I testing it and didn't need to do a build in the host app. Not unless a new child app was added.

joeldenning commented 6 years ago

@sharpcoder28 happy to hear it's working!

Yes, as long as you don't change anything in the main file or the the loaders directory, you don't have to re-build the root application (or "host app")