现在前后端分离
前后端分离已成为一种趋势,前端不再提供专门的机器进行部署,而是采用发布到CDN的方式,同时在启动后端服务的时候,设置一个根路由,通过get方法获取CDN地址的index.html 文件绑定到路由上,即可实现服务的正常运行。
好处就是前端发布非常方便,CND可采用依赖版本号的方式,升级非常容易。
个人遇到的问题
问题一、发布后,本地访问不到静态资源文件(baseUrl 和 deployUrl搞混了)
环境信息
server 端: nodejs, egg工程,启动了个localhost:18081的服务;
client 端: ts angular8工程,启动了个localhost:9991的服务(就是用来放静态资源)
打包:client 使用默认的 ng build 进行打包,打包完之后放在src同级目录dist下。
server端使用的html如下,大家看出来问题没有
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ConsoleManageClient</title>
<base href="http://localhost:9991/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
<script src="runtime.js" type="module"></script>
<script src="polyfills.js" type="module"></script>
<script src="styles.js" type="module"></script>
<script src="vendor.js" type="module"></script>
<script src="main.js" type="module"></script>
</body>
</html>
如下是server端使用正确的index.html, 也是client端正常生成的index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ConsoleManageClient</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
<script src="http://localhost:9991/runtime.js" type="module"></script>
<script src="http://localhost:9991/polyfills.js" type="module"></script>
<script src="http://localhost:9991/styles.js" type="module"></script>
<script src="http://localhost:9991/vendor.js" type="module"></script>
<script src="http://localhost:9991/main.js" type="module"></script>
</body>
</html>
你会发现有两处不一样:
1、base href="/" 这个是路由的根地址,建议最好默认为 "/";
2、script src="http://localhost:9991/runtime.js" 这个src要指向静态服务器的地址,才能正确取到资源。
问题二、发布后,本地访问不到 assets下的国际化文件或者图片等静态资源文件(代码中)
angular.json 中关于静态资源assets的打包处理是这样的,其实就是直接copy到对应目录
{
"projects": {
"ConsoleManageClient": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "less"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.less"
],
"scripts": []
},
}
// 环境变量中设置
export const environment = {
production: false,
cdnAddr: 'http://localhost:9991',
};
// app.module.ts中设置
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, environment.cdnAddr + '/assets/i18n/', '.json');
}
@NgModule({
declarations: [
AppComponent
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
AppRoutingModule,
xxxModule,
TranslateModule.forRoot({
loader: {
useFactory: HttpLoaderFactory
},
}),
]
})
仔细看 environment.cdnAddr 使用的地方,使用了http请求的方式,增加了环境变量参数,这样每次就能取到CDN的资源了,如果没有前缀,取到的就是 server:18081/下的东西,拿不到资源。
总结:
本地开发打包使用 ng build --watch --deploy-url http://localhost:9991/
生产环境打包使用 npx ng build --prod --deploy-url http://cdnxxx/
client端代码静态资源地址获取也要配置CND的前缀地址