HTML import is not working in Electron app - javascript

I'm trying to build desktop app using Electron.
I'm having issue importing HTML template.
Code
<link rel="import" href="fileLocation/file.html">
file.html
<template>
<div>Template html content </div>
</template>
//script in index.html file
<script>
const links = document.querySelectorAll('link[rel="import"]')
Array.prototype.forEach.call(links, (link) => {
let template = link.import.querySelector('template')
//error: cannot read property "querySelectorAll" of undefined
//I tried to console.log(link)
//it gives output: <link rel="import" href="fileLocation/file.html">
//but in electron demo app it is giving actual template.
})
</script>
//running below code in my index.html to test html import compatibility
console.log(
"Native HTML Imports?", 'import' in document.createElement('link'),
"Native Custom Elements v0?", 'registerElement' in document,
"Native Shadow DOM v0?", 'createShadowRoot' in document.createElement('div'));
//output: Native HTML Imports? false Native Custom Elements v0? false Native Shadow DOM v0? false
//running the same code in Electron API demo app (example app given on electron github repo)
console.log(
"Native HTML Imports?", 'import' in document.createElement('link'),
"Native Custom Elements v0?", 'registerElement' in document,
"Native Shadow DOM v0?", 'createShadowRoot' in document.createElement('div'));
//output: Native HTML Imports? true Native Custom Elements v0? true Native Shadow DOM v0? true
Please tell me how can I configure my app so that my result matches with Electron demo app.

I had same issue and seem like it's related to new version of electron (10.1.5).
Revert back to version 7.2.4 works for me

Related

Polymer 1.x: Incompatible with native web-components?

(tl;dr - yes. However Polymer 2.0 is not and is an easy upgrade.)
I am trying to migrate an old front-end code base away from polymer 1.11.3 (webcomponentsjs 0.7.24) to native web-components.
However, I'm running into the following issue:
When Polymer is included in a page, even trivial native web-components are effectively broken. Web-components that have neither custom methods nor properties seem work. But, include a custom method or property and try to access it, and you'll encounter an error indicating that the property or method does not exist.
For example, given the following component:
customElements.define( 'x-hello', class J extends HTMLElement {
hello() { console.log( 'hello called' ) }
})
document.createElement( 'x-hello' ).hello()
If I run this on a page that includes Polymer,
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="application-name" content="re">
<script src="../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
</head>
<body>
<h1>Here</h1>
</body>
<script>
customElements.define( 'x-hello', class J extends HTMLElement {
hello() { console.log( 'hello called' ) }
})
document.createElement( 'x-hello' ).hello()
</script>
</html>
Then I get the following error:
Uncaught TypeError: document.createElement(...).hello is not a function
<anonymous> debugger eval code:5
However, run it in a page that doesn't include Polymer and it will run just fine.
The few components that I've migrated away from Polymer so far fail in the same way when included in the Polymer-based app I pulled them from. Similarly, running them in a test project that doesn't contain Polymer and they function fine.
I get that both the Polymer lib and webcomponentjs were intended to provide webcomponent support and functionality at a time when browsers didn't support it, but it seems like Polymer should at least be compatible with native web-components.
Is there a work-around for this? Is there some way to incorporate native web-components into an application that is using Polymer 1.x?
I'd really like to be able to migrate components away from Polymer and to native one at a time rather than all at once.

How to fetch HTML and CSS files for web components when hosted on a different domain than the application itself?

