cujojs / curl

curl.js is small, fast, extensible module loader that handles AMD, CommonJS Modules/1.1, CSS, HTML/text, and legacy scripts.
https://github.com/cujojs/curl/wiki
Other
1.88k stars 216 forks source link

How to help curl guess the right plugin? (e.g. json! for *.json) #298

Closed mk-pmb closed 7 years ago

mk-pmb commented 7 years ago

The simple use case: Is there a way to tell curl to use the "json!" plugin for all require()s that specify a module name that ends with .json? That would help me a lot for node.js compatibility.

The more general use case: Is there a way to register a function that optimizes a module name before it is resolved? Some few regexp matches there could save me a lot of aliases.

unscriptable commented 7 years ago

Hey @mk-pmb,

There are two possible solutions.

If all of your .json files are in one directory, you can configure a package for that directory and use a curl plugin as a curl loader. Here's the basic information for creating a package: https://github.com/cujojs/curl#package-support To configure a curl loader for a package, see here: https://github.com/cujojs/curl/tree/master/src/curl/loader (last example is very close to what you want, just replace the link plugin with the json plugin.

If you have .json files mixed with normal modules, you can try the experimental "ext" plugin. It's here: https://github.com/cujojs/curl/commit/6859c8cb8eb2b7e6935590bb44c66642745730d9 Copy that module and put it somewhere within your project. It looks like it should Just Work™, but it hasn't been tested on recent versions of curl.js, afaict.

You can use the package configuration (as above) to specify the loader, or you can specify it for the entire app by specifying a loader: 'path/to/ext.js' at the top-level config.

Let us know if either of these works! :)

-- John

unscriptable commented 7 years ago

I just noticed that you asked about a general solution. Yes, you can use the experimental ext loader as an example.

The ext loader probably shows you what you need to know. There are other loaders with more complex needs, here, too: https://github.com/cujojs/curl/tree/master/src/curl/loader (look at the source code for docs).

mk-pmb commented 7 years ago

If all of your .json files are in one directory,

Nope, that would've been too easy. :-)

you can try the experimental "ext" plugin

Thanks! Looks like what I need, I'll try it asap. (Edit: The ext loader is currently also available as a branch)

mk-pmb commented 7 years ago

So my loader gets a require function as one of its arguments. Is that one guaranteed to avoid loops? I couldn't find that guarantee in the docs. Assume I find a way to configure my nio (node inter-op) plugin to be used for everything, or at least for the "package" that is all of my node_modules/, thus includes curl-amd and nio. Then nio decides that mystery.mys is for the mystery plugin, and forwards it with require('mystery!' + resourceId, …), mystery knows a filename with exactly 3 ys must be AMD-style JS and thus forwards it without any prefix. (Worked before nio because .mys was configured as a dontAddFileExt.) Will curl give that resourceId to nio again?

PS: In case there is no guarantee: Is there a mechanism to specify that a resourceId is final, no plugins shall be applied? Maybe ! as first character of the resourceId?

unscriptable commented 7 years ago

Hmmmm... yah. There is a circle. Bummer.

If you can stipulate that your loader will only be configured for packages that contain node modules, then you could prepend the "json!" prefix to .json files and prepend "cjsm11!" to node files. (See the cjsm11 loader/plugin.) This will ensure that a different loader/plugin will be used for the recursive require.

If the above isn't feasible, it's also possible to override curl's internal API. See here for an example of overriding the define function and here for an example of overriding the require function (which is different for each module).

mk-pmb commented 7 years ago

Thanks! :+1: I'll try and hack a custom require then. Nevertheless I think an official and easy way to bypass plugins would be nice, so I requested https://github.com/cujojs/curl/issues/299 .

mk-pmb commented 7 years ago

So I've adapted the dojo shim require code

define(/*…*/ ['curl/_privileged'], function (priv) { /*…*/
    origCreateContext = priv['core'].createContext;

… to this: (live: demo)

    var core = require('curl/_privileged').core;
    console.log('internode init:', {
      version:  require('curl').version,    // "0.8.13"
      core:     String(core),               // "[object Object]"
      origCC:   String(core.createContext), // "undefined"
    });

which seems to indicates that I managed to reach the core but there's no .createContext function in it. What did I miss?

Update 1: Seems to be about minification. I dumped the core object's keys and they were A, j, M, ea, na, T, ma, U, $, b, s, Z, B, m, S, la, ga, N, F, ja, ia, oa, ka, ha, ba, o. So I'll probably have to build my own curl in order to monkey-patch it, or is cC exported somewhere else with a better name? If not, could you ship a non-minified alias for it in the default kitchen-sink build? In that one, people won't mind the few bytes given what feature they get. ;-)

Update 2: Looking for where to add the aliases, I found that .createContext won't be the only problem, because probably the .require is minified as well. Also toUrl and toAbsId sound good for monkey-patching as well, would you mind exporting them too?

mk-pmb commented 7 years ago

Thanks for suggesting SystemJS over in #271. It has all the plugin guessing that I currently need, so for now I won't pursue my curl approach. Curl is great nonetheless, it helped me a lot in the past few years. Excellent work!