I just wrote a module ( https://github.com/mercmobily/simpleDeclare ) and made it available as a Node module via NPM. It follows CommonJS.
I would like to make it also available to people using Bower, and AMD-like loader, and a straight include using the browser.
What's the current pattern to make this happen? Or, is it even possible? I remember seeing a few modules that did it, but cannot find them and am only finding outdated and not-so-definite information (but I suspect I am looking for the wrong thing).
Related
I was going through the React codebase, and I noticed how React's require doesn't quite behave like in Nodejs. I don't get what's going on here.
Looking at line 19 on ReactClass.js for instance, there's a require('emptyObject'), but emptyObject isn't listed in package.json, nor does it say anywhere where that module's coming from.
https://github.com/facebook/react/blob/master/src/isomorphic/classic/class/ReactClass.js#L19
I did find "emptyObject" on npmjs, but the API there seems different from the one used in React; the .isEmpty grepped in React isn't related to emptyObject.
So where is emptyObject getting loaded from, and how is React's require doing what it's doing? This is not intuitive. At all.
The location of the emptyObject module which React refers to is https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/emptyObject.js#L9 Note that it doesn't follow the CommonJS module system.
To make it easier for Facebook to share and consume our own JavaScript. Primarily this will allow us to ship code without worrying too much about where it lives, keeping with the spirit of #providesModule but working in the broader JavaScript ecosystem.
From https://github.com/facebook/fbjs#purpose
The way of defining a module by adding #providesModule in the license header and loading those modules with require in Node is called Haste, a customized module system built for Facebook's open source projects.
In fact, unless you would like to understand the inner workings of React or contribute to Facebook's open source projects, you don't need to know that. In other words, it's not recommended to use Haste to write your own project.
Along the same lines, the invariant module being loaded at line 10 of ReactClass.js is declared at https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/__forks__/invariant.js#L9
As far as I know, both Eclipse and WebStorm don't support Haste so IDE can't help. But with Haste, the name of file and module should be the same, so you can find a module by searching for the filename, i.e. double shift in Webstorm and Ctrl+Shift+r in Eclipse. However, the emptyObject you asked about or invariant are not part of React so it's still cumbersome to find their origin.
Otherwise, there is a team that shares and organizes what they learn from hacking React that I contribute to occasionally and they have linked those requires by following Haste to the corresponding origin file e.g. https://annot.io/github.com/facebook/react/blob/cc3dc21/src/isomorphic/classic/class/ReactClass.js?l=19 You may want to see that.
I noticed how React's require doesn't quite behave like in Nodejs.
Right. Facebook has its own module loader. All modules have unique identifiers, provided by the #providesModule directive in each module. This allows you to use the identifier to load the module, instead of the file path.
Of course that doesn't work in a Node.js based environment. So when React or any other Facebook project is published to npm, all require calls are rewritten automatically to something that Node understands.
This functionality is provided by fbjs which contains shared dependencies and build helpers for all Facebook projects. This is where you find the emptyObject module.
If you look at React's gulp file, you can see how the module maps are constructed and that a custom Babel plugin is used to convert all require calls.
I'm currently working on a server side Node project. Although node has it's own module loader using CommonJS I'm evaluating whether to use RequireJS with it. Whilst there are advantages to using RequireJS with Node if the application that has some client side aspects to it, I can't find any benefits for a project which is entirely server side.
Is it commonly thought that for a 100% server side Node project, there are no real advantages to incorporating RequireJS?
There exist reasons to use RequireJS server-side but they are few. Unless you can state a reason, like:
I must use RequireJS because X
where "X" is a reason which justifies the use of RequireJS, then you should not do it.
Note that just wanting to write modules in the AMD format is not reason enough as there exist loaders (like node-amdl-loader) which allow loading AMD modules in Node. I actually use this when I want to test code which does not depend on a browser. I write the modules in AMD format and specify that if used in Node, an AMD loader like node-amd-loader should be used. This way the library works both in Node and in the browser but I test it in Node.
One reason to use RequireJS server-side is for instance, if you need to run code that needs a DOM implementation. If you use something like jsdom to provide the DOM and the code you want to load is a series of AMD modules, then using RequireJS to load the code into the DOM environment created by jsdom makes sense.
I've never found a good reason to use RequireJS in node. However, RequireJS can be run on node, and the documentation has a brief explanation of why you might want to run RequireJS on a Node server:
By using RequireJS on the server, you can use one format for all your
modules, whether they are running server side or in the browser. That
way you can preserve the speed benefits and easy debugging you get
with RequireJS in the browser, and not have to worry about extra
translation costs for moving between two formats.
Most of that is only useful in a project that also has a client element. If it were me, I'd stick with Node's internal module loader.
I have written a self contained angular js module using browserify in order to make use of the commonJS/Node style syntax.
The module works fantastic when tested by itself, so I then use gulp to minify and host that on GitHub.
I've then imported that into another app that is also using browserify. When I run browserify it seems to try and rebrowserify the module and causes no end of problems.
I believe this is because the module requires angular and jquery and qtip2. So it's obviously trying to re parse these.
Is there a standard to not parse modules, or is there a way to exclude the browserifying of the modules? Or is it best to not include things like angular and jquery within your modules? I was trying to make them perfectly stand alone, maybe that's unwise?
Many thanks!
I would suggest providing both options, if it is important for you to have a standalone version that includes angular. This will provide people using your code with a total of three ways of using your code: Using the standalone version, the version that only includes the module, and cloning the repository directly and including the source files as part their build process.
I generally use the third option, but people who don't have build processes will likely prefer the first or second.
Let's say someone didn't publish their module in npm and even if they did let's say they didn't have it as commonjs module. Would there be a way to still use that plugin or module inside node? I'm aware that we can use node code in browsers using browserify but I was just wondering if there's a way to do the other way around.
This question seems like the most closest that I'm looking into but there's no response yet.
What my end goal really is to be able to use libraries that are not specifically CJS module in node and still be able to test my code in node/cli.
I want to ask if it is possible (and generally a good idea) to use npm to handle front-end dependencies (Backbone, jQuery).
I have found that Backbone, jQuery and so on are all available through npm but I would have to set another extraction point (the default is node_modules) or symlink or something else...
Has somebody done this before?
Is it possible?
What do I have to change in package.json?
+1 for using Browserify. We use it here at diy.org and love it. The best introduction and reasoning behind Browserify can be found in the Browserify Handbook. Topics like CommonJS & AMD solutions, build pipelines and testing are covered there.
The main reason Browserify works so well is it transparently works w/ NPM. As long as a module can be required it can be Browserified (though not all modules are made to work in the browser).
Basics:
npm install jquery-browserify
main.js
var $ = require('jquery-browserify');
$("img[attr$='png']").hide();
Then run:
browserify main.js > bundle.js
Then include bundle.js in your HTML doc and the code in main.js will execute.
Short answer: sort of.
It is largely up to the module author to support this, but it isn't common. Socket.io is an example of such a supporting module, as demonstrated on their landing page. There are other solutions however. These are the two I actually know anything about:
http://ender.no.de/ - Ender JS, self-described NPM analogue for client modules. A bit too involved for my tastes.
https://github.com/substack/node-browserify - Browserify, a utility that will walk your dependencies and allow you to output a single script by emulating the node.js module pattern. You can use a jake|cake|rake|make build script to spit out your application.js, and even automate it if you want to get fancy. I used this briefly, but decided it was a bit clunky, and became annoying to debug. Also, not all dual-environment npm modules like to be run through browserify.
Personally, I am currently opting for using RequireJS ( http://requirejs.org/ ) and manually managing my modules, similar to how Mozilla does with their BrowserQuest sample application ( https://github.com/mozilla/BrowserQuest ). Note that this comes with the challenge of having to potentially shim modules like backbone or underscore which removed support for AMD style module loaders. You can find an example of what is involved in shimming here: http://tbranyen.com/post/amdrequirejs-shim-plugin-for-loading-incompatible-javascript
Really it seems like it is going to hurt no matter what, which is why native module support is such a hot topic.
Our team maintains a tool called Lineman for building front-end projects. The tool is node-based, so a project relies on a lot of npm modules that operate server-side to build your assets, but out-of-the-box it expects to find your client-side dependencies in copied and committed to vendor/js.
However, a bunch of folks (myself included) have tried integrating with browserify, and we've run into a lot of complexity and problems, ranging from (a) npm modules being maintained by a third party which are either out of date or add unwanted changes, to (b) actual libraries that start failing when loaded traditionally whenever a top-level function named require is even defined, due to AMD/Require.js baggage.
My short-term recommendation is to hold off and stick with good ol' fashioned script concatenation until the dust settles. Until you have problems big enough or complex enough to warrant it, I suspect you'll spend more time debugging and remediating your build than you otherwise would. And I think most of us agree the best use of your time is focusing on your application code, not its build tools.
You might want to take a look at http://jspm.io/ which is a browser package manager. Has nice ES6 support too.
I personally use webmake for my small projects. It is an alternative to browserify in the way it brings npm dependencies into your browser, and it's apparently lighter.
I didn't have the opportunity to compare in details browserify and webmake, but I noticed webmake doesn't work well with modules internally using global variables such as socket.io (which is full of bloat anyway IMO).
I would be cautious about RequireJS, which has been recommended above. Because it is an AMD loader, your browser will load your JS files asynchronously. It will induces more exchanges between your client and server and may degrade the UX of people browsing from mobile networks / under bad WiFi. Moreover, if you succeed to keep your JS code simple and tiny, asynchronous loading is absolutely not needed !