cli javascript angular typescript webpack angular-router

javascript - cli - Carga dinámica de un paquete web externo incluido ngModule como manejador de ruta



webpack angular 4 (1)

Como has mencionado

Las aplicaciones deben ignorar la configuración del otro.

Tuve un problema similar en Angular2. Lo resolví creando una sub-aplicación. Un archivo sub-main.browser.ts e index.html por separado. Tenía sus propias dependencias, compartiendo los mismos módulos de nodos. Ambos módulos principales arrancan diferentes componentes de la aplicación. Estábamos trabajando en Angular sin angular-cli.

En la configuración de la carpeta web, agregué

entry: { ''polyfills'': ''./src/polyfills.browser.ts'', ''main'' . : ''./src/main.browser.aot.ts'', ''sub-main'' : ''/src/sub-main.browser.ts'' },

y un HtmlWebpackPlugin más detallado. En los trozos, solo cargamos los módulos que se usarán en ambas aplicaciones. Si vemos polyfills es común.

new HtmlWebpackPlugin({ template: ''src/index.html'', title: METADATA.title, chunksSortMode: ''dependency'', metadata: METADATA, inject: ''head'', chunks: [''polyfills'',''main''] }), new HtmlWebpackPlugin({ template: ''src/index2.html'', title: ''Sub app'', chunksSortMode: ''dependency'', metadata: METADATA, inject: ''head'', filename: ''./sub-app.html'', chunks: [''polyfills'',''sub-main''] }),

La siguiente tarea fue crear puntos finales separados para ambas aplicaciones secundarias para el entorno de desarrollo.

devServer: { port: METADATA.port, host: METADATA.host, historyApiFallback: true, watchOptions: { aggregateTimeout: 300, poll: 1000 }, proxy: { "/sub-app": { target: "http://localhost:3009", bypass: function(req, res, proxyOptions) { return "/index2.html"; } } } },

Ahora, cuando construyo el proyecto, se generan dos archivos HTML diferentes. Cada uno con sus propias dependencias de paquetes javascript y activos comunes. Se pueden implementar en un servidor diferente también.

Pude terminar mi POC con muchas pruebas y errores. Mi sugerencia será mirar un paso por encima de angular. Vea cómo el paquete web está implementando su proyecto actual. Y si puede configurarlo para su propósito.

Queremos dividir nuestros proyectos frontend grandes en múltiples proyectos implementados por separado con los que es más fácil trabajar. Estoy tratando de incluir un ngModule incluido para manejar una ruta desde otra aplicación. Las aplicaciones deben ignorar la configuración del otro. Los paquetes compartirán algunas dependencias grandes (como Angular) a través de globales. No necesitamos agitar los paquetes y podemos tener que aceptar algunas dependencias duplicadas.

El enrutador raíz se queja de que

Error: No NgModule metadata found for ''TestsetModule''.

lo que me lleva a creer que el módulo hijo no está compilado de forma angular en la carga, o que no está registrando su módulo por alguna razón. Creo que puede ser necesario compilar manualmente el módulo, pero no estoy seguro de cómo usar este https://angular.io/api/core/Compiler#compileModuleAndAllComponentsAsync

La aplicación raíz carga al niño a través de una ruta:

import { ModuleWithProviders } from ''@angular/core''; import { Routes, RouterModule } from ''@angular/router''; const load = require("little-loader"); const routes: Routes = [ { path: ``, loadChildren: () => new Promise(function (resolve) { load(''http://localhost:3100/testset-module-bundle.js'',(err: any) => { console.log(''global loaded bundle is: '', (<any>global).TestsetModule ) resolve((<any>global).TestsetModule) } ) })} ]; export const HostRouting: ModuleWithProviders = RouterModule.forRoot(routes);

También traté de usar la sintaxis de resolución de cadena del enrutador angular en lugar de esta extraña cosa global que ves, pero tuve problemas similares.

Aquí está el módulo que se está cargando, muy estándar a excepción de la exportación global:

import { NgModule } from ''@angular/core''; import { CommonModule } from ''@angular/common''; import { HttpModule } from ''@angular/http''; //import { MaterialModule } from ''@angular/material''; import { FlexLayoutModule } from ''@angular/flex-layout''; import { FormsModule } from ''@angular/forms''; import { LoggerModule, Level } from ''@churro/ngx-log''; import { FeatureLoggerConfig } from ''./features/logger/services/feature-logger-config''; import { TestsetComponent } from ''./features/testset/testset.component''; import { TestsetRouting } from ''./testset.routing''; @NgModule({ imports: [ CommonModule, //MaterialModule, FlexLayoutModule, HttpModule, FormsModule, LoggerModule.forChild({ moduleName: ''Testset'', minLevel: Level.INFO }), TestsetRouting, ], declarations: [TestsetComponent], providers: [ /* TODO: Providers go here */ ] }) class TestsetModule { } (<any>global).TestsetModule = TestsetModule export {TestsetModule as default, TestsetModule};

Aquí está la configuración de paquete web del paquete raíz. Tenga en cuenta las exportaciones globales a través del mal llamado "ProvidePlugin".

const webpack = require(''webpack''); const AotPlugin = require(''@ngtools/webpack'').AotPlugin; const path = require(''path''); const BrowserSyncPlugin = require(''browser-sync-webpack-plugin''); const IgnorePlugin = require(''webpack/lib/IgnorePlugin''); const PolyfillsPlugin = require(''webpack-polyfills-plugin''); const WebpackSystemRegister = require(''webpack-system-register''); module.exports = (envOptions) => { envOptions = envOptions || {}; const config = { entry: { ''bundle'': ''./root.ts'' }, output: { libraryTarget: ''umd'', filename: ''[name].js'',//"bundle.[hash].js", chunkFilename: ''[name]-chunk.js'', path: __dirname }, externals: { }, resolve: { extensions: [''.ts'', ''.js'', ''.html''], }, module: { rules: [ { test: //.html$/, loader: ''raw-loader'' }, { test: //.css$/, loader: ''raw-loader'' }, ] }, devtool: ''#source-map'', plugins: [ new webpack.ProvidePlugin({ ''angular'': ''@angular/core'', ''ngrouter'': ''@angular/router'', ''ngxlog'':''@churro/ngx-log'' }) ] }; config.module.rules.push( { test: //.ts$/, loaders: [ ''awesome-typescript-loader'', ''angular-router-loader'', ''angular2-template-loader'', ''source-map-loader'' ] } ); } return config; };

Y aquí está la configuración de paquete web del paquete hijo. Tenga en cuenta los "externos" que buscan angular como global.

module.exports = (envOptions) => { envOptions = envOptions || {}; const config = { entry: { ''testset-module-bundle'': ''./src/index.ts'' }, output: { //library: ''TestsetModule'', libraryTarget: ''umd'', filename: ''[name].js'',//"bundle.[hash].js", chunkFilename: ''[name]-chunk.js'', path: path.resolve(__dirname, "dist") }, externals: { //expect these to come from the app that imported us // name to be required : name from global ''angular'': ''@angular/core'', ''ngrouter'': ''@angular/router'', ''ngxlog'': ''@churro/ngx-log'' }, resolve: { extensions: [''.ts'', ''.js'', ''.html''], }, module: { rules: [ { test: //.html$/, loader: ''raw-loader'' }, { test: //.css$/, loader: ''raw-loader'' }, ] }, devtool: ''#source-map'', plugins: [ ] }; config.module.rules.push( { test: //.ts$/, loaders: [ ''awesome-typescript-loader'', ''angular-router-loader'', ''angular2-template-loader'', ''source-map-loader'' ] } ); } return config; };

Y para una buena medida, aquí está mi archivo tsconfig que lee ''awesome-typescript-loader''.

{ "compilerOptions": { "target": "es5", "module": "es2015", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "removeComments": false, "noImplicitAny": true, "suppressImplicitAnyIndexErrors": true, "baseUrl": ".", "rootDir": "src", "outDir": "app", "paths": { "@capone/*": [ "*" ], "@angular/*": [ "node_modules/@angular/*" ], "rxjs/*": [ "node_modules/rxjs/*" ] } }, "exclude": ["node_modules", "src/node_modules", "compiled", "src/dev_wrapper_app"], "angularCompilerOptions": { "genDir": "./compiled", "skipMetadataEmit": true } }

Si todavía estás leyendo, increíble. Pude hacerlo funcionar cuando ambos paquetes forman parte de la misma configuración de paquete web y el módulo hijo es solo un pedazo. Angular está diseñado para hacer eso. Pero nuestro caso de uso es hacer que los hijos y el padre sean ignorantes el uno del otro hasta el momento de la ejecución.