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

Unable to use math.js on frontend with webpack #601

Closed
chmln opened this Issue Mar 13, 2016 · 34 comments

Comments

Projects
None yet
6 participants
@chmln

chmln commented Mar 13, 2016

Hello!

First off, koodos to author for a fantastic library.

I'm having trouble importing mathjs to frontend through webpack.

Whenever I import mathjs, here's what happens:
webpack

The module is imported like any other node module.
code

And here's my webpack config

var path = require('path')
var webpack = require('webpack')

module.exports = {
  entry: ['./src/main.js'],
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/',
    filename: 'build.js'
  },
  resolveLoader: {
    root: path.join(__dirname, 'node_modules'),
  },
  module: {
    loaders: [

        { test: /\.jade$/, loader: "jade" },

        { 
            test: /\.js$/, 
            loader: 'babel', 
            include: [                
                path.resolve(__dirname, "src")
              ] 
        },

        { test: /\.json$/, loader: 'json' },

        { test: /\.vue$/, loader: 'vue' },

        { test: /\.scss$/, loaders: ["style", "css", "sass"], exclude: /node_modules/ },

        { 
            test: /\.styl$/,
            loaders: ["style", "css", "stylus"],
            exclude: /node_modules/

        },

        {
            test: /\.(png|jpg|gif|svg)$/,
            loader: 'url',
            query: {
            limit: 10000,
            name: '[name].[ext]?[hash]'
        }

      }
    ]
  },

  devtool: 'eval-source-map'
}

module.exports.devtool = 'source-map'
// http://vuejs.github.io/vue-loader/workflow/production.html

module.exports.plugins = (module.exports.plugins || []).concat([

    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),

    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),

    new webpack.optimize.OccurenceOrderPlugin()

])

No problems, however, using mathjs in node backend.

@josdejong

This comment has been minimized.

Owner

josdejong commented Mar 14, 2016

Thanks.

It's hard to guess what's going wrong here and where (babel? uglify? webpack?). math.js itself is built using WebPack and Uglify too. The code is regular ES5, so no babel needed. To see whether it's caused somehow by Babel you could maybe configure Babe not ignore all math.js code?

@chmln

This comment has been minimized.

chmln commented Mar 14, 2016

I've tried tweaking babel, disabling uglify and source maps, but I couldn't get the node module import to work in any case.

However, including the math.min.js file instead works perfectly fine.

Suspecting it is rather an issue with uglify and/or webpack than the library itself.
In case I find a culprit I'll report back here for sure.

@josdejong

This comment has been minimized.

Owner

josdejong commented Mar 15, 2016

Hm, that's not really satisfactory. Great that you found a solution but I'm still curious what's causing this - others may encounter similar issues.

@medja

This comment has been minimized.

medja commented Apr 7, 2016

I stumbled upon this as well and after quite a bit of digging I think I found the root of the problem.
The error is caused by typed-function when a it tries to use a signature function's name as the typed function's name.

In my case the bug was actually caused by Chrome (51.0.2693.2 dev-m) when trying to create the middle helper function inside lib/function/statistics/median.js:

var middle = typed({
  'number | BigNumber | Unit': function (value) {
    return value;
  }
});

Because the function is anonymous and bound to an object, Chrome decided to use it's object key for the function name, which works fine when setting it as a property on the function but causes issues when typed-function tries to use it to evaluate a new function.

var factory = (new Function(refs.name, 'createError', body));
var fn = factory(refs, createError);

This problem can be avoided by explicitly naming anonymous functions but that's really nothing more then a workaround at this point, since the problem lies in another package.

typed-functions will probably need a patch to handle cases where a browser, a transpiler or a minifier use invalid function names. I guess I could make a PR and propose a fix.

In the meanwhile one solution is to run a script that adds proper names to those functions. Babel with the ES2015 preset does that, but minifying will undo the process.

@josdejong

This comment has been minimized.

Owner

josdejong commented Apr 9, 2016

Wow, you're right, Chrome 51 actually changes the name of an anonymous function to its object key.

It's indeed not safe to rely on the name property of functions, since names can change when minifying code, or like Chrome 51 does for unnamed functions in objects. I've changed typed-function such that it only uses the name property of other typed-functions, not of regular JavaScript functions. That should solve the issue. I've updated in the develop branch, it would be great if you could give it a try (don't forget to run npm update).

@medja

This comment has been minimized.

medja commented Apr 9, 2016

It worked perfectly. I made sure the published version still threw the exception first, just in case the latest Chrome (dev) update changed anything. And after switching to the develop branch everything seems to work as expected. Hopefully this also fixes any similar issues. Good job 👍

@josdejong

This comment has been minimized.

Owner

josdejong commented Apr 9, 2016

great to hear, thanks for the quick feedback.

medja added a commit to medja/ovs-prirocnik that referenced this issue Apr 9, 2016

fix(project): switch to develop branch of math.js
This fixes a Chrome specific issue with the library (josdejong/mathjs#601)
and allows the use of proper minification.

@josdejong josdejong closed this in 9c8eb5a Apr 16, 2016

@richburdon

This comment has been minimized.

richburdon commented May 27, 2016

Hey @josdejong any update on this? Does the dev branch work? I still have the same error. Thanks.

@josdejong

This comment has been minimized.

Owner

josdejong commented May 28, 2016

As far as I know this issue was fixed in v3.2.0. Apparently not? How to reproduce your issue?

@chmln

This comment has been minimized.

chmln commented May 28, 2016

@josdejong can confirm working since v3.2 w/ webpack
@richburdon try reinstalling? webpack config might also help investigate the issue

@richburdon

This comment has been minimized.

richburdon commented May 30, 2016

@chmin thanks -- reinstalling worked.

But leads to a different problem -- I have the following in my webpack.config.js (which is necessary to have JS classes that use ES6 classes transpiled to ES5 for PhantomJS testing).

  {
    test: /\.js$/,
    loader: 'babel-loader',
    query: {
      presets: ['es2015'],
      compact: false
    }
  },

But this causes:

Module build failed: Error: Couldn't find preset "es2015" relative to directory "node_modules/mathjs"

babel-preset-es2015 is installed (and has been working with many libs and JS files up until this point).

Sorry if it's unrelated, but I haven't figured it out yet.

@josdejong

This comment has been minimized.

Owner

josdejong commented May 31, 2016

Good to hear the original issue is indeed solved.

I think this is a generic babel related thing. mathjs doesn't use babel but apparently babel tries to find configuration/presets for itself in the folder of mathjs. Maybe you can exclude mathjs from being transpiled by babel?

@chmln

This comment has been minimized.

chmln commented May 31, 2016

@richburdon its a good idea to exclude node modules from babel transpiling.
You could also use the include option to only search for js files in specific directories.

  {
    test: /\.js$/,
    loader: 'babel-loader',
    query: {
      presets: ['es2015'],
      compact: false
    },
    exclude: /node_modules/
  },
@timvdalen

This comment has been minimized.

timvdalen commented May 22, 2017

I am seeing this error again with mathjs 3.13.1 and Chrome 58.0 in TypeScript. I'm using @angular/cli to build.
Whenever I call math.parse(), I get a TypeError on the snippet referenced above:

var factory = (new Function(refs.name, 'createError', body));
var fn = factory(refs, createError);
Uncaught TypeError: factory is not a function
    at _typed (typed-function.js:1116)
    at typed (eval at _typed (typed-function.js:1115), <anonymous>:15:16)
    at Object.factory (matrix.js:36)
    at load (core.js:106)
    at Object.factory (subtract.js:8)
    at load (core.js:106)
    at Object.factory (Unit.js:9)
    at load (core.js:103)
    at Object.factory (SymbolNode.js:12)
    at load (core.js:103)

I'm getting math.js into TypeScript with import * as math from 'mathjs';

@josdejong

This comment has been minimized.

Owner

josdejong commented May 22, 2017

Thanks for reporting

@josdejong josdejong reopened this May 22, 2017

@josdejong

This comment has been minimized.

Owner

josdejong commented May 22, 2017

what is the easiest way to reproduce this issue? Is it something related to just TypeScript? (running math.js in Chrome 58 still works as far as I can see)

@timvdalen

This comment has been minimized.

timvdalen commented May 22, 2017

I'll try to set up a demo repository tomorrow.
I'm not exactly sure where this is happening, but it does seem related to either the TypeScript transpilation or angular>=2.

I'm migrating an angular 1 app with webpack to an angular 4 app with webpack.
In the previous app, math.js worked just fine.

@josdejong

This comment has been minimized.

Owner

josdejong commented May 22, 2017

awesome, thanks. Would be great if you could do some pinpointing already.

@josdejong

This comment has been minimized.

Owner

josdejong commented May 22, 2017

Just to be sure: what was is the last version of mathjs that still works then?

@timvdalen

This comment has been minimized.

timvdalen commented May 22, 2017

Both the angular 1 and angular 4 apps are running on 3.13.1

@josdejong

This comment has been minimized.

Owner

josdejong commented May 22, 2017

Yes but I mean mathjs 3.13.1 gives this problem, but 3.13.0 not? Or is it for all (recent) versions of mathjs and has purely to do with upgrading to angular 4?

@timvdalen

This comment has been minimized.

timvdalen commented May 24, 2017

I've prepared two repositories for easier reproduction:

It turns out that in this very limited demo, mathjs actually works fine.
I'm going to dig a bit deeper to see if I can find why it doesn't work in my actual application.

@josdejong

This comment has been minimized.

Owner

josdejong commented May 24, 2017

Thanks for the update, hope you will find the cause!

@timvdalen

This comment has been minimized.

timvdalen commented May 26, 2017

Finally figured it out!
The error only occurs if you're debugging the application in the Chrome DevTools.

In the new angular 4 application, I was testing if mathjs was working without fully implementing it, getting the error.
In the demo, I just implemented it fully without debugging.

Now, I can reproduce in both angularjs and angular (TypeScript).

I've updated both repositories.
If you open:

With devtools open, you'll get to a breakpoint with a comment that includes some code to execute.
Executing this code in the debugging context will result in the error similar to the one that I described above.

@josdejong

This comment has been minimized.

Owner

josdejong commented May 27, 2017

Thanks for working out these demos!

I've opened them in Chrome (Version 58.0.3029.110 (64-bit)), with dev tools open. Then it steps though three break points but in both cases the application runs fine and shows 2 + 2 = 4 in the end. You're running Chrome 58 too right? Is there anything else I have to do in the dev tools to get the error triggered?

@timvdalen

This comment has been minimized.

timvdalen commented May 27, 2017

Sorry if it wasn't clear - if you run the code in the comment after each of the breakpoints in the devtools console you'll get the error.

The applications indeed run fine but invoking mathjs from the debugger/console in devtools throws an error.

@josdejong

This comment has been minimized.

Owner

josdejong commented May 28, 2017

Ah, Thanks. I can reproduce this issue now. I've narrowed it quite a bit: it has not to do with angular, typescript or math.js, you can reproduce this issue in Chrome 58 with just one line of plain JavaScript:

http://jsbin.com/raluwu/edit?html,output

<!DOCTYPE html>
<html>
<head>
  <title>math.js | issue #601</title>
</head>
<body>
  <script>
    // open the developer console in Chrome 58, 
    // and run this code until the debug point
    debugger;
    // when at the debug point, enter the following in the console:
    //
    //     var f = new Function ('a', 'return a + a');
    //     // f should be a function but is undefined when in debug mode
    // 
    //     console.log(f(2));   
    //     // should return 4, but throws "Uncaught TypeError: f is not a function"
    
    // without debug point, everything runs fine
    var f = new Function ('a', 'return a + a');
    console.log(f(2));
  </script>
</body>
</html>

This might be a bug in Chrome 58. I've asked on stackoverflow: https://stackoverflow.com/questions/44228320/new-function-returns-undefined-in-chrome-58-when-in-debug-mode

@timvdalen

This comment has been minimized.

timvdalen commented May 28, 2017

Nice, that's progress! I'll be monitoring the SO thread.

EDIT: Just checked, Firefox does not have this behaviour and works as expected.

@josdejong

This comment has been minimized.

Owner

josdejong commented May 28, 2017

I found an existing bug report on this issue: https://bugs.chromium.org/p/chromium/issues/detail?id=705149

@josdejong

This comment has been minimized.

Owner

josdejong commented May 28, 2017

I will close this issue now, it's not something I can fix.

@yogeshborad

This comment has been minimized.

yogeshborad commented Apr 2, 2018

Just hit the command:

npm install mathjs

@josdejong

This comment has been minimized.

Owner

josdejong commented Apr 2, 2018

good point @yogeshborad I suppose that this issue is resolved in math.js v4, since there new Function isn't used anymore?

@yogeshborad

This comment has been minimized.

yogeshborad commented Apr 3, 2018

Yes, sorry for that. This issue is only resolved in math.js v4. Thanks to @josdejong for reminding and correcting to me.

@josdejong

This comment has been minimized.

Owner

josdejong commented Apr 3, 2018

Good to hear, thanks for the confirmation Yogesh.

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