我正在制作Angular + NestJS应用,我想为所有路由发送index.html
文件。
main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useStaticAssets(join(__dirname, '..', 'frontend', 'dist', 'my-app'));
app.setBaseViewsDir(join(__dirname, '..', 'frontend', 'dist', 'my-app'));
await app.listen(port);
}
app.controller.ts
@Controller('*')
export class AppController {
@Get()
@Render('index.html')
root() {
return {};
}
}
当我打开localhost:3000/
时,它可以正常工作,但是如果我打开localhost:3000/some_route
,则服务器与500 internal error
一起运行并显示Can not find html module
。
我正在搜索为什么会收到此错误,而每个人都说set default view engine like ejs or pug
,但是我不想使用某些引擎,我只想发送由angular构建的纯html,而不会像res.sendFile('path_to_file')
那样被黑客入侵。请帮助
答案 0 :(得分:1)
您只能将setBaseViewsDir
和@Render()
与诸如把手(hbs)之类的视图引擎一起使用;用于提供静态文件(Angular),但是,您只能使用useStaticAssets
和response.sendFile
。
要通过其他所有路线投放index.html
,您可以选择以下几种方式:
您可以创建执行重定向的中间件,请参见以下article:
@Middleware()
export class FrontendMiddleware implements NestMiddleware {
resolve(...args: any[]): ExpressMiddleware {
return (req, res, next) => {
res.sendFile(path.resolve('../frontend/dist/my-app/index.html')));
};
}
}
,然后为所有路由注册中间件:
export class ApplicationModule implements NestModule {
configure(consumer: MiddlewaresConsumer): void {
consumer.apply(FrontendMiddleware).forRoutes(
{
path: '/**', // For all routes
method: RequestMethod.ALL, // For all methods
},
);
}
}
您可以将所有NotFoundExceptions
重定向到您的index.html
:
@Catch(NotFoundException)
export class NotFoundExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.sendFile(path.resolve('../frontend/dist/my-app/index.html')));
}
}
,然后将其注册为main.ts
中的全局过滤器:
app.useGlobalFilters(new NotFoundExceptionFilter());
答案 1 :(得分:0)
您还可以将Cloud Functions for Firebase与Firebase Hosting一起使用。您在 main.ts 中拥有的一切都很好,使用这种方法,您甚至不需要控制器。您应该执行以下操作:
index.html
重命名为index2.html
。这对于渲染路径很重要,否则,除了根/
以外,所有路径上的渲染效果都很好。angular.json
使其具有以下"index": "apps/myapp/src/index2.html",
(将index.html
更改为index2.html
)。 注意:index.html的路径可能与您不同,我正在使用Nx工作区。templatePath: join(BROWSER_DIR, 'index2.html'),
添加到NestJS的ApplicationModule
中,很可能是在服务器目录中将文件命名为 app.module.ts 。像这样:
@Module({
imports: [
AngularUniversalModule.forRoot({
bundle: require('./path/to/server/main'), // Bundle is created dynamically during build process.
liveReload: true,
templatePath: join(BROWSER_DIR, 'index2.html'),
viewsPath: BROWSER_DIR
})
]
})
初始化Firebase云功能和Firebase托管,有关如何设置的信息,请检查https://hackernoon.com/deploying-angular-universal-v6-with-firebase-c86381ddd445或https://blog.angularindepth.com/angular-5-universal-firebase-4c85a7d00862
编辑您的 firebase.json 。
应该看起来像这样,或者至少是hosting
部分。
{
"hosting": {
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"public": "functions/dist/apps/path/to/browser",
"rewrites": [
{
"function": "angularUniversalFunction",
"source": "**"
}
]
}
}
在极简主义的情况下,它会像这样:
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
admin.initializeApp(); // Initialize Firebase SDK.
const expressApp: Express = express(); // Create Express instance.
// Create and init NestJS application based on Express instance.
(async () => {
const nestApp = await NestFactory.create<NestExpressApplication>(
ApplicationModule,
new ExpressAdapter(expressApp)
);
nestApp.init();
})().catch(err => console.error(err));
// Firebase Cloud Function for Server Side Rendering (SSR).
exports.angularUniversalFunction = functions.https.onRequest(expressApp);
使用这种方法,您不必关心NestJS方面的路由。您可以在Angular端设置所有内容,仅此而已。 Angular负责路由。您可能已经注意到,这是服务器端渲染(SSR),但是可以结合使用用于Firebase的NestJS + Cloud Functions将所有路由重定向到index.html
(或更准确地说是index2.html
)。另外,您还可以免费获得SSR:)
展示项目:
1)Firebase的Angular + Angular Universal(SSR)+云功能:https://github.com/Ismaestro/angular8-example-app(缺少NestJS)。
2)Angular + NestJS:https://github.com/kamilmysliwiec/universal-nest(缺少Firebase的云功能)。
答案 2 :(得分:0)
2019年12月10日更新的答案
您需要创建用于发送react index.html的中间件
创建中间件文件
frontend.middleware.ts
import { NestMiddleware, Injectable } from '@nestjs/common';
import {Request, Response} from "express"
import { resolve } from 'path';
@Injectable()
export class FrontendMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: Function) {
res.sendFile(resolve('../../react/build/index.html'));
}
}
在其中包含中间件
app.module.ts
import { FrontendMiddleware } from './frontend.middleware';
import {
Module,
MiddlewareConsumer,
RequestMethod,
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
configure(frontEnd: MiddlewareConsumer) {
frontEnd.apply(FrontendMiddleware).forRoutes({
path: '/**', // For all routes
method: RequestMethod.ALL, // For all methods
});
}
}
应用参考结构: