Closed 3gwebtrain closed 2 years ago
@arturovt thanks for your replay. Is there any demo repo we have? if so can you share me please?
Hi there, as a trial, I tried to remove my local "single-spa" and added the same in "import-map". But still I am getting following error:
ERROR in src/ambient.d.ts:1:30 - error TS2307: Cannot find module 'single-spa'.
1 import { ParcelConfig } from 'single-spa';
~~~~~~~~~~~~
src/main.ts:3:28 - error TS2307: Cannot find module 'single-spa'.
3 import * as singleSpa from 'single-spa';
~~~~~~~~~~~~
src/services/single-spa.service.ts:2:43 - error TS2307: Cannot find module 'single-spa'.
2 import { Parcel, mountRootParcel, } from 'single-spa';
~~~~~~~~~~~~
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
i 「wdm」: Failed to compile.
I understood that, I am missing some configuration. can you please point out the configuration i need do here?
Thanks in advance.
here is my import:
{
"imports": {
"single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/5.4.0/umd/single-spa.min.js",
"content": "https://amxanedevaoscmsui01-as-spa.azurewebsites.net/main-es2015.js",
}
}
This is a TypeScript error. single-spa is published with types included, so you'll need to install it as a devDependency it to have those types available to the compiler, eg npm install --save-dev single-spa
.
How to add that with, imports? my intension is to import that in wrapper application. both wrapper and child applications to use. sorry for inconvenience. please help me. As a simple I am trying to convert "single-spa" as browser module instead of locally installed. reason to share all child apps. If I am wrong please show me right direction.
How to add that with, imports?
Yes. Both installed locally (only because you're using TypeScript!) as well as in the import map. You should install the module (OR just the types) so that TypeScript can do its thing and analyze the code with types. So for this reason, you would install the module locally. For example, npm install --save-dev single-spa
to install the library or npm install --save-dev @types/some-library
to install just the types that are published on DefinitelyTyped. But, assuming your Webpack config is configured correctly, that module would not be bundled into your application. SystemJS serves the purpose of enabling in-browser module resolution so you need to then ensure that the library is in your import map.
There isn't an example of doing all of this yet (though some issues, like https://github.com/single-spa/single-spa-angular/issues/288, might be a good reference) that I know of. You'll need to pioneer the rest of this setup and architecture on your own, and it would be a great example or case study to share with the single-spa community!
As per your suggestion I have installed the single spa with "--dev" flag. it works. as well I added a link with index.html
as like below:
<script type="systemjs-importmap">
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.4.0/lib/system/single-spa.min.js"
}
}
</script>
But I not insure that, it downloads in local. assuming it's only required for bundling purpose, I need to update the webpack.config.js
, I see that there is number of example for handle the extra-webpack.config.js
which connected with single-spa-angular
. But my case I am using single-spa
so in this case how can i write the webpack-config
?
can you help me?
at preset my map import-map-dev
look like this:
{ "imports": { "content": "https://content-as-spa.azurewebsites.net/main-es2015.js", "user": "https://management-as.azurewebsites.net/main-es2015.js", "status": "https://message-as.azurewebsites.net/main-es2015.js", } }
here is my index.html: ( need a way to test the import)
<script type="systemjs-importmap">
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.4.0/lib/system/single-spa.min.js"
}
}
</script>
I am appending the import-map
with index.html
like this:
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import * as singleSpa from 'single-spa';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
const script = document.createElement('script');
script.src = `/assets/json-map/import-map-${environment.type}.json`;
script.type = 'systemjs-importmap';
document.head.appendChild(script);
singleSpa.start();
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
Now the pending thing is, how to write the webpack-config
without single-spa-angular
installed?.
please help me to complete my integration.
Basically, I am using the approach like here : https://github.com/matt-gold/single-spa-angular-cli
Thanks for help.
I didn't understand anything past the initial request, but here is the summary to have shared dependencies. That's a guide. Check your versions and file and project types.
Root config index.ejs (on sharing block)
<script type="systemjs-importmap">
{
"imports": {
"rxjs": "https://cdn.jsdelivr.net/npm/@esm-bundle/rxjs@6.6.3-fix.0/system/es5/rxjs.min.js",
"rxjs/operators": "https://cdn.jsdelivr.net/npm/@esm-bundle/rxjs@6.6.3-fix.0/system/es5/rxjs-operators.min.js",
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.8.2/lib/system/single-spa.min.js",
"single-spa-angular": "https://cdn.jsdelivr.net/npm/single-spa-angular@4.9.0/bundles/single-spa-angular.umd.min.js",
"single-spa-angular/internals": "https://cdn.jsdelivr.net/npm/single-spa-angular@4.9.0/bundles/single-spa-angular-internals.umd.min.js",
"@angular/core": "https://cdn.jsdelivr.net/npm/@angular/core@10.2.3/bundles/core.umd.js",
"@angular/common": "https://cdn.jsdelivr.net/npm/@angular/common@10.2.3/bundles/common.umd.min.js",
"@angular/compiler": "https://cdn.jsdelivr.net/npm/@angular/compiler@10.2.3/bundles/compiler.umd.js",
"@angular/forms": "https://cdn.jsdelivr.net/npm/@angular/forms@10.2.3/bundles/forms.umd.min.js",
"@angular/platform-browser": "https://cdn.jsdelivr.net/npm/@angular/platform-browser@10.2.3/bundles/platform-browser.umd.min.js",
"@angular/platform-browser-dynamic": "https://cdn.jsdelivr.net/npm/@angular/platform-browser-dynamic@10.2.3/bundles/platform-browser-dynamic.umd.min.js",
"@angular/router": "https://cdn.jsdelivr.net/npm/@angular/router@10.2.3/bundles/router.umd.min.js"
}
}
</script>
Application main-single-spa.ts
if (environment.production) {
try {
enableProdMode();
} catch (exception) {
// Prod/dev mode already defined
}
}
Application extra-webpack.config.js
singleSpaWebpackConfig.externals.push(
"rxjs",
"rxjs/operators",
"@angular/core",
"@angular/common",
"@angular/compiler",
"@angular/platform-browser",
"@angular/platform-browser-dynamic"
);
Application tsconfig.app.json (Angular 9+)
"angularCompilerOptions": {
"enableIvy": false
}
Edited: Actually this is for sharing dependencies, not libraries. I misunderstood the issue. But can be helpful for #321 .
@daniloesk, thanks for your help. in my host application I am not using singleSpaWebpackConfig
at all. instead i have the main.ts
with following:
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import * as singleSpa from "single-spa";
import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";
if (environment.production) {
enableProdMode();
}
singleSpa.start(); //starting my app
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.error(err));
so how to handle this? if require I can add the "custom-webpack" with my app. if so how to config? please help me.
I guess you need to decide to either follow the recommended setup or understand all the involved components to build your own solution. How can you expect to share dependencies without a custom webpack? Or are you using one and not posting it?
I haven't tried it, but I guess you could manually build a simple root config into your host application.
For your imports, I see no reason for changing package.json dependencies. You need to include such packages on webpack's external for them not to be packed but loaded from import map.
I am ready to install custom-webpack
and do the root config. please help me to add the configuration with singleSpa
environment.
I guess I misunderstood your issue. You are trying to reuse a library. But from #321 it seems you are struggling with single-spa-angular .
For this one, create a brand new Angular project with npx create-single-spa
and see how webpack is configured. Then apply it to your project and follow @arturovt https://single-spa.js.org/docs/recommended-setup/#cross-microfrontend-imports. I guess just running ng add single-spa-angular
does not make sense on your host project because... it is the host.
Probably you should try build a test with a couple of brand new empty projects to better understand single-spa instead of looking for a magic copy and paste solution. That's what I am doing =). It is quite hard to just apply something to existing projects.
sure daniloesk, will try and update in this space, thank for your time with me.
@daniloesk if do not mind, I have installed the new app using npx create-single-spa
but how to load my child app which is running in http://localhost:3000
to created app? it show to load the external app from public path
if so what should i do? sorry for silly questions.
@arturovt found a way to share Ivy dependencies. You make @angular/core
, @angular/router
, etc all separate webpack entries, and then compile them with webpack + angular compiler. The resulting output bundles can be put into the systemjs import map.
I have been meaning to create an example of this, but haven't gotten to that yet.
I successfully loaded at runtime using Ivy like this:
webpackConfig.entry.angular_core = '@angular/core'
Loaded commons, platform-browser and core, in this order, then got the error:
ERROR TypeError: Cannot read property 'bindingStartIndex' of null
at Module.ɵɵelementStart (core.js:14781)
Anyone got past that?
It worked after setting runtimeChunk
as documented here:
And importing the runtime.js on Root.
Now I am trying to make this into a real world usage. The exported bundles using entry are keeping multiple copies of libraries. For example each one of them has core.js. Any ideas?
I just remember I saw a dependency somewhere on the docs...
dependOn requires webpack 5 :-/
Please do share once you succeed in this. I have not yet got a chance to look at this myself. Got redirected here from slack thread.
OK, I am struggling a little bit with this. I succeeded having runtime dependencies with Ivy on, but the bundles have duplicated dependencies, making the overall very large. Then I have some ideas for this:
entry = [ '@angular/common', '@angular/core', '@angular/platform-browser' ]
splitChunk
only (no entries): tried building single ou multiple bundles, but couldn't get them loaded with SystemJS.
entry
and splitChunk
: same as above.dependOn
between entries should work, but webpack 5 is a whole new issue. Angular 11 just started experimenting with it and no idea if single-spa will work.Any suggestions are welcome. Also I am not an expert on webpack / SystemJS / Angular / single-spa, so it is very possible I missed something on any of the ideas I tested. Most importantly, I would love to know how this was handled by @arturovt and @joeldenning . :-)
Demo of sharing using entry, but still with duplicated code: https://github.com/daniloesk/single-spa-examples/releases/tag/v20201215-entry
Using webpack 5 dependOn
seems a no go. It seems both the usual load method with import and providing a custom load are not supported yet: https://github.com/webpack/webpack/blob/10ad4e95b850bbe20019275fd1d364666c4b69ea/lib/javascript/EnableChunkLoadingPlugin.js#L71-L112
Although using multiple entry points per page is allowed in webpack, it should be avoided when possible in favor of an entry point with multiple imports:
entry: { page: ['./analytics', './app'] }
. This results in a better optimization and consistent execution order when using async script tags. https://webpack.js.org/guides/code-splitting/
I can pack but I can't use.
splitChunks should work, right? Considering it is used by Angular to load lazy modules.
EDIT: Angular lazy loads async imports only
Breaktrough on dependOn
with webpack 5. There is no need for a @angular/common to lazy load @angular/core if it is loaded directly by the entry. The problem is that when using webpack 4 for the app (not the Angular builder), the load was in the wrong order. With webpack 5 the dependency graph is used and dependencies loaded in correct order.
Webpack 4: System.register(["@angular/common", "@angular/core","@angular/router","@angular/platform-browser"]
Webpack 5: System.register(["@angular/core","@angular/router","@angular/platform-browser","@angular/common"]
OK, solved the duplication problem by using multiple projects. It is a bit ugly but works really well with Ivy on and webpack 4. Here is the example: https://github.com/daniloesk/single-spa-examples/releases/tag/v20201217-importmap-ivy
@joeldenning , any chance of a project like esm-bundle for that? LOL Does esm-bundle builds automatically whenever let's say rxjs releases?
Can this thread be closed?
This also handles #268 ?
I am trying to run after installation, getting error as:
app11
:
An unhandled exception occurred: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration.entry['main'] should not contain the item 'C:\Users\722333\722333\Import-Map\app11\node_modules\webpack-dev-server\client\index.js?http://0.0.0.0:0&sockPath=/sockjs-node' twice.
-> A non-empty array of non-empty strings
See "C:\Users\722333\AppData\Local\Temp\ng-SFOWTE\angular-errors.log" for further details.
error Command failed with exit code 127.
builder11
:
An unhandled exception occurred: No projects support the 'serve' target.
See "C:\Users\722333\AppData\Local\Temp\ng-ue5Me2\angular-errors.log" for further details.
error Command failed with exit code 127.
what is the correct way to start the app?
@joeldenning , any chance of a project like esm-bundle for that? LOL Does esm-bundle builds automatically whenever let's say rxjs releases?
@daniloesk Yes, I started work on this a long time ago but was doing it with rollup which doesn't work since angular compiler only works with webpack. I hope to switch over the esm-bundle repos for angular to webpack and then have those available that way. If you have interest in helping implement that, let me know. See the following links:
https://github.com/esm-bundle/angular__core https://github.com/esm-bundle/angular__common https://github.com/esm-bundle/angular__platform-browser https://github.com/esm-bundle/angular__router
any insight on @3gwebtrain 's last question so far?
Closing the issue since it was implemented, see this guide: https://single-spa.js.org/docs/ecosystem-angular/#shared-angular. All Angular packages (even Cdk + Material) are built & published in SystemJS format (see esm-bundle repo).
I am using angular 8.x with "single-spa-angular": "3.1.0". I have 4 separate sub apps. all it's assembled with container app. all works fine. I have created a angular library with generic components. it's installed in all 4 apps and container app. I really find it's unnecessary.
So how can all this 5 apps can use a single angular-library with them? what is the correct approach to implement this? now all 5 apps having their own copy of angular-library. I want to avoid this.
All my apps created using angular-cli
Please advice. Thank you. Note: If I find a solution, there is a idea to remove all angular common modules from "node_module" bundle from other than wrapper app.