How to use relative path?

21 views
Skip to first unread message

Yuri Karadzhov

unread,
Oct 26, 2017, 8:26:32 AM10/26/17
to Web Components Organisation
Hi, I'm trying to move our team to web components, but I got this problem - all paths inside a template and style should be absolute, so if I move component around or decide to put it on server it stops working.

e.g. having such component test-hi.html
<template>
 <link rel="stylesheet" href="./test-hi.css"> <!-- THIS RELATIVE PATH WON't WORK -->
 <p>Hello <span id="name"></span>!</p>
</template>
<script src="./test-hi.js"></script> <!-- this relative path works because it is part of a component document which has correct baseURI -->
with style test-hi.css in a component folder
span {
 color: red;
}
and script test-hi.js
const innerDocument = document.currentScript.ownerDocument; // We need a link to a component's document to be able to query for a template

class TestHi extends HTMLElement {
 static get observedAttributes() {
   return [ 'name' ];
 }

  get name() {
   return this._name;
 }

  set name(val) {
   this._name = val;
   this.setAttribute('name', this.name);
 }

  constructor() {
   super();
   this.attachShadow({ mode: 'open' });
// Next line is different from official example https://developers.google.com/web/fundamentals/web-components/customelements // that does not work because, during construction, main document is equal to root document rather then component's document.
// However it still works with webcomponents.js polyfill in Safari (just document.querySelector, relative paths are broken as well)
   const { content } = innerDocument.querySelector('template'); // document.querySelector('template') will return template from root document or null, but not component template
   const instance = content.cloneNode(true); // instance will have baseURI equals to root document baseURI rather then component's document baseURI so all relative paths will be broken
   this.shadowRoot.appendChild(instance);
 }

  attributeChangedCallback(name, oldValue, newValue) {
   switch (name) {
     case 'name': {
       const nameField = this.shadowRoot.querySelector('#name');
       if (nameField) nameField.textContent = newValue;
       break;
     }
   }
 }
}

window.customElements.define('test-hi', TestHi);

And importing it like this
<link rel="import" href="/test-hi/test-hi.html"> <!-- here should be absolute path to the component from the project root -->

I will have problems with loading correct styles (same for images and all resources with relative paths).
But as component suppose to be independent and may be put in different places or even servers it is not possible to specify absolute (from the main project root) paths.

Well it is possible to parse CSS and DOM inside component's constructor and correct all relative paths to absolute ones, or alternatively put everything together into single HTML template, but there should be more elegant solution.

Please share it if you know it.

Rob Dodson

unread,
Oct 26, 2017, 10:48:09 PM10/26/17
to webcom...@googlegroups.com
I'd suggest asking this on StackOverflow. Unfortunately I don't remember the workarounds off the top of my head. I usually put everything in one file to avoid path weirdness :\

--
You received this message because you are subscribed to the Google Groups "Web Components Organisation" group.
To unsubscribe from this group and stop receiving emails from it, send an email to webcomponent...@googlegroups.com.
To post to this group, send email to webcom...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/webcomponents/41e8a039-7d3d-4bd5-9389-dcc523725b22%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Yuri Karadzhov

unread,
Oct 27, 2017, 8:14:19 AM10/27/17
to Web Components Organisation
Thanks, I will ask for other solutions, but isn't it look like a problem with specification? There should be a way to split structure (html), style (css) and logic (js) in different files and still have ability to move it around, otherwise it is hard to call a real component.

Here https://github.com/GoogleChromeLabs/howto-components/blob/master/elements/howto-checkbox/howto-checkbox.js you are using build step to put actual absolute path into html template.

I'm not sure there is a possibility to fix it without parsing and changing all the paths manually (during the build or runtime) or putting everything together in one file.

Yuri Karadzhov

unread,
Oct 27, 2017, 9:44:38 AM10/27/17
to Web Components Organisation
Another problem here is that if I decide to import anything inside component script and make it type equals to module (so the import will work) I will lose the reference to currentScript and won't be able to query for a template.

Yuri Karadzhov

unread,
Oct 27, 2017, 10:08:36 AM10/27/17
to Web Components Organisation
Well packing everything together does not solve the issue with import and images inside css and html, so there is the only way to parse and change path (on build or run time).

Stack overflow has a question about this problem from 2015 https://stackoverflow.com/questions/33454910/paths-in-web-components-are-relative-to-root that pointed out the specification problem.

Seems like the problem is not addressed after these years and web components are still not ready to use as they are, we will still be required to use build tools to make them work somehow.
Reply all
Reply to author
Forward
0 new messages