Closed hug0b closed 5 years ago
Oh well I figured templates need to be outside of the src folder
Hello! How did you structured your project for transpilation from /src/templates to /dist/templates or /templates/ to /dist/templates? Thanks in advance!
@humbertowoody Like I wrote in my comment I put them in a folder outside of src
, at the root of the project.
Hi There, I put the templates folder in the root of the project and my app Module configures the mailer as follows:
imports: [
MailerModule.forRootAsync({
useFactory: () => ({
transport: 'smtps://user@domain.com:pass@smtp.domain.com',
defaults: {
from:'"nest-modules" <modules@nestjs.com>',
},
template: {
dir: __dirname + '/templates',
adapter: new HandlebarsAdapter(),
options: {
strict: true,
},
},
}),
}),
I have a file in the Root/templates/mailer.hbs
Here is the code for sending the email:
mailerService .sendMail({ to: toMail, subject, template: 'mailer', // The
.pugor
.hbsextension is appended automatically. context: { // Data to be sent to template engine. body, link, btn, }, });
I'm still getting the error that implies that the templates folder is not transpiled to the dist folder.
What could the problem possibly be?
@RenaldoV did you figure it out how to do this? I have similar issue.
Same problem !!
When Nestjs compiling files didn't copied template to dist
So I got it running. The trick is to copy the template files to the dist folder after it's compiled.
My steps
1) Add path to app.module.ts
import * as path from 'path';
2) my template object:
template: {
dir: path.join(__dirname, 'templates'),
adapter: new HandlebarsAdapter(),
options: {
strict: true,
},
},
3) Created a folder "templates" in the "src" folder and put my .hbs in there
4) Install npm module: cpx
5) Create a npm run command to copy the templates in package.json
"copy:templates": "cpx './src/templates/**' 'dist/templates'"
6) run the copy command after the the build
"build": "rimraf dist && tsc -p tsconfig.build.json && npm run copy:templates",
Now when I do npm run build , the templates are copied in the dist folder. yay!
I found a easy way to use without copy to dist folder.
const path = `${__dirname.split('dist')[0]}/x/src/common/templates`;
this
.mailerService
.sendMail({
to: 'x@x.com',
from: 'noreply@x.com',
subject: 'test',
template: `${path}/test.hbs`,
context: {
code: 'cf1a3f828287',
username: 'john doe',
},
})
.then(() => {})
.catch((e) => {
Logger.error(e);
});
I found a easy way to use without copy to dist folder.
const path = `${__dirname.split('dist')[0]}/x/src/common/templates`; this .mailerService .sendMail({ to: 'x@x.com', from: 'noreply@x.com', subject: 'test', template: `${path}/test.hbs`, context: { code: 'cf1a3f828287', username: 'john doe', }, }) .then(() => {}) .catch((e) => { Logger.error(e); });
Hmm I will try this. Not sure if it will work on Zeit Now. In order to make it work on Zeit Now, I need to build the Nest application first before uploading to Zeit Now and then Zeit Now will serve from dist/ folder.
But the problem is that when building the dist package on local, the templates are not copied into the dist package therefore they are not uploaded (even if I put it in src/ )
Actually there is an easier way to handle this.
nest comes with its own cli that can handle these kind of processes.
So in my configuration, I am using .hbs which is staying inside src/templates/[container]/[some-example-template].hbs
with modifying nest-cli.json file as given below, when the code is compiled templates folder structure is transfered to dist folder as intended.
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["**/*.hbs"]
}
}
@musyilmaz oh nice!!!! this works like a charm!
@fransyozef nice that it worked :) I think, adding this to readme and expanding the documentation might be a correct way.
Just complementing @musyilmaz solution (thanks for that), for default the compiler just copy the files to dist folder only when start. So if you change a template (when the project is runing in dev mode), its necessary to stop the compiler and start again to update the file in dist folder.
To enable the assets copy in watch mode, add the flag "watchAssets" to compilerOptions in nest-cli.json:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["**/*.hbs"],
"watchAssets": true
}
}
If you have more than one asset and don't want to turn on watch mode to all, its possible to turn on just in the templates:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [
{ "include": "**/*.hbs", "watchAssets": true },
{ "include": "**/*.txt" }
]
}
}
Like @musyilmaz said, I think this is important to be in documentation too.
My reference: https://docs.nestjs.com/cli/monorepo#assets
@VictorAssis Watch mode does hear the changes from the .hbs files ? because it is not in my case, only if I create new files it hears but not the changes in self.
@ruslanguns By default Watch mode does not update .hbs files as they are changed. I managed to solve this by adding the above settings to nest-cli.json.
yes, I actually have modified the nest-cli.json in order to add them, however typescript only updates/watch when I create a new file with extension .hbs BUT NOT the code changes in the files. Do you have the same issue or it's only me?
I am not having this problem here. Can you send your nest-cli.json and your package.json here?
@VictorAssis I'm having the same issue with .ejs
files.. when I update the contents of a .ejs
file it does not detects it and it does not restart the app.
Here's the contents of my nest-cli.json
:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["**/*.ejs"]
},
"watchAssets": true
}
and here's the contents for my package.json
:
{
"name": "coachspace-backend",
"version": "0.0.1",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@alphaapps/nestjs-auth": "^1.2.93",
"@alphaapps/nestjs-common": "^1.2.97",
"@alphaapps/nestjs-config": "^1.2.68",
"@alphaapps/nestjs-db": "^1.2.68",
"@hapi/joi": "^17.1.1",
"@nestjs/common": "^7.3.2",
"@nestjs/core": "^7.3.2",
"@nestjs/jwt": "^7.1.0",
"@nestjs/passport": "^7.1.0",
"@nestjs/platform-express": "^7.3.2",
"@nestjs/sequelize": "^0.1.0",
"@nestjs/swagger": "^4.5.12",
"@nestjsx/crud": "^4.6.2",
"@nestjsx/crud-request": "^4.6.2",
"@sentry/node": "^5.20.1",
"@shelf/winston-datadog-logs-transport": "^2.0.0",
"accesscontrol": "^2.2.1",
"aws-sdk": "^2.721.0",
"axios": "^0.20.0",
"bcrypt": "^5.0.0",
"class-transformer": "^0.2.3",
"class-validator": "^0.12.2",
"config": "^3.3.1",
"debug": "^4.1.1",
"ejs": "^3.1.5",
"express-rate-limit": "^5.1.3",
"firebase-admin": "^9.0.0",
"google-libphonenumber": "^3.2.10",
"hashids": "^2.2.1",
"lodash": "^4.17.19",
"mime-types": "^2.1.27",
"moment": "^2.27.0",
"nest-access-control": "^2.0.2",
"nest-router": "^1.0.9",
"nest-winston": "^1.3.6",
"passport": "^0.4.1",
"passport-anonymous": "^1.0.1",
"passport-jwt": "^4.0.0",
"pg": "^8.3.0",
"rate-limit-redis": "^2.0.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^6.6.0",
"sequelize": "5.21.12",
"sequelize-typescript": "^1.1.0",
"swagger-ui-express": "^4.1.4",
"twilio": "^3.49.0",
"winston": "^3.3.3",
"winston-daily-rotate-file": "^4.5.0",
"winston-transport": "^4.4.0"
},
"devDependencies": {
"@nestjs/cli": "^7.5.1",
"@nestjs/schematics": "^7.0.1",
"@nestjs/testing": "^7.3.2",
"@types/bcrypt": "^3.0.0",
"@types/express": "^4.17.7",
"@types/google-libphonenumber": "^7.4.19",
"@types/hapi__joi": "^17.1.4",
"@types/jest": "26.0.7",
"@types/jsonwebtoken": "^8.5.0",
"@types/mime-types": "^2.1.0",
"@types/node": "^14.0.26",
"@types/sequelize": "^4.28.8",
"@types/supertest": "^2.0.10",
"@typescript-eslint/eslint-plugin": "3.7.1",
"@typescript-eslint/parser": "3.7.1",
"chalk": "^4.1.0",
"chalk-table": "^1.0.2",
"eslint": "7.5.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-plugin-import": "^2.22.0",
"jest": "26.1.0",
"prettier": "^2.0.5",
"nestjs-command": "^1.5.0",
"rimraf": "^3.0.2",
"sequelize-cli": "^5.5.1",
"supertest": "^4.0.2",
"ts-jest": "26.1.3",
"ts-loader": "^8.0.1",
"ts-node": "^8.10.2",
"tsc-watch": "^4.2.9",
"tsconfig-paths": "^3.9.0",
"typescript": "^3.9.7"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
I'm calling the npm run start:dev
command in dev mode.
@SamiSammour your "watchAssets" option is out of "compilerOptions", maybe this is the reason. Try this:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["**/*.ejs"],
"watchAssets": true
},
}
In case anyone lands here:
As of now for "@nestjs-modules/mailer": "^1.6.0"
even with properly configured watchAssets you won't see changes in templates.
The reason is here:
So templates are only compiled once per application run and currently, there is no way to change this behaviour. And the application does not reload on assets change. I did not go the route of figuring out how to make it reload. Instead, I have yielded this possible solution with a minimal hack:
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
import { MailerOptions } from '@nestjs-modules/mailer';
export class CustomEmailHandlebarsAdapter extends HandlebarsAdapter {
compile(mail: any, callback: any, mailerOptions: MailerOptions) {
super.compile(
mail,
(res) => {
if (mailerOptions.template.options.disableTemplateCache) {
//@ts-ignore
this.precompiledTemplates = {}
}
if (typeof callback === 'function') {
callback(res)
}
},
mailerOptions
);
}
}
Afterwards, it is possible to configure mailer template sections as such:
template: {
adapter: new CustomEmailHandlebarsAdapter(),
options: {
strict: true,
disableTemplateCache: config.get('NODE_ENV') === 'development'
},
},
I had a problem where templates where copied to dist
folder instead of dist/src
.
I updated nest-cli.json
to make it work:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [{ "include": "mail/templates/**/*", "outDir": "dist/src" }],
"watchAssets": true
}
}
outDir
tells compiler to copy templates to dist/src
folder, it works now.
i'm using serverless and the templates are not included in the deployment package that is copied to AWS.
i've updated the nest-cli.json
to look like this:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [{ "include": "utils/emails/templates/**/*", "outDir": "dist/src" }],
"watchAssets": true
}
}
what am i doing wrong?
The problem I discovered is that SOMETIMES
nest build
command doesn't read the include
path correctly when it ends with a file extension.
So instead of doing:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["@nestjs/swagger"],
"assets": [
{
"include": "**/mail/template/**/*.hbs",
"outDir": "dist/src",
"watchAssets": true
}
]
}
}
Do
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["@nestjs/swagger"],
"assets": [
{
"include": "**/mail/template/**/*",
"outDir": "dist/src",
"watchAssets": true
}
]
}
}
In my observation, when it ends with .hbs
, it copied the files successfully some times, but when I removed the .hbs
, the files are copied successfully all times
I had no nest-cli.json by default using NX monorepo, Created json file manually, tried everything. Then I ended up manually copying the template to dist folder and it worked. I don't know if it's right approach or not.
This is quite ugly code but might be helpful to some. I've reverted to simply using two paths for my template directories. During development, I will use my non-dist folder and for production purposes, I will use the corresponding dist
folder. Of course, this comes with its own caveats (Can we guarantee that dev and prod will match?).
This way it works for me and I find it ugly but manageable:
Example use
const compiledFunction = compileFile(
process.env.NODE_ENV === 'development'
? `${process.cwd()}/src/digest/templates/editor.content-list.pug`
: path.join(
path.dirname(path.dirname(__dirname)),
'digest/templates/editor.content-list.pug',
),
);
nest-cli.json
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["**/*.pug"],
"watchAssets": true
}
}
Actually there is an easier way to handle this.
nest comes with its own cli that can handle these kind of processes.
So in my configuration, I am using .hbs which is staying inside
src/templates/[container]/[some-example-template].hbs
with modifying nest-cli.json file as given below, when the code is compiled templates folder structure is transfered to dist folder as intended.
{ "collection": "@nestjs/schematics", "sourceRoot": "src", "compilerOptions": { "assets": ["**/*.hbs"] } }
That worked for a fresh monolith project.. Do you have any idea about a monorepo application?. it is not working there :(
实际上有一种更简单的方法来处理这个问题。 nest 带有自己的 cli 可以处理这些类型的进程。 所以在我的配置中,我使用的是留在里面的 .hbs
src/templates/[container]/[some-example-template].hbs
通过如下所示修改 nest-cli.json 文件,当编译代码时,模板文件夹结构按预期传输到 dist 文件夹。{ "collection": "@nestjs/schematics", "sourceRoot": "src", "compilerOptions": { "assets": ["**/*.hbs"] } }
这适用于一个新的单体项目。你对 monorepo 应用程序有任何想法吗?它在那里不起作用:(
Hi, bro, Have you solved this problem?
实际上有一种更简单的方法来处理这个问题。 nest 带有自己的 cli 可以处理这些类型的进程。 所以在我的配置中,我使用的是留在里面的 .hbs
src/templates/[container]/[some-example-template].hbs
通过如下所示修改 nest-cli.json 文件,当编译代码时,模板文件夹结构按预期传输到 dist 文件夹。{ "collection": "@nestjs/schematics", "sourceRoot": "src", "compilerOptions": { "assets": ["**/*.hbs"] } }
这适用于一个新的单体项目。你对 monorepo 应用程序有任何想法吗?它在那里不起作用:(
Hi, bro, Have you solved this problem?
I could not get nest to do the auto copy into the dist folder for monorepo applications. So, I instead made a workaround writing scripts in package.json like so:
{
"name": "someProject",
"version": "0.0.1",
"scripts": {
"start:all": "concurrently \"nest start admin --watch\" \"nest start customer --watch\" \"npm run copy:admin\" \"npm run copy:customer\"", ## call copy:admin and copy:customer from scripts below
"copy:admin": "mkdir .\\dist\\apps\\admin\\templates && cp.exe -R libs/common/src/email/templates/* dist/apps/admin/templates/ ", ## actual workaround to make directory and copy files from templates folder to dist folder
"copy:customer": "mkdir .\\dist\\apps\\customer\\templates && cp.exe -R libs/common/src/email/templates/* dist/apps/customer/templates/" ## actual workaround to make directory and copy files from templates folder to dist folder
"start:customer": "nest start customer --watch",
"start:admin": "nest start admin --watch",
"build": " npm run build:customer && npm run build:admin",
"build:customer": "nest build customer && cp.exe package.json dist/apps/customer/ && npm run copy:customer",
"build:admin": "nest build admin && cp.exe package.json dist/apps/admin/ && npm run copy:admin",
},
"dependencies": {
"@nestjs/common": "^8.0.0",
"@nestjs/core": "^8.0.0",
"concurrently": "^7.1.0" ## Added concurrently to run admin/customer module concurrently
}
}
@RamenSayami Hi, bro, I may have found an easier way:
we should update workspace.json
to make nx auto copy assets files to dist folder . Please try it :D
inspired by: https://nx.dev/nx-plugin/overview#including-assets
For those of you who get error that file not found error.
So, I'll try to put some clarifications too, because it took me 3 hours to figure out!!! Here is what worked for me.
For example you have following structure
.
├── project
│ └── src
│ └── mymodule
│ ├── templates
│ │ └── myemail.hbs
│ └── app.module.ts <== here you import MailerModule
└── ...
nest-cli.json
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["**/*.hbs"],
"watchAssets": true
}
}
//app.module.ts
...
MailerModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
...
template: {
// __dirname = is current COMPILED JS file directory, for example /app/dist
// put email templates (*.hbs) in template root directory, no SUBDIRECTORIES in templates root directory!!!
// when sending emails, template name must be just 'templatename' (without ./ or /)
dir: __dirname + '/mymodule/templates',
adapter: new HandlebarsAdapter(),
options: {
strict: true,
},
},
}),
inject: [ConfigService],
}),
...
Somewhere in your service
this.mailerService.sendMail({
...
template: 'myemail', // NO preceding "./"
...
})
Now i get this
error TS5023: Unknown compiler option 'assets'.
Looks like we can no longer use assets in the tsconfig compileroptions?
Now i get this
error TS5023: Unknown compiler option 'assets'.
Looks like we can no longer use assets in the tsconfig compileroptions?
I think you are using the wrong file to add the compilerOptions configuration. You have to put the configuration inside of nest-cli.json
file
yes im using tsconfig.json does it not work there?
yes im using tsconfig.json does it not work there?
No, It has to be in nest-cli.json
🙁 . Are you using NestJS right?
It hit me in the face today when I moved one of our mailing micro service.
here's how I solved it.
nestcli.json to copy the folder to dist location.
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [{ "include": "concerns/mail/templates/**/*", "outDir": "dist/src/" }],
"watchAssets": true
}
}
template: {
// For some reason this stopped working don't know why
//path.resolve(__dirname, "templates"),
// i have to manually resolve path
dir: join(__dirname, '..', 'mail', 'templates'),
adapter: new HandlebarsAdapter(),
options: {
strict: true
},
},
I was using a NX monorepo with nestjs and I have to configure the webpack using a plugin for it
const { composePlugins, withNx } = require('@nrwl/webpack'); const path = require("path"); const HandlebarsPlugin = require("handlebars-webpack-plugin");
thats solve my problem
// Nx plugins for webpack.
module.exports = composePlugins(withNx(), (config) => {
// Update the webpack config as needed here.
// e.g. `config.plugins.push(new MyPlugin())`
config.plugins.push(new HandlebarsPlugin({
// path to hbs entry file(s). Also supports nested directories if write path.join(process.cwd(), "app", "src", "**", "*.hbs"),
entry: path.join(process.cwd(), "apps", "api", "src", "app", "mailer", "templates", "*.hbs"),
// output path and filename(s). This should lie within the webpacks output-folder
// if ommited, the input filepath stripped of its extension will be used
output: path.join(process.cwd(), "dist", "apps", "api", "templates", "[name].hbs"),
// you can also add a [path] variable, which will emit the files with their relative path, like
// output: path.join(process.cwd(), "build", [path], "[name].html"),
}))
return config;
});
I think you need to change the nest-cli.json file. You need to specify the output directory in the assets to let nest know where to output your templates files.
"compilerOptions": {
"deleteOutDir": true,
"assets": [{ "include": "templates/**/*", "outDir": "dist/" }],
"watchAssets": true
}
My whole nest-cli.json file is like this
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"assets": [{ "include": "templates/**/*", "outDir": "dist/" }],
"watchAssets": true
}
}
@ghost worked! { "collection": "@nestjs/schematics", "sourceRoot": "src", "compilerOptions": { "assets": ["*/.hbs"] } }
adding ../ in the beginning worked for me
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"assets": [
{
"include": "../src/custom-mailer/templates/**/*",
"outDir": "dist/custom-mailer/templates",
"watchAssets": true
}
]
}
}
So I got it running. The trick is to copy the template files to the dist folder after it's compiled.
My steps
- Add path to app.module.ts
import * as path from 'path';
- my template object:
template: { dir: path.join(__dirname, 'templates'), adapter: new HandlebarsAdapter(), options: { strict: true, }, },
- Created a folder "templates" in the "src" folder and put my .hbs in there
- Install npm module: cpx
- Create a npm run command to copy the templates in package.json
"copy:templates": "cpx './src/templates/**' 'dist/templates'"
- run the copy command after the the build
"build": "rimraf dist && tsc -p tsconfig.build.json && npm run copy:templates",
Now when I do npm run build , the templates are copied in the dist folder. yay!
Thanks man! That was quite helpful. I wasted hours trying to fix this issue
Node.js 10.16.0 @nest-modules/mailer 1.1.3 nestjs 6.5.2
When sending an email using handlebars I get the following error:
Mailer config