0
votes

I created a StencilJS project that has a bunch of web components bundled in my mwc project. From within Stencil, I can execute npm run start and see my components working as expected.

I created an Electron project and in it I'm importing the stencil mwc package using :

<script src="dist/mwc/mwc.js"></script>

When I do this I've noticed the stencil generated code fails to run any for-loops that iterate over a Map or Set. Basically the for-loop exits and never iterates.

For example, in one of my components I have a class that defines a variable this way:

private _groupedItems : Map<string, Item[]> = new Map();

This variable gets populated and when the following code tries to run, it always fails:

@Method()
async updateItemAsync( arg : { value : string, data : UpdateSelectItem } ) {
  //find where the item value is located
  let item : Item | undefined = undefined;
  for( const key of this._groupedItems.keys() ) {
    const groupedItems = this._groupedItems.get( key );
    if( groupedItems ) {
      item = groupedItems.find( item => item.value === arg.value );
      if( item ) {
        break;
      }
    }
  }
  if( item === undefined ) {
    console.error( 'Could not find item to update with value=', arg.value );
    return;
  }
  //NEVER GETS HERE!
  //more code below snipped out
}

In Chrome devTools I can see that the generated JavaScript that is trying to run looks like this:

e.prototype.updateItemAsync = function(e) {
  return __awaiter(this, void 0, void 0, function() {
    var t, i, n, r, s;
    return __generator(this, function(a) {
      t = undefined;
      for (i = 0,
           n = this._groupedItems.keys(); i < n.length; i++) {
        r = n[i];
        s = this._groupedItems.get(r);
        if (s) {
          t = s.find(function(t) {
          return t.value === e.value
        });
        if (t) {
          break
        }
      }
    }
    if (t === undefined) {
      console.error("Could not find item to update with value=", e.value);
      return [2]
    }

I discovered if instead of using the aforementioned script, I use this instead :

<script type="module" src="dist/mwc/mwc.esm.js"></script>

Then everything works fine (sort of). Basically when I fire up my Electron package using webpack all the code works as expected and my for-loops are now working. The problem with this solution is that when I package my Electron application using electron-webpack, I can't run the resulting standalone EXE because I get an error message when the application starts up. Chrome gives me an error when it tries to load the mwc.esm.js file:

Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.

What is the difference between the mwc.js and mwc.esm.js files? Why won't the mwc.js file run my for-loops properly?

1

1 Answers

2
votes

The esm.js file is a Javascript Module which will be served to browsers that support it.

When you use the old way of including a Stencil component (/dist/mwc.js) you will get a console warning about how to properly include it, which is also documented in the breaking changes for version 1:

[mwc] Deprecated script, please remove: <script src="/dist/mwc.js"></script>
To improve performance it is recommended to set the differential scripts in the head as follows:
<script type="module" src="/dist/mwc/mwc.esm.js"></script>
<script nomodule src="/dist/mwc/mwc.js"></script>

I don't know why Map and Set loops would not work with the non-module file but the module is the recommended way of importing in Chrome.

The MIME type error seems to be a known issue in Electron which seems to be because Electron uses the file:// protocol by default which doesn't allow including modules, as per spec.