14 ms·
That people produce HTML with string templates is telling us something
- june_twenty 3y agoThere is no issue with producing HTML with string templates.
- fallat 3y agoI use string templates for small hidden services and I have never ever once ran into a problem. So yeah, really no issue. Anyone complaining otherwise is being really picky about subtleties in particular contexts. At large they completely work!
- cesarb 3y ago> There is no issue with producing HTML with string templates. There is no issue, until you forget to use escaping (or use the wrong one) for one variable, and someone uses that hole to inject arbitrary HTML and/or JS into your page. As long as all your escaping of interpolated variables is perfect, producing HTML with string templates is fine.
- Izkata 3y agoThat's just a bad system, not inherent to templating systems in general. Django (python) got it right: All variables that go into a template are escaped by default, you have to go out of your way to tell it not to do that. String formatting on the other hand, yeah, no good way like that in a language not designed for it. Not sure which you and GP meant by "string templates".
- ec109685 3y agoUnless the template is aware of the semantics of the html being output, it can’t always know how to escape. E.g. the escaping rules are different for a css variable embedded in an inline style compared to using it in a javascript context. That is what made JSX so neat.
- theamk 3y agoand modern templating systems do! https://pkg.go.dev/html/template https://pkg.go.dev/html/template > This package understands HTML, CSS, JavaScript, and URIs. No JSX needed.
- nitwit005 3y agoFailure to properly escape HTML and SQL used to be the most common security issues people found (and perhaps bugs).
- manicennui 3y agoHow is this problem solved using most of the libraries people have mentioned in this discussion that don't use strings?
- nitwit005 3y agoWhy don't you just look up one of those libraries? Most of them have some sort of description of how they work.
- dwohnitmok 3y agoYou'll generally have two functions: addFragment : (String, IntermediateHtmlAST) -> IntermediateHtmlAST renderHtml : IntermediateHtmlAST -> String There is a sanitation pass that occurs either in the final conversion of the intermediate data structure to an HTML string (renderHtml), or immediately on the function call (addFragment). This is similar to how database query libraries let you build up a SQL query via an intermediate data structure and then convert that to a prepared SQL statement (most common) or do data sanitization on the input fragment (less ideal).
- zoul 3y agoJSX is the first template system that I really like.
- scrollaway 3y agoYeah, jsx implements this idea the right way. Of course that also means it’s not a template language :)
- madeofpalk 3y agoDoes JSX count as 'string interpolation'?
- yuchi 3y agoBy definition, no. JSX is syntax sugar to some underlying function that transforms a JSX element (made by tagName, props, children) into something else. That could be a string, but usually it produces an abstract node representation, an object that collects those three parts.
- tombert 3y agoI think I like Clojure's Hiccup/Reagent a bit better. It gives you a structure that's basically the same as vanilla HTML, but it uses vanilla Clojure data types and keywords to do it. Doing this makes testing trivial, and you also don't need to worry about closing tags as much. As far as I can tell, the compilation is fast enough to where the overhead of translating to HTML doesn't seem to take any amount of time. Plus I just really like Clojure :)
- cynicalsecurity 3y agoCompilation of HTML. Now this is something.
- tombert 3y agoIs that really any different than JSX? I'm assuming that JSX doesn't just directly do `"<div>" + user.name + "</div>"`. Presumably it maps it to some kind of data structure and eventually compiles that into something that can be rendered.
- ysleepy 3y agoI have been using https://j2html.com/ https://j2html.com/ for some projects and after some initial doubt and discomfort I have to say it is a really nice way to do it. All the IDE tools just work: refactoring, auto-completion, usage search, debugging. Also I get really nice exceptions and can express stuff about templates in their types. When combined with Classes = Templates, static functions = macros and using implementation inheritance (the one permissible case haha) it covers all the usual corners of nice templating engines. Sure the syntax and indentation is a little wonky, but for me it pays off in so many more convenient ways that it is easily worth the tradeoff. Is this the best implementation of the concept? Probably not, but it is good.
- dmux 3y agoI really like using j2html as well. The number of times I've accidentally passed in a Map with a wrongly typed key-name has happened too often. With a statically typed template, that's caught at development time, not run-time.
- gwd 3y agoI just switched my project from open-coded SQL to goqu; inspired by this article, I searched for "golang html builder" and got this project: https://github.com/julvo/htmlgo https://github.com/julvo/htmlgo Which definitely looks interesting.
- abound 3y agoIn a similar-but-also-totally-opposite vein to goqu is sqlc [1], where you write the SQL and the Go bindings get generated. [1] https://sqlc.dev/ https://sqlc.dev/
- gwd 3y agoHaving type-safe calls to queries would be sweet. In my case I'm actually constructing multiple variations of fairly complicated queries using SQLite, and am trying to avoid repeating myself.
- omeid2 3y agoIt's telling something, for sure; but that it must be "HTML (alternative?) must address use-by-string-interpolation" is a questionable suggestion, no matter how subtle. I believe people use string interpolation to construct HTML, or just about any other language (eg. SQL, JSON, and even human languages) -- is that they see it as a nail and the hammer of string manipulation is almost universally acquired in the very first lessons of any programming language, only second to arithmetics. People construct HTML with string because the language and environments they use doesn't have mainstream and suitable -- in terms of accessibility and efficiency-- constructs for building HTML. This problem doesn't exists with React, Elm, and friends that has first class constructs for building HTML.
- troupo 3y agoThe problem isn't "every programming language has a way to format strings". It's that JS's string templates are (ab)used to create ad-hoc poorly specified DSLs that are nothing but strings and string substitution. And on top of that you have no end of "web-purists" that claim that this is "standards-compliant browser-supported way of doing things unlike that non-standard abomination of React". String templates are literally not much more more than this [1]: tagFunction`Hello ${firstName} ${lastName}!` becomes tagFunction(['Hello ', ' ', '!'], firstName, lastName) // note, first parameter isn't strictly an array That's it. Yet people use them as a (rathe poor) substitute for proper DSLs and macros. [1] https://exploringjs.com/es6/ch_template-literals.html https://exploringjs.com/es6/ch_template-literals.html
- vbezhenar 3y agoScala had XML syntax. I always wonder why it didn't take off and was eventually deprecated while JSX was praised.
- elitepleb 3y agoit wouldn't be such a big deal if accidentally poisoning it with JavaScript wasn't so dang dangerous 77 years since Von Neumann, and we're still stuck holding our instructions in the data
- justin_oaks 3y agoGood point. If only there were a way to mark a section of HTML as "no scripting here". Inside that section all <script> tags would be ignored, all onclick and similar attributes would be ignored, etc. That said, even if that existed, there'd still probably be some dangers you'd have to be careful to avoid.
- yyyk 3y ago>If only there were a way to mark a section of HTML as "no scripting here" iframe sandbox with srcdoc? Not so elegant, but it works. [Alternatively, iframe to another document and use CSP header there to ban everything]
- kaliszad 3y agoThat is why I like Hiccup/ Clojure so much: https://github.com/weavejester/hiccup https://github.com/weavejester/hiccup It is very natural to produce something resembling a document in pure Clojure data structures and then just convert it to valid HTML. I think, Reagent has some hiccup extensions that are nice like writing the class or id with a . or # notation right in the keyword describing the tag. So there probably still is some space to improve the ergonomics and probably performance. Concatenating strings still wins performance wise by a lot.
- wryoak 3y agoOoo that’s slick
- i2cmaster 3y agoThe LISP people were right to make trees essentially a first class data structure.
- mbork_pl 3y agoLists, technically, but nestable lists are indeed basically trees.
- singularity2001 3y agoThe problem with lists as tree is that there is no universal way to distinguish a:{ b c:d } from a:{ b:(c d) } which is why we need proper maps as first class citizen for "the next lisp"
- kaliszad 3y agoClojure does have maps as a first class citizen (besides sets, vectors and lists). Then there is clojure.walk and other namespaces suitable for tree manipulation. https://clojure.org/api/cheatsheet https://clojure.org/api/cheatsheet Using trees of these collections is quite customary in Clojure - on the front-end you might keep the application state in a single atom, like re-frame does and update various branches of it using events/ effects and listening on changes to those branches using subscriptions. This approach work for us at orgpad.com quite well.
- gred 3y agoIt's not just HTML -- same thing for SQL, JSON, XML. Java is doing some interesting work in this area: https://openjdk.org/jeps/430 https://openjdk.org/jeps/430
- mananaysiempre 3y agoSQL itself, as it turns out[1], has interesting work in this area: as originally envisioned, dynamic execution of SQL strings is the secondary option for using it, while the primary one is embedding SQL statements as statements in your source code, then passing it through a (DBMS-specific) preprocessor before feeding it to the host language implementation. Unfortunately, it seems that byte strings as the ultimate ABI won out in this case. [1] https://news.ycombinator.com/item?id=35598251 https://news.ycombinator.com/item?id=35598251
- taeric 3y agoPeople output C and Java, as well. Sometimes using string templating. Reasoning will vary, of course, but the pipeline through your build almost certainly involves a lot of intermediate steps. And auditing the representation close to what a human should be writing makes a lot of sense.
- neallindsay 3y agoJSON at least I pretty much never see being generated from templates. In the few cases where someone I worked with suggested it I've easily argued them away from it. The difference between JSON and HTML in this regard is illustrative. Every language already has a data structure that is easy to manipulate and also to translate directly into JSON. There is generally no built-in "DOM" data structure. And even if you have one (as you do in browser JS) or find a third-party DOM library, it's usually awkward to manipulate.
- hyperhopper 3y ago> But that it has suggests that people see string templating as having real advantages over their alternatives and those advantages keep being compelling I wholeheartedly disagree. Occam's razor: Doing it the right way takes knowledge that string substitution is wrong. Many people don't have that. Also, it's hard(er) than the simple string solution. It takes knowledge of dom APIs, or frameworks, or other things that a fresh grad wouldn't intuitively create in 5 seconds to insert a value.
- mananaysiempre 3y agoWe stop teaching EDSL design, we disparage EDSLs as unreadable and opaque in favour of “just” using the host language, we use host languages that are at best awkward at EDSLs, then when “many people” encounter a problem that calls for an EDSL it turns out they don’t have the knowledge to recognize it as such. Seems fair.
- 112233 3y agoIt can be argued that constricting HTML using string manipulation is the right way, because HTML is defined in terms of strings. Alternatively, HTML standart leaves generation as an exercise to the reader.
- hyperhopper 3y agoEvery output can be said to be "defined in terms of strings" Get real, the whole point is some strings in HTML are HTML, and some are malicious code. You're being adversarial to equate the two.
- 112233 3y agoI am not making a point about "HTML uses strings", but calling out the lack of separation between encoding and logical structure in the standart. Just for example, and sorry for mentioning it, but ASN.1 with its encoding rules provides terminology and a way to talk about encoding and semantics, so library writers do not have to reinvent it. Or, say, you want to generate some C++ code — what options except string templates do you even have? Standart does not help you to understand how to represent and encode senantics of a c++ source.
- timw4mail 3y agoComparing view source to a string template is easy. So is JSX to the DOM. The trick is that JSX looks like a string template. Compared to building a tree of nodes (or using the DOM API), XML transforms, or other "more proper" ways to generate HTML, it's more intuitive. Of course, there are issues with string interpolation, like XSS.
- vmfunction 3y agopretty sure JSX can be work into the ES standard. As E4X was part of JS before 2014.
- timw4mail 3y agoIt would be a mess, as JSX is syntax that calls to a specific library function. There would likely need to be some new kind of syntax delimiter for it to be a native feature. E4X-style would conflict with JSX-type syntax.
- vmfunction 3y agofor sure not suggesting using E4X as it is, JSX has evolved a lot from E4X. For example, as small implementation such as https://nanojsx.io https://nanojsx.io would be a good start.
- spacesuitman2 3y ago>I don't have any particular answers to why string templating has been enduringly popular so far (although I can come up with theories, including that string templating is naturally reusable to other contexts, such as plain text). This sounds similar to the concept of narrow waists: https://news.ycombinator.com/item?id=30483914 https://news.ycombinator.com/item?id=30483914
- ummonk 3y agoClicked on that expecting it to be an article about how corsets remained popular with women in the Victorian and Edwardian eras even as doctors kept recommending against them.
- pmontra 3y agoLow and smooth learning curve, ease of maintenance for every skill level, nearly the same in every language and framework.
- psychoslave 3y agoThat makes a lot of compelling arguments indeed. The main drawback I see is how large a door it can let open on security side. Not that I can’t be done with reasonable security check, but it’s far easier to inadvertently shoot oneself in the foot.
- ptx 3y ago> Strict structural containment [...] requires that every element and attribute start and end in the same template. This assumption is violated by several very common idioms, such as the header-footer idiom in ways that often require drastic changes to repair. Similarly, structured programming makes assumptions that are violated by common idioms such as unrestricted GOTO statements jumping all across your tangled spaghetti code. Maybe the header-footer idiom is not a good idiom.
- hajile 3y agoYet another incident of Greenspun’s Tenth Rule. Lisp macros make adding HTML syntax easy. You won’t find anyone using string templates in that language because a handful of macros means you can just program like it’s just lisp. Strings such primarily because they don’t establish regularity. If you don’t understand everything fully and follow their patterns exactly, it’s easy to accidentally lose your pseudo-macro hygiene and output garbage. JSX was a revelation simply because it was a “macro” (DSL) that ECMA had already designed an entire spec around (E4X) and thoroughly baked into the language. Like with Lisp, you could just use your normal coding patterns to interface. A custom HTML macro baked into the syntax makes sense in a language where almost everyone using it is going to need HTML. It would make far less sense to dedicate all that syntax space in a more general purpose language. And in JS, even with all that design time spent on E4X, you are still back to doing string interpolation the second you step away from that specific syntax (or you’re forced to express everything as HTML even if it’s not a good fit). The world would be a better place if JS had been scheme and people had been forced to learn a lisp.
- kortilla 3y ago>The world would be a better place if JS had been scheme and people had been forced to learn a lisp. None of the modern web would be around though because we’d still be waiting for a sufficiently advanced compiler.
- mananaysiempre 3y ago> None of the modern web would be around though because we’d still be waiting for a sufficiently advanced compiler. Huh? This doesn’t make any sense. I don’t think people have done a lot of Scheme JITs, but Scheme has some pretty damn impressive compilers—Chez[1] first and foremost. Certainly ones with better codegen than pre-V8 JavaScript ones. Scheme (the standard fragment) is less dynamic than JavaScript, not more (which has been used as an argument against that fragment by more OG-Lisp-inclined people). (The one potenial problem I can name is tail calls—IME LuaJIT is much, much worse at compiling Lua’s Scheme-like proper tail calls than it is at the same code expressed as a loop. But then the price for LuaJIT’s small size is that it’s a bit picky at which code it’s willing to compile well. Production JS engines probably handle that better, if at a cost of a couple of orders of magnitude more code.) [1] https://www.scheme.com/ https://www.scheme.com/
- intrasight 3y agoI don't think, in 20 years with HTML, that I've used string interpolation. Why would you when there's a web standard (XSLT) that gives you declarative templates? In my more recent work, I've used LINQ to XML "templates" for this. It's functional vs declarative. The approach works with JSON or XML input. And seeing how Microsoft isn't invested in XSLT, it'll be my approach moving forward. https://learn.microsoft.com/en-us/dotnet/standard/linq/functional-transformation-xml https://learn.microsoft.com/en-us/dotnet/standard/linq/funct...
- binarymax 3y agoI don't think, in 30 years with HTML, that I've come across a library or technique that I prefer over string templates. They're so easy. And especially since ES6 has `format ${my_variable}` interpolation, it's even easier!
- psychoslave 3y agoWith ES6 there is actually even more: tagFunction`string text ${expression} string text` https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- pmontra 3y agoThere has been a short moment in the history of the web when XML + XSLT looked like to become the way to go. It was at the end of the 90s, when we were looking at a way to develop web sites for both people at home with modems or slow fiber and for people with 2G phones (that is even slower modems and very small screens). We had HTML and WAP and products to apply XSLT to XML and deliver the same site to both audiences. Then 3G came with larger screens, faster CPUs, better browsers and in a few years we were using HTML for everybody with responsive layouts, media query, etc to the rescue. This is probably the first time I heard about XSLT in the last 10 years.
- jgalt212 3y agoDon't the people who read your code get angry that you used XSLT?
- zokier 3y agoHow can there be discussion on HTML generation that doesn't even mention DOM, the standard API for HTML manipulation. Using createElement etc are perfectly valid method of producing HTML.
- jameshart 3y agoBecause people are taught to think in strings. And programming languages coddle them with tools like concatenation and string formatting. And because we let people think they can do useful things with strings as a result. But what people actually need are grammars. The exact same reason why parsing HTML with a regex unleashes Zalgo is why generating HTML with string templates is bad. Because both treat HTML as a string, not a grammatically restricted language.
- bruce343434 3y agoWhat is your suggestion besides string templates? Writing out the html syntax tree? No thanks!
- psychoslave 3y agoSomething like Pug[1] is really nice to avoid all the xml cluttering. [1] https://pugjs.org/ https://pugjs.org/
- marcomourao 3y agoAs a mediocre developer at best, I love PUG but I'm a bit afraid about the lack of updates.
- psychoslave 3y agoIndeed https://github.com/pugjs/pug/issues/3339 https://github.com/pugjs/pug/issues/3339
- gdprrrr 3y agoMany frameworks do exactly that, including React and https://github.com/vanjs-org/van https://github.com/vanjs-org/van
- naasking 3y agoI think Mithril was the first one to pioneer this.
- recursivedoubts 3y ago"One of my fundamental rules of system design is when people keep doing it wrong, the people are right and your system or idea is wrong." excellent, and in hilarious contrast with the responses in this thread...
- Dudester230526 3y ago[flagged]
- jrm4 3y agoRight? I've never seen a thread like this; it's hilarious. Hacker news thread talks about how to do HTML. Guy writes article refuting the thread. But it happens backwards TENET!
- mananaysiempre 3y agoCan you explain? What I’m reading here is people discussing drawbacks of various non-string-based systems, which seems like an appropriate reaction to a guy telling them that maybe people use strings because the non-string-based stuff sucks. (Not being well-known or available in a widely-used language is a drawback in this context!)
- jrm4 3y agoAnd the author made the (annoying) point that I'm now ready to call as a bit of an old-timer here. When people keep recreating the "bad design pattern" over and over, you should probably get over it and roll with it.
- andrewflnr 3y agoNo matter what other damage it causes?
- warkdarrior 3y ago"Roll with it" probably means that we should expect people to use strings for templating, so we should design other downstream mechanisms to handle or prevent potential damage.
- tpoacher 3y agoYes. That it's both easy and possible to do so, and the alternatives are not.
- namaria 3y agoStringly typed languages are easy. Strings and duct tape get shipped because it's easy. What externalities? Tragedy of the commons and whatnot.
- henrydark 3y agoHot take: it's possible to have a strict language where tags don't have to start and end in the same template. For example, make linear types Html, HtmlOpen, HtmlBody, and HtmlClosed, with the addition rules (which could be functions or what have you) HtmlOpen + HtmlBody = HtmlOpen HtmlBody + HtmlBody = HtmlBody HtmlBody + HtmlClosed = HtmlClosed HtmlOpen + HtmlClosed = Html and only Html has whatever it takes to be valid output. A separate point is that string templating is simply a local maximum.
- reuben364 3y agoReminds me of Edward Kmett's talks on monoidal parsing in which he has Dyck languages as an example. I'm confused about the need for "linear types", unless you mean a monoid. I'm not sure of a use case where you would want a open fragment of html or a closed one other than to a have a hole, that is something like f : HtmlBody -> HtmlBody f x = someOpenFragment + x + someClosedFragment
- henrydark 3y agoThe example in the reference in the piece is to have a header and a footer, where header would be open and footer closed. As for linear types, I mean that somewhere the type system won't allow progress if you have an open type that wasn't converted to some final state. This is strictly necessary.
- reuben364 3y agoAh, you don't need linear types for that. Linear types will prevent you from duplicating or discarding values, but all you need is to only allow "final state" values to be used in your API. Also a reminder that I should read articles before commenting.
- henrydark 3y agoSorry, auto correct malfunction, I meant "isn't strictly necessary"
- stblack 3y agoBecause hard-coding HTML in source code is supposedly better? What are you gonna do, recompile and ship new and different executables to all {1, 10, 100, 1000, …} of your customers or end users for each point release? WTF? That’s bananas. No thank you.
- bckr 3y agoThat’s not the idea. The idea is to build the document in a way that has more guarantees, by working at the document object level instead of the source level, and then compiling instead of interpolating.
- hwc 3y agoI've begun relying on building DOM trees and then using a render() function to serialize them. e.g. <https://gist.github.com/HalCanary/fd4ec75ae950196454f09051a5d8779a#file-htmlhelp-go-L142 https://gist.github.com/HalCanary/fd4ec75ae950196454f09051a5...> or <https://gist.github.com/HalCanary/169105aad5971268988fee80d1824714 https://gist.github.com/HalCanary/169105aad5971268988fee80d1...>. When producing PDF document back when I was in charge of SkPDF (used by billions!), we had to generate the PDF files that way, since the serialized format is very precise.
- lelanthran 3y agoI've done the same, in a way that I think is slightly better. Not yet opensource (too tied into my current project to refactor into an isolated package/module), but I hope to do so soon.
- jmbwell 3y agoAuthor doesn’t have real answers as to why people have been using strings for so long, but (as author almost speculates) it’s possibly just because the people who have been programmatically generating HTML the longest had only string functions to work with in the beginning, and only relatively recently have there been robust, reliable, sufficiently-flexible and sufficiently-capable libraries for generating structured documents any other way. That’s not to mention years of having to cook up hacks to deal with inconsistent browser implementations that violated the document structure you’d be trying to create. In the early 2000s I was working on web projects. We built such data structures, we did XML/XSLT, we were very careful to make sure everything was well-formed… and we still ended up using string templates somewhere. The tools just didn’t always exist to do everything the way we wanted, so we had to work with what we had. It hurt every time we resorted to it, because we knew we’d have to clean it up someday. But sometimes you just have to do what gets you home in time for dinner.
- givan 3y agoThe most common pattern to treat html as string is to use a a template language that works by replacing some patterns like {$variable} in the html with real data from a database. A better way is to use html as what it really is, a dom document and with a simple glue language fill it with data, in this way you keep the html code unchanged for better maintainability and reuse. For example a very basic way is to use a list of css selectors with the data that you want to fill eg: div#id > span.class a = "lorem ipsum" #product > .product-title = $product.title Something like https://github.com/givanz/vtpl https://github.com/givanz/vtpl
- cnity 3y agoYou know, I'm not sure why I've thought of it this way but you're right. Interestingly this fits the model for most JS SPAs, but I've never seen it done server-side.
- TylerE 3y agoCSS selectors get really annoying when you need to assign something to the 7th column in the 4th row. Most browsers don't even support the full set of selectors they're already supposed to! Realistically this could result in having ugly ids on everything just because writing things with selectors sucks.
- Izkata 3y agoFor a strange idea, TinyButStrong is a PHP template language that works halfway between this and traditional templating: You work in an HTML template file, but the engine understands the HTML structure so the values you insert are like vtpl but in reverse. It was designed to work with WYSIWIG HTML editors. Here's their example page for arrays, you can see how the template is completely valid HTML without having to make the engine render it: https://www.tinybutstrong.com/examples.php?e=dataarray&m=template https://www.tinybutstrong.com/examples.php?e=dataarray&m=tem... (then on the upper-left you can click "Result" to see how the "tr" elements, as specified in "block=tr" in the template, are duplicated for the passed-in array)
- rerdavies 3y agoYou "don't have any particular answers to why string templating has been enduringly popular so far", but "the people are right"?! How about "the people are right in wanting systems that automatically prevent extremely dangerous injection vulnerabilities", and "lazy developers are wrong", but "there's a tiny minority of amateur developers that use the works of lazy developers because they don't yet appreciate the dangers of string templating, but soon will"?
- datavirtue 3y agoSo dangerous. Just last week I lost a finger to string templating.
- scottLobster 3y agoNot being a frontend developer, I'm not sure why everyone in the comments (and the post) is so convinced this is a bad thing. Maybe I missed it, but the only reason listed so far as to why this is bad is some hand-wavy "might be insecure", which would also be true of hand-written HTML or HTML generated by other means. As an outsider this strikes me as a purely stylistic argument, like people who argue bubble sort is the worst sort and should never be used. If it's sufficient to the task, who cares?
- cnity 3y agoI like to read and sometimes participate in these types of arguments, but do people actually hope to convince one another? We're all just flexing our viewpoint and knowledge, as far as I can tell. If you told, for example, suckless that their page builder code[0] should not use string wrangling they'd certainly laugh and ignore the advice. [0] https://git.suckless.org/sites/file/build-page.c.html#l23 https://git.suckless.org/sites/file/build-page.c.html#l23
- austin-cheney 3y agoAs somebody doing this work for over 20 years I agree with you. You have to understand that HTML is itself a string serialization as is XML, markdown, YAML, and JSON. HTML is not the end state or the goal. The end state is a DOM object in memory and the goal is something visual and/or auditory rendered onto a screen. That said, HTML immediately achieves obsolescence when a browser accepts any string format with which to parse into a DOM instance.
- Falkon1313 3y agoI don't really think that's quite correct. To someone reading (or authoring) a document, the end state/goal is having that string of text visible and formatted well enough. They don't care about DOM objects. The main reason we use HTML is not because people enjoy DOM-traversal or parsing or abstract syntax trees. It's because a little markup in your strings can make them format nicely and make it easy to link to and embed other stuff like images, video, and audio. String templating/interpolation is the goal.
- bandrami 3y agoNearly 20 years ago I was working at a shop that was an early Rails adopter. We used templates religiously, and then later used builder religiously (I may have reverse the timeline in my senility there, but you get the idea), and without fail when marketing came in with a show-stopping change 15 minutes before we went live we would just create and inject a string because that was what we had time for.
- sparks1970 3y agoI also feel that generating HTML from string templates is wrong because its so fine-grained. We use a lot of boostrap and its verbose, repetitive and hard to keep standardized using string templating. Recently I did an experiment in python using the XIST library for generating HTML vs a Jinja2 template. Things I found: 1. The XIST approach was 10x slower, probably related to XML serialization vs string building with Jinja2 2. Although an HTML template looks a bit like a set of nested functions (like the lisp people say it is) you actually end up wanting to pass context deep down the call tree. For example. You end up adding parameters to all the parent functions or you pass in a "context" dict which makes it hard to see what is actually being consumed from the context and by what. def make_header(user) -> html.Div: <-- user passed return html.Div( make_logo(), make_user_section(user) # <-- so this can use it ) This might not seem that different from normal programming but html-as-functions can mean you end up with a very deeply nested call stack with each function a thin wrapper around the next (Russian Doll programming) passing parameters down and down and down. 3. As demonstrated by the example above, instead of a set of "what you see is what you get" html strings you end up with a lot of component/function calls which actually make it hard to correlate what is rendered and sent to the browser vs where it came from. I still like the idea of saying button(icon="plane", text="Book ticket") vs 3 lines of html, and the idea of getting type checking on my html generation functions but this experiment put me off it.
- mixmastamyk 3y agoGuessing the lib is not optimized. Dominate is relatively slow as well. Probably could be sped up with some profiling and/or Cython. I believe Jinja is accelerated similarly as well. Not sure what to make of the second point, but I'd probably try to log it in debug mode somehow, hopefully avoiding performance degradation when not used.
- emptysea 3y agoThe passing stuff down when it isn't needed also comes up with JSX / React. The basic options for solving it are either: - pass it down manual - use Context, essentially thread local variables but React both have tradeoffs and it really depends on what you're building your codebase.
- 0x445442 3y agoTreating HTML as strings is fine if one remembers what it’s original intended use was; stateless display of hyperlinked text with a smattering of hypermedia.
- taf2 3y agoI looked into using <template with <slot tags but really it’s so much more typing no thanks back to strings.
- taeric 3y agoThis is an odd take. For many reasons. xhmtl tried the push for xslt. It didn't fly. Maybe it is time for that ship again, but I have my doubts. But, perhaps worse, people produce most everything with string templates and string construction of some sort. Just look at how the LLM craze is panning out. We aren't leaving it, we are doubling down on it.
- thinkmassive 3y agoLook at the popularity of helm charts, despite the availability of alternatives like jsonnet.
- taeric 3y agoI'm embarrassed to admit that I don't know those two things. :( Quickly searching, seems both are structured text? One use string template style more than the other?
- thinkmassive 3y agoApologies for the lack of context, and for missing this comment until today. Both are tools for defining kubernetes manifests (which are YAML) in a reusable manner. Jsonnet is a formally specified extension of JSON. It’s essentially a functional programming language (w/some object oriented features) that generates config files in JSON/YAML/etc, so it’s straightforward to determine whether an input file is valid, and to throw an error that points to an exact line if it’s not. It has a high learning curve, especially for people whose only experience is with imperative languages. https://jsonnet.org/ https://jsonnet.org/ Helm charts also generate YAML/JSON config files, but they use Go templating. This is easier and faster to understand, since it’s mostly string substitution and not much logic (there’s conditionals, iterators, and very basic helper functions). Unfortunately a simple typo or mistake can cause errors that are difficult to diagnose (the message may indicate a problem far away in code from the actual mistake). It can also generate output that’s valid according to the string templating rules, but not what was intended, which can be very confusing to debug. Despite these shortcomings, the vast majority of kubernetes applications are distributed as helm charts. I understand why things ended up this way, but I still wish it were more common for people to invest the upfront effort to learn the superior tool, so it could be more widespread.
- WillBAnders 3y agoThe best way to represent HTML is with HTML itself, not an HTML-like system that varies in subtle ways between languages and libraries that happens to be missing the one feature you need. I'm a large fan of Embedded DSLs (Domain-Specific Languages) for these types of problems, as they allow using normal HTML syntax directly in the rest of your code. Combined with macros (for compile-time parsing/analysis) and interpolation (for safely templating values), DSLs can be safer, more performant, and overall more maintainable than other approaches. For languages like HTML and SQL that are standard and well-defined, this is undoubtedly a better approach in my mind. I've been developing my own approach to Embedded DSLs as my thesis research with my own programming language Rhovas [0], which addresses concerns with syntax restrictions (e.g. string quotes), semantic analysis (AST/IR transformations), and most importantly tooling. Happy to answer any questions about work in this area. [0]: https://blog.willbanders.dev/articles/introducing-syntax-macros.html https://blog.willbanders.dev/articles/introducing-syntax-mac...
- fnordsensei 3y agoI guess we have to confront whether we think that HTML fundamentally is a string that happens to contain tokens that could be interpreted as a data structure, or whether we see it as a data structure that has a string representation. I think it just happens to be that the string representation is one of the most familiar and accessible formats to many people. I don't subscribe to the idea that HTML somehow fundamentally is a string. However, even if we see it as a data structure, to many languages, data structures are not at hand, while objects with parochial APIs are. So you end up with a flurry of different libraries with their own way of doing things, instead of "this is just data, I'll use my language's generic data manipulation tools to deal with this".
- WillBAnders 3y agoI'd say it's definitely a data structure, but one with a canonical string representation. It may not be fundamentally a string, but that representation is critical to how we convey it's meaning to such extent that it's used across languages and browsers as the method of transport. JSON is conceptually simpler and there's still a lot of quirks between libraries for that already (e.g. null/undefined, integer/decimal representation, and large numbers). XML has more going on to start, and then you get all the different libraries inventing their own abstractions as you said and it picks up a lot of pitfalls. FWIW; I've messed around a lot with configuration languages and it's definitely hard to get right so I understand how this differences accumulate.
- zb3 3y agoIt's the easiest solution in many cases.
- dbrueck 3y agoI don't like saying something is always wrong, but over time we've abandoned string templates for HTML generation because of maintenance issues - anything from fixing issues on a particular device/browser to doing a design refresh tend to cause lots of changes to code even though the problem isn't in the logic or "programmy" parts per se. An alternative that has worked well for us - especially if you have a dedicated web designer (not just a graphical designer, but someone who can get it all the way to clean HTML/CSS) - is to have the designer build the end result in terms of visuals and then a developer go back and "wire it up". (svelte is a fantastic framework for this model, BTW) Sometimes we'll instead have a developer do a rough implementation and then have the designer go back and make it look good, but in general the first approach works best because a good designer is often better at taking into consideration all the intricacies of HTML organization, and also be able to own changes to it over the long term.
- iainmerrick 3y agoThis seems like it’s missing some important data: are people using string templates for HTML? As much as they used to? More, less? You would also need to look at client-side and server-side code separately. On the client, it seems to me people are using string templates much less than before, and instead using JSX.
- ghusbands 3y agoThe output is a string and a lot of the input is strings, so it's not so unusual to treat HTML generation as an exercise in string templating. It also more easily enables optimizations (coalescing of output strings and similar). Getting the filtering/escaping right is essential, of course and it's best if you can only output valid HTML. But it shouldn't be surprising that people turn to string-handling for handling something where most of the inputs are strings and all of the output is.
- ngneer 3y agoI was hoping to see an explanation for why the pattern is prevalent, but the author does not know. "One of my fundamental rules of system design is when people keep doing it wrong, the people are right and your system or idea is wrong." I am not sure under what circumstances this is true, but for security it is definitely false. People keep forgetting to sanitize inputs, for example. Does that render input sanitization a broken idea?
- guns 3y ago> People keep forgetting to sanitize inputs, for example. Does that render input sanitization a broken idea? Possibly. You could prevent careless use of unsanitized inputs with a type system. Fail-safe designs should be more common.
- ncallaway 3y agoIt’s actually a critical concept for security contexts. If everyone forgets to sanitize input, that means our current processes are fucking broken. I like to imagine if this excuse happened in aviation how it would sound. “Everyone forgets to put down landing gear before landing, so does that mean landing gear is a bad idea?” No, but it does mean the process for landing is catastrophically broken, and needs to be overhauled. If that happened twice, we’d implement strict rules around landing like checklists with standardized procedures to have a second person verifying that the process was followed and each task was accomplished, and defining a “sterile phase of flight” where talking about anything other than the landing process was disallowed. So, input sanitization isn’t a broken idea, but the fact that it keeps going wrong clearly demonstrates that out process and culture around security are catastrophically broken.
- ngneer 3y agoPresumably pilots know to do that? I absolutely agree that psychological acceptability is key for building secure systems, and that the human factor must not be neglected. I also agree that process and culture around security are deeply broken. I just do not agree with the idea that if all are doing it, there must be some deep truth beneath. Yes, people habits must not be ignored, but to claim that an idea that goes against those habits is wrong, as the author claims, is inaccurate.
- timcavel 3y ago[dead]
- zoogeny 3y agoThis is one of the reasons I was always a bit annoyed with WhatWG splintering from w3c. If we had bitten the bullet 20 years ago and stuck with xhtml then I think we would be significantly closer to people using structured formats for web documents by default. HTML being loosely structured was a conscious choice - not a mistake. I'm also surprised that TypeScript finally managed to sway people. I would bet a large number of people here won't even remember the whole ES4/ES5 debacle. There was a time when types (and much more) were being added to ECMA Script proper through the standards process before Yahoo and others killed it.
- JohnFen 3y agoWhen I've done it, it has been because using a string template was the simplest solution that met my design needs. It's also, in many cases, easier for other devs to understand and maintain.
- theknocker 3y ago[dead]
- ummonk 3y agoIt's why JSX is such a god-send in React (and very rarely do people use string templates to produce HTML in React). String templates are much easier to read and understand than nested function calls. If a language incorporates a safe readable HTML-generation feature akin to JSX, people will be much more enthusiastic about it. More generally, syntactic sugar matters a lot. E.g. Python's list comprehensions are merely syntactic sugar for filter + map, but they make functional code so much more readable.
- MBlume 3y agoClojure's great for this too, I've never seen a Clojure programmer generating HTML with string templates and that's not because Clojure programmers are more disciplined, it's because Clojure's syntax is flexible/simple enough to make generating HTML in a structured way the natural solution. https://github.com/weavejester/hiccup https://github.com/weavejester/hiccup
- everforward 3y agoI think it's more that the syntax is fairly similar to HTML already. HTML is basically deeply nested lists with some attributes attached to the nodes, and lisp code is deeply nested lists with keywords replacing attributes. That is to say Clojure/lisp programmers are likely more familiar working with deeply nested lists of data. You could write a very similar library in Python if you wanted using lists, I'm just doubtful anyone would use it because it's not "Pythonic".
- alex-robbins 3y agoIn the context of this article, it's worth pointing out that hiccup doesn't escape strings automatically. Rum does, and I've been using it as a drop-in replacement: user> (require '[rum.core :as rum] '[hiccup.core :as hiccup]) nil user> (rum/render-static-markup [:p "<script>alert('you have been pwned')</script>"]) "<p><script>alert('you have been pwned')</script></p>" user> (hiccup/html [:p "<script>alert('you have been pwned')</script>"]) "<p><script>alert('you have been pwned')</script></p>" (Note that Rum is also a React wrapper, but you don't have to use that part of it; you can simply use it for static rendering of HTML.) https://github.com/tonsky/rum https://github.com/tonsky/rum
- kupopuffs 3y agoin this thread: no one reads TFA
- hlandau 3y agohlandau here. This article responds to my own, so here are my thoughts: - "No one has structured HTML creation that's as easy as string templates." -> I think this is usually true, but not always. Lisp allows use of S-expressions to define HTML (via SXML), and I genuinely find that more pleasant and powerful than writing HTML, or HTML with string templates. JSX is also arguably easier than adopting a string templating system since you can just drop into it instantly and write it as a function; it's language-integrated. I also actually classify languages such as Haml as structural containment, which might be counterintuitive, since they're largely just seen as a syntax sugar on writing HTML. But because these languages are completely different to HTML, they're necessarily defined and parsed as languages in their own right, and the capacity for interpolating variables, etc. is integrated into the definition of that language as part of its syntax. (Consider how you can't provide mis-structured HTML with Haml, for example.) So this is a bit of a surprising result where something which is just seen as sugar on top of HTML actually takes you from string templating to structural containment. Thus using languages like Haml is a simple and easy way to move to structural separation in ecosystems where Haml or similar technologies are available. Since the whole point of Haml is to make writing HTML easier/lower effort, I also think this is another counterexample to "no one has structured HTML creation that's as easy as string templates." - "One of my fundamental rules of system design is when people keep doing it wrong, the people are right and your system or idea is wrong." -> Yeah. If web developers keep adopting the wrong solution, it does suggest a lack of better leadership in this area in terms of the web development tools and languages they're provided with. I agree with this constructive view of leading via positive example; it's not reasonable to blame people for not using the wheel if they live in a world where nobody has ever seen one. - It's mentioned that Go came up with html/template rather than come up with a better solution. It seems like the problem here is that in order for a language to be flexible enough to allow articulating HTML in a structural way that is actually ergonomic, it basically has to either a) be as flexible as Lisp, or b) be a DSL or language extension specially designed for the task (JSX, Haml). While Chris takes a different view here I find his POV interesting, so I've added a link to his page from mine.
- yawaramin 3y agoI found your article very informative and it matches up quite a bit with my own thinking about HTML generation. In fact it looks like we independently arrived at pretty much the same conclusions. A lot of the issues you raise are the impetus behind the way I designed my HTML-generation DSL: https://github.com/yawaramin/dream-html https://github.com/yawaramin/dream-html
- neilv 3y agoThe languages usually don't have great support for doing it any other way. So people often do it the same way they would've done it in the mid-1990s (as strings, only in Perl CGI scripts). Racket (and most other Lisps) have built-in syntax transformation features that will let you do it as your own macros, or even inlining with different parsers, without some distinct preprocessor kludge. Here's a macro example: https://www.neilvandyke.org/racket/html-template/ https://www.neilvandyke.org/racket/html-template/ Here's doing it with data: https://www.neilvandyke.org/racket/html-writing/ https://www.neilvandyke.org/racket/html-writing/ You could also make a Racket reader so that you could have inline HTML in its customary angle-bracket syntax.
- davidw 3y agoIf you have a lisp program that generates HTML, now your 'HTML person' can no longer easily work on it with familiar tools.
- neilv 3y agoWith Lisps, you can also make it work with external HTML files (or HTML template files), for that person. In my case, I'm usually more productive doing HTML in my main programming language code, which is why I wrote those particular libraries.
- syngrog66 3y agosimilar to why vim is my default text editor. its not because its necessarily the best, most domain tailored tool for any given target file type. its because I get to leverage the same workflow experience and muscle memory whether dealing with code, config, docs, stories, notes, TODOs, commit messages etc. and it runs wverywhere I care about absolutely sips host resources, and imposes ultra minimal distractions and cognitive burden. and that touch-to-reaction latency, oh my.
- felcro 3y ago[dead]
- jerf 3y agoI wrote about a similar thing a while ago [1] and the conclusion I came to then is you can not compete with what is in most languages a single-character token "+" that does the wrong thing. (I justify my claim that it does the wrong thing in the linked essay.) There are, as any number of other comments on this topic are pointing out, a huge number of "correct" ways to do it that exist today. None of them are as simple as html = "<p class=\"" + params["post_type"] + "\">" and they can't be, because the only thing that beats a one-token string append is a zero-token string operation... which to the extent programming languages have them, is also always an append. (Before you say your way is simpler than that... you need to include the setup code. That has no setup code; it is built into the language. If you so much as type "import " followed by anything you've already exceeded that in complexity, let alone if you add documentation you have to read for so much as 15 seconds or anything like that. It's not just about character count at the payload location.) To fix this problem, first "room" has to be made to make the right thing easier than the wrong thing, and that involves the counter-intuitive requirement of not building the broken operator right into the language. Simply jamming two strings together must become more complicated than it is. It also suggests that there ought to be something about the process of concatenation that raises alerts to a human reader, something like the minimum concatenation operation being format_string("%RAW;%RAW;", str1, str2) or perhaps "%UNSAFE;" or something. But I don't expect to see that happen anytime soon. Should a new language even try it, it would simply become the number one complaint people have about using the language ("omigosh this language is so broken you can't even concatenate strings" "wow thanks for that now I know never to try it out"), and a newborn language can't afford that. We need to come up with something, though. The historical #1 security issue has been memory safety issues. It may still be, such things are hard to measure, but if they are, they're hanging on by a thread. The issue of string handling is rapidly taking over the #1 security slot, and it's probably going to be a similarly multi-decade adventure for the programming community to figure out what to do about it. I do know that just as we eventually realized git gud was not a solution to memory safety, we're going to realize git gud is not a solution to this problem either. I am pretty gud, have a deep understanding of the issue, and it's still walking through a minefield for me whenever I'm dealing with this issue. I have no idea how to fix this thought, even in theory, without "making room" of some sort and making string concatenation fundamentally a harder operation. (And honestly most programmers would simply bash together an "string_append" function anyhow and call it "sa" or something and just bypass the attempt at security.) [1]: https://www.jerf.org/iri/post/2942/ https://www.jerf.org/iri/post/2942/
- mannyv 3y agoTo be fair, I did this with SOAP/XML for one project. 99.999% of the time the messages are exactly the same except for the payload, and nobody cares about the other .001%. If it's parametrizable why bother with completely dynamic generation? That's just more code to maintain.
- mixmastamyk 3y agoCode can be verified, i.e. linted, tested, type checked, factored, formatted, and sometimes sorted. More maintainable than a blob of text on larger projects.
- sigmonsays 3y agowe could say the same thing today about yaml. Everyone templates yaml. HA!
- Spivak 3y agoIt's embarrassing that some projects are templating yaml. It's a fully generic object serialization language that supports custom object types and you can build arbitrary DSLs in it. There should never be a need for templating it on the string level.
- lucideer 3y ago> I don't think it's going to change, either. No one has structured HTML creation that's as easy as string templates. This... isn't true. JSX is structured HTML creation. Lisp too obviously but that's not as popular in modern web dev. JSX is surely the most popular HTML creation method in modern web dev? > I don't have any particular answers to why string templating has been enduringly popular so far I was disappointed to read to the end and see this, as the article title wording - "is telling us something" - seemed to hint that the central topic would be trying to pose answers to what that "something" is. > (although I can come up with theories, including that string templating is naturally reusable to other contexts, such as plain text). This is something I think JSX is really close on, but not quite there - it might be nice to see a fully HTML/XML-compatible syntax that works exactly like JSX does. I know JSX started out with that idea, and the incompatibilities introduced were well considered and made sense, but I'd still be curious to try. Overall, while I think the author makes a good point (fighting user tendencies head on is mostly futile) the benefits of structural generation are clear, while strings have no real benefits beyond UX/DX - acknowledging that the fight is futile is ok but I think it's still worthwhile to continue the fight in a more compromising/self-aware/middleground type approach. JSX fits this really well. Would be nice to see the concept spread further outside of the React ecosystem, maybe even to other languages in some form.
- deleted 3y ago[deleted]
- carom 3y agoI am a heavy user of Go's html/template library. The reason is that it allows me to not write Javascript. With vanilla JS you have to translate to JSON, then build elements in the front end. The solution to building elements in JS is to use a framework, but compiling Javascript just never sat right with me. It's like ok, now I have an incomprehensible bundle of minified JS and I probably need to run a JS backend if I don't want to go insane. Alternatively, you can skip all of that and just template. I'm excited for htmx but haven't used it yet. Simplicity wins. LAMP stack was great for its simplicity. Go monoliths are a modern solution.
- r3trohack3r 3y agoI’ve been using <template> to avoid the whole “create DOM elements in JS” thing, and it’s been working well so far. I wrote a little wrapper class to help with it: https://github.com/retrohacker/template https://github.com/retrohacker/template
- carom 3y agoI use that, is there a better pattern than doing a query selector to put the values in the correct places?
- Spivak 3y agoYou're conflating two things, dynamically creating HTML is great and lets you avoid JS in a lot of cases. It's whether you should treat your HTML document as the tree of nodes that it is in your programming language or treat it like a string. https://github.com/Knio/dominate https://github.com/Knio/dominate is a Python lib that implements this principal.
- jacksnipe 3y agoI don’t think it tells us something terribly interesting though. ALL complexity has a cost. String manipulation is such a core operation for so many software engineers that for many of them, the complexity of using an imperfect tool for the problem is outweighed by the complexity of bringing a new tool into the toolkit. (Or at least the perceived costs, at the time the decision is made.)
- throwawaaarrgh 3y agoProgramming by hand is wrong in general. Web pages needing 3 different kinds of programming by hand is really wrong
- FireInsight 3y agoThat's why I write all my CSS with Tailwind and TS with AI :)
- tannhaeuser 3y ago> (I'll pass on the question of how important it is to replace the most powerful context aware autoescaping HTML string templating with something else.) It's probably me, but I'm not grokking this ending sentence. Is this praising go's "html/template" or is it meant as satire? I believe it isn't but genuinely can't say for sure. From a cursory look, html/template looks like doing the right thing, but come on, you have to tell it explicitly and procedurally which kind of escaping(s) you want for every individual var expansion. Compared to SGML which automatically detects where expansion of an entity reference occurs (within attributes, within CDATA or RCDATA, within normal parsed character data, and so on) while also considering the entity type and type-checking the final expanded result against the expected content model (not just for preventing <script> injection) this is a joke. Maybe SGML templating is what the author considers 'strict structural containment'? I mean, SGML isn't just any rando templating system, it's what HTML is based on, has been with us since 1986, and should be the point of reference.
- tantalor 3y agoIs there another way? Please do tell
- leontrolski 3y agoSee also "What if we'd had better html-in-js syntax all along?" https://leontrolski.github.io/dom-syntax.html https://leontrolski.github.io/dom-syntax.html
- bcrosby95 3y agoIt's the same reason why some people love ORMs. And some people hate them. Because string templates have one less layer of abstraction. I'd rather learn SQL and HTML than every language and framework's personal take on how to do this "right".
- jqcoffey 3y ago> I don't have any particular answers to why string templating has been enduringly popular so far (although I can come up with theories, including that string templating is naturally reusable to other contexts, such as plain text) My hunch is that it’s for the same reason folks love other plaintext formats: they’re readable and easily manipulated. HTML has the added upside that it’s pretty straightforward for humans to write, which whether one likes it or not is why some folks would rather not learn some else’s DSL for generating it. Btw, I suspect there’s a similar division in the write your own SQL vs ORM/linq world.
- sixplusone 3y ago1. html is ascii based, from the headers to the body, naturally leading to string manipulation 2. browser engines try very hard to accept as much malformed slop as possible and still give usable results ( https://en.wikipedia.org/wiki/Robustness_principle https://en.wikipedia.org/wiki/Robustness_principle ), this was probably a mistake
- jiggawatts 3y agoPeople forgot that XHTML was a thing. What I discovered was that libraries and components written for HTML would regularly output invalid XML, making them unusable for XHTML — even if they claimed to support it! Something like 30% of the time this revealed a real bug, like double escaping or no escaping. People gave up and went back to HTML, which is non-strict and will happily parse gibberish.
- XCSme 3y agoFor me there is one big reason: with string templating you know exactly what happens, who is in charge of filling in the data and where. With external templating libraries, where you write your HTML in a separate page and add slots for the content, usually there is a lack of transparency in how that data gets filled, by who and when, especially when seeing the code for the first time.