Files
nullcart/backend/src/main.ts
T
nobswebdev 0dcffb394e Cache storefront images aggressively while keeping CSS revalidatable.
Split static asset mounts by type and centralize paths in storefrontAssetPaths so icon URLs stay aligned with the server.
2026-09-07 14:06:44 +02:00

110 lines
4.3 KiB
TypeScript

import { RequestMethod, ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { ConfigService } from '@nestjs/config';
import cookieParser from 'cookie-parser';
import hbs from 'hbs';
import path from 'node:path';
import {
getStorefrontCssDir,
getStorefrontImgDir,
storefrontCssUrlPrefix,
storefrontImgUrlPrefix
} from './config/storefrontAssetPaths';
import { getPublicUploadsDir, publicUploadsUrlPrefix } from './config/uploadPaths';
import { AppModule } from './AppModule';
import { registerStorefrontHelpers } from './modules/storefrontCore/utils/registerStorefrontHelpers';
import { registerStorefrontPartials } from './modules/storefrontCore/utils/registerStorefrontPartials';
import { shopSurfaceHeaderMiddleware } from './middleware/shopSurfaceHeaderMiddleware';
import { Config } from './types/Config';
import { NodeEnv } from './types/NodeEnv';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
const configService = app.get(ConfigService);
const { port, corsOrigins, nodeEnv } = configService.get('app') as Config['app'];
app.useStaticAssets(getPublicUploadsDir(), {
prefix: publicUploadsUrlPrefix,
maxAge: '1y',
immutable: true
});
app.useStaticAssets(getStorefrontImgDir(), {
prefix: storefrontImgUrlPrefix,
maxAge: '1y',
immutable: true
});
app.useStaticAssets(getStorefrontCssDir(), {
prefix: storefrontCssUrlPrefix
});
app.use(cookieParser());
if (nodeEnv === NodeEnv.Production) {
app.use(shopSurfaceHeaderMiddleware);
}
const storefrontViewsDir = path.join(__dirname, 'modules', 'storefrontCore', 'views');
registerStorefrontHelpers(hbs);
registerStorefrontPartials(hbs, path.join(storefrontViewsDir, 'partials'));
app.setBaseViewsDir(storefrontViewsDir);
app.setViewEngine('hbs');
app.set('view options', { layout: 'layouts/shop' });
app.set('trust proxy', 1);
app.useGlobalPipes(
new ValidationPipe({
transform: true,
transformOptions: { enableImplicitConversion: true }
})
);
app.setGlobalPrefix('api', {
exclude: [
{ path: '/', method: RequestMethod.GET },
{ path: 'shop/categories/:id', method: RequestMethod.GET },
{ path: 'shop/products/:id/variants/:variantId', method: RequestMethod.GET },
{ path: 'shop/assets/{*path}', method: RequestMethod.GET },
{ path: 'shop/preferences/theme', method: RequestMethod.POST },
{ path: 'shop/error', method: RequestMethod.GET },
{ path: 'shop/cart', method: RequestMethod.GET },
{ path: 'shop/cart/product', method: RequestMethod.POST },
{ path: 'shop/cart/product/update', method: RequestMethod.POST },
{ path: 'shop/cart/product/remove', method: RequestMethod.POST },
{ path: 'shop/cart/discount', method: RequestMethod.POST },
{ path: 'shop/cart/discount/remove', method: RequestMethod.POST },
{ path: 'shop/checkout/pay', method: RequestMethod.POST },
{ path: 'shop/checkout', method: RequestMethod.GET },
{ path: 'shop/checkout/cancel', method: RequestMethod.POST },
{ path: 'shop/check-order', method: RequestMethod.GET },
{ path: 'shop/check-order', method: RequestMethod.POST },
{ path: 'shop/order/:orderId', method: RequestMethod.GET },
{ path: 'shop/order/:orderId/refresh', method: RequestMethod.GET },
{ path: 'shop/order/:orderId/confirm-access-token-saved', method: RequestMethod.POST },
{ path: 'shop/order/:orderId/logout', method: RequestMethod.POST },
{ path: 'shop/order/:orderId/messages', method: RequestMethod.POST },
{ path: 'shop/order/:orderId/messages/:messageId/delete', method: RequestMethod.POST },
{
path: 'shop/order/:orderId/attachments/:attachmentId/download',
method: RequestMethod.GET
}
]
});
app.enableCors({
origin: corsOrigins,
credentials: true
});
await app.listen(port);
}
void bootstrap();