3

I'm new to both Polymer and Webpack and trying to work out how to get the polymer-webpack-loader transpiling correctly. According to the new Polymer 3.x way of importing HTML into JS (Polymer 2.x was the other way round), I've created a separate .html file and attempting to import it into my 'extends PolymerElement' class.

Here is my simple template.html file:

<div>This is my chosen colour: [[colour]] (Made by the [[name]] app)</div>

Here is my Polymer index.js file:

import { PolymerElement, html } from '@polymer/polymer';
import * as view from './template.html';

export class NpsWidget extends PolymerElement {

  static get is() { return 'nps-widget'; }

  // Define a string template instead of a `<template>` element.
  static get template() {

    return html(`${view}`);

  }

  constructor() {
    super();
    this.name = 'Polymer 3.0 test';
    console.log(this.name + ' constructor run successfully.');
  }

  static get properties() {
    return {
      name: {
        type: String
      },
      colour: {
        type: String,
        value: '#777777'
      }
    };
  }

}

customElements.define(NpsWidget.is, NpsWidget);

And here's my webpack config file:

const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const pkg = require(path.resolve(__dirname, '../package.json'));

let libraryName = pkg.name;

const config = {
  mode: 'development',
  entry: path.resolve(__dirname, '../src/index.js'),
  devtool: 'source-map',
  output: {
    globalObject: 'typeof self !== \'undefined\' ? self : this',
    path: path.resolve(__dirname, '../lib/dev'),
    filename: libraryName + '.js',
    library: libraryName,
    libraryTarget: 'umd',
    umdNamedDefine: true
  },
  module: {
    rules: [
    {
      test: /\.html$/,
      use: [
        // Chained loaders are applied last to first
        { loader: 'babel-loader' },
        { loader: 'polymer-webpack-loader' }
      ]
    },
    {
        test: /\.js$/,
        // We need to transpile Polymer itself and other ES6 code
        // exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [[
              'env',
              {
                targets: { browsers: ['last 2 Chrome versions', 'Safari 10'] },
                debug: true
              }
            ]],
            plugins: [['transform-object-rest-spread', { useBuiltIns: true }]]
          }
        }
      },
      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
      {
        test: /(\.tsx|\.ts)$/,
        loader: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    modules: [path.resolve(__dirname, '../node_modules'), path.resolve(__dirname, '../src')],
    extensions: ['.ts', '.tsx', '.json', '.js', '.html']
  },
  plugins: [
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: 'static',
        ignore: ['.*']
      },
      {
        from: path.resolve(__dirname, '../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js')
      },
      {
        from: path.resolve(__dirname, '../node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js')
      }
    ])
  ]
};

module.exports = config;

The result that I get is that the import statement in the template.html seems to be simply creating the div tag in the bundled script and including it in the document and of course the class can't find the value... Here's the output:

This is my chosen colour: [[colour]] (Made by the [[name]] app)

undefined

If I include the template in a literal HTML string in the JS file and remove the import statement, it works fine:

//import * as view from './template.html';
...
return html`<div>This is my chosen colour: [[colour]] (Made by the [[name]] app)</div>`;

This is my chosen colour: #777777 (Made by the Polymer 3.0 test app)

Can anyone help me understand how to get this to work? I suspect it's some configuration to do with polymer-webpack-loader. This style of code works fine in a vanilla Polymer app that isn't being bundled by Webpack.

Thanks,

Paul

Community
  • 1
  • 1
Paul M Sorauer
  • 667
  • 8
  • 10
  • PS: There seems to be a similar-ish issue reported on the Github for the polymer-webpack-loader but it seems to digress and being a noob to this I'm not sure how relevant it is: https://github.com/webpack-contrib/polymer-webpack-loader/issues/60 – Paul M Sorauer May 30 '18 at 04:48

1 Answers1

1

I had the same problem: I wanted to write the HTML in an HTML file, not inside JavaScript. After some work I've come with such configuration and I can confirm it works if all of your elements are 3.0. I haven't tried legacy elements yet.

Inside webpack.config.js, HTML rule looks like this:

test: /\.html$/,
include: resolve(__dirname, 'src/elements'), // This makes sure I only catch HTML files that are actually my templates
use: [{
  loader: 'html-loader',
  options: {
    minimize: true
    attrs: // Fill those in as needed
  }
}]

And in the JS file you need to import it like this:

import ElementContent from './path/to/template.html';

And in class put:

static get template() {
  const template = document.createElement('template');
  template.innerHTML = ElementContent;
  return template;
}

Notice that you don't need html from @polymer/polymer in such case.

myfrom
  • 133
  • 1
  • 7