Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReferenceError: self is not defined #4593

Closed
jhjhjh96 opened this issue Apr 17, 2017 · 38 comments · Fixed by #9749
Closed

ReferenceError: self is not defined #4593

jhjhjh96 opened this issue Apr 17, 2017 · 38 comments · Fixed by #9749

Comments

@jhjhjh96
Copy link

Mapbox gl does not work in my node js.

-error code-
C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:402
"use strict";module.exports=self;

ReferenceError: self is not defined
at Object.__dirname.196 (C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:402:29)
at s (C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:1:684)
at C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:1:735
at Object.__dirname.194../window (C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:398:25)
at s (C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:1:684)
at C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:1:735
at Object.__dirname.65.../package.json (C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:139:26)
at s (C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:1:684)
at e (C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:1:855)
at C:\Users\YJH\Documents\Visual Studio 2017\Projects\mapbox\mapbox\node_modules\mapbox-gl\dist\mapbox-gl.js:1:873

I don't know, what was wrong.
I read a mapbox document. Initial setting also installed such as 'webpack', 'browserify' ect...
Help me solve this problem.

@jfirebaugh
Copy link
Contributor

Hi, thanks for using Mapbox. mapbox-gl-js is a client-side module; it doesn't work in node.js except in very specialized circumstances.

Note that this issue tracker is for reporting bugs and feature requests. If you need general help with the node/webpack/browserify ecosystem, please refer to the documentation for those projects. Thank you!

@rudza
Copy link

rudza commented May 30, 2017

@jhjhjh96 Did managed to fix this error?

@marcellobarile
Copy link

Hi @rudza and @jhjhjh96
I might be too late for you guys, but here it is something worked for me:

Add the following plugin to your Webpack configuration. This will create a "global" variable that you will use lately before instantiating the map.

new webpack.DefinePlugin({
  __CLIENT__: !isServer            // Your logic to define if webpack is running in server or client mode
}),

(!!) If you are on TypeScript remember to define the variable in your "index.d.ts" file (or whatever you have)
declare var __CLIENT__: boolean;

In your (component | class | whatever) you need to use the mapbox-gl use it like this:

const mapboxGl = __CLIENT__
   ? require('mapbox-gl')
   : {};

mapboxGl.accessToken = MAPBOX_TOKEN;

const map = new mapboxGl.Map({
      container: this.mapContainer,                  // The reference to your DOM el.
      style: 'mapbox://styles/mapbox/streets-v9',
      center: [lng, lat],
      zoom: 5,
});

Another way might be implementing the webpack-isomorphic-tool

@aendra-rininsland
Copy link
Contributor

aendra-rininsland commented Jul 4, 2019

Please reopen this.

The issue isn't so much that people are trying to render WebGL on the server, it's that mapbox-gl-js eagerly accesses browser-specific globals upon module import. The library shouldn't try to touch the DOM or global namespace at all until Mapbox is instantiated.

Examples:

@samkelleher
Copy link

samkelleher commented Jul 17, 2019

The use case for reopening this is for an isomorphic website, we don't call or initialize the mapbox API, but it is still imported in the file, and this library does browser specific calls just from being imported, which it should not.

I.e., this code should not do any execution. The library has side effects, meaning it is executing and trying to access browser specific APIs.

import mapbox from "mapbox-gl";

@AtlantisPleb
Copy link

Same error on a Next.js app.

@tbredin
Copy link

tbredin commented Aug 18, 2019

I've hit this one too, in Gridsome

@martinblostein
Copy link

Another use case affected by this issue: I have an internal library of shared JS code, bundled with webpack. Some of the code is front end (react components) and some could be useful on either front end or backend (functions). If I import mapbox-gl anywhere in this library then it can no longer be used on the backend, without some kind of hack.

@mourner mourner reopened this Sep 13, 2019
@weslleyaraujo
Copy link

The library has side effects, meaning it is executing and trying to access browser specific APIs.

This is true, happening on any isomorphic node js project (in my case razzle) 😬

I think its expected for most of the features not work at all on SSR, but importing should not throw an expection 🙂

Workaround that we are doing here is having a ssr-safe-mapboxgl module which does a simple check on process.browesers and re export mapboxgl

let __ssr_safe__mapboxgl;

if (process.browser) {
  __ssr_safe__mapboxgl = require("mapbox-gl");
}

export { __ssr_safe__mapboxgl };

Then we can use it anywhere on the app, nodejs safe

import { __ssr_safe_mapboxgl as mapboxgl } from "./ssr-safe-mapboxgl";
const foo = new mapboxgl.Map(...)

@omasback
Copy link

Here is the temporary workaround for Gatsby. Put this in gatsby-node.js

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === 'build-html') {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /mapbox-gl/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

@nonphoto
Copy link

@omasback The above fix worked great for me using Gatsby, thank you. Saved me a lot of time figuring out the Webpack config.

@alexlavr
Copy link

I got this error on a Next.js app too but got it to work using dynamic import without server-side rendering.

import dynamic from 'next/dynamic'
const MyMapView = dynamic(() => import('../components/MyMapView'),  { ssr: false })

Then in MyMapView I can use import mapboxgl from 'mapbox-gl'; without the error.

@tstirrat15
Copy link
Contributor

This is still an issue for me as well. I've worked around it by internalizing (i.e. excluding from webpack-node-externals) webpack and then using webpack's null-loader to make sure that it isn't included.

@NameFILIP
Copy link

👋 @mourner would it be possible to prioritize this? Looks like it makes a lot of people unhappy..

In my case, I'm trying to import:

import { setRTLTextPlugin } from 'mapbox-gl';

but the import fails with ReferenceError: self is not defined (this self: https://github.com/mapbox/mapbox-gl-js/blob/master/src/util/browser/window.js#L5)

@NameFILIP
Copy link

NameFILIP commented Jan 29, 2020

this can be solved with global/window: https://github.com/Raynos/global/blob/master/window.js

Let me know which approach do you prefer and I can submit a PR if necessary.

@hjrobinson
Copy link

NameFILIP do you have an example of implementing global/window? For example is there some way to bring it into an index.js which contains the mapboxgl.Map? I'm not sure how exactly to use this solution. Does this enable server side rendering of the map? Sorry if my question is off base.

@NameFILIP
Copy link

NameFILIP commented Feb 3, 2020

@hjrobinson the usage will be the following:

import window from 'global/window';

On the second thought, global/window might be an overkill. I think a simple implementation that I provided as a pull-request is better. @kkaefer has rejected the change though, feel free to express your opinion here.

@tstirrat15
Copy link
Contributor

@hjrobinson you're not going to be able to do a server render of the map - WebGL doesn't work that way.

You can provide a global.window object, but that's essentially a workaround, not a fix. I'd argue that the most correct fix for this particular issue would be to not reference window at import time - it's understood that code that references window shouldn't be used in a nodeJS environment, but given that there's useful code in the library that doesn't require window, it'd be nice if mapbox-gl could be imported without referencing window.

@hjrobinson
Copy link

hjrobinson commented Feb 4, 2020

This is beyond my expertise, but I thought I would throw this out there. Any thoughts on using headless-gl to make server side rendering work with mapbox-gl.js? I noticed Mapbox has a fork and has discussed it in one of their issues. See links below:
https://github.com/mapbox/headless-gl
#1447

@martinblostein
Copy link

This is beyond my expertise, but I thought I would throw this out there. Any thoughts on using headless-gl to make server side rendering work with mapbox-gl.js? I noticed Mapbox has a fork and has discussed it in one of their issues. See links below:
https://github.com/mapbox/headless-gl
#1447

This issue isn't really about server-side rendering, it's just the fact that you can't even import the mapbox-gl library in node without an error.

@mwarren2
Copy link

mwarren2 commented May 3, 2020

I'm facing this problem for the second time.

The first time was for normal use of mapbox-gl in a .vue file.
This second time is for testing that same .vue file.

I work with Meteor and Vue.

  1. For the first use case in order to avoid mapbox-gl running on the server I put in a guard clause and used require (even though I use ES6) instead of import. This works.
    let mapboxgl;
    if (Meteor.isClient) {
        mapboxgl = require('mapbox-gl');
    }
  1. When I try to test the same .vue file using Vue Test Utils, Meteor.isClient just seems to be ignored, even though a console.log reveals that it is true.
    To cut a long story short, hours of fiddling about have not produced a solution. The test crashes, and the usual error message is shown.
    There is a workaround which is to move all my javascript code out of the .vue file into its own .js file, and test from there. This is not ideal.

I hope that you will be able to dedicate it some time soon. It's been knocking around for 3 years now!

Could the error be caught and an INFO message printed? Does it have to crash everything?

@axe312ger
Copy link

This is packed with workarounds for a very common use case.

Server side rendering is around for many years, does mapbox really not consider this in their libraries? :(

@mwarren2
Copy link

mwarren2 commented May 10, 2020

UPDATE: I moved my testing to Jest to try and solve this problem.
I now get our favourite message simply from importing mapbox-gl types

This seems absurd

Test suite failed to run

    ReferenceError: self is not defined

      1 | import {Point} from "geojson";
      2 | 
    > 3 | import {AnyPaint, SymbolLayout, Layer, GeoJSONSourceRaw} from "mapbox-gl";
        | ^

@luqmanoop
Copy link

luqmanoop commented May 18, 2020

Here is the temporary workaround for Gatsby. Put this in gatsby-node.js

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === 'build-html') {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /mapbox-gl/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

Fixes issue in Gatsby. Thank you!

@MarkLyck
Copy link

Any updates on this?

I can't do a dynamic import in my project as the build tools doesn't support multiple entry/target points.

Even though the project is never rendered server-side, it still causes this error simply by importing the module.

@mwarren2
Copy link

Yes, I really don't like complaining, it's not fair on a lot of hard-working people.

But this has to be the most annoying, show-stopping error that I've come across where nothing is happening.

It keeps rearing its weird, ugly head all over the place, and I've wasted so much time on it.

@ryanhamley
Copy link
Contributor

Hey all. I just want to chime in to assure people that we aren't ignoring this issue. We understand it's been frustrating for some specific use cases. The GL JS team is small though and we have to prioritize our work. So far, this issue hasn't become high priority because it represents a bit of an edge case. Additionally, there seem to be a number of workarounds in this thread for various setups.

Server side rendering is around for many years, does mapbox really not consider this in their libraries?

WebGL is not available in server environments such as Node so server-side rendering is not something that GL JS has worried about. There's not much we can do on this front. That being said, it is possible to render GL JS in headless environments such as Selenium and Puppeteer using e.g. a Node driver.

Finally, I'm not sure that it's a totally simple change to remove all the references to window before map initialization. For example, #9391 added mapboxgl.prewarm() which allows a developer to fire up a pool of worker threads before map creation in order to increase performance. In order to determine an appropriate number of workers to create, we make use of the hardwareConcurrency property. One can imagine ways to resolve this, but every place where window is referenced needs this sort of careful look. The work to do this properly hasn't been added to our roadmap yet.

const availableLogicalProcessors = Math.floor(browser.hardwareConcurrency / 2);
WorkerPool.workerCount = Math.max(Math.min(availableLogicalProcessors, 6), 1);

We've left this issue open because we'd like to eventually fix it. Hopefully this gives a little more context from our end.

@MarkLyck
Copy link

MarkLyck commented May 27, 2020

@ryanhamley I don't think the problem here is so much that it should render serverside as it is that we cannot even import it in very common projects like next.js, Gatsby, Metor etc.

Sure the workarounds mentioned here "works" if you are building an application, and can conditionally render it. But in our case, we're building an npm module that DON'T support multiple entries/outputs which makes it impossible conditionally render mapbox.

Rather than updating every single instance of window to work without it. Surely at the entry point you can just check if the window exists. If it does not exist, just don't try to render or run anything?

This should be a fairly trivial task?

Something like

if (typeof window === 'undefined') {
  return;
}

We don't need it to work on the server. We just need it to not break if the npm module is simply installed in the project.

@mwarren2
Copy link

mwarren2 commented May 28, 2020

@MarkLyck sums it up perfectly.

I use Meteor, which has a grey area where server and client code can coexist.
We guard against client code running on the server using methods supplied by Meteor core, but they are no help here.

I realise it may seem all too simple to us on the outside, but all I'm looking for is:

if( !isClient ){
    return;
}

@aendra-rininsland
Copy link
Contributor

aendra-rininsland commented May 29, 2020

@ryanhamley With all due respect, you still are totally missing what the actual issue is here.

Pardon the shoutiness for emphasis, but:

THIS HAS NOTHING TO DO WITH SERVER-SIDE RENDERING!

This does have everything to do with the fact that browser-only globals are accessed on module import as a side-effect. Solving this problem seriously can't be any more difficult than gating browser-only side-effects behind functions and requiring them to be called upon map initialisation. I think this can probably even be done as a non-breaking change.

Addendum:

Again, really not trying to be snarky, I'd chip in more but I so don't have time to troubleshoot this right now, I'm working 50 hour weeks as it is and I don't have any map-related projects on the horizon. But my best guess is the problem originates here:

restore() is called inside the top-level module body, meaning as soon as that module is imported, restore is called. This is what I mean by "side-effect".

@mwarren2
Copy link

mwarren2 commented May 30, 2020

mapbox-gl@1.10.0
on mac

Here's the trace I get, which is always the same:

    ReferenceError: self is not defined

    > 1 | import mapboxgl from "mapbox-gl";
        | ^
      2 | 
      3 | 
      4 | 

      at node_modules/mapbox-gl/src/util/browser.js:6:13
      at define (node_modules/mapbox-gl/dist/mapbox-gl.js:23:7)
      at node_modules/mapbox-gl/dist/mapbox-gl.js:16582:3
      at node_modules/mapbox-gl/dist/mapbox-gl.js:7:134
      at Object.<anonymous> (node_modules/mapbox-gl/dist/mapbox-gl.js:8:3)
      at Object.<anonymous> (imports/api/services/helper.ts:1:1)

@Aendrew as far as I can see @ryanhamley was saying exactly what you were saying about server-side rendering, except that he said it nicely.

@aendra-rininsland
Copy link
Contributor

@mwarren2 Apologies if I came across as somewhat exasperated there, I really didn't mean to. But I've been following this issue for literally years now and it's really frustrating when the problem still being seen as "trying to use WebGL on the server" when it's absolutely not.

Will try to take a deeper dive on this later today in penance for being a bit shouty there... 🙇🏼‍♀️

@mourner
Copy link
Member

mourner commented Jun 2, 2020

Hey friends, sorry for not getting to this earlier and misunderstanding the problem. I just made a quick attempt at shimming the window object when evaluating the browser bundle in Node at #9749 — can you check this out and see if it solves your case? I'm not sure because I've never worked with things like Meteor, but at least node mapbox-gl.js should no longer throw an error right away after the change.

@mwarren2
Copy link

mwarren2 commented Jun 2, 2020

@mourner I'm confident that Meteor and node have one and the same problem, so we should be good

@aendra-rininsland
Copy link
Contributor

@mourner You're awesome; thank you!!! 🙌 I did take a look as promised, but alas it seems I was looking in totally the wrong spot, my debugging methods would definitely not have caught that bit in the Rollup config. Apologies again for the earlier exasperation!

@mwarren2
Copy link

mwarren2 commented Jun 5, 2020

Sorry to bother, but:

I wanted to work with the solution but have been unable to install the current dev version which includes the merged solution.

There was once an indication in a ReadME, but that seems to have disappeared.
Can anyone point me to some documentation ?

Here's what I did:

  1. Clone the repository to my machine and rename the folder 'mapbox-gl'
  2. cd to the folder and call npm run build-prod-min (found in package.json) which creates /dist/mapbox-gl.js
  3. cd to my app and npm install path/to/mapbox-gl, which creates a link to the cloned folder.

But when I start the app I get 'cant find module mapbox-gl'.
Please don't waste time on this but if you can see something obvious please let me know.
Thanks.

@ryanhamley
Copy link
Contributor

@mwarren2 That should work. I tried building my Next.js app with both npm link and npm install <localPath> and wasn't able to reproduce this. If you keep having trouble, another approach you could try is to install the master branch directly (note that we use Yarn internally).

npm i mapbox/mapbox-gl-js#master
cd node_modules/mapbox-gl-js
yarn (installs Rollup and other devDependencies)
yarn run build-prod-min

Also, this will be included in a release next week (either a 1.11.0-beta.2 or a final 1.11.0 release).

@mwarren2
Copy link

mwarren2 commented Jun 5, 2020

Looking at your steps, I should also have included at step 2
2. cd to the folder and do npm install to install all the dependencies

However it doesn't want to work, even with the master branch, so I'll wait for a release and no harm done.

I'm guessing that Meteor is failing on the symlink and has to be configured somewhere to follow symbolic links.

EDIT: All solved now as far as Meteor is concerned with 1.11.0 release.

Thanks

jameshadfield added a commit to nextstrain/nextstrain.org that referenced this issue Dec 7, 2020
Gatsby wouldn't build with the older libraries -- see mapbox/mapbox-gl-js#4593 for full context. Note that dev mode worked.

Avoided v5 of react-mapbox-gl as I encountered this bug: alex3165/react-mapbox-gl#904

This commit also adds updates the package-lock and removes a linting error which prevented TravisCI passing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet