Angular 7.0.3 cli - Dynamically load external module from webpack bundle












1















I have two Angular 7.0.3 cli apps. When I navigate to a certain route, I would like to get the second app as an external webpack bundle from a proxy server and mount it on my main application.



Specifically I'm having trouble understanding how exactly I need to set up my angular.json and/or custom webpack.config file (if i need one at all) so that I have a single bundle that I can serve up. Additionally, I'm not quite sure how to handle my CustomModuleLoader.load() function.



Some background:



I am using APP_INITIALIZER to get a config that holds data on what routes need to be dynamically added. I reset the config with the new values. Lets say my second app is handling a clients page:



{ provide: APP_INITIALIZER, useFactory: (myCustomServiceFactory: SomeService) => () => myCustomServiceFactory.get(), deps: [SomeService], multi: true },


Service:



    get() {
return this.http.get(this.url)
.toPromise()
.then((body: DataApiResponseMessage) => {
let router = this.injector.get(Router);
let routeArray: Route = ;
//example route
let route: Route = {
path: 'clients',
loadChildren: '@myapp/clients#ClientsModule'
};
routeArray.push(route);
router.resetConfig([...routeArray, ...router.config]);
})
.catch((error) => this.handleError(error))
}


When '/clients' is navigated to I ask for the external bundle from my second app:



app.use('/@myapp/clients', function (req, res) {
apiProxy.web(req, res, { target: 'http://localhost:3001' });
});


My second app responds with dist/main.js



res.sendFile(path.resolve(process.cwd(), 'dist/main.js'));


My CustomModuleLoader:



import { Injectable, Injector, Compiler, NgModuleFactoryLoader, 
NgModuleFactory } from '@angular/core';

const SEPARATOR = '#';

@Injectable()
export class CustomModuleLoader implements NgModuleFactoryLoader {
constructor(private compiler: Compiler, private injector: Injector) {

}

load(path: string): Promise<NgModuleFactory<any>> {
let [url, moduleName] = path.split(SEPARATOR);

return this.loadScript(url).then(() => {
//build and return ngModuleFactory here from
//@myapp/clients bundle.js file or window (?)
}).catch((err) => {
console.log(err);
});
}

loadScript(url) {
return new Promise((resolve, reject) => {
var script = document.createElement('script');
var body = document.getElementsByTagName('body')[0];
script.src = url;
script.charset = "UTF-8";
script.onload = function () {
resolve();
}
script.onerror = function () {
reject();
}
body.appendChild(script);
});
}
}


In my second app I'm using @angular-builders/custom-webpack:browser and declaring customWebpackConfig. I have (an empty because I'm not quite sure what to put in there) webpack.config.js file where I would declare angular and other major libraries as external and output a single bundle.js file.



What angular.json / webpack.config.js confiurgation do I need to correctly serve up my second application ? How then do I handle mounting the webpack bundle as an ngModule in my main app inside my CustomModuleLoader.load() function?










share|improve this question























  • Split one app into two module(two 'app' ) will be simpler,or you can use Mona github.com/phodal/mooa

    – junk
    Nov 14 '18 at 2:12


















1















I have two Angular 7.0.3 cli apps. When I navigate to a certain route, I would like to get the second app as an external webpack bundle from a proxy server and mount it on my main application.



Specifically I'm having trouble understanding how exactly I need to set up my angular.json and/or custom webpack.config file (if i need one at all) so that I have a single bundle that I can serve up. Additionally, I'm not quite sure how to handle my CustomModuleLoader.load() function.



Some background:



I am using APP_INITIALIZER to get a config that holds data on what routes need to be dynamically added. I reset the config with the new values. Lets say my second app is handling a clients page:



{ provide: APP_INITIALIZER, useFactory: (myCustomServiceFactory: SomeService) => () => myCustomServiceFactory.get(), deps: [SomeService], multi: true },


Service:



    get() {
return this.http.get(this.url)
.toPromise()
.then((body: DataApiResponseMessage) => {
let router = this.injector.get(Router);
let routeArray: Route = ;
//example route
let route: Route = {
path: 'clients',
loadChildren: '@myapp/clients#ClientsModule'
};
routeArray.push(route);
router.resetConfig([...routeArray, ...router.config]);
})
.catch((error) => this.handleError(error))
}


