Skip to content
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

Client side include feature for HTML #2791

Open
TakayoshiKochi opened this issue Jun 27, 2017 · 233 comments
Open

Client side include feature for HTML #2791

TakayoshiKochi opened this issue Jun 27, 2017 · 233 comments
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest

Comments

@TakayoshiKochi
Copy link
Member

TakayoshiKochi commented Jun 27, 2017

Spun off from HTML modules discussion

There are certain amount of interest that including HTML snippet into an HTML document, without using JavaScript. That would be similar to <iframe>, but more lightweight and merged into the same document.

It would work as a naive way to have your header and footer sections defined in one place.


(Edit by @zcorpan: also see #3681)

@TakayoshiKochi
Copy link
Member Author

TakayoshiKochi commented Jun 27, 2017

I personally do not buy this much (sorry!), as we have enough primitives (fetch, DOM APIs, maybe Custom Elements) to realize a equivalent feature very easily. Other than ease of use, what is the benefit of having this in the platform?

@mathiasbynens
Copy link
Member

How would this differ from HTML Imports?

@TakayoshiKochi
Copy link
Member Author

TakayoshiKochi commented Jun 27, 2017

HTML Imports load a HTML document, via <link rel="import" href=...> and its contents are never rendered without DOM manipulation via script. The document is stored in $(link).import property. HTML Imports have more, like <script> is executed etc.

This idea is about inserting HTML snippet in HTML document. e.g.

main document

<include src="header.html"></include>
Awesome contents
<include src="footer.html"></include>

header.html

<h1>Welcome!</h1>

footer.html

<footer>Copyright 2017 by me</footer>

will result in

<h1>Welcome!</h1>
Awesome contents
<footer>Copyright 2017 by me</footer>

@rianby64
Copy link

I was always dreaming to see this feature in the browser. This tag, as exposed by @TakayoshiKochi should allow to put some HTML content in the DOM in a simple way. I think the <include> tag should stay and not be replaced.

I would like to propose the following:

<include id="my-include" src="an_URL.html"></include>

And the event could be:

var included = document.querySelector('#my-include');
included.addEventListener('load', e => {
  // ...
});

included.loaded.then((included_) => {
  // here you see that
  // included_ === included
  // and this promise is ready once the HTML code
  // from included.src has been fetched and appended to the DOM
});

Reproducing the behavior from document.currentScript I found easy to use document.currentInclude, so if a script is executed inside an <include> then it should know where it is.

So, an include has a small set of features

  • load event
  • loaded promise
  • currentInclude (or a better name)

Hope this idea will be useful.

@rianby64
Copy link

There are some questions around this tag that I'd like to expose too.

  • How to resolve the src path if it's relative?
  • What about if src changes. The fetched content should change too?
  • If an include contains some tags?
<include src="an_URL.html">
  <div class="preloader">...</div>
</include>

After fetching, the innerHTML content should be replaced?

  • In which order should be dispatched the load event? from most nested up to the top?

@domenic
Copy link
Member

domenic commented Jun 27, 2017

I don't think we should do this. The user experience is much better if such inclusion is done server-side ahead of time, instead of at runtime. Otherwise, you can emulate it with JavaScript, if you value developer convenience more than user experience.

I'd encourage anyone interested in this to create a custom element that implements this functionality and try to get broad adoption. If it gets broad adoption we can consider building it into the platform, as we have done with other things like jQuery -> querySelectorAll.

@domenic domenic added addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest labels Jun 27, 2017
@rianby64
Copy link

@domenic I tried to develop this idea as a custom element for my projects, and found that it's possible to achieve HTML import, but there are some things that made that solution hard to debug. For instance, beforescriptexecute was removed or even not implemented. Because of that I was forced to turn all my scripts into "inline" scripts.

I'll keep on spreading the word with more cases about how to split the code into small pieces without using extra JS effort.

@Yay295
Copy link
Contributor

Yay295 commented Jun 27, 2017

What's the actual purpose of this? As domenic mentioned, you can already do this quite easily server-side, so why do we need an HTML element to do it less effectively?

@rianby64
Copy link

Personally, I found this feature very useful in my projects. But, this is only my personal opinion. And, what @domenic said sounds fair. The only thing that I'd like to repeat is the absence of beforescriptexecute event, that forces me to turn all the scripts into inline scripts. All other primitives are enough to implement this functionality into a custom element.

I'll be happy to share with you @Yay295 or anybody else my experience with this feature, the pros and cons, but that chat should be outside this issue.

@brandondees
Copy link

I think it would be quite useful for any cases where we want DRY html authoring but not the burden of running code server side or requiring JS. It's actually what I naively expected html imports to do at first.

The use cases may be relegated primarily to the realm of small, static-only websites but I think it's a huge advancement for those cases. Simple static-only sites are a large number of websites, or sites that probably should be purely static but cannot be for reasons such as requiring server side rendering to DRY shared fragments such as header/footer, etc. I'm thinking of all the shared web hosting site builder tools and a large number of wordpress sites (a security/maintenance nightmare for typical site owners in my experience) and things along those lines. These kinds of sites are typically owned/maintained by the least tech-savvy operators and are therefore likely under-represented in these kinds of platform-advancement discussions. I'm aware that dynamic rendering or static build tools can get the job done, but those are inaccessible tools to a majority of simple website owners (again, in my personal experience).

The JS-free aspect gets back into the philosophy of progressive enhancement including "site basically works without scripting enabled" and I think that's still important, personally, particularly when we have Brave browser picking up steam with JS disabled by default for security/privacy purposes.

I may try to take a stab at faking this using a custom element backed by fetch, but it wouldn't fill the same gap IMHO and would merely be a demonstration for illustrating the convenience it can provide to the page authoring experience once it's all set up.

@brandondees
Copy link

I might also comment that I would expect client side includes to do something efficient with caching based on server headers or whatever, minimizing the UX cost of the extra round trips after first load (and I would presume we could also use link rel=preload etc. to great effect for load time beyond the first page). With http/2 implemented appropriately the UX cost of this feature should go away entirely.

@grepsedawk
Copy link

grepsedawk commented Jun 29, 2017

I want to jump in and mention that PHP (Personal Home Page) was literally created to solve this problem "In the most simple way possible". This could be simply done on the browser/markup level so much easier.
Imagine if the client could cache the entire HEADER and FOOTER and only need to d/l the main content... Sounds like pretty dang powerful feature to me!

@rianby64
Copy link

HTML import feature is what big frameworks offer indirectly. I think, if we've this feature then we've more possibilities to write nice things in a simple way. If HTML imports will be present right into the browser then I'll feel that it is a complete framework.

@AshleyScirra
Copy link

Further to @brandondees' point, I think I'd point out that offline-first PWAs using Service Worker very much encourage a client-side approach. For example in our PWA (editor.construct.net), despite it being a large and complex web app, we generate virtually nothing on the server side. This is the obvious way to design something that keeps working offline, because everything is static and local, and there's no need for a server to be reachable, especially if all the server is doing is a trivial substitution of content that could easily be done client side. So I think there are actually some significant use cases where you might want to process an include client-side, and "just do it on the server" doesn't cover everything.

@TakayoshiKochi
Copy link
Member Author

FYI, there was a same discussion happened at WICG/webcomponents#280

@brandondees
Copy link

I've implemented my own very quick-and-dirty demonstration here devpunks/snuggsi#109 to begin experimenting with the pros/cons this feature might have, and we're attempting to keep track of other related efforts for reference as well. @snuggs took it beyond the most basic proof of concept and appears to have brought it close to general production-readiness.

I had a discussion recently with a colleague whose initial impression was that this concept merely re-invents server-side includes, which should otherwise be easy enough to work with for most content authors, but I think there are some significant subtle differences still. It's not clear to me why server side includes have not been well leveraged in commonly used website building tools, and I think the reasons boil down to a lack of accessible (read: free) and user-friendly (enough for non tech-savvy users) authoring tools supporting that technology, and lack of standardization. There can be performance benefits from automatically leveraging client side caching of partial documents, which is something I was always baffled by the absence of since I first began learning web dev. New page loads for a given site can retrieve primarily only the portions of the document that are unique, without the need to re-transmit boilerplate sections such as header, navigation, footer, sidebars, etc. without even getting into how the same kinds of benefits also apply when using web component templates.

@TakayoshiKochi
Copy link
Member Author

TakayoshiKochi commented Jul 21, 2017

Oops - sorry about closing accidentally.

I had not been sure about the advantage of client-side processing against server-side include (including PHP's include(), which sounds popular but I don't have any data), but PWA (especially, using service worker to save client-server roundtrips) story in Ashley's #2791 (comment) sounds one of the good reasons of having client-side processing of HTML being okay.

@snuggs
Copy link
Member

snuggs commented Jul 21, 2017

Indeed @TakayoshiKochi we created a super simple <include- src=foo.html> iteration utilizing the DOMParser. Methinks this is how polyfills are (not doing a good job of) handling HTMLImports.

I'd encourage anyone interested in this to create a custom element that implements this functionality and try to get broad adoption. If it gets broad adoption we can consider building it into the platform, as we have done with other things like jQuery -> querySelectorAll.

I concur with @domenic. on providing a sound iteration/adption/developer ergonomics being worked on in this pull request.

The algoritm was as simple as follows. Also works with nested dependencies due to custom elements lifecycle reactions:

  Element `import-html`

  (class extends HTMLElement {

    onconnect () {
      this.innerHTML = 'Content Loading...'
      this.context.location = this.getAttribute `src`

      let headers = new Headers({'Accept': 'text/html'})

      fetch (this.context.location, {mode: 'no-cors', headers: hdrs})
        .then (response => response.text ())
        .then (content => this.parse (content))
        .catch (err => console.warn(err))
    }

    parse (string) {
      let
        root = (new DOMParser)
          .parseFromString (string, 'text/html')
          .documentElement

      , html = document.importNode (root, true)

      , head = html.querySelector
          `head`.childNodes

      , body = html.querySelector
          `body`.childNodes

      this.innerHTML = ''
      this.append ( ... [ ... head, ... body ] )
    }
})

Any caveats to DOMParser would be great. Especially older versions of IE.

Hope this helps @TakayoshiKochi

/cc @brandondees

@rianby64
Copy link

rianby64 commented Jul 21, 2017

I was thinking last days since @TakayoshiKochi opened this issue. And found really interesting how to integrate this feature include with Worker, <link>, <iframe> and so on, also don't forget to take in count CORS... Looks too hard to achieve the goal of HTML import in a simple way. If <base> could be more flexible, then this feature could be done "as we have enough primitives".

@Yay295
Copy link
Contributor

Yay295 commented Jul 21, 2017

Ignoring the fact that that code doesn't work, at all, you're really overthinking it. Here's a complete HTML test page. Just change the source to include.

<!DOCTYPE html>
<html>
    <head>
        <script>
            class include extends HTMLElement {
                connectedCallback() {
                    fetch(this.getAttribute('src'), {mode: 'cors', credentials: 'same-origin'})
                        .then(response => response.text())
                        .then(text => this.outerHTML = text)
                        .catch(err => console.warn(err));
                }
            }

            customElements.define('include-html', include);
        </script>
    </head>
    <body>
        <!-- Include the partial HTML. -->
        <!-- If the included HTML has includes, they will be included too. -->
        <include-html id="test" src="to_include.html" />

        <!-- No problems here either. It just logs an error if this happens. -->
        <!-- script>document.getElementById('test').remove()</script -->
    </body>
</html>

This should be a void element in my opinion. There's nowhere to put any nested elements except after everything, so you might as well just put them outside the include instead.

p.s. "Any caveats to DOMParser would be great. Especially older versions of IE." is irrelevant considering custom elements currently only work in WebKit browsers.

@rianby64
Copy link

rianby64 commented Jul 21, 2017

@Yay295 Nice. But how to execute scripts that are present in src="to_include.html"?

The concept of HTML import should be more than just pasting static HTML, right?

@AshleyScirra
Copy link

I think the intent here is just to paste DOM content in to another document. HTML imports are a different feature.

@rianby64
Copy link

Ok @AshleyScirra . You're right. As consumer, If paste DOM content in to another document then I expect to see scripts, links, workers et al and other inclusions parsed and executed. Hope this feature will gain broad adoption.

@snuggs
Copy link
Member

snuggs commented Jul 21, 2017

Ignoring the fact your code doesn't work ...

  1. @Yay295 the code works fine. Was a snippet from the pr that was clearly referenced in the previous comment. Spared you the details.
  2. This code is also intended to be used as a polyfill of sorts for the crappy implementation of webcomponentsjs polyfill that currently breaks for reasons outside of this thread. Therefore to be clear we PERSONALLY need a bonafied Document not a string.
  3. tried your method but ran into a few issues on different (ancient) platforms. Have you tried (with scripts) more than just your browser @Yay295 ? Just curious.
  4. was the fastest past could think of that runs external scripts and styles. DOMParser is fairly "ancient" based off spec. (thanks for the refactor tho 😎 will add it to our pull request if HTML Imports keels over)

/cc @brandondees @pachonk

@bahrus
Copy link

bahrus commented Dec 3, 2022

I suppose it could be argued that if you need a callback, maybe better just to import the HTML programmatically, but then there are other features that the include-fragment-element have that would need to be rewritten. So maybe the built in include element could be extended by consumers to include a callback. But support for extending built-in elements doesn't have full support across all browser vendors, so there's that.

What a tangled web.

@sashafirsov
Copy link

@sasha-firsov-bs SaxonJS is exactly what you're talking about: a client-side XSLT 3.0 engine with support for DOM manipulation and event handling.

@namedgraph , SaxonJS is good as part of polyfill, for browser vendor the native C implementation is more suitable. Free OSS libxslt or commercial choice from Saxonica, Altova, etc. As XSLT is a standard, vendors would choose which is more performant, supported, or costly :)

