html-loader icon indicating copy to clipboard operation
html-loader copied to clipboard

Including html partials within html partials without the interpolate option

Open leo-petrucci opened this issue 5 years ago • 84 comments

Documentation Is:

  • [x] Missing
  • [ ] Needed
  • [x] Confusing
  • [ ] Not Sure?

Please Explain in Detail...

At some point in the past html-loader had an interpolate option. This allowed to load partials within partials in templates. As far as understand it this recently got deprecated and replaced with preprocessor.

So, answers like this one aren't working anymore.

A couple of questions like this one asking how to achieve it popped up, but they've gone without answers.

The documentation seems unclear as if this is still possible as the only example mentions handlebars and only shows this implementation within the webpack config.

Your Proposal for Changes

Is there any chance an official explanation of how to achieve this could be provided in the docs or even in this thread? I've tried everything possible and I'm absolutely lost.

leo-petrucci avatar Jun 01 '20 20:06 leo-petrucci

I ended up reverting to 0.5.5, which works without any problems. I'm unsure why this breaking change was included without a way to replace it?

leo-petrucci avatar Jun 02 '20 09:06 leo-petrucci

Can you provide example how you want to include? You have JS, so you can include anything

alexander-akait avatar Jun 02 '20 11:06 alexander-akait

Can you provide example how you want to include?

Including already works:

<%= require('html-loader!../components/navbar/index.html') %>

The problem is that without the interpolate option (as well as the root option), if one of the files I include has another inclusion within it, then it won't actually be included. This means I can't have a component within a component which severely limits what's possible.

Why not bring back how it used to work?:

<%= require('html-loader?root=.&interpolate!../components/sidebar/index.html') %>

You have JS, so you can include anything

If I include from JS it will be added client side, which is of course not great for SEO. I need Webpack to build all my files into a single component.

leo-petrucci avatar Jun 02 '20 12:06 leo-petrucci

It is out of scope HTML spec, HTML doesn't support <=% require() %=>, so we do not support it, you need loader for this loader, also JS has import and it can be used with it

alexander-akait avatar Jun 02 '20 12:06 alexander-akait

https://github.com/webpack-contrib/html-loader#preprocessor

You should always return valid HTML

alexander-akait avatar Jun 02 '20 12:06 alexander-akait

It is out of scope HTML spec, HTML doesn't support <=% require() %=>, we doesn't support it, you need loader for this loader, also JS has import and it can be used with it

The html-loader already supports <=% require() %=>. Either way that's not my point. I'm not asking to support <=% require() %=>, I'm asking to either:

  • Get an entry in the docs to explain how to properly replace interpolate with preprocessor to allow html components
  • Bring back interpolate so that interpolating html is possible

Which are not out of scope

leo-petrucci avatar Jun 02 '20 12:06 leo-petrucci

Get an entry in the docs to explain how to properly replace interpolate with preprocessor to allow html components

We have examples for handlebars/PostHTML, it is a most popular solutions, we can't cover all edge cases

Bring back interpolate so that interpolating html is possible

No interpolating more, if you need it you can create own loader, we support only pure HTML, because it will be part of core webpack, webpack supports non standard stuff only through loaders/plugins

alexander-akait avatar Jun 02 '20 13:06 alexander-akait

The html-loader already supports <=% require() %=>.

It is just luck that you did not receive an error while parsing.

alexander-akait avatar Jun 02 '20 13:06 alexander-akait

I strongly recommend migrate on a template system, using require is the bad solution and have many bugs and limitations

alexander-akait avatar Jun 02 '20 13:06 alexander-akait

Would it be a problem if I spun html-loader 0.5.5 (the last version that supported this) into its own loader?

The demand is there and people clearly prefer using this rather than learning some other templating system. It's also the suggested way by webpack-html-plugin to load partial HTML files, so it seems a bit closeminded to say

It is just luck that you did not receive an error while parsing.

As far as I see it there's not really enough information on how to use preprocessor. It would probably serve the function I'm asking fairly well, it's just unclear how I could set preprocessor to use a normal loader rather than another library to process my files.

On top of that the changelog states:

the interpolate option was removed, please consider migration on the preprocessor

But doesn't offer much explanation on how to do so.

leo-petrucci avatar Jun 02 '20 13:06 leo-petrucci

Would it be a problem if I spun html-loader 0.5.5 (the last version that supported this) into its own loader?

Yep, you can do it temporary, but I would advise speed up migration on a template system

The demand is there and people clearly prefer using this rather than learning some other templating system. It's also the suggested way by webpack-html-plugin to load partial HTML files, so it seems a bit closeminded to say

We should remove it from examples

As far as I see it there's not really enough information on how to use preprocessor. It would probably serve the function I'm asking fairly well, it's just unclear how I could set preprocessor to use a normal loader rather than another library to process my files.

Yep, we can improve docs about it.

On top of that the changelog states:

the interpolate option was removed, please consider migration on the preprocessor But doesn't offer much explanation on how to do so.

I provide examples for handlebars/PostHTML, I thought that was enough, maybe improving it for compatibility with other loaders will be great

alexander-akait avatar Jun 02 '20 14:06 alexander-akait

The crucial part for me to have the included file processed by webpack again before being included. I can include the file with PostHTML, but it only loads the raw file. If there is a way to achieve this could you please explain how?

philippdieter avatar Jun 02 '20 22:06 philippdieter

I can include the file with PostHTML, but it only loads the raw file.

What do you mean?

alexander-akait avatar Jun 03 '20 11:06 alexander-akait

What do you mean?

I set up posthtml and posthtml-include created a file file1.html with includes ~~<include src="file2.vue"></include>~~<include src="file2.pug"></include>. As output I got the content of ~~file2.vue~~file2.pug insertet into the html of file1.html.

Including the old way processed the content of file2.~~vue~~pug via webpack and the configured loaders.

philippdieter avatar Jun 03 '20 14:06 philippdieter

@philippdieter Maybe you can provide small example of configuration? I want to make sure that I understand you correctly

alexander-akait avatar Jun 03 '20 15:06 alexander-akait

I made the mistake and mixed up the endings of my files in the post above, I have updated them there, I am sorry.

I build an example located at https://github.com/philippdieter/html-loader-include-sample

The resulting output file is https://github.com/philippdieter/html-loader-include-sample/blob/master/webroot/file1.html

The output possible with include was <h1>Content file1</h1><h1>Content file2</h1> as the included file was processed by webpack, now its <h1>Content file1</h1>h1 Content file2

philippdieter avatar Jun 03 '20 16:06 philippdieter

@philippdieter Thanks, I will look at this tomorrow

alexander-akait avatar Jun 03 '20 16:06 alexander-akait

Yes, the same problem, here other problems most if loaders for HTML preprocessing returns JS content instead HTML, it's a little wrong, for example postcss-loader return CSS content, not JS, so css-loader + postcss-loader work fine

alexander-akait avatar Jun 04 '20 17:06 alexander-akait

Ideally pug-loader should return pure HTML for html-loader, here no solutions, only open an issue in pug-loader, even include not help here, it is a fundamental problem.

In theory we can add some magic to html-loader, like:

<div>My Custom Text</div>
<link rel="webpack-import" href="./index.html" />
<div>My Custom Text</div>

Will be compiled to:

import __HTML_LOADER_LINK_IMPORT_1__ from './index.html';

export `<div>My Custom Text</div>` +__HTML_LOADER_LINK_IMPORT_1__ + '<div>My Custom Text</div>';

And extracted to

<div>My Custom Text</div>
<div><img alt="Image" src="./path/to/img.png"><span>Foo</span></div>
<div>My Custom Text</div>

It is HTML compatibility, no problems with require/import, maybe even no lint problems

alexander-akait avatar Jun 04 '20 17:06 alexander-akait

I would like to hear your opinion.

alexander-akait avatar Jun 04 '20 19:06 alexander-akait

Other good idea https://github.com/w3c/webcomponents/issues/645

alexander-akait avatar Jun 04 '20 19:06 alexander-akait

JS has imports/exports, CSS only imports, HTML has not imports/exports :smile:

alexander-akait avatar Jun 04 '20 19:06 alexander-akait

Just to be sure you looked at the right module: In my example it's pug-plain-loder, not pug-loader. I remember vaguely about having used this loader because it returns html(?). I don't know enough about webpack internals to tell if there is a problem, all I know is that my setup worked with html-loader 0.5.5 and include ':D

I like the idea of the link tag very much.

As far as I understand w3c/webcomponents#645 it's about using includes on client side, right? As my current workflow relies on having the result of the including written into an html file to disk I would much appreciate the solution with the link tag.

philippdieter avatar Jun 04 '20 19:06 philippdieter

Just to be sure you looked at the right module: In my example it's pug-plain-loder, not pug-loader. I remember vaguely about having used this loader because it returns html(?).

Yes, I mean pug-plain-loader.

As far as I understand w3c/webcomponents#645 it's about using includes on client side, right?

Yes :+1:

I would not want to make this part as a separate option or an official solution, as this is still not standardized.

But we can do something small and simple.

We just need improve the attributes option, like:

{
  tag: 'include',
  attribute: 'src',
  type: 'template',
},

You can:

  • Using any tags/attributes
  • No new options, it is just advanced abilities
  • We do not ship new non standard features for HTML

alexander-akait avatar Jun 05 '20 16:06 alexander-akait

We just need improve the attributes option, like:

Having the option to specify a tag even sounds better than having a fixed one. I like this idea very much!

philippdieter avatar Jun 05 '20 19:06 philippdieter

<link rel="webpack-import" href="./index.html" />

I would really like this. Super elegant solution.

leo-petrucci avatar Jun 06 '20 22:06 leo-petrucci

Feel free to send a PR, I will do it, but only after next week

alexander-akait avatar Jun 07 '20 15:06 alexander-akait

Feel free to send a PR, I will do it, but only after next week

I'm not familiar with how html-loader works but I will definitely give it a shot.

leo-petrucci avatar Jun 07 '20 15:06 leo-petrucci

I am having the same issue, as I made a lot of use of interpolate too. My situation was like this.

The app has various HTML files that used this syntax to include HTML partials:

<%= require('html-loader?interpolate!../templates/header.html') %>

The example, header.html, uses commands that are parsed by Webpack. For example (removing irrelevant code).

<!doctype html>
<html lang="en">
<head>
  <script type="text/javascript">
  var appUrl = "${process.env.APP_URL}";
  ${require("!!raw-loader?esModule=false!uglify-loader!../static/browser-support.js")}
  </script>
</head>

<body>
  ${require("html-loader?interpolate!./nav.html")}

The interpolate feature was very useful. I don't need a templating engine, and it wouldn't really help in this case as I'm using Webpack to embed a JS file too...

Any chance it can be brought back, or is there a workaround?

ItalyPaleAle avatar Jun 11 '20 04:06 ItalyPaleAle

@ItalyPaleAle no interpolate and never, it is JS-in-HTML and very dirty way and never work fine, with future webpack versions you will get a lot of problems with this, solution was written above

Using:

<script type="text/javascript">
  var appUrl = "${process.env.APP_URL}";
  ${require("!!raw-loader?esModule=false!uglify-loader!../static/browser-support.js")}
  </script>

is very terrible, a lot of optimizations was missed + you can't use split chunks correctly, avoid it

alexander-akait avatar Jun 11 '20 11:06 alexander-akait