fastify / point-of-view

Template rendering plugin for Fastify
MIT License
335 stars 86 forks source link

Proposal: Remove `send` calls #412

Closed mweberxyz closed 3 months ago

mweberxyz commented 5 months ago

Prerequisites

Issue

I'd like to propose a semver-major change: remove remaining calls to send throughout the plugin. Instead, the async reply decorator would always return a promise resolving to the rendered html.

This would necessitate docs, test, and code changes. It would require a prominent "Breaking Changes" to be added to README.md.

Pros

Cons

Samples

README.md - Quick start

fastify.get("/", (req, reply) => {
  return reply.view("/templates/index.ejs", { text: "text" });
});

Alternatives

As a less-invasive alternative, perhaps a reply decorator such as ${propertyName}Safe or ${propertyName}AsPromise could be implemented, with all of the semantics described above, and keep the existing reply decorator as-implemented.

Uzlopak commented 5 months ago

Are you referring to calls to @fastify/send?

Uzlopak commented 5 months ago

Scratch that, we dont use this in this repo.

mweberxyz commented 5 months ago

Essentially, the implementation would be changing this:

  fastify.decorateReply(propertyName, async function (page) {
    if (!page) {
      this.send(new Error('Missing page'))
    }
    try {
      const result = await renderer.apply(this, arguments)
      if (!this.getHeader('Content-Type')) {
        this.header('Content-Type', 'text/html; charset=' + charset)
      }

      if (minify && !isPathExcludedMinification(this)) {
        this.send(minify(result, globalOptions.htmlMinifierOptions))
      } else {
        this.send(result)
      }
    } catch (err) {
      this.send(err)
    }
    return this
  })

to this:

  fastify.decorateReply(propertyName, async function (page) {
    if (!page) {
      throw new Error('Missing page')
    }

    const promise = renderer.apply(this, arguments)
      .then((result) => {
        if (!this.getHeader('Content-Type')) {
          this.header('Content-Type', 'text/html; charset=' + charset)
        }
        return result
      })

    if (minify && !isPathExcludedMinification(this)) {
      return promise.then((result) => minify(result, globalOptions.htmlMinifierOptions))
    }

    return promise
  })

Writing it out I realize a few things:

mcollina commented 4 months ago

Can you put it behind a flag for backward compatibility?