surma/rollup-plugin-off-main-thread

Loader code not transpiled with babel

chrisfinch opened this issue · 6 comments

The loader code injected by this plugin is not compatible with older browsers dues to ES6 syntax.

rollup-babel-plugin will not transpile the code as it uses the transform rollup plugin hook rather than the renderChunk hook - see here a discussion about this problem with wrapper code: rollup/rollup-plugin-babel#303

Wondering if there is any known method to get the loader/wrapper code transpiled with babel so I can use it in my build which targets older browsers?

General guidelines are that node module outputs should not require transpilation (although I understand that you are generally targeting browsers with worker support here..) - perhaps the loader code could be switched out for a transpiled version?

Decided to go with SystemJS for the time being - would be great to use this at some point though 👍

Ran into this as well, decided to hand-transpile loader.ejs and pass that. Here's what I'm using at the moment, can't confirm all paths work since I'm only using 1, but I think I caught everything and made it es5-ish. In my opinion i think the plugin should switch over to es5-friendly source until there's better support for transpiling at build time, but at least there's support for passing a custom loader.

/**
 * Copyright 2018 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// If the loader is already loaded, just stop.
if (!self.define) {
  var singleRequire = function(name) {
    if (!registry[name]) {
      <% if (useEval) { %>
      return fetch(name).then(function(resp) { return resp.text() })
      .then(function(code) {
        eval(code);
      <% } else { %>
      return new Promise(function(resolve) {
        if ("document" in self) {
          var script = document.createElement("script");
          <% if (publicPath) { %>
          script.src = <%- "'" + publicPath + "' + name.slice(1)" %>
          <% } else { %>
          script.src = name;
          <% } %>
          // Ya never know
          script.defer = true;
          document.head.appendChild(script);
          script.onload = resolve;
        } else {
          importScripts(name);
          resolve();
        }
      })
      .then(function() {
      <% } %>
        if (!registry[name]) {
          throw new Error("Module " + name + " didn’t register its module");
        }
        return registry[name];
      });
    } else {
      return Promise.resolve(registry[name]);
    }
  };

  var require = function(names, resolve) {
    Promise.all(names.map(singleRequire))
    .then(function(modules) {
      resolve(modules.length === 1 ? modules[0] : modules);
    });
  };

  var registry = {
    require: Promise.resolve(require)
  };

  self.define = function(moduleName, depsNames, factory) {
    if (registry[moduleName]) {
      // Module is already loading or loaded.
      return;
    }
    registry[moduleName] = new Promise(function(resolve) {
      var exports = {};
      var module = {
        <% if (publicPath) { %>
          uri: location.origin + <%- "'" + publicPath + "' + moduleName.slice(1)" %>
        <% } else { %>
          uri: location.origin + moduleName.slice(1)
        <% } %>
      };
      Promise.all(
        depsNames.map(function(depName) {
          if (depName === "exports") {
            return exports;
          }
          if (depName === "module") {
            return module;
          }
          return singleRequire(depName);
        })
      ).then(function(deps) {
        var facValue = factory.apply(null, deps);
        if(!exports.default) {
          exports.default = facValue;
        }
        resolve(exports);
      });
    });
  };
}
surma commented

I honestly don’t quite know how to make sure the loader gets transpiled. But if this is mostly about the usage or async/await, then this is a duplicate of #19 .

If you agree, let me know and I’ll close this one :)

Hi! So async/await is definitely one piece, but there are a few other things, specifically looking at IE11 support. First one is template strings, used at L39. Second is the spread operator, used at L75. Arrow functions are used in a few places as well (L16, L45, and L54).

I think that was all the issues I ran into. Sorry, it's been a minute since I looked at this last so I may have missed something, but I don't remember anything else significant. And refactoring async/await was definitely most of the pain lol.

surma commented

The fact that the loader doesn’t get transpiled is most likely a bug with babel (or whatever transpiler you use). I currently append the loader in renderChunk, which seems like the right point to do this. Babel should arguable run on thee same hook or even in generateBundle, which runs after renderChunk.

The reason this bug exists to remove async/await is because transpiling async/await to promises/generators generates really bad (and a lot of) code. So I should do that manually.

surma commented

When I wrote the reply above, I thought I was commenting on #19. Turns out I was not 😂

I am pretty sure I am doing the right thing here and as @lukastaegert says in #19, there is a fix for the babel plugin about to land. I’ll close this as I believe it’s not actionable to me. Please re-open if you disagree :)