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

Import/require html from js #926

Conversation

pierredavidbelanger
Copy link
Contributor

@pierredavidbelanger pierredavidbelanger commented Mar 1, 2018

This is the first time I contribute to this project, so I am sorry if I missed something important.

I wanted to do something like what is described here #848
In short, I wanted to be able to const template = require('./other.html');

You will see that I have no idea what I'm doing ;)
I am especially not proud of how I ended up butchering src/packagers/HTMLPackager.js

Also, all 232 tests are still passing.

Fixes #848
Closes #178

@codecov-io
Copy link

codecov-io commented Mar 1, 2018

Codecov Report

Merging #926 into master will increase coverage by 0.15%.
The diff coverage is 90%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #926      +/-   ##
==========================================
+ Coverage   89.58%   89.73%   +0.15%     
==========================================
  Files          68       68              
  Lines        3255     3264       +9     
==========================================
+ Hits         2916     2929      +13     
+ Misses        339      335       -4
Impacted Files Coverage Δ
src/Bundler.js 92.88% <100%> (+0.02%) ⬆️
src/packagers/JSPackager.js 100% <100%> (+10%) ⬆️
src/packagers/HTMLPackager.js 95.74% <87.5%> (-1.76%) ⬇️
src/assets/CSSAsset.js 81.73% <0%> (-4.35%) ⬇️
src/utils/installPackage.js 61.9% <0%> (-3.18%) ⬇️
src/assets/JSAsset.js 90.83% <0%> (-3.06%) ⬇️
src/WorkerFarm.js 91.93% <0%> (-1.62%) ⬇️
src/visitors/fs.js 80.55% <0%> (+0.69%) ⬆️
src/utils/PromiseQueue.js 97.67% <0%> (+2.32%) ⬆️
src/assets/StylusAsset.js 86.04% <0%> (+2.32%) ⬆️
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e7ea515...ee2236c. Read the comment docs.

@pierredavidbelanger
Copy link
Contributor Author

I initially assumed some things wrong. So I just pushed a new commit.

All tests are still passing.
Also, I am able to use the new feature in my simple angularjs projets.

Still, I do not really know what I am doing, I essentially just randomly hack here and there.

I do not know why I get this same error with my OnsenUI project.
I hope it is not related to my parcel hack.
I cannot tel for now.

Anyways, I hope this PR can help someone :)

@davidnagli
Copy link
Contributor

How does this relate to #293?

@pierredavidbelanger
Copy link
Contributor Author

@davidnagli I am actually using such a custom bundle loader to implements the HTML loading part.

But, in retrospect, and to be honest, I am not sure I am heading the right way with this PR.

I guess, one want to fetch(require('./other.html')).then(...)
but not const content = require('./other.html'); as this PR does.

What do your think ?
I can discuss this further on the Slack if you want.

@davidnagli davidnagli added the 📝 WIP Work In Progress label Mar 3, 2018
@BrOrlandi
Copy link

I want this feature too! 👍

@lbguilherme
Copy link
Contributor

@pierredavidbelanger You want import('./other.html').then(...), which this PR seems to cover

@arabsight
Copy link

This will enable me to use aurelia, I was hoping something like this would be added 👍

@davidnagli davidnagli removed the 📝 WIP Work In Progress label Mar 7, 2018
Copy link
Contributor

@davidnagli davidnagli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! 🎉