I am looking for a clean solution to split web components into JS, HTML and CSS files and host them on a CDN. I try to avoid the webpack html and css-loader as they dont allow me to export my web component as a plain ES module.
The goal is to use a web component from any frontend app just by importing it from a spcified URL. Thereby seperation of concerns should be preserved. Individual files for style, markup and logic also allow for syntax highlighting.
In a local dev environment I found the following to work great:
WebComponent.js:
export default class WebComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
const style = new CSSStyleSheet();
const template = document.createElement("template");
fetch("./WebComponent.css").then((res) =>
res.text().then((css) => {
style.replaceSync(css);
this.shadowRoot.adoptedStyleSheets = [style];
})
);
fetch("./WebComponent.html").then((res) =>
res.text().then((html) => {
template.innerHTML = html;
this.shadowRoot.appendChild(template.content.cloneNode(true));
})
);
}
}
WebComponent.css:
button {
/* Some styling */
}
WebComponent.html:
<button>Custom buttom</button>
I can import the component by using browser native ES module imports:
index.html:
<!DOCTYPE html>
<html>
<body>
<web-component></web-component>
<script type="module">
import WebComponent from "./WebComponent";
customElements.define("web-component", WebComponent);
</script>
</body>
</html>
This works until I move the web component files to a different location (a google cloud storage bucket) than my index.html and import WebComponent.js from there.
<!DOCTYPE html>
<html>
<body>
<web-component></web-component>
<script type="module">
import WebComponent from "https://storage.googleapis.com/storage-bucket/WebComponent.js";
customElements.define("web-component", WebComponent);
</script>
</body>
</html>
WebComponent.js gets imported correctly but it then tries to fetch WebComponent.css and WebComponent.html from a URL relative to localhost where index.html is served. However it should fetch from a URL relative to where it is hosted (https://storage.googleapis.com/storage-bucket/).
Any ideas how something like that can be achieved? Without hard coding the url into both fetch calls. That's not an option as the url can change automatically from time to time.
You are having issue with linking resources in the JS web page for which :
local component is working
import WebComponent from "./WebComponent";
remote component is failing
import WebComponent from "URL";
It might be that for this to work you should try this :
<script type="module" src="https://storage.googleapis.com/storage-bucket/WebComponent.js">
customElements.define("web-component", WebComponent);
</script>
References :
https://cloud.google.com/storage/docs/hosting-static-website
https://www.npmjs.com/package/webcomponent?activeTab=readme
https://lit-element.polymer-project.org/guide/use
JavaScript file paths are relative to the displayed page. So the behavior you are observing is expected.
You can use a JavaScript variable with a simple js declaration like below and use this variable across whenever you assign URLs dynamically:
<script type="text/javascript">
var webComponentPath = 'https://storage.googleapis.com/storage-bucket/';
</script>

How to link a paper-button to another Polymer page?

I created a Polymer 2.0 app from the starter kit template in order to get to know the framework a little bit. I have a paper-button that should link to another page of the app. However, I still haven't figured out how to do so, since Polymer is loading pages dynamically via JavaScript rather than the browser just calling another one.
I also noticed something else strange: When I click a link in my app-drawer, the page changes automatically and the URL in my browser tab is being updated. However, when I hit refresh with that new URL in my address bar, I get a 404 error since the URL doesn't exist. So is there any way I can resolve this issue and link my button to another page?
This is my button:
<paper-button id="buttonStartQuiz" on-click="startQuiz">
go! <iron-icon icon="chevron-right"></iron-icon>
</paper-button>
And this is the JavaScript class that corresponds to the layout:
class MyView1 extends Polymer.Element {
static get is() { return 'my-view1'; }
/* This method is the listener for the button click */
startQuiz(e) {
// Found this on a website, but doesn't work
this.set('route.path', '/view-question');
}
}
window.customElements.define(MyView1.is, MyView1);
I don't know if it's any useful, but here are my imports in case you need to know.
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../bower_components/paper-input/paper-input.html">
<link rel="import" href="../bower_components/paper-button/paper-button.html">
The fact is Polymer doesn't do that, some element (app-route which implement with Polymer) do that. The Polymer itself is the library that help you work with custom element easier.
This behavior done by JavaScript and History API. See how to use it on mdn. An application like this, dynamically rewriting the current page rather than loading entire new pages its called a single-page application (SPA).
Basically application like this have only one page (index.html). When you try to load from another path the server will cannot find it.
You can resolve this by config the server to serve every path you used with index.html. For development you can easily use polymer serve command from polymer-cli see here.
To link to another page you can done by many ways:
=> Wrap your element with <a>:
<a href='/another-page'>
<paper-button>...</paper-button>
</a>
=> Change route variable from app-location: in my-app.html
<app-location route='{{route}}'></app-location>
...
<paper-button on-click='changeRoute'>...</paper-button>
class MyApp extends Polymer.Element {
...
changeRoute () {
this.set('route.path', '/another-page')
}
...
}
If you want to do this in your file just import and use app-location.
=> Use History API
window.history.pushState({}, null, '/another-page');
// Notify to `app-location`
window.dispatchEvent(new CustomEvent('location-changed'))

Create and Use a Custom HTML Component?

I have the following local html:
<html>
<head>
<link rel="import" href="https://mygithub.github.io/webcomponent/">
</head>
<body>
<!-- This is the custom html component I attempted to create -->
<img-slider></img-slider>
</body>
</html>
and the following attempt at a template:
<template>
<style>
.redColor{
background-color:red;
}
</style>
<div class = "redColor">The sky is blue</div>
</template>
<script>
// Grab our template full of slider markup and styles
var tmpl = document.querySelector('template');
// Create a prototype for a new element that extends HTMLElement
var ImgSliderProto = Object.create(HTMLElement.prototype);
// Setup our Shadow DOM and clone the template
ImgSliderProto.createdCallback = function() {
var root = this.createShadowRoot();
root.appendChild(document.importNode(tmpl.content, true));
};
// Register our new element
var ImgSlider = document.registerElement('img-slider', {
prototype: ImgSliderProto
});
</script>
As described in this article. When I run the code, I get:
Uncaught TypeError: Cannot read property 'content' of null
at HTMLElement.ImgSliderProto.createdCallback ((index):20)
In other words document.querySelector('template'); returns null. What gives?
My goal is to create custom html element and display it on the website that links the template code. I am 100% sure I am pulling the remote template code correctly (obviously, since I get the error in that code).
P.S. I am using latest Chrome, so I shouldn't need polyfills.
Try this:
var tmpl = (document.currentScript||document._currentScript).ownerDocument.querySelector('template');
The problem you ran into is that the template isn't really part of document but it is part of the currentScript. Due to polyfills and browser differences you need to check for currentScript and _currentScript to work correctly.
Also be aware that HTML Imports will never be fully cross browser. Most web components are moving to JavaScript based code and will be loaded using ES6 module loading.
There are things that help create templates in JS files. Using the backtick (`) is a reasonable way:
var tmpl = document.createElement('template');
tmpl.innerHTML = `<style>
.redColor{
background-color:red;
}
</style>
<div class = "redColor">The sky is blue</div>`;

HTML import angular2 app and pass parameter

I want to use webcomponents and HTML import to import an angular2 module into another webapplication which do not use angular2. I know HTML import is only natively supported in few browsers but i will use the polymer framework to pollify other browsers.
I can import the angular app but i'm unable to pass parameters to the angular app from my web app that imports the angular app. I'm trying this:
<dom-module id="sale-stats">
<link rel="import" href="../bower_components/polymer/polymer.html">
<template>
<!-- contains my angular app bundled js files -->
<link rel="import" href="imports.html">
{{saleid}} <!-- this displays the saleid just to see that the parameter is passed to the webcomponent -->
<app-root saleid='{{saleid}}'>Loading... </app-root>
</template>
<script>
HTMLImports.whenReady(function () {
Polymer({
is: 'sale-stats',
properties: {
saleid: {
type: String,
value: '0'
}
},
});
});
</script>
</dom-module>
<script src="/Scripts/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="http://localhost:9600/salestats/index.html" />
<sale-stats saleid="1234567"></sale-stats>
How do i pass parameters to my angular app when using the angular app as a webcomponent that is imported into another app? Or is it just completely wrong to try and import an angular app as an webcomponent?
In order to polyfill HTML Imports, you just have to include HTMLImports.js which is available in the webcomponents.js repository. You can install it with bower (or npm):
bower install webcomponentsjs
Just include the polyfill before the <link> element:
<script src=".../bower_components/webcomponentsjs/HTMLImports.js"></script>
To wait for the imported file to be loaded, you can use the Promise, or instead wait for the standard onload event. For example:
<script src=".../bower_components/webcomponentsjs/HTMLImports.js"></script>
<link rel="import" href="imports.html" onload="run( 1234567 )">
Inside the imported HTML file:
<!-- contains my angular app bundled js files -->
<script>
function run ( id )
{
var app = document.createElement( 'app-root' )
app.setAttribute( 'saleid', id )
document.body.appendChild( app )
}
</script>
Notes: you can also place the onload callback function in the main document. Also, the import is synchronous on native implementation (Chrome and Opera); use async in <link> if you don't want to block the parsing.

Categories

Resources