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

Add webpack support #1649

Closed
twelch opened this issue Oct 26, 2015 · 68 comments
Closed

Add webpack support #1649

twelch opened this issue Oct 26, 2015 · 68 comments

Comments

@twelch
Copy link
Contributor

twelch commented Oct 26, 2015

I'm able to bundle gl-js using webpack, but I'm getting a runtime error (in glify) with Chrome 46 on OSX. @tmcw mentioned this has been reported before and that a webpack alternative to glify may be needed. Adding an issue for reference and noting workaround.

Uncaught TypeError: Cannot read property 'match' of undefined

at https://github.com/mapbox/glify/blob/master/index.js#L13

Simple example showing my work -- https://github.com/twelch/react-mapbox-gl-js/tree/webpack-test
One workaround is to shim with the pre-built gl-js library using the webpack script-loader module.

require("script!mapbox-gl/dist/mapbox-gl.js");

instead of

import mapboxgl from 'mapbox-gl';
@tmcw
Copy link
Contributor

tmcw commented Nov 3, 2015

My PR at cutting-room-floor/glify#7 avoids the browserify check, and combined with a section in the webpack config like

{
  node: {
   fs: "empty"
  }
}

(people recommend this but nobody knows what it does)

That said, that only gets us to the point where it appears that the transform doesn't work. Hands-on testing and development of this compatibility layer might be better left to someone with more knowledge of webpack internals.

@Madumo
Copy link

Madumo commented Nov 5, 2015

I putted an alias in my webpack config: 'mapbox-gl': path.resolve('./node_modules/mapbox-gl/dist/mapbox-gl.js') so i can still use the es6 module syntax. But it would be great if the lib could be bundled by webpack.

@hannesj
Copy link

hannesj commented Nov 13, 2015

It is not just the glify that is the problem. I tried manually compiling the shaders and using the result to build with webpack but it still fails, as dispatcher.js uses webworkify to generate the worker files/blobs with browserify. I tried to change those to webpack's worker-loader but failed in getting that to work.

@yuvadm
Copy link

yuvadm commented Nov 30, 2015

Curious how far we are on getting gl-js + react + webpack to work. Is this a problem that requires a long term architectural-level solution?

@lucaswoj
Copy link
Contributor

@hannesj Could you elaborate on why webpack's worker-loader didn't work?

I tried to change those to webpack's worker-loader but failed in getting that to work.

@hannesj
Copy link

hannesj commented Nov 30, 2015

@lucaswoj, Sorry, I didn't debug it very thoroughly, as it works to just bundle in the pre-packaged js. It seemed that the individual workers were spun up correctly, but for some reason the event listeners in the worker didn't get executed when messages were sent from the main thread.

@yuvadm
Copy link

yuvadm commented Nov 30, 2015

@hannesj can you explain a bit more about your solution? Did you just use a prebundled shim same way as in https://github.com/twelch/react-mapbox-gl-seed/blob/master/src/components/GLMap.js#L3-L4 ?

@hannesj
Copy link

hannesj commented Nov 30, 2015

@yuvadm, basically yes, except that we don't use the script-loader as mapbox-gl is exposed ad a commonJS module. You can see our usage here

@TheBubbleDuck
Copy link

Even if you are building with webpack (I have been doing so), minifyify is also a regular dep. Because it is a regular dep, it has a peerDep of Browserify. That might also cause some issues at some point (npm shrinkwrap issue for us).

@cezary
Copy link

cezary commented Dec 25, 2015

I was running into problems bundling mapbox-gl-js into a webpack package (ridiculously long production build times when using dist/mapbox-gl-dev, dist/mapbox-gl not working), so I made a webpack-compatible branch.

The main changes were using loaders to package the shaders and worker files. Documentation generation no longer works because of non-js dependencies.

@jingsam
Copy link
Contributor

jingsam commented Jan 23, 2016

Is there any progress to support webpack?

@lucaswoj
Copy link
Contributor

Any progress updates will be posted to this ticket. We would be thrilled to review a PR adding Webpack support by someone who uses and understands the platform.

@jingsam
Copy link
Contributor

jingsam commented Feb 25, 2016

I found a blog about it.
https://mikewilliamson.wordpress.com/2016/02/24/using-mapbox-gl-and-webpack-together/

It just works.
Thx Mike Williamson

@DenisCarriere
Copy link

Thanks @sleepycat (Mike) for making this blog post!

@bensleveritt
Copy link

@misterfresh This is very helpful.

Might want to consider setting up a way to inform users of your lib when/if your lib becomes deprecated.

@eltoro
Copy link

eltoro commented Apr 21, 2016

This finally worked for me for anyone using react 0.15, map box-gl-js 0.17 and ES6 import:

npm install brfs, json-loader, transform-loader, webworkify-webpack -S

inside webpack.config.js

resolve: {
    alias: {
      webworkify: 'webworkify-webpack'
    }
 },