When '/clients' is navigated to I ask for the external bundle from my second app:



app.use('/@myapp/clients', function (req, res) {
apiProxy.web(req, res, { target: 'http://localhost:3001' });
});


My second app responds with dist/main.js



res.sendFile(path.resolve(process.cwd(), 'dist/main.js'));


My CustomModuleLoader:



import { Injectable, Injector, Compiler, NgModuleFactoryLoader, 
NgModuleFactory } from '@angular/core';

const SEPARATOR = '#';

@Injectable()
export class CustomModuleLoader implements NgModuleFactoryLoader {
constructor(private compiler: Compiler, private injector: Injector) {

}

load(path: string): Promise<NgModuleFactory<any>> {
let [url, moduleName] = path.split(SEPARATOR);

return this.loadScript(url).then(() => {
//build and return ngModuleFactory here from
//@myapp/clients bundle.js file or window (?)
}).catch((err) => {
console.log(err);
});
}

loadScript(url) {
return new Promise((resolve, reject) => {
var script = document.createElement('script');
var body = document.getElementsByTagName('body')[0];
script.src = url;
script.charset = "UTF-8";
script.onload = function () {
resolve();
}
script.onerror = function () {
reject();
}
body.appendChild(script);
});
}
}


In my second app I'm using @angular-builders/custom-webpack:browser and declaring customWebpackConfig. I have (an empty because I'm not quite sure what to put in there) webpack.config.js file where I would declare angular and other major libraries as external and output a single bundle.js file.



What angular.json / webpack.config.js confiurgation do I need to correctly serve up my second application ? How then do I handle mounting the webpack bundle as an ngModule in my main app inside my CustomModuleLoader.load() function?










share|improve this question























  • Split one app into two module(two 'app' ) will be simpler,or you can use Mona github.com/phodal/mooa

    – junk
    Nov 14 '18 at 2:12
















1












1








1








I have two Angular 7.0.3 cli apps. When I navigate to a certain route, I would like to get the second app as an external webpack bundle from a proxy server and mount it on my main application.



Specifically I'm having trouble understanding how exactly I need to set up my angular.json and/or custom webpack.config file (if i need one at all) so that I have a single bundle that I can serve up. Additionally, I'm not quite sure how to handle my CustomModuleLoader.load() function.



Some background:



I am using APP_INITIALIZER to get a config that holds data on what routes need to be dynamically added. I reset the config with the new values. Lets say my second app is handling a clients page:



{ provide: APP_INITIALIZER, useFactory: (myCustomServiceFactory: SomeService) => () => myCustomServiceFactory.get(), deps: [SomeService], multi: true },


Service:



    get() {
return this.http.get(this.url)
.toPromise()
.then((body: DataApiResponseMessage) => {
let router = this.injector.get(Router);
let routeArray: Route = ;
//example route
let route: Route = {
path: 'clients',
loadChildren: '@myapp/clients#ClientsModule'
};
routeArray.push(route);
router.resetConfig([...routeArray, ...router.config]);
})
.catch((error) => this.handleError(error))
}


When '/clients' is navigated to I ask for the external bundle from my second app:



app.use('/@myapp/clients', function (req, res) {
apiProxy.web(req, res, { target: 'http://localhost:3001' });
});


My second app responds with dist/main.js



res.sendFile(path.resolve(process.cwd(), 'dist/main.js'));


My CustomModuleLoader:



import { Injectable, Injector, Compiler, NgModuleFactoryLoader, 
NgModuleFactory } from '@angular/core';

const SEPARATOR = '#';

@Injectable()
export class CustomModuleLoader implements NgModuleFactoryLoader {
constructor(private compiler: Compiler, private injector: Injector) {

}

load(path: string): Promise<NgModuleFactory<any>> {
let [url, moduleName] = path.split(SEPARATOR);

return this.loadScript(url).then(() => {
//build and return ngModuleFactory here from
//@myapp/clients bundle.js file or window (?)
}).catch((err) => {
console.log(err);
});
}

loadScript(url) {
return new Promise((resolve, reject) => {
var script = document.createElement('script');
var body = document.getElementsByTagName('body')[0];
script.src = url;
script.charset = "UTF-8";
script.onload = function () {
resolve();
}
script.onerror = function () {
reject();
}
body.appendChild(script);
});
}
}


