3

I'm trying to use pug layouts in NestJS, however when extending a layout from an absolute path, pug requires the basedir option to be set.

In ExpressJS you would use app.locals.basedir = ..., what would be the equivalent in NestJS?

const server = await NestFactory.create<NestExpressApplication>(AppModule);
server.setViewEngine('pug');
server.setBaseViewsDir(join(__dirname, 'templates', 'views'));
await server.listen(config.server.port);

Using extends /layouts/index in a view would throw the following; the "basedir" option is required to use includes and extends with "absolute" paths.

I'm not looking to use relative paths, since this quickly becomes very messy. E.g. extends ../../../layouts/index

woutr_be
  • 9,532
  • 24
  • 79
  • 129

2 Answers2

6

From what I can tell, you can achieve the same functionality as /layouts/index with just using layout/index so long as layout is a folder in your templates/views directory.

I've set up a git repo as a working example so you can test it out yourself and see if I need to go in more depth about anything.

EDIT 6/27/2019:

Thank you, I misunderstood your initial question.

With creating and express based application, you can send an express server to the NestFactory to use that server instance instead of having Nest create a plain instance for you. From here you can set up the express server as you normally would and get the desired functionality. I've modified the git repo to be able to test the scenario better and believe this is what you are looking for.

My main.ts

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication, ExpressAdapter } from '@nestjs/platform-express';
import * as express from 'express';
import { AppModule } from './app.module';
import { join } from 'path';

async function bootstrap() {
  // Creating and setting up the express instanced server
  const server = express();
  server.locals.basedir = join(__dirname, '..', 'views');
  // Using the express server instance in the nest factory
  const app = await NestFactory.create<NestExpressApplication>(AppModule, new ExpressAdapter(server));
  app.useStaticAssets(join(__dirname, '..', 'public'));
  app.setBaseViewsDir(join(__dirname, '..', 'views'));
  app.setViewEngine('pug');
  await app.listen(3000);
}
bootstrap();

Overall the folder set up is like so

src
|-app.controller.ts
|-app.module.ts
|-app.service.ts
|-main.ts
views
|-hello
  |-home.pug
|-message
  |-message.pug
|-templates
  |-layout.pug

And the beginning of my home.pug and message.pug files is extends /templates/layout

Jay McDoniel
  • 57,339
  • 7
  • 135
  • 147
  • Thanks for your answer, but like I indicated in the question, I’m not looking to use relative paths. – woutr_be Jun 27 '19 at 01:29
  • You're right! I totally misinterpreted that. See the edit for an updated answer. – Jay McDoniel Jun 27 '19 at 15:16
  • 1
    Saw your edit a bit late, but you're right, however Nest will create it's own Express instance that you can access with `getHttpAdapter().getInstance()`, from there you're able to set the `locals.basedir`. – woutr_be Jun 28 '19 at 02:13
  • Both are viable options. Nest will create its own instance if one is not already passed to it. I saw Kamil respond to your GitHub issue with the `getHttpAdatper().getInstance()`. I think that overall is a better approach, but it is nice to know both work. – Jay McDoniel Jun 28 '19 at 02:52
2

After looking around through the documentation, NestJS uses an express under the hood, and gives you access to the underlying instance with getHttpAdapter().getInstance().

Keeping that in mind, we can set the basedir as follows;

const express = server.getHttpAdapter().getInstance();
express.locals.basedir = join(__dirname, 'templates');
woutr_be
  • 9,532
  • 24
  • 79
  • 129