Coder Social home page Coder Social logo

Comments (5)

guybedford avatar guybedford commented on June 18, 2024

Thanks for reporting the issue, and as you can likely tell there is quite a bit of complex reasoning for how we got here.

The short answer is that the cases you're talking about supporting like function obj () {}; obj.foo = ... are all cases where it's impossible to tell foo is an export before the CommonJS has executed.

The restriction of needing to work out what a CommonJS module will export before we can execute it is one that was imposed by a combination of requirements from the ECMAScript modules spec itself to Node.js requirements, that were all fought and argued extensively.

While it is possible in theory to support these cases via static analysis, the other constraint this project has is to extract the list of exports incredibly quickly so there is no execution slowdown. More advanced code analysis to determine obj is a function that is later exported, that has properties applied, is simply out of the scope of this project unfortunately.

There are likely simple cases we can improve - eg we don't currently support module.exports = { a: 1 }, simply because a number on the value side of an object expression isn't yet supported by the parser. So if you hit simpler cases where your eyes don't need to understand JavaScript execution to easily see what is exported (about the level of this project), then we can certainly add support for those.

Let me know if that answers your question and sorry we can't do better than this.

from cjs-module-lexer.

k2snowman69 avatar k2snowman69 commented on June 18, 2024

I think it answers my questions and makes sense why an eval is completely out of the question. Further I wondered if we could use the *.d.ts if available to try aid in the populating of exports. I think this could be more efficient than running eval on the js file itself, however still goes against your goals and probably would have perf impact as it's still not just a regex expression. Cutting that as an option as a whole then.

Below you'll find some notes I had per package and why they didn't work based on your answers. This is mostly for anyone who comes to see this issue later. On this, I definitely think there is a bug with the enzyme scenario and I even added the unit test code in that example. Hopefully it helps you quickly be able to come up with a fix (I think it's related to the module.exports = { a: 1 } case).

At this point, feel free to close this issue or keep it open to fix the enzyme example I provided. However I think you've answered all my questions so thank you!

chalk

unpkg link to package contents

Reason this library is unable to parse the commonjs contents is because the exports are defined as such module.exports = chalk; which to your point, requires an eval to determine the values.

However, this package does provide a index.d.ts... which is very complicated and would not be useful. That idea's out the door too.

commander

unpkg link to package contents

Reason this library is unable to parse is because the exports line is as such: exports = module.exports = new Command();. Effectively same issue as chalk.

glob

unpkg link to package contents

Same as chalk and commander

enzyme

unpkg link to package contents

This one actually should be parseable. The exports are as follows:

module.exports = {
  render: _render2["default"],
  shallow: _shallow2["default"],
  mount: _mount2["default"],
  ShallowWrapper: _ShallowWrapper2["default"],
  ReactWrapper: _ReactWrapper2["default"],
  configure: _configuration.merge,
  EnzymeAdapter: _EnzymeAdapter2["default"],
};

I created a unit test for this particular file and found that it's only picking up the first key render however the rest of the keys seem to be missing.

  test("complex values", () => {
    const { exports, reexports } = parse(`
    var _ReactWrapper = require('./ReactWrapper');
    var _ReactWrapper2 = _interopRequireDefault(_ReactWrapper);
    var _ShallowWrapper = require('./ShallowWrapper');
    var _ShallowWrapper2 = _interopRequireDefault(_ShallowWrapper);
    var _EnzymeAdapter = require('./EnzymeAdapter');
    var _EnzymeAdapter2 = _interopRequireDefault(_EnzymeAdapter);
    var _mount = require('./mount');
    var _mount2 = _interopRequireDefault(_mount);
    var _shallow = require('./shallow');
    var _shallow2 = _interopRequireDefault(_shallow);
    var _render = require('./render');
    var _render2 = _interopRequireDefault(_render);
    var _configuration = require('./configuration');
    
    function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
    
    module.exports = {
      render: _render2['default'],
      shallow: _shallow2['default'],
      mount: _mount2['default'],
      ShallowWrapper: _ShallowWrapper2['default'],
      ReactWrapper: _ReactWrapper2['default'],
      configure: _configuration.merge,
      EnzymeAdapter: _EnzymeAdapter2['default']
    };
    `);
    assert.equal(exports[0], "render");
    assert.equal(exports[1], "shallow");
    assert.equal(exports[2], "mount");
    assert.equal(exports[3], "ShallowWrapper");
    assert.equal(exports[4], "ReactWrapper");
    assert.equal(exports[5], "configure");
    assert.equal(exports[6], "EnzymeAdapter");
    assert.equal(exports.length, 7);
  });

tslib

unpkg link to package contents

Seems to work as expected which is great!

from cjs-module-lexer.

guybedford avatar guybedford commented on June 18, 2024

Agreed it would be nice to parse the enzyme one. There's actually a way we could support this in the parser I think, although it would be an interesting new parser approach... are you interested in working on the parser?

from cjs-module-lexer.

k2snowman69 avatar k2snowman69 commented on June 18, 2024

As much as I'd love to I simply wont have time. This is only one of multiple issues I'm running into while trying to move my org to be able to use ESM. Currently hunting and debugging each one to open tickets in all the respective projects (as you can see from the investigation above I'm going package by package) is very time consuming.

I'll try to loop back when time opens up in case it hasn't been tackled but I'd estimate months out at this point.

from cjs-module-lexer.

guybedford avatar guybedford commented on June 18, 2024

Ok I've posted #58 which we can leave open to track the specific support for whenever whomever has time! Thanks again for the comments.

from cjs-module-lexer.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.