Blog do projektu Open Source JavaHotel

środa, 1 sierpnia 2018

Polymer 2 to Polymer 3

I decided to upgrade from Polymer 2 to Polymer 3.  According to
"we've made a smooth upgrade path our top priority for Polymer 3.0. Polymer's API remains almost unchanged, and we're providing an upgrade tool (polymer-modulizer) that will automatically handle most of the work in converting your 2.x-based elements and apps to 3.0.". 
Encouraged by this advertisement, I run "modulizer --out ." and ... It depends on what one means by "most of the work" and "smooth".

Module names instead of path names
Instead of import pathnames like:
<href="../bower_components/polymer/polymer-element.html" rel="import"></link>
module names are used:
import {PolymerElement, html} from '@polymer/polymer/polymer-element.js'
I understand the rationale behind that but Chrome browser I'm using obviously does not. It still insists that @polymer is a directory name and demands the path name to resolve it. Adding the path names manually is challenging because not only custom elements should be touched but also all internal Polymer elements. So it looks that some kind of "build" process is necessary after every upgrade. After some trials, errors and research I ended up using:
polymer build --module-resolution node
which does the job. Then I replace current "node_modules" directory with "build/default/node_modules". In the case of the Polymer upgrade,  "yarn install" should be launched beforehand. Previously, no build process was required. It was enough to run "bower install".

ReferenceError: IntlMessageFormat is not defined
Uncaught (in promise) ReferenceError: IntlMessageFormat is not defined
    at HTMLElement. (app-localize-behavior.js:285)
    at runMethodEffect (property-effects.js:905)
    at Function._evaluateBinding (property-effects.js:3079)
    at Object.runBindingEffect [as fn] (property-effects.js:648)
    at runEffectsForProperty (property-effects.js:169)
    at runEffects (property-effects.js:131)
    at HTMLElement._propagatePropertyChanges (property-effects.js:1933)
    at HTMLElement._propertiesChanged (property-effects.js:1891)
    at HTMLElement._flushProperties (properties-changed.js:370)
    at HTMLElement._flushProperties (property-effects.js:1731)
Unfortunately, "polymer build" does not catch "node_modules/intl-messageformat" package and it is absent after build. So we have to reinstall the package again.
npm install intl-messageformat 
ReferenceError: IntlMessageFormat is not defined
Although "intl-messageformat" is downloaded, it should be also imported somewhere to make "IntMessageFormat" class visible.
I ended up patching manually "node_modules/@polymer/app-localize-behavior/app-localize-behavior.js" file.
import "../polymer/polymer-legacy.js";
import "../iron-ajax/iron-ajax.js";
import "../../intl-messageformat/dist/intl-messageformat.js";
Uncaught TypeError: Cannot set property 'IntlMessageFormat' of undefined
Uncaught TypeError: Cannot set property 'IntlMessageFormat' of undefined
    at main.js:7
    at main.js:7
It was a stab in the back because Chrome does not tell where this disaster happens. After some time I found a hint here.
The solution is to patch manually "node_modules/intl-messageformat/dist/intl-messageformat.js".
At the end of the file replace:
    var src$main$$default = $$core$$default;
    this['IntlMessageFormat'] = src$main$$default;

    var src$main$$default = $$core$$default;
    this['IntlMessageFormat'] = src$main$$default;
Uncaught ReferenceError: KeyframeEffect is not defined
This exception was thrown from paper-dropdown-menu element. Instead of spending time trying to resolve it, I decided to remove this dependency and replaced it with something different. Replace namespace with imports
In Polymer 2 I was using Polymer namespace for custom classes.
olymer.CivData = function(superClass) {

        return class extends Polymer.CivLocalize(superClass) {

                constructor() {

class CivTLevel extends Polymer.CivData(Polymer.Element) {

    static get is() {
        return 'civ-tlevel';
Polymer 3 enforces transforming all class to ES6 modules. So sequence above should be replaced by:
import { CivLocalize} from "../js/civ-localize.js";

export const CivData = function (superClass) {
  return class extends CivLocalize(superClass) {
    constructor() {

import { html } from "../node_modules/@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "../node_modules/@polymer/polymer/polymer-element.js";
import { CivData} from "../js/civ-data.js";

class CivTLevel extends CivData(PolymerElement) {
  static get template() {

"modulizer" utility has nothing to do with that, it should be done manually.
"Smooth upgrade" ended up in several sleepless nights. But in the end, I made it. On the whole, I really like this ES6 module, it provides a good encapsulation and isolation which is very important in every programming language including JavaScript.

Brak komentarzy:

Prześlij komentarz