dart-lang / language

Design of the Dart language
Other
2.67k stars 205 forks source link

Add support for "js tagged string like" feature #1987

Open dam0vm3nt opened 7 years ago

dam0vm3nt commented 7 years ago

ES6 tagged string are a powerfull feature that can be leveraged to easly build wonderfull things like template engines.

justinfagnani commented 7 years ago

Hey, author of lit-html and former Dart team member here :)

The technique behind lit-html is already proving to be extremely fast and lightweight for HTML templating, and now there's a proposal (that implementers are very interested in) being discussed to add something like the internals of lit-html directly to the web platform: https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Template-Instantiation.md

It's really nice to be able to write HTML templates in your programming language where you have direct access to data, can use first-class language constructs, and in a way that doesn't require any reflection. I've been thinking about how to do something similar in Dart, but it really does hinge on some specifics of tagged template literals that are not possible in Dart currently.

The key feature of tagged template literals for this use case is that they separate the literal parts from expression results, and pass the literals as a single, immutable argument that's guaranteed to be referentially identical across evaluations of the tagged literal.

lit-html.dart:

Map<TemplateLiteralStrings, Template> _templateCache;

TemplateResult html(TemplateLiteralStrings strings, List values) {
  Template template = _templateCache[strings];
  if (template == null) {
    template = _makeTemplate(strings);
    _templateCache[strings] = template;
  }
  return new TemplateResult(template, values);
}

User code:

TemplateResult nameTemplate(name) => html`<div>$name</div>`;

// first render
// This passes TemplateLiteralStrings(["<div>", "</div>"]) and ["Kasper"] to html()
render(nameTemplate('Kasper'), window.document.body);

// efficient re-render
// This passes TemplateLiteralStrings(["<div>", "</div>"]) and ["Dan"] to html()
// the first argument to html is identical to the previous call
render(nameTemplate('Dan'), window.document.body);

This feature turns out to be really useful for all kinds of DSLs that are used in cases where the embedded snippet has to be evaluated repeatedly. I've seen similar techniques used in GraphQL tags that parse the GraphQS query once, the let it be re-evaluated efficiently with different query parameters.

/cc @kasperl

dam0vm3nt commented 7 years ago

Thank you @justinfagnani ! html-lit is a super promising and interesting approach to HTML Templating and of course it's going to play an important role in the next polymer major release).

That's why I'd like to support it in polymerize but to do that definitively ES6 tagged string interpolation should be supported in dart, and that's should be no such a big problem IMHO : with a little effort there could be a great advantage for the dart lang.

/cc @jakemac53 @jmesserly @vsmenon

knownasilya commented 5 years ago

Agreed that this is important for JS interop.

cah4a commented 4 years ago

I'm the maintainer of gettext package. I am working on a complete gettext ecosystem for dart and stumble upon interpolation.

For now, I have the only option is to separate the original string and placeholders and interpolate them only after I get the translated string. Something like:

gettext("Hello, %s", [userName])

Developers often make the same mistake, and habitually write:

gettext("Hello, ${userName}") 

And in that case, localization will not work because inside gettext function, there is no option to find out the original string.

With tagged templates support, it will be possible to make gettext as it should be: simple and intuitive.

munificent commented 2 years ago

See #1988.