In my second app I'm using @angular-builders/custom-webpack:browser and declaring customWebpackConfig. I have (an empty because I'm not quite sure what to put in there) webpack.config.js file where I would declare angular and other major libraries as external and output a single bundle.js file.



What angular.json / webpack.config.js confiurgation do I need to correctly serve up my second application ? How then do I handle mounting the webpack bundle as an ngModule in my main app inside my CustomModuleLoader.load() function?










share|improve this question














I have two Angular 7.0.3 cli apps. When I navigate to a certain route, I would like to get the second app as an external webpack bundle from a proxy server and mount it on my main application.



Specifically I'm having trouble understanding how exactly I need to set up my angular.json and/or custom webpack.config file (if i need one at all) so that I have a single bundle that I can serve up. Additionally, I'm not quite sure how to handle my CustomModuleLoader.load() function.



Some background:



I am using APP_INITIALIZER to get a config that holds data on what routes need to be dynamically added. I reset the config with the new values. Lets say my second app is handling a clients page:



{ provide: APP_INITIALIZER, useFactory: (myCustomServiceFactory: SomeService) => () => myCustomServiceFactory.get(), deps: [SomeService], multi: true },


Service:



    get() {
return this.http.get(this.url)
.toPromise()
.then((body: DataApiResponseMessage) => {
let router = this.injector.get(Router);
let routeArray: Route = ;
//example route
let route: Route = {
path: 'clients',
loadChildren: '@myapp/clients#ClientsModule'
};
routeArray.push(route);
router.resetConfig([...routeArray, ...router.config]);
})
.catch((error) => this.handleError(error))
}


When '/clients' is navigated to I ask for the external bundle from my second app:



app.use('/@myapp/clients', function (req, res) {
apiProxy.web(req, res, { target: 'http://localhost:3001' });
});


My second app responds with dist/main.js



res.sendFile(path.resolve(process.cwd(), 'dist/main.js'));


My CustomModuleLoader:



import { Injectable, Injector, Compiler, NgModuleFactoryLoader, 
NgModuleFactory } from '@angular/core';

const SEPARATOR = '#';

@Injectable()
export class CustomModuleLoader implements NgModuleFactoryLoader {
constructor(private compiler: Compiler, private injector: Injector) {

}

load(path: string): Promise<NgModuleFactory<any>> {
let [url, moduleName] = path.split(SEPARATOR);

return this.loadScript(url).then(() => {
//build and return ngModuleFactory here from
//@myapp/clients bundle.js file or window (?)
}).catch((err) => {
console.log(err);
});
}

loadScript(url) {
return new Promise((resolve, reject) => {
var script = document.createElement('script');
var body = document.getElementsByTagName('body')[0];
script.src = url;
script.charset = "UTF-8";
script.onload = function () {
resolve();
}
script.onerror = function () {
reject();
}
body.appendChild(script);
});
}
}


In my second app I'm using @angular-builders/custom-webpack:browser and declaring customWebpackConfig. I have (an empty because I'm not quite sure what to put in there) webpack.config.js file where I would declare angular and other major libraries as external and output a single bundle.js file.



What angular.json / webpack.config.js confiurgation do I need to correctly serve up my second application ? How then do I handle mounting the webpack bundle as an ngModule in my main app inside my CustomModuleLoader.load() function?







angular webpack dynamic angular-cli bundle






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 14 '18 at 1:00









bradleybradley

113212




113212













  • Split one app into two module(two 'app' ) will be simpler,or you can use Mona github.com/phodal/mooa

    – junk
    Nov 14 '18 at 2:12





















  • Split one app into two module(two 'app' ) will be simpler,or you can use Mona github.com/phodal/mooa

    – junk
    Nov 14 '18 at 2:12



















Split one app into two module(two 'app' ) will be simpler,or you can use Mona github.com/phodal/mooa

– junk
Nov 14 '18 at 2:12







Split one app into two module(two 'app' ) will be simpler,or you can use Mona github.com/phodal/mooa

– junk
Nov 14 '18 at 2:12














0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53291684%2fangular-7-0-3-cli-dynamically-load-external-module-from-webpack-bundle%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53291684%2fangular-7-0-3-cli-dynamically-load-external-module-from-webpack-bundle%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Florida Star v. B. J. F.

Danny Elfman

Lugert, Oklahoma