guybedford / cjs

CommonJS loader plugin for RequireJS
MIT License
17 stars 4 forks source link

How to make it add `.js` to file paths? #4

Open trusktr opened 7 years ago

trusktr commented 7 years ago

Hello Guy,

I have some CommonJS modules that I'm trying to load in a "legacy" RequireJS project, and it has require statements like this:

// foo.js
require('./bar');

that seems to load bar/ relative to the current file, instead of bar.js, so it gets a 404 error in my case.

Would it be safe to assume that if we detect this style of require statement that we can just append .js to it? If so, I would be willing to make a PR.

Or, what other solution could there be? Is there some way to configure requirejs to make it work without modifying this plugin and without modifying the CommonJS sources?

I tried some map and paths configs like the following with no luck:

requirejs.config({
    map: {
        '*': {
            '/path/to/bar': '/path/to/bar.js',
        }
    },
    paths: {
        '/path/to/bar': '/path/to/bar',
    }
});

I'm not sure if it is possible to configure it.

trusktr commented 7 years ago

I was able to get around the problem with this change: https://github.com/guybedford/cjs/pull/5

But I'm not sure what the implications are; it might need more care.

Now I'm having the problem that some of those files import, for example, things like lodash/split, etc, from node_modules. It's just a big'ol mess. I'm not sure what I need to further do to make it work with node_modules.

in my case, foo is an NPM module, and I was able to set a map for it like

requirejs.config({
    map: {
        '*': {
            'foo': '/path/to/node_modules/foo/index.js',
        }
    }
});

That part works, and it seems it is able to load ./relative files, but then messes up when importing other node_modules.

Maybe I just have to make a map for everything, but I'm not sure how to do that while also adding the cjs! prefix, which doesn't seem to work (requirejs tries to place cjs! at the beginning of the import path.

I imagine I could go and make a map for each node module, but I would have to modify each node module source to have the cjs! prefixes, I think that would work, but I'm trying to do this without modifying any of the dependencies.

trusktr commented 7 years ago

I put some console.logs in the plugin, so it looks like this:

define("cjs", ["amd-loader"], function(amdLoader) {
    console.log('csj-loader!')
  var cjsRequireRegExp = /\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g;
  return amdLoader("cjs", "js", function(name, source, req, callback, errback, config) {
    source = source.replace(cjsRequireRegExp, function(match, dep) {
      if(dep.substr(0, 1) == ".") {
        if (dep.search(/\.js$/) == -1) dep = dep + '.js'
          console.log(' ----- relative dep!', dep)
        return" require('cjs!" + dep + "')"
      }else {
          console.log(' ----- module dep!', dep)
        return" require('" + dep + "')"
      }
    });
    callback("define(function(require, exports, module) { (function(){var define=undefined;" + source + " \n//# sourceURL=" + req.toUrl(name) + "\n})() });")
  })
});

So, the relative deps work fine now, but the module deps don't. The output for those looks like this, for example:

----- module dep! react

Maybe I just need to output all of those, and make a map config for them. Gonna keep trying...

trusktr commented 7 years ago

I tried a map config like

 'cheerio': '/path/to/node_modules/foo/node_modules/cheerio/index.js',

but no luck. It also gives an error (among tons of other errors) like

Uncaught Error: Module name "lib/cheerio" has not been loaded yet for context: _. Use require([])

Does map config work with paths inside the CommonJS modules?

Have you ever loaded node_modules with requirejs before? If so, what'd you do?

trusktr commented 7 years ago

I think I'll just fork the package in question, and add a build step to compile a UMD module. I think that's probably easier.