-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(root): refactor control compilation #7590
base: next
Are you sure you want to change the base?
feat(root): refactor control compilation #7590
Conversation
✅ Deploy Preview for dashboard-v2-novu-staging ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
✅ Deploy Preview for dev-web-novu ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
commit: |
const templateControls = await this.createStepControls(step, event); | ||
|
||
if (this.compileControls) { | ||
controls = await this.renderTemplateControls(templateControls, event); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, the framework compiles the controls by default. However, if the user prefers to compile the controls themselves, they have the option to do so.
* Whether to compile controls. | ||
* Defaults to true. | ||
*/ | ||
compileControls?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, this is a global option. However, we could make it more granular in the future, for example, configurable on a per-step basis.
@@ -33,7 +34,7 @@ export class EmailOutputRendererUsecase { | |||
|
|||
const liquifiedMaily = this.wrapMailyInLiquidUsecase.execute({ emailEditor: body }); | |||
const transformedMaily = await this.transformMailyContent(liquifiedMaily, renderCommand.fullPayloadForRender); | |||
const parsedMaily = await this.parseMailyContentByLiquid(transformedMaily, renderCommand.fullPayloadForRender); | |||
const parsedMaily = await parseLiquid(transformedMaily, renderCommand.fullPayloadForRender); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Main purpose of this PR:
Previously, the framework would parse controls once before execution, and then parse them again during execution.
With this update, controls are parsed only once, improving efficiency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the compileControls
flag required for this improvement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is driven by two main reasons:
- Performance Improvement: The most obvious benefit is improving performance, as we no longer compile multiple times.
- Flexibility and Bug Prevention: The second reason is increased flexibility and the potential to address bugs, which I will elaborate on.
From the beginning, we relied on maily.variable.type
, but there came a point when we considered decoupling from maily.variable.type
and switching to maily.text.type
using the simple text with {{...}}
syntax. This approach would allow us to manage variables independently using Liquid, a change I support because it grants us greater control and simplifies our codebase.
Why is this important? If we do not control the content rendering process and the framework renders the controls before we execute the "render" step, it could lead to bugs like the one mentioned. Taking control of the rendering process helps prevent such issues.
|
||
// Only evaluate a skip condition when the step is the current step and not in preview mode. | ||
if (!isPreview && stepId === event.stepId) { | ||
const templateControls = await this.createStepControls(step, event); | ||
const controls = await this.compileControls(templateControls, event); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change removes the second (for all client users) or third (for email Novu users) duplicate control compilation, simplifying the process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, would love to hear some other thoughts on the compileControls terminology 🙏
return JSON.parse(renderedString); | ||
} | ||
|
||
export async function parseLiquidString(value: string, variables: object): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A small question, is it possible some how to reuse the same liquid instance from the framework SDK? The reason I'm asking is because we might want to add custom liquid filters to the system, and in this case we will have to duplicate them twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, i thought about it as well, we need to find a good way to export it from @novu/framework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can export it from @novu/framework/internals
.
@@ -33,7 +34,7 @@ export class EmailOutputRendererUsecase { | |||
|
|||
const liquifiedMaily = this.wrapMailyInLiquidUsecase.execute({ emailEditor: body }); | |||
const transformedMaily = await this.transformMailyContent(liquifiedMaily, renderCommand.fullPayloadForRender); | |||
const parsedMaily = await this.parseMailyContentByLiquid(transformedMaily, renderCommand.fullPayloadForRender); | |||
const parsedMaily = await parseLiquid(transformedMaily, renderCommand.fullPayloadForRender); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the compileControls
flag required for this improvement?
return JSON.parse(renderedString); | ||
} | ||
|
||
export async function parseLiquidString(value: string, variables: object): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can export it from @novu/framework/internals
.
What changed? Why was the change needed?
Screenshots
Expand for optional sections
Related enterprise PR
Special notes for your reviewer