系列文章目录?
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用
提示:本文比较适用有[angular]基础的小白,大佬的话可以忽略应该提供不了什么参考价值;本文适用于angular 7以上的版本,为angular 提供一种较为简单但又可以应用于实际开发微前端实现方案。第一次写发布文章希望对大家有帮助
目录
系列文章目录?
前言
一、什么是portal、什么是子应用
二、使用步骤
1.配置portal?
1-1.主应用(portal)安装版本对应的依赖包?
1-2.主应用(portal)app.module.ts 引入NgxPlanetModule
?1-3主应用(portal)使用Planet服务
2.配置子应用
2-1.子应用安装angular版本对应的依赖包?
2-3.子应用用添加一个路由输出用的组件(TenAppRouterOutLetComponent)以及关联配置:
2-4.子应用angular.json配置:
2-5?package.json
?2-6.子应用通过defineApplication定义如何启动子应用的AppModule, 同时可以设置PlanetPortalApplication服务为主应用的全局服务
2-7 启动测试
?3.portal 注册子应用
?3-1.portal?app.component.ts 注册子应用
3-3.app-routing.module.ts 添加路由
4.总结?
5.报错处里 及注意事项
报错?An accessor cannot be declared in an ambient context.
前言
为了解决部门前端因随着功能的叠加导致前端工程的越发膨大;可维护性逐渐降低(例如到部署到k8s、run pipeline 时间越来越长,本地任意的改动dev-server重新呈现都越来越费时,不同团队都放置一个git仓库越发的乱,分支数倍增,升级难...)可谓是牵一发何止动全身的问题;最终实现将前端应用分解成一些更小、更简单的能够独立开发、测试、部署的小块,这些小块可以有独立的依赖,独立的样式,可以单独的升级,而在用户看来仍然是内聚的单个产品。
注:本文只教你如何快速基于ngx-planet快速搭建出Angular微前端,(不介绍 git cicd的配置,k8s的配置,sonarqube 配置.... 即自动化(自动部署)流程不做任何介绍);其他的(例如:样式分离,样式按需应用)有空再补充。
一、什么是portal、什么是子应用
portal :是所有子应用的入口,一般提供子应用的挂载,子应用的基底(公共)数据和(公共)serve。longin(即登录)、主页一般也放在实现。
子应用:就是功能模块,例如新开的专案。
二、使用步骤
1.配置portal?
angular8 新创建的项目v8-portal-web为例.
1-1.主应用(portal)安装版本对应的依赖包?
@angular/cdk
@worktile/planet
npm install @angular/cdk@8 --save --force
npm install @worktile/planet@^1.2.4 --save --force
1-2.主应用(portal)app.module.ts 引入NgxPlanetModule
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NgxPlanetModule } from '@worktile/planet';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
NgxPlanetModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
?1-3主应用(portal)使用Planet 服务
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Planet, SwitchModes } from '@worktile/planet';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
get loadingDone() {
return this.planet.loadingDone;
}
constructor(private planet: Planet,
private router: Router) {
}
ngOnInit() {
this.planet.setOptions({
switchMode: SwitchModes.default,
errorHandler: error => {
console.error(`Failed to load resource, error:`, error);
}
});
// common Dataa
this.planet.setPortalAppData({
foundationSvc: {}
});
// 注册子应用
this.planet.registerApps([
]);
// start monitor route changes
// get apps to active by current path
// load static resources which contains javascript and css
// bootstrap angular sub app module and show it
this.planet.start();
}
gotoDomePage(event: any) {
this.router.navigate([`/admin/dome-page`]);
}
}
2.配置子应用
angular10?新创建的项目ten-web为例.
2-1.子应用安装angular版本对应的依赖包?
@angular/cdk
@worktile/planet
@angular-builders/custom-webpack
npm install @angular/cdk@10 --save --force
npm install @worktile/planet@^10 --save --force
npm install @angular-builders/custom-webpack@10 --save-dev
其他可选依赖
webpack-assets-manifest:?"^4.0.6"
concurrently
const WebpackAssetsManifest = require('webpack-assets-manifest');
// const PrefixWrap = require('@worktile/planet-postcss-prefixwrap');
module.exports = {
optimization: {
runtimeChunk: false
},
plugins: [new WebpackAssetsManifest()],
// module: {
// rules: [
// {
// test: /\.scss$/,
// use: [
// {
// loader: 'postcss-loader',
// options: {
// plugins: [
// PrefixWrap('.ten-web', {
// hasAttribute: 'planet-inline',
// prefixRootTags: true
// })
// ]
// }
// },
// 'sass-loader'
// ]
// }
// ]
// }
};
2-3.子应用用添加一个路由输出用的组件(TenAppRouterOutLetComponent)以及关联配置:
import { Component } from '@angular/core';
@Component({
selector: 'ten-app-router-outlet',
template: '<router-outlet></router-outlet>'
})
export class TenAppRouterOutLetComponent {
}
子应用ten-app.module.ts?:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { TenAppRoutingModule } from './ten-app-routing.module';
import { TenAppComponent } from './ten-app.component';
import { TenAppRouterOutLetComponent } from './ten-app-router-outlet-component';
import { ProjectsModule } from 'src/projects/projects.module';
@NgModule({
declarations: [
TenAppComponent, // root 组件
TenAppRouterOutLetComponent // 子应用输出组件
],
imports: [
BrowserModule,
TenAppRoutingModule,
ProjectsModule
],
providers: [],
bootstrap: [TenAppComponent]
})
export class TenAppModule { }
子应用ten-app-routing.module.ts:配置router
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { DomePageComponent } from 'src/projects/dome-page/dome-page.component';
import { TenAppRouterOutLetComponent } from './ten-app-router-outlet-component';
const routes: Routes = [
{
path: 'ten',
component: TenAppRouterOutLetComponent,
children: [
{
path: 'dome-page',
component: DomePageComponent,
}
]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class TenAppRoutingModule { }
2-4.子应用angular.json配置:
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "src/extra-webpack.config.js",
"mergeStrategies": {
"module.rules": "prepend"
},
"replaceDuplicatePlugins": true
},
"vendorChunk": false,
...
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "ten-web:build",
"port": 3002,
"vendorChunk": false
},
2-5?package.json
serve:ten-web: // 执行该指令 用于单独启动该子应用
start: // 在启动子应用的同时也会启动portal 的start? (portal要放置跟子应用同一个文件夹下才起作用)
"serve:ten-web": "ng serve ten-web --deploy-url=/ten-web/",
"start": "concurrently \"npm run start --prefix=../v8-portal-web\" \"npm run serve:ten-web\"",
"build": "ng build ten-web --prod --deploy-url=/ten-web/",
?2-6.子应用通过defineApplication 定义如何启动子应用的AppModule , 同时可以设置PlanetPortalApplication 服务为主应用的全局服务
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { defineApplication, PlanetPortalApplication } from '@worktile/planet';
import { TenAppModule } from './ten-app/ten-app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
// platformBrowserDynamic().bootstrapModule(TenAppModule)
// .catch(err => console.error(err));
defineApplication('ten-web', (portalApp: PlanetPortalApplication) => {
return platformBrowserDynamic([
{
provide: PlanetPortalApplication,
useValue: portalApp
}
])
.bootstrapModule(TenAppModule)
.then(appModule => {
return appModule;
})
.catch(error => {
console.error(error);
return null;
});
});
2-7 启动测试
?
?
?3.portal 注册子应用
?3-1.portal?app.component.ts 注册子应用
this.planet.registerApps([
{
name: 'ten-web',
hostParent: '#app-root-portal',
hostClass: 'thy-layout',
routerPathPrefix: '/ten',
selector: 'ten-app-root',
preload: false,
manifest: 'ten_proxy/ten-web/manifest.json',
scripts: [
'ten_proxy/ten-web/main.js',
],
styles: [
// 'ten_proxy/ten-web/styles.css',
'ten_proxy/ten-web/ten-styles.css'
]
}
]);
?3-2.使用方向代理?proxy.conf.js
const PROXY_CONFIG = {};
PROXY_CONFIG["/admin-web"] = {
target: "http://localhost:3001",
secure: false,
changeOrigin: true,
pathRewrite: { // 对请求路径进行重定向以匹配到正确的请求地址
"^/admin-web": "/admin-web",
},
};
// ten-web 的方向代理
PROXY_CONFIG["/ten_proxy"] = {
target: "http://localhost:3002",
secure: false,
changeOrigin: true,
pathRewrite: { // 对请求路径进行重定向以匹配到正确的请求地址
"^/ten_proxy": "",
},
};
module.exports = PROXY_CONFIG;
?portal?angular.json: ?
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "v8-portal-web:build",
"proxyConfig": "proxy.conf.js"
},
"configurations": {
"production": {
"browserTarget": "v8-portal-web:build:production"
}
}
},
3-3.app-routing.module.ts 添加路由
const routes: Routes = [
{
path: 'admin',
component: EmptyComponent,
children: [
{
path: '**',
component: EmptyComponent
}
]
},
{
path: 'ten',
component: EmptyComponent,
children: [
{
path: '**',
component: EmptyComponent
}
]
},
...
4.总结?
?案例代码Git?仓储地址::angualr-ngx-planet-self · GitLab
以上就是angular 最全也最简单的实现方案
5.报错处里 及注意事项
报错?An accessor cannot be declared in an ambient context.
一般出现在angular8或更低的版本TypeScript 某个版本的缺陷?
tsconfig.app.json? ?"skipLibCheck": true
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": [],
"skipLibCheck": true
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"src/test.ts",
"src/**/*.spec.ts"
]
}
style报错:
?
注意事项:
|