VeryGoodOpenSource / dart_frog

A fast, minimalistic backend framework for Dart 🎯
https://dartfrog.vgv.dev
MIT License
1.82k stars 148 forks source link

feat: HTML template support #90

Open paurakhsharma opened 2 years ago

paurakhsharma commented 2 years ago

Description As a user, I want to be able to respond with an HTML template.

If we don't want to implement it in this core project. Would love to see separate project to support it as a plugin either by VG team themselves or by the community.

felangel commented 2 years ago

Hi @paurakhsharma 👋 Thanks for opening an issue!

Can you please provide a bit more context regarding the expectation? Currently, you can create an endpoint that responds with html like:

import 'dart:io';

import 'package:dart_frog/dart_frog.dart';

Response onRequest(RequestContext context) {
  return Response(
    body: '<p>Hello World</p>',
    headers: {HttpHeaders.contentTypeHeader: ContentType.html.value},
  );
}
paurakhsharma commented 2 years ago

That is awesome. I can see we can use String interpolation for adding some values from the variable. But other things like looping or conditional rendering might be difficult.

I was thinking something like.

import 'dart:io';

import 'package:dart_frog/dart_frog.dart';

Response onRequest(RequestContext context) {
  return RenderTemplate(
            'index.html',
             params: {
                 "hello": "world",
                 "bestLanguages": ["Dart", "Dart"],
                 "isDartFrogAwesome": true,
              }
        );
}

And in templates/index.html

<p>Hello {{hello}}</p>

<div>
   {% for language in bestLanguages %}
        <li>{{ language|toUpperCase }}</li>
    {% endfor %}
</div>

{% if isDartFrogAwesome %}
    <p>Dart Frog is awesome 🚀</p>
{% endif %}
felangel commented 2 years ago

@paurakhsharma thanks for clarifying! I definitely think this can be supported via a separate package. I’ll discuss with the team and update the ROADMAP accordingly, thanks again 🙏

paurakhsharma commented 2 years ago

Amazing! Thank you so much 😊

AlvaroVasconcelos commented 2 years ago

What do you think of OverReact to assemble the html?

render() {
  return (Dom.div()..className = 'container')(
    Dom.h1()('Click the button!'),
    (Dom.button()
      ..id = 'main_button'
      ..onClick = _handleClick
    )('Click me')
  );
}
Mastersam07 commented 2 years ago

Hi, @felangel is it possible to return an HTML file directly in the response?

ushieru commented 2 years ago

@Mastersam07 Yes, you can.

// routes/index.dart

import 'dart:io';

import 'package:dart_frog/dart_frog.dart';
import 'package:path/path.dart' as path;

Response onRequest(RequestContext context) {
  final file = File(path.join(Directory.current.path, 'public', 'index.html'));
  if (!file.existsSync()) {
    return Response(body: 'Index Not found');
  }
  final indexHtml = file.readAsStringSync();
  return Response(body: indexHtml, headers: {'Content-Type': 'text/html'});
}
felangel commented 2 years ago

If you just want to respond with a static html file you can just serve the static asset

Mastersam07 commented 2 years ago

Thanks, @ushieru @felangel. I already found a solution to the issue.

AlvaroVasconcelos commented 1 year ago

What do you guys think of jasper?

Eghosa-Osayande commented 1 year ago

Hello @paurakhsharma @felangel

I recently wrote an article that illustrates how to use HTML templates in a dart frog application using the jinja package. https://yande.hashnode.dev/jinja-html-templates-with-dart-frog

A Quick Explanation:

pubspec.yaml

dependencies:
    ...
    jinja: ^0.5.0

routes/index.dart

import 'package:dart_frog/dart_frog.dart';
import 'package:jinja/jinja.dart';
import 'package:jinja/loaders.dart';

Response onRequest(RequestContext context) {
  final environment = Environment(
    loader: FileSystemLoader(
      paths: [
        'templates'
      ],
    ),
  );

  final template = environment.getTemplate(
    'base.html',
  );

  final tutorials = [
    'Jinja Templates Tutorial',
    'Flutter Tutorials',
    'Dart Fundamentals',
  ];

  return Response(
    body: template.render({
      'title': 'Home',
      'tutorials': tutorials,
    }),
    headers: {
      'Content-Type': 'text/html'
    },
  );
}

templates/base.html

<html lang="en">

<head>

  <meta charset="utf-8">

  <title>{{ title }}</title>

</head>

<body>

  <h1>Welcome to {{ title }}!</h1>

  {% for tutorial in tutorials %}

  <ul>

    <li>

      {{ tutorial }}</em>

    </li>

  </ul>

  {% endfor %}

</body>

</html>

Output

Screenshot 2023-08-22 at 17 21 39

I hope this helps.

Mastersam07 commented 1 year ago

Nice read @Eghosa-Osayande

I also resorted to using jinja templating given that i have background in django and used jinja template in the past. I forgot to mention in my last update on this issue.