Mathis Kyd
Mathis Kyd

Reputation: 41

ES6 Import breaks Gatsby Build : WebpackError: ReferenceError: Element is not defined

I want to include the following npm package in my component: tiny-slider-react.

However, while it works fine in Gatsby Develop, Gatsby Build fails with the following message:

error Building static HTML failed

See our docs page on debugging HTML builds for help https://gatsby.dev/debug-html

  3 |   "use strict";
  4 | 
> 5 |   if(!("remove" in Element.prototype)){
    | ^
  6 |     Element.prototype.remove = function(){
  7 |       if(this.parentNode) {
  8 |         this.parentNode.removeChild(this);


  WebpackError: ReferenceError: Element is not defined

  - childNode.remove.js:5 
    [lib]/[ventura-slider]/src/helpers/childNode.remove.js:5:1

  - childNode.remove.js:12 Object../node_modules/ventura-slider/src/helpers/childNode.remove.js
    [lib]/[ventura-slider]/src/helpers/childNode.remove.js:12:2

  - bootstrap:19 __webpack_require__
    lib/webpack/bootstrap:19:1

  - tiny-slider.module.js:1 Module../node_modules/ventura-slider/src/tiny-slider.module.js
    [lib]/[ventura-slider]/src/tiny-slider.module.js:1:1

  - bootstrap:19 __webpack_require__
    lib/webpack/bootstrap:19:1

  - Carousel.js:19 Object../node_modules/tiny-slider-react/build/Carousel.js
    [lib]/[tiny-slider-react]/build/Carousel.js:19:19

  - bootstrap:19 __webpack_require__
    lib/webpack/bootstrap:19:1

  - index.js:7 Object../node_modules/tiny-slider-react/build/index.js
    [lib]/[tiny-slider-react]/build/index.js:7:17

  - bootstrap:19 __webpack_require__
    lib/webpack/bootstrap:19:1


  - bootstrap:19 __webpack_require__
    lib/webpack/bootstrap:19:1


  - bootstrap:19 __webpack_require__
    lib/webpack/bootstrap:19:1

  - sync-requires.js:12 Object../.cache/sync-requires.js
    lib/.cache/sync-requires.js:12:57

  - bootstrap:19 __webpack_require__
    lib/webpack/bootstrap:19:1

  - static-entry.js:9 Module../.cache/static-entry.js
    lib/.cache/static-entry.js:9:22

Commenting out this import and its’ React component fixes the issue.

Slideview.js

import React from 'react';
import TinySlider from "tiny-slider-react";

...

class SlideView extends React.Component{
    render(){
        return(
            <TinySlider settings={settings}>
                ...
            </TinySlider>
        );
    }
}

Expected: Slider works in production just like develop. Actual results: Breaks on build

Upvotes: 0

Views: 3253

Answers (2)

Mathis Kyd
Mathis Kyd

Reputation: 41

Turns out I had to had the following lines to gatsby-node.js

gatsby-node.js

// /**
//  * Implement Gatsby's Node APIs in this file.
//  *
//  * See: https://www.gatsbyjs.org/docs/node-apis/
//  */

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
    if (stage === "build-html") {
      actions.setWebpackConfig({
        module: {
          rules: [
            {
              test: /tiny-slider-react/,
              use: loaders.null(),
            },
          ],
        },
      })
    }
  }

It's at the bottom of this doc page. https://www.gatsbyjs.org/docs/debugging-html-builds/

Thanks Phillip for your help

Upvotes: 2

Phillip
Phillip

Reputation: 6253

During development, React components are only run in the browser. When building, Gatsby renders these components on the server - and in that context Element (and stuff like window and document) is not defined.

I have no solution to your specific use-case, but when you want to do DOM-related manipulations, it should be done in componentDidMount, which will only run in the browser.

My ideas for solving your issue:

  • Somehow only import and use the component in a parent componentDidMount. This is IMO very fragile, and not the correct way

  • Fork the package and patch it, so the code that manipulates the Element prototype is only run on browser. Eventually make a PR

EDIT:

I did some searching an came across this (somewhat) similar issue and solution: https://github.com/gatsbyjs/gatsby/issues/309#issuecomment-373359887.

// index.js
import React from "react";
import Link from "gatsby-link";

// import "uikit/dist/js/uikit";
// Third party JS access `window` without
// `typeof window !== "undefined"` check

class Template extends React.Component {
  componentDidMount() {
    import("uikit/dist/js/uikit")
      .then((uikit) => {
        this.uikit = uikit;
      })
      .catch((error) => console.error(error));
  }
  render() {
    // ...
  }
}

// ...

In essence, what you do is import the component in the componentDidMount lifecycle hook, bind it to this.<MyComponent>, and then use it in the render function:

render() {
   const MyComponent = this.MyComponent;
   return <MyComponent />;
}

Please note I have not tried this myself, but I don't see how this should not work. Do your own testing ;)

Upvotes: 1

Related Questions