module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'react-hot!babel',
        exclude: /node_modules/,
      },
      {
        test: /\.json$/,
        loader: 'json-loader'
      }
    ],
    postLoaders: [
      {
        include: /node_modules\/mapbox-gl/,
        loader: 'transform',
        query: 'brfs'
      }
    ]
  }

@DenisCarriere
Copy link

@eltoro I'm pretty sure this is a typo son-loader should be >> json-loader

@eltoro
Copy link

eltoro commented Apr 22, 2016

Yep, thanks. I also added the resolve alias for webworkify-webpack. Without it the styles don't work. I can confirm that this setup is working for me.

@DenisCarriere
Copy link

@eltoro Still having issues when using mapbox-gl 0.18.0.

Google Chrome Runtime Error

use_program.js?6fd0:11Uncaught TypeError: fs.readFileSync is not a function

I've fixed it by adding another loader for use_program.js.

loaders: [
  {
    test: /\.js$/,
    include: path.resolve(__dirname, 'node_modules/mapbox-gl/js/render/painter/use_program.js'),
    loader: 'transform/cacheable?brfs'
  }
...

@kislovskij
Copy link

In my case webpack had trouble to resolve to mapboxgl using mapbox-gl 0.18.0. I changed the import statement and now it works.

import * as mapboxgl from 'mapbox-gl';

Also I added a post loader in my webpack config.

postLoaders: [ { include: /node_modules\/mapbox-gl/, loader: 'transform', query: 'brfs' } ]

@ReLrO
Copy link

ReLrO commented Aug 15, 2016

@dvreed77 I found a solution to the bug if you are interested. There is a memory leak in mabox-gl and its connection with webworkify. My solution involves modifying code both in mapbox-gl and in webworkify-webpack.

Basically in webworkify-webpack you need to change the last lines of index.js to:

var objectUrl = URL.createObjectURL(
        new Blob([src], { type: 'text/javascript' })
    );
    var w = new Worker(objectUrl);
    w.objectUrl = objectUrl;
    return w;

Then in mapbox-gl/js/util/actor.js add
this.first = true;
to the Actor constructor (lines 15 - 22) and in Actor.prototype.receive function add the following lines:

if (this.first) {
        // revoke the Object URL that was used to create this worker, so as
        // not to leak it
        URL.revokeObjectURL(this.target.objectUrl);
        this.first = false;
    }

This removes the blob instead of keeping it in memory, which causes a memory leak.

I also added this line:
this.actors[i].target.removeEventListener('message', this.actors[i].receive);
to the for loop in the remove function in mapbox-gl/js/util/dispatcher.js
to ensure the event listener is also removed once the map is removed.

Hope this helps.

@dvreed77
Copy link

@ReLrO Wow, great find! Does anyone else know of this memory leak? Should definitely do a pull a request in this case

@ReLrO
Copy link

ReLrO commented Aug 15, 2016

@dvreed77 I thought of it, but the fix depends on the modification of webworkify-webpack and until webworkify-webpack will change, the fix for mapbox-gl-js wont work...

@steinbachr
Copy link

steinbachr commented Sep 13, 2016

Weird error happening over here. Everything compiles just fine and is working great in all environments (Recent versions of Chrome + Firefox + Safari tested) EXCEPT for Safari v.8.0 (tested on 8.0.8 on desktop + iOS 8). When running on Safari v.8.x, the following error is surfaced:

[Error] Error: webworkify-webpack: Could not locate module containing worker function! Make sure you aren't using eval sourcemaps and that you pass named functions to webworkify-webpack!

stacktrace

perform (core.js, line 5)
batchedUpdates (core.js, line 5)
s (core.js, line 5)
r (core.js, line 5)
enqueueCallback (core.js, line 5)
setState (core.js, line 5)
(anonymous function) (2.6aa3fec414b8cd3371d7.bundle.js, line 9)
(anonymous function) ([native code], line 0)
s (core.js, line 2)
fireWith (core.js, line 2)
r (core.js, line 3)
(anonymous function) (core.js, line 3)

UPDATE 1 When running the webpack build without uglify, the problem disappears. Investigating further now.

@steinbachr
Copy link

steinbachr commented Sep 15, 2016

in other browsers (this time chrome 34.0.1847.116) getting a different runtime error. Here's a better stacktrace from an un-minified bundle:

Uncaught TypeError: undefined is not a function 
5.chunk.js:27473
module.exports 5.chunk.js:27473
module.exports 5.chunk.js:27384
Dispatcher 5.chunk.js:27244
Style 5.chunk.js:17050
util.extend.setStyle 5.chunk.js:14942
module.exports 5.chunk.js:14503
VenueMapMapbox.createMap

some of the above lines:

// find the first moduleId from the above list that contains fnString
27473: var key = potentialFnModuleIds.find(function (moduleId) {
27383: module.exports = function () {
27384:   return new WebWorkify(__webpack_require__(567));
27385: };

UPDATE After some debugging, i've found the error is occurring because the method find wasn't added to the Array prototype on Chrome till v.45.
screen shot 2016-09-15 at 2 54 30 am

polyfilling the method with the snippet here - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find -
solved the issue for me

@WAHeisenberg
Copy link

@aidanlister Hi there, I am facing the same issue, but didn't figure it out. Is yours resolved? Thanks!

@henningko
Copy link

henningko commented Mar 2, 2017

Has anyone gotten it to work with Webpack 2? → https://webpack.js.org/configuration/

Here's my non-working configuration

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}
module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
  ...
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'mapbox-gl': resolve('node_modules/mapbox-gl/dist/mapbox-gl.js'),
      'webworkify': 'webworkify-webpack'
    }
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'node_modules/mapbox-gl/js/render/painter/use_program.js'),
        loader: 'transform/cacheable?brfs'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {
        test: /node_modules\/mapbox-gl/,
        loader: 'transform',
        enforce: 'post',
        query: 'brfs'
      }
    ],
  }
}

Results in

This dependency was not found:

* mapbox-gl in ./~/babel-loader/lib!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/Mapbox.vue

@henningko
Copy link

Solved it by removing the two loaders (just not in conjunction with UglifyJS, see below)

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}
module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
  ...
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'mapbox-gl': resolve('node_modules/mapbox-gl/dist/mapbox-gl.js'),
      'webworkify': 'webworkify-webpack'
    }
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      }
    ],
  }
}

However, building it with UglifyJsPlugin results in Uncaught ReferenceError: n is not defined for the Mapbox component. Thoughts?

@stereobooster
Copy link

In create-react-app project

import mapboxgl from 'mapbox-gl';

I'm getting Critical dependencies: 1:481-488 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results. @ ./~/mapbox-gl/dist/mapbox-gl.js 1:481-488

@kudapara
Copy link

kudapara commented May 2, 2017

I am using the default webpack configuration that comes with the vuejs project scaffolded using the vue-cli together with the webpack template. Mapbox works perfectly during development but when I build the project mapbox throws this error:
Uncaught ReferenceError: e is not defined.

My webpack file looks like this

var path = require('path')
var utils = require('./utils')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: "pre",
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        query: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        query: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  }
}

Someone help please

@onehorsetown
Copy link

@paradzayi

Try doing what @zezhipeng mentions here:

#4359

module: {
     ...
     noParse: /(mapbox-gl)\.js$/,
     ...
}

It fixed the exact same problem for me:

@kudapara
Copy link

kudapara commented May 3, 2017

@onehorsetown your solution works like charm. Thanks a lot 👍 👏 .

I had come up with a not so elegant work around. I added

module.exports = {
  ...
  externals: {
      "mapbox-gl": 'mapboxgl'
   }
  ...
}

to the webpack.config.js file. I did this to prevent the mapbox-gl package from being bundled with webpack but I had to require it in the index.html file using <script> tags.

@Nepomuceno
Copy link

Nepomuceno commented May 4, 2017

I end up doing just adding

module.exports = {
  ...
  node: {
    fs: 'empty'
  },
  module: {
    rules: [
      {
        test: /node_modules.+js$/,
        loader: 'ify-loader'
      }
    ]
  }
  ...
}

and it woks using web pack 2.0 you need to add ify-loader npm i -D ify-loader

johangirod pushed a commit to johangirod/vitaminjs that referenced this issue Jul 21, 2017
…ey in .vitaminrc

Justification: sometimes, you want to be able to specify custome aliases, for instance for libraries
where entry point need some very specific webpack config to be built. In that case you may want to
use the compiled js instead (for instance, that the case of mapbox-gl
mapbox/mapbox-gl-js#1649
@mitulgolakiya
Copy link

We are using it with Angular 6 and getting an error. I'm not sure where should I added this. Any idea in which file(probably tsconfig.json) and in which block I should add it?

@eggp
Copy link

eggp commented Jul 3, 2018

@mitulgolakiya add angular json => "scripts": ["node_modules/mapbox-gl/dist/mapbox-gl.js"]

@bujoralexandru
Copy link

Why is this issue marked as closed? There is not clear way of using this lib with, maybe, the most used js bundler out there.

@stepankuzmin
Copy link
Contributor

Hi @bujoralexandru,

We've outlined the possible solutions in the transpiling section of GL JS docs here https://docs.mapbox.com/mapbox-gl-js/guides/install/#transpiling

We also have a test application that uses webpack, which loads and transpiles the Web Worker separately: https://github.com/mapbox/mapbox-gl-js/tree/main/test/build/transpilation

@bujoralexandru
Copy link

Hi @stepankuzmin,

Thank you for the fast response 💯 !
I managed to make my project correctly build, using this approach
image

One issue still remains: we lose the magic of typescript for the mapboxgl default import. Do you happen to know if there is a way to still obtain those types?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests