javascript - tutorial - install angular 5
Cargue nuevos módulos dinámicamente en tiempo de ejecución con Angular CLI y Angular 5 (6)
Creo que esto es posible usando SystemJS para cargar un paquete UMD si compila y ejecuta su aplicación principal usando un paquete web. Utilicé una solución que utiliza ng-packagr para crear un paquete UMD del módulo de complemento / complemento dinámico. Este github muestra el procedimiento descrito: https://github.com/nmarra/dynamic-module-loading
Actualmente estoy trabajando en un proyecto que se hospeda en un servidor de clientes. Para los nuevos ''módulos'' no hay intención de volver a compilar toda la aplicación. Dicho esto, el cliente desea actualizar el enrutador / los módulos cargados perezosamente en tiempo de ejecución . He intentado varias cosas pero no puedo hacer que funcione. Me preguntaba si alguno de ustedes sabe lo que todavía podría intentar o lo que me perdí.
Una cosa que noté, la mayoría de los recursos que probé, usando angi angi, se están agrupando en fragmentos separados por webpack de forma predeterminada al compilar la aplicación. Lo que parece lógico ya que hace uso de la división de código webpack. pero ¿qué sucede si el módulo aún no se conoce en el momento de la compilación (pero un módulo compilado se almacena en algún lugar de un servidor)? El agrupamiento no funciona porque no puede encontrar el módulo para importar. Y el uso de SystemJS cargará los módulos UMD siempre que se encuentren en el sistema, pero también se incluyen en paquetes separados por un paquete web.
Algunos recursos que ya probé;
- dynamic-remote-component-loader
- module-loading
- Cargando módulos de diferentes servidores en tiempo de ejecución
- Cómo cargar componentes externos dinámicos en una aplicación angular
- Implementación de una arquitectura de complementos / sistema de complementos / marco conectable en Angular 2, 4, 5, 6
- Angular 5: cargar módulos (que no se conocen en tiempo de compilación) dinámicamente en tiempo de ejecución
- https://medium.com/@nikolasleblanc/building-an-angular-4-component-library-with-the-angular-cli-and-ng-packagr-53b2ade0701e
- Algunos otros relacionados con este tema.
Algún código ya lo probé e implementé, pero no funcionó en este momento;
Enrutador extensible con el modulo normal.
this.router.config.push({
path: "external",
loadChildren: () =>
System.import("./module/external.module").then(
module => module["ExternalModule"],
() => {
throw { loadChunkError: true };
}
)
});
Normal SystemJS Importación de paquete UMD
System.import("./external/bundles/external.umd.js").then(modules => {
console.log(modules);
this.compiler.compileModuleAndAllComponentsAsync(modules[''External'']).then(compiled => {
const m = compiled.ngModuleFactory.create(this.injector);
const factory = compiled.componentFactories[0];
const cmp = factory.create(this.injector, [], null, m);
});
});
Importar módulo externo, no funciona con webpack (afaik)
const url = ''https://gist.githubusercontent.com/dianadujing/a7bbbf191349182e1d459286dba0282f/raw/c23281f8c5fabb10ab9d144489316919e4233d11/app.module.ts'';
const importer = (url:any) => Observable.fromPromise(System.import(url));
console.log(''importer:'', importer);
importer(url)
.subscribe((modules) => {
console.log(''modules:'', modules, modules[''AppModule'']);
this.cfr = this.compiler.compileModuleAndAllComponentsSync(modules[''AppModule'']);
console.log(this.cfr,'','', this.cfr.componentFactories[0]);
this.external.createComponent(this.cfr.componentFactories[0], 0);
});
Utilice SystemJsNgModuleLoader
this.loader.load(''app/lazy/lazy.module#LazyModule'').then((moduleFactory: NgModuleFactory<any>) => {
console.log(moduleFactory);
const entryComponent = (<any>moduleFactory.moduleType).entry;
const moduleRef = moduleFactory.create(this.injector);
const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
});
Intenté cargar un módulo hecho con rollup.
this.http.get(`./myplugin/${metadataFileName}`)
.map(res => res.json())
.map((metadata: PluginMetadata) => {
// create the element to load in the module and factories
const script = document.createElement(''script'');
script.src = `./myplugin/${factoryFileName}`;
script.onload = () => {
//rollup builds the bundle so it''s attached to the window object when loaded in
const moduleFactory: NgModuleFactory<any> = window[metadata.name][metadata.moduleName + factorySuffix];
const moduleRef = moduleFactory.create(this.injector);
//use the entry point token to grab the component type that we should be rendering
const compType = moduleRef.injector.get(pluginEntryPointToken);
const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(compType);
// Works perfectly in debug, but when building for production it returns an error ''cannot find name Component of undefined''
// Not getting it to work with the router module.
}
document.head.appendChild(script);
}).subscribe();
El ejemplo con SystemJsNgModuleLoader solo funciona cuando el Módulo ya se proporciona como una ruta ''perezosa'' en el RouterModule de la aplicación (que se convierte en un trozo cuando se construye con un paquete web)
Encontré mucha discusión sobre este tema en StackOverflow aquí y allá, y las soluciones proporcionadas parecen realmente buenas para cargar módulos / componentes dinámicamente, si se conocen por adelantado. Pero ninguna es adecuada para nuestro caso de uso del proyecto. Por favor, hágamelo saber en lo que todavía puedo intentar o sumergirme.
¡Gracias!
EDIT: he encontrado; https://github.com/kirjs/angular-dynamic-module-loading y lo intentaré.
ACTUALIZACIÓN: he creado un repositorio con un ejemplo de carga de módulos de forma dinámica utilizando SystemJS (y utilizando Angular 6); https://github.com/lmeijdam/angular-umd-dynamic-example
Estaba enfrentando el mismo problema. Por lo que yo entiendo hasta ahora:
Webpack pone todos los recursos en un paquete y reemplaza todo
System.import
con
__webpack_require__
.
Por lo tanto, si desea cargar un módulo dinámicamente en tiempo de ejecución utilizando SystemJsNgModuleLoader, el cargador buscará el módulo en el paquete.
Si el módulo no existe en el paquete, obtendrá un error.
Webpack no le va a pedir al servidor ese módulo.
Este es un problema para nosotros, ya que queremos cargar un módulo que no conocemos en el momento de compilación / compilación.
Lo que necesitamos es un cargador que cargue un módulo para nosotros en tiempo de ejecución (perezoso y dinámico).
En mi ejemplo, estoy usando SystemJS y Angular 6 / CLI.
- Instale SystemJS: npm install systemjs –save
- Agréguelo a angular.json: "scripts": ["node_modules / systemjs / dist / system.src.js"]
app.component.ts
import { Compiler, Component, Injector, ViewChild, ViewContainerRef } from ''@angular/core'';
import * as AngularCommon from ''@angular/common'';
import * as AngularCore from ''@angular/core'';
declare var SystemJS;
@Component({
selector: ''app-root'',
template: ''<button (click)="load()">Load</button><ng-container #vc></ng-container>''
})
export class AppComponent {
@ViewChild(''vc'', {read: ViewContainerRef}) vc;
constructor(private compiler: Compiler,
private injector: Injector) {
}
load() {
// register the modules that we already loaded so that no HTTP request is made
// in my case, the modules are already available in my bundle (bundled by webpack)
SystemJS.set(''@angular/core'', SystemJS.newModule(AngularCore));
SystemJS.set(''@angular/common'', SystemJS.newModule(AngularCommon));
// now, import the new module
SystemJS.import(''my-dynamic.component.js'').then((module) => {
this.compiler.compileModuleAndAllComponentsAsync(module.default)
.then((compiled) => {
let moduleRef = compiled.ngModuleFactory.create(this.injector);
let factory = compiled.componentFactories[0];
if (factory) {
let component = this.vc.createComponent(factory);
let instance = component.instance;
}
});
});
}
}
my-dynamic.component.ts
import { NgModule, Component } from ''@angular/core'';
import { CommonModule } from ''@angular/common'';
import { Other } from ''./other'';
@Component({
selector: ''my-dynamic-component'',
template: ''<h1>Dynamic component</h1><button (click)="LoadMore()">LoadMore</button>''
})
export class MyDynamicComponent {
LoadMore() {
let other = new Other();
other.hello();
}
}
@NgModule({
declarations: [MyDynamicComponent],
imports: [CommonModule],
})
export default class MyDynamicModule {}
other.component.ts
export class Other {
hello() {
console.log("hello");
}
}
Como puede ver, podemos decirle a SystemJS qué módulos ya existen en nuestro paquete.
Por lo tanto, no necesitamos cargarlos nuevamente (
SystemJS.set
).
Todos los demás módulos que importemos en nuestro
my-dynamic-component
(en este ejemplo,
other
) se solicitarán al servidor en tiempo de ejecución.
Hazlo con la librería angular 6 y el resumen haz el truco. Acabo de experimentar con él y puedo compartir el módulo AOT angular independiente con la aplicación principal sin tener que reconstruir en último lugar.
-
En la biblioteca angular, establezca
angularCompilerOptions.skipTemplateCodegen
en falso y después de compilar la biblioteca obtendrá la fábrica de módulos. -
Después de eso, genere un módulo umd con resumen como este:
rollup dist/plugin/esm2015/lib/plugin.module.ngfactory.js --file src/assets/plugin.module.umd.js --format umd --name plugin
- Cargue la fuente de texto umd bundle en la aplicación principal y evalúela con el contexto del módulo
- Ahora puede acceder a ModuleFactory desde el objeto de exportación
Aquí https://github.com/iwnow/angular-plugin-example puede encontrar cómo desarrollar plugin con edificio independiente y AOT
He probado en Angular 6, la solución de abajo funciona para cargar dinámicamente un módulo desde un paquete externo o desde un módulo interno.
1. Si desea cargar dinámicamente un módulo de un proyecto de biblioteca o un paquete:
Tengo un proyecto de biblioteca "admin" (o puede usar un paquete) y un proyecto de aplicación "app". En mi proyecto de biblioteca "admin", tengo AdminModule y AdminRoutingModule. En mi proyecto "app":
a. Hacer cambio en tsconfig.app.json:
"compilerOptions": {
"module": "esNext",
},
segundo. En app-routing.module.ts:
const routes: Routes = [
{
path: ''admin'',
loadChildren: async () => {
const a = await import(''admin'')
return a[''AdminModule''];
}
},
{
path: '''',
redirectTo: '''',
pathMatch: ''full''
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
2. Si desea cargar un módulo del mismo proyecto.
Hay 4 opciones diferentes:
a. En app-routing.module.ts:
const routes: Routes = [
{
path: ''example'',
/* Options 1: Use component */
// component: ExampleComponent, // Load router from component
/* Options 2: Use Angular default lazy load syntax */
loadChildren: ''./example/example.module#ExampleModule'', // lazy load router from module
/* Options 3: Use Module */
// loadChildren: () => ExampleModule, // load router from module
/* Options 4: Use esNext, you need to change tsconfig.app.json */
/*
loadChildren: async () => {
const a = await import(''./example/example.module'')
return a[''ExampleModule''];
}
*/
},
{
path: '''',
redirectTo: '''',
pathMatch: ''full''
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
``
He utilizado la solución https://github.com/kirjs/angular-dynamic-module-loading con el soporte de la biblioteca de Angular 6 para crear una aplicación que compartí en Github. Debido a la política de la empresa tenía que ser desconectado. Tan pronto como terminen las discusiones sobre el ejemplo de fuente del proyecto, lo compartiré en Github!
ACTUALIZACIÓN: se puede encontrar repo; https://github.com/lmeijdam/angular-umd-dynamic-example
Sí, puede cargar los módulos de forma diferida si los consulta como módulos en el enrutador. Aquí hay un ejemplo https://github.com/start-angular/SB-Admin-BS4-Angular-6
- Primero junta todos los componentes que estás usando en un solo módulo
- Ahora refiera ese módulo en el enrutador y angular cargará perezosamente su módulo en la vista.