As stated, XSLT engine alone is not sufficient, there is a need for data layer access update and syntax sugar adjustments.

@LeaVerou
Copy link

LeaVerou commented Dec 3, 2022

(Skipping last few posts about XSLT, as I don't think that’s a productive avenue right now…)

As someone who teaches HTML to CS students who are web dev beginners, the lack of this currently makes for a very steep learning curve. Re-using blobs of HTML is needed in pretty much every multi-page website. However, to do that today, you need either JS, or build tools, both of which are far more advanced concepts to teach than HTML alone.

@bahrus
Copy link

bahrus commented Dec 4, 2022

Correction:

I think the include-fragment-element does provide the ability to make adjustments of the content , which would only work in a non-streaming scenario.

@sashafirsov
Copy link

sashafirsov commented Dec 4, 2022

@bahrus , the ability to interrupt/inject the content via pre- and post- load events or another methods are not relevant to html include alone and can be skipped in this thread.

The pattern of load transformation pipeline is essential for evolutionary architecture approach on resources and module loading. Applicable as for html modules as for css, JS and all kind of dependencies. It is necessary for co-existing of different API/implementation versions. It is essential for adoption of new proposals by polyfill substitution by native code and fallback for legacy polyfills by browser as a platform itself.

@here, please thumb up if want to participate in transformation pipeline discussion. The proposal is baking.

@bahrus
Copy link

bahrus commented Dec 6, 2022

I've updated this package to use the trick mentioned earlier, to stream a fetch to a target element, in case anyone finds that helpful.

@bahrus
Copy link

bahrus commented Dec 6, 2022

Re-using blobs of HTML is needed in pretty much every multi-page website. However, to do that today, you need either JS, or build tools, both of which are far more advanced concepts to teach than HTML alone.

Even if in some of those cases, it might make sense in the end to have a build step so that the inclusion happens on the server, we have plenty of precedent where the platform allows us to develop in a way that isn't always optimal in the final product:

  1. We can test our code with non-minified JavaScript (with or without source maps).
  2. We can use import maps of unbundled js during development, even if we end up bundling.
  3. There's a stage 1 tc39 proposal to treat typing as comments.

I think if the browser blesses some syntax for inclusion, a syntax could organically grow across multiple server technologies that extends the syntax to (conditionally) do the inclusion on the server. As github developers put it:

This declarative approach is very similar to SSI or ESI directives. In fact, an edge implementation could replace the markup before its actually delivered to the client.

<include-fragment src="/github/include-fragment/commit-count" timeout="100">
  <p>Counting commits…</p>
</include-fragment>

A proxy may attempt to fetch and replace the fragment if the request finishes before the timeout. Otherwise the tag is delivered to the client. This library only implements the client side aspect.

@andremarcondesteixeira
Copy link

This discussion will never be productive until the "application-centric" folks refuse to open their minds to understand that we want a *simple" way to compose HTML, wait for it, WITHOUT scripting languages or complex tooling.

@maherbo
Copy link

maherbo commented Dec 8, 2022

To anyone interested, the latest discussion stirred up some ideas to play with and I develop the following solution:

https://github.com/maherbo/include-HTML-document-fragment

Although I have not tested the concept extensively, I'm quite satisfied with the results:

  • Uses methods already implemented and optimized by the user agents, each in their own way;
  • Degrades gracefully for user agents that do not have those methods (even ones not using javascript; although this shouldn't be a problem once such a method is implemented in the specs);
  • Simply defines a few new attributes to an already defined element, i.e. the anchor element <a>.

@bahrus
Copy link

bahrus commented Dec 8, 2022

Discovery of the day:

With the stream-orator package, which streams html to a target element, if I first attach a deep mutation observer on the target, and rename all the img/src attributes to data-src the moment the mutation observer picks up on the presence of the element, it does successfully block most of the requests going out to invalid image url's, at least with Chrome. No such luck with Firefox. Eventually I'll fire up my old mac mini if it hasn't died in its sleep and try there. Also not sure yet how much the mutation observer weighs on the performance, if it cancels out the benefits of streaming. I suspect not.

So in the absence of an HTMLRewriter solution like Cloudflare supports, it seems we can apply transforms to the DOM before it's too late, even for image links, on Chrome at least.

Demo here.

@sashafirsov
Copy link

@andremarcondesteixeira ,

we want a *simple" way to compose HTML

there is no contradiction on simple use case. The subject for debates is how to handle advanced scenarios.
Once folks get used to INCLUDE, immediately discussion would come around fallback with inline DOM, how to apply base attribute, how to handle template filling tags, etc.

The weird part that all this deviations are making the primary argument of keeping the proposal alive: previous ones been closed due to "small interest". Ouch!

@bahrus
Copy link

bahrus commented Dec 10, 2022

Package be-written is now working. It allows streaming to a DOM element, declaratively:

<div be-written=https://html.spec.whatwg.org></div>

It builds on be-based which tries its best to rewrite url links as soon as possible. It seems to work pretty well with Chrome, but isn't as effective with Firefox, as far as preventing preemptive downloads before the links have adjusted.

It also builds on stream-orator, which borrows code from here.

It doesn't yet have support for CSP which the github include component has.

PR's/suggestions welcome.

Cross-browser support for streaming like this is a fairly recent rollout (with little fanfare), so that's something to celebrate.

Still, something so fundamental like this (declarative includes) should be built-in, like yesterday.

Original idea might have been first publicized here. Another thing to celebrate is we don't need to use that iframe hack (any longer?), and the custom code size has greatly reduced since then.

@DavidJCobb
Copy link

Template stamping (#6417) has been brought up a few times, but I'm surprised to see that in most of the five years this issue has existed, it wasn't brought up specifically as something that alleviates concerns about network requests and blocking the parser. Right now, SVG has several places where you can refer to other files (href(url)) or to previously defined elements in the same file (#id); I see no reason why template stamping couldn't be made to work the same way, which would unify #6417 and this request.

Here are my own thoughts on some of the other topics brought up in here, along with some edge cases I've thought of, all from the perspective of having a single feature handle both template stamping and the use of external HTML resources. I'll be using the term "substitution" to refer to what the feature does, in contrast to "importing" (name of a deprecated spec) or "including," but I don't really care what the feature is called, in the end.

  • Substitution must be usable without any JavaScript whatsoever. It's worthless otherwise; it would offer nothing new, and would arguably be redundant with other proposals.

  • Substitution should be akin to copying and pasting the full content of the specified template element or external file. That means that concerns about relative paths, unscoped styles, etc., in the included file are completely irrelevant. (In particular, if the included content needs to contain scoped styles, then a more general mechanism for CSS scoping should be standardized and then used within the included content.) Use the base URL of the substituting document; allow style tags in the substituted document to affect rendering of the substituted document; et cetera. At most the only special behavior should be to refuse to execute script tags in the substituted-in content (maybe unless they're same-origin?).

    There are other proposals and suggestions for far more advanced and powerful "HTML module" ideas elsewhere, and IMO those ideas would be the place to tackle any behaviors beyond an automated copy and paste.

  • Substitutions should block rendering and interaction unless they're marked with a async attribute. When using substitutions for large chunks of a page's layout, blocking rendering and interaction also be needed to ensure a consistent user experience (no FOUC or massive layout shifts; no race conditions in keyboard navigation or screen reader navigation; etc.). Another user commented that using substitutions for large chunks of a site's layout is a desirable use case that could reduce bandwidth usage when browsing around; I agree with this view.

    In any case, whether substitutions block or are async should be the page author's choice: as others here have suggested, give people tools like async, and let them use or forgo those tools based on their page's unique needs.

  • Asynchronous substitutions introduce an edge-case: consider a page which substitutes in A and, later in the document, B; A contains a template element C; and B substitutes in the content of C. If B loads and is substituted in before A, then B may fail to find and substitute in C. There are two ways to handle this.

    a) If a substitution S specifies an element ID that does not match any template currently in the DOM, then suspend the substitution until parsing is complete and all other substitutions are either completed, failed, or suspended. After any other substitution completes, check whether the ID requested by S now corresponds to a valid template element; if so, perform S immediately. Once all substitutions are either completed, failed, or suspended, all suspended substitutions should become failed.

    b) Do not allow nested substitutions.

    The former approach is, in my opinion, the better of the two. I personally don't like the complexity here for what ought to be just an automated copy-and-paste, but it's necessary as long as blocking the parser is prohibited or an async option is considered desirable.

  • We should be allowed to perform substitution anywhere in the substituting file i.e. the head or the body.

  • The token (element or attribute) that triggers HTML substitution should not be left behind after substitution, to avoid breaking CSS as mentioned previously.

  • If substitution is triggered by a special element, e.g. <paste id="template"/> or <paste src="file.html"/>, then creating this element via document.createElement or via setting the value of innerHTML should have no effect. It's tempting to allow it to work in innerHTML and similar, but if it refers to an external file, then that means that the innerHTML setter has to block on a network request.

  • If substitution is triggered by a special attribute, e.g. paste="#template" or paste="file.html", then setting this attribute on an existing element via JavaScript should have no effect. This attribute should also have no effect when present in a string passed to innerHTML and similar, as with the previous bullet point.

    If an attribute is used for substitution and an element with that attribute has other children already, I am unsure whether those children should be replaced, appended to, or moved into any substituted-in template slot(s). Replaced content could function as fallback content for older UAs, but only if elements using the substitution attribute are display:none by default in supporting UAs.

  • I lean toward having substitution use an element, and toward having that element not be void. Child elements, if present, could be used as fallback content. Alternatively, if implementors are interested in expanding the feature, one way to do that would be having children of the substitution element replace slot elements in the substituted-in content. That would allow for a relatively small and controllable amount of dynamism when making substitutions, though it moves beyond the use case of "automated copy and paste," which is valuable on its own.

@bahrus
Copy link

bahrus commented Dec 28, 2022

More dispatches from the Department of Overcoming Browser Vendor Dereliction of Duty:

be-importing

Supports defining web components with streaming HTML, and rudimentary support for import maps.

Demo

Feedback/PR's welcome.

@bahrus
Copy link

bahrus commented Dec 29, 2022

Update: I'm finding that on Safari 16.4 (that comes with Playwright), web components aren't picked up when streaming inside ShadowDOM. Is this a known issue?

@bahrus
Copy link

bahrus commented Dec 29, 2022

stream-orator has been updated to explicitly avoid streaming in the case of the Safari browser, because I've confirmed in multiple ways that in fact when streaming into a ShadowDOM fragment, already registered web components aren't recognized, and remain unknown elements.

I would file a bug, but I know Safari is undergoing experiments with Streaming and ShadowDOM, so I imagine this might be a side effect of that ongoing work, and hopefully will be fixed as part of that rollout.

@coolaj86
Copy link

coolaj86 commented Sep 10, 2024

The user experience is much better if such inclusion is done server-side ahead of time, instead of at runtime.

you can already do this quite easily server-side, so why do we need an HTML element to do it less effectively

These are simply strawman / bad faith arguments.

If those statements were identifying the true maxims, then why would we have bothered with @import for CSS or import for JS then? Or <picture>?

We've been bundling for 20+ years now, so if server-side were the end-all be-all we would have never gotten baseline import in (it did take until March of 2023, but hey, that's better than never - and it seems that import for JSON and css will be supported as well: https://caniuse.com/?search=import%20type).

In any case, it's turned out that bundlers have been a mostly bad idea. Although the biggest tech companies may be using them effectively, the average websites are loading HUGE packages - the most I've seen for a single top-level package is 37mb (though I'm sure that's just because I don't look often and I'm on fiber - most of us techies never have to deal with phone speeds and when we do, eh, any given web page being broken is just the norm these days).

And look at any React site: You want to load a simple form component and, 500mb of node_modules and 2mb of client-side JS later, viola! React is pretty much solving that "simple" problem of PHP, but reimplemented on the fontend... leaving out a substantial number of mishaps, but still almost no one is using it effectively. It's a very, very complex way to include some HTML with a few click and submit handlers.

So if we can get to the point were it's easier to do the right thing than the wrong thing - allow developers to fall into the pit of success - imagine how much less complexity we would have. Imagine if including a form component to post a sub to an email marketing list were as simple as a client-side include without node or vite or express or rails?

It's deceptive - you think those round trips will get you - but as mentioned, client-side caching can actually be quite good - especially when you can automate it via keeping to existing standards, and when you code more simply it's quite paradoxical - you end up writing more lines of code to get the hello world or define a component... but then total lines of code are several orders of magnitude less.

And if the server is truly the right place to do it, well, web servers are already pre-compressing and caching assets. How would having a standard for knowing exactly which HTML files to pre-bundle be a bad thing?

That's a win-win-win!

@jakearchibald
Copy link
Contributor

In any case, it's turned out that bundlers have been a mostly bad idea. Although the biggest tech companies may be using them effectively, the average websites are loading HUGE packages

Removing bundlers doesn't solve that problem. Without a bundler you'd still be loading the same amount of code, but over multiple request/responses. Compression would be hurt too.

To avoid loading the whole tree, the developer would need to use multiple entry points, and lazy-load code that isn't immediately. When this is done, bundlers can optimise with this information too.

This isn't an argument against client side HTML includes, just pointing out that the argument presented here doesn't make sense.

@dy
Copy link

dy commented Sep 15, 2024

Certain frameworks, like alpine, petite-vue, sprae and similar cannot have components because of that limitation. Eg. alpine suggests using server templating for that.
Also, variety of declarative custom elements libs are blocked from client-side modularization.
I guess that is one obvious argument for HTML includes proposal.

@andremarcondesteixeira
Copy link

andremarcondesteixeira commented Sep 15, 2024

I completely agree with @coolaj86

Would be a dream being able to have a blog using only static html files and no javascript. And then updating the whole layout (even for old posts) without the need to use Static Site Generators.

I think we would not need Static Site Generators anymore as soon as we have HTML includes.

Caching and lazy loading would prevent network issues.

Also, this specific thread started in 2017. It's been at least 7 years that people are asking for it (probably even longer)

@sashafirsov
Copy link

@andremarcondesteixeira ,

Would be a dream being able to have a blog using only static html files

Just HTML include would not be the answer for your demand. Declarative Custom Element would be. As the site would need not just include but templating.
custom-element as one of DCE implementations allows that. Eventually would make the proposal based on it,

@o-t-w
Copy link

o-t-w commented Sep 19, 2024

The HTML modules discussion this issue was spun off of is still an open issue, but also worth noting this newer somewhat related issue for HTML Module Imports and Exports WICG/webcomponents#1059

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest
Development

No branches or pull requests