Harmony export in bundle breaks ESLint `no-use-before-define` rule

Do you want to request a feature or report a bug?

It may be a bug or a future bug source. Not sure yet.

What is the current behavior?

Everything works as expected.

If the current behavior is a bug, please provide the steps to reproduce.

It’s not a bug, but you can reproduce it using the snippet below or just by exporting something from within a javascript module.

What is the expected behavior?

Everything works as expected but this can produce bugs in the future. Even though it’s not syntactically ‘illegal’ it’s considered bad practise unless there is a good reason for that. ESLint supports my view with this rule.

Please mention other relevant information such as the browser version, Node.js version, webpack version, and Operating System.

Chrome v68
node v10
webpack v4.17.0
macOS


For the following sample snippet:

const top = document.createElement("div");
top.innerText = "This is the top";
top.style = red;

export { top };

Webpack produces the following chunk:

// ...

"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "top", function() { return top; });

// ...

const top = document.createElement("div");
top.innerText = "This is the top";
top.style = red;

Even though it works because JavaScript allows variables to be declared after they are used, the way top is exported breaks the no-use-before-define ESLint rule.

Is there a particular reason for placing module exports at the top instead of at the bottom of the file?

EDIT: I have already asked the same question on StackOverflow but the response I got was along the lines: “It’s perfectly valid since the export is guaranteed to not be used before top is defined.”

However it doesn’t justify why webpack does it. Why not use best practises and place the export at the bottom instead?

Author: Fantashit

1 thought on “Harmony export in bundle breaks ESLint `no-use-before-define` rule

  1. Is there any way at all to make export const value = 42; actually print 42 in module.js using circular dependancies?

    // module.js
    import { value, fn } from "./entry.js";
    
    try {
      console.log(fn()); // should log 42
      console.log("Works correctly");
    } catch(e) {
      console.log("Broken " + e);
    }
    
    try {
      console.log(value); // should throw a TDZ error
      console.log("Broken");
    } catch(e) {
      console.log("Works correctly");
    }
    
    Promise.resolve().then(() => {
      try {
        console.log(value); // should log 42
        console.log("Works correctly");
      } catch(e) {
        console.log("Broken " + e);
      }
    });

    Best way to avoid such problems. Avoid running code at module evaluation. Lazy initialize stuff when used in exported functions or only run code in exported function.

Comments are closed.