@@ -0,0 +1,5 @@
module.exports = function loadTextBundle(bundle) {
return fetch(bundle).then(function (res) {
return res.text();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use an arrow function here 😀

module.exports.loadTextBundle = bundle => fetch(bundle).then(res => res.text())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linter (in the pre-commit hook) does not seems to like arrow functions:

src/builtins/loaders/text-loader.js
  1:26  error  Parsing error: Unexpected token >

✖ 1 problem (1 error, 0 warnings)


husky > pre-commit hook failed (add --no-verify to bypass)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to commit this:

module.exports = bundle => fetch(bundle).then(res => res.text())

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ya builtins are supposed to be in ES5 👍

@@ -0,0 +1,5 @@
module.exports = function loadTextBundle(bundle) {
return fetch(bundle).then(function (res) {
return res.text();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ya builtins are supposed to be in ES5 👍

@ghost
Copy link

ghost commented Mar 9, 2018

Is this PR supposed to be released with the next release?

@davidnagli
Copy link
Contributor

Just realized the broader implications of merging this PR...

Currently HTML file imports are treated like RawAssets, in that they just return the resolved URL pointing to the file and not the actual contents of the file itself.

However, by changing this behavior to allow HTML imports, we effectively break the way it previously worked.

That means that anything like:

import loginPage from 'login.html'

<a href=loginPage>Link to login page</a>

would suddenly break, since now loginPage would be the actual contents of the login page rather than the url to the login page as it was before.

Maybe I'm wrong? Does your code magically handle this somehow?

Most likely we're gonna need to carefully design how this will play out and potentially introduce a breaking release when the time comes (Parcel 2.0?). Let me know if I'm wrong, but if not we should open a separate RFC issue to discuss / design everything and then come back to this once that's ready.

Copy link
Contributor

@davidnagli davidnagli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding blocking review to prevent merging for now until we work through those kinks

@pierredavidbelanger
Copy link
Contributor Author

@davidnagli You are absolutely right. This PR breaks the way it previously worked. And my code does NOT magically handle this :)

I had a bad felling a couple days ago about heading the wrong way with this PR.
Now you proved it.

If was just me, I would close this one, until we know what we need and, of course, when Parcel is ready for a breaking release.

@pierredavidbelanger
Copy link
Contributor Author

@davidnagli just to be sure though,

right now, with the master branch, your snippet is not working:

import loginPage from 'login.html'

<a href=loginPage>Link to login page</a>

for at least 2 reasons:

  • the generated HTML file name (the the file system) is not the same as the dependency name required() in the parent .js file
  • the HTMLAsset is not treated like a RawAssets, so no module.exports="/whateverf171619ff7dcf2171a706973.html"; is generated in the parent .js like it should with, say, a .txt file

I can try to have a look at this.

@pierredavidbelanger
Copy link
Contributor Author

@davidnagli I created the simplest app that demonstrate the problem:

git clone https://github.com/pierredavidbelanger/parcel-html-test
cd parcel-html-test
yarn install
yarn run build
ls dist && tail dist/*.js
510368565fb792405acc6a86524a444c.html 510368565fb792405acc6a86524a444c.js   index.html
LazyPromise.prototype.then = function (onSuccess, onError) {
  return this.promise || (this.promise = new Promise(this.executor).then(onSuccess, onError));
};

LazyPromise.prototype.catch = function (onError) {
  return this.promise || (this.promise = new Promise(this.executor).catch(onError));
};
},{"./bundle-url":10}],0:[function(require,module,exports) {
var b=require(8);b.load([["6b4a33c18b69460d577328b29c800143.html",6],4]);
},{}]},{},[0])

Just in the little snippet here you can see both points (file name VS dep name, raw URL VS bundle-loader) I mentioned earlier.

@pierredavidbelanger
Copy link
Contributor Author

I am sorry, it may seems spaghetti at first, but I tried to keep the concern separated, in case you accept one PR ant not the other.

I submit two PRs, for both the points I mentioned in a previous comment.

I suggest you try my simple app that demonstrate the problem, then pull #1016 and #1017 into your local parcel, and try again my simple app; the problem is gone.

I think that #1016 and #1017 are better fixes than this PR for the problem of require('./other.html');

@adrian7
Copy link

adrian7 commented May 4, 2018

FYI when all you need is to import a html file inside a string (e.g. like a nav menu or a logo with link) -

//Import html as string
import templateString from './template.html';

//Parse string to dom node
let template       = document.createElement('template');
templateString     = templateString.trim(); // Never return a text node of whitespace as the result
template.innerHTML = templateString;

//Return DOM Node
console.log(template.content.firstChild);
return template.content.firstChild;

You can use the babel plugin: babel-plugin-transform-html-import-to-string

@bricss
Copy link

bricss commented May 15, 2018

FIY -> It's impossible to use Parcel almost in any project without this feature.

@BrOrlandi
Copy link

@adrian7 That's the perfect solution. I think that would be nice to have it by default in Parcel bundler.
@bricss It's not true, I'm using Parcel in projects without needing to import HTML files.
I wanted to import HTML files to be able to develop my own Router, it would be a nice use case.

I have implemented a sample project with @adrian7 solution:
https://github.com/BrOrlandi/ParcelImportHTML

@mjgerace
Copy link

I think this is a pretty crucial feature to merge in. Voicing support for this feature.

@jluisgarcia
Copy link

jluisgarcia commented May 21, 2018

yes, import/include (whatever you want to call it). It would be Awesome
html includes typically to share navigation across multiple pages.
Edit in one place and parcel would take care to include across all pages
i.e. <include src="./nav.html"></include> (inside index.html)

@bricss
Copy link

bricss commented May 21, 2018

Simple question to ask about this PR. What if I don't want to put HTML, CSS and JS in one file, e.i. JSX? How to build projects then? Therefore, Parcel is mainly useful for a projects using React and similar libraries.

@Elazul
Copy link

Elazul commented May 30, 2018

@adrian7 I owe you a big thanks. Your solution is perfect for importing AngularJS 1.6 component templates.

@stevengill
Copy link

Thanks @adrian7! The babel plugin worked at getting a string representation of the html.

One issue it doesn't handle is resolving the dependencies/assets in the html file. For instance, if i have <img src="./imgPath.png" />, ./imgPath.png isn't copied into dist.

@stevengill
Copy link

I've posted an updated PR based on this work over at #1528.

@jpenna
Copy link

jpenna commented Jul 22, 2018

It would be nice to have the solution @adrian7 suggested (babel-plugin-transform-html-import-to-string) in the docs. I've been struggling with this for a long time already and this not just fixed my problem but also simplified a lot the code, without the readFileSync (which only runs in the entry JS, for what I observed) and it's "results".

If you think it is valid to have it there I can do the PR.

@devongovett
Copy link
Member

@jpenna this issue has been solved, and the html bundle loader will be available in the next release.

@soncodi
Copy link

soncodi commented Jul 22, 2018

@devongovett Attribute lowercasing in included HTML files appears to break Angular templates:

<div *ngFor="let t of xyz$ | async">
is returned as:
<div *ngfor="let t of xyz$ | async">

@JudeOsborn
Copy link

Is this supposed to be working? When I do this:

import someFile from './somefile.html

I get this:

Uncaught SyntaxError: Unexpected token '<'

I suppose that's what I would expect with a typical import because I'm importing an HTML file and it's expecting a module, but this ticket gives me the impression it should work with parcel. Am I misunderstanding?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.