I'm writing a JS library and organizing the code in a hierarchy of CommonJS modules connected with require calls. Then in addition there are also external dependencies (like Underscore).
How can I bundle all my library modules into a single file (CommonJS+AMD) excluding the external dependencies which should remain as require calls?
I've experimented with Browserify and came close with --standalone and --external but when using Browserify again on the application that is using this bundled library it gets confused with the remaining require calls inside the bundled lib. And when I get rid of them with something like Derequire it will also strip out the require calls to external dependencies.
I tried to figure out how other libraries approach this but they mostly seem to have some custom concatenation scripts. Is there a simpler solution? Seems like it should be a common enough use case.
Try what you're already doing with standalone and external, then when you bundle the second time pass the noParse option to browserify (e.g. browserify({noParse: ['/abs/path/to/first/bundle']})). Or you could try minifying the first bundle. See also this answer.
Related
I am new to jspm. I have requrieJs background.
Is it true that jspm while bundling compiles all dependencies into one big file ? like jquery, jquery-ui,bootstrap, databases to other 50 plguins used in project ?
If yes, then What is benefit ? would it not be much faster to fetch items when required like in requrieJs ?
By default jspm does not bundle your dependencies. Every dependency is imported on its own. So if you have three files, say main.js, smth.js and jquery.js, jspm will require them one by one as soon as System.import is called. For static dependencies (like ES6 modules), it happens before the code is executed. But you can also require additional modules at runtime.
The idea behind is that bundling is not really required with HTTP/2. jspm knows the entire dependency tree and it can request all of the dependencies in parallel. Then all files will be delivered over the same network connection which should be pretty the same as if you were bundling them at the build time.
But since HTTP/1 is still to common, jspm offers bundle & build CLI. But those command only put everything in one big file by default. The process is highly configurable. You can exclude certain dependencies such as jquery and put them in a separate bundle or even load jquery from CDN. See https://jspm.io/docs/production-workflows.html#creating-a-bundle for more info how exclude/include modules.
Basically I have a number of legacy web applications that reference and use a library from a CDN (Kendo UI). I have a task to remove such requests to remote hosts and so I'd like to encorporate the library into an existing npm script task that collects all dependencies into a single local js file which the application references.
The problem I'm having is that this library does not provide pre-compiled js files that can be used immediately (unlike other libraries such as jquery or angular), but it is modularised and requires webpack or browserify to use it.
Since our legacy applications do not use the modular approach to loading dependencies, and I have no scope to rewrite them, I would like to somehow package the modularised library into an equivalent js file that will load the library so my application can access it simply via a <script> reference to it.
I have tried using browserify to compile from a source js file that contains simply a require reference to the library, but then referencing the compiled file in my application results in an error as the library's functions are not available to my application.
Can anyone point me in the right direction?
If your using some library's that are module based, and you want to use them standalone, you will need to do 2 things.
expose the module to the global scope. Maybe using the expose loader https://github.com/webpack-contrib/expose-loader or even just assign to the window object.
If the modules are also using a library that your also including standalone, you need to tell webpack about these,.
eg.
{
externals: {
jquery: 'jQuery'
}
// other stuff..
}
Finally when you include these, remember the ordering of your script tags. eg. make sure you include jquery before your bundled javascript.
I read through many articles on Browserify like http://javascriptplayground.com/blog/2013/11/backbone-browserify/ and there is always a step such as below:
$ browserify app/app.js | uglifyjs > app/bundle.js
This seems to be done before you run the script in the browser to see how it works. Is there a way NOT having to do build each time I change code? Something similar to define() function in requirejs...
It's 2015 now and there's a library for this, it's called drq. It uses internally sync xhr requests, so it's only well suited for development purposes. You just have to include it:
<script src="drq.js"></script>
And then, you can do your require calls in any script of the page:
<script>
var myModule = require('my-module'),
myClass = require('./classes/my-class.js');
// etc.
</script>
It will look for node modules up to your web root, so be sure to npm install them at a directory not upper than it. Also, please take a look at the GitHub page where you can find some tips to increase performance.
Again, please remember that bundles are the optimal solution for production.
I originally said you can't do this for the reasons below, but I want to add that where there is a will there is a way. I'm sure given enough time and effort, you (or someone) could (and probably will) come up with a way to accomplish this task - but as of right now (12/12/13), I don't know if there's any out of the box tools that will facilitate it.
browserify "modules" are written using the same concept as node.js modules. You write your code, and export any public methods/properties/etc via a module.exports object. Javascript in the browser doesn't support this sort of thing natively. There are some boilerplate templates (some info here) to help facilitate this in the browser, and they can be compatible with browserify, but...
When you browserify your code, the browserify script analyzes your syntax and finds the modules that it has to make available via the require method. This require method gets defined right in your bundle.js that you export, along with all the code for all the dependencies that your module needs. This allows the require method that browserify defines to work synchronously, returning a reference to the module that you requested immediately without waiting for any kind of web response (like, loading a js script).
Require.js works fundamentally differently than browserify. Require.js defines your packages using the define syntax you referenced, and exposes a require method which you use to tell Require.js which modules your code depends on. Require.js then, in turn, looks up the dependencies you require and if it hasn't loaded them for another module yet, generates a new script tag and forces your browser to load that module, waiting to execute your code until that is complete. This is an asynchronous process, which means, the javascript engine continues to process instructions while it waits for the new script to download, parse, and execute. Require.js wraps all of this up in some callbacks, so it can wait until all your dependencies are satisfied, before allowing your defined code to execute (which is why you pass functions to require and define, so require.js can execute them when it's ready).
The biggest reason to not want to bundle every time you make a change in development, is just for speed of iteration. Some things you can do (with browserify) to improve performance (that is, speed of bundling) are:
Don't uglify your code during development. You can just bundle it using browserify (make sure you use -d, for sourcemaps) without uglifying/minifying it, that should speed up the bundle performance a bit (for larger projects, anyway).
Split up your modules a little bit. Modules that don't have direct dependencies with one another don't have to be built at the same time. You can include different modules in your application using multiple script tags, or you can concatenate browserify bundles files together. You could absolutely set up some grunt tasks to watch your code for changes, and only compile the modules which contained the code change. This will cut out a lot of wasted cpu cycles, since browserify won't have to parse and transform multiple modules, just the ones that changed. From there you can re-concatenate into one big bundle, or just stick with the multiple bundle includes on the page.
I have written a JavaScript app using requirejs to handle dependency injection. I have compiled the file, but I get the obvious error when including it as a script:
Uncaught ReferenceError: define is not defined
I would like my JavaScript app NOT to depend on an AMD loader if the developer decides not to use one. However, due to the complexity of the application, I would like to use it to handle my app's dependencies.
Is there a compiler available that compiles JavaScript to remove the AMD dependency? I've seen a little bit of buzz around Grunt, but haven't found any straight answers on whether or not this is a feature of Grunt.
You can't completely remove the require/define dependency, but you can replace it with a much smaller shim that doesn't introduce any significant performance penalty. See the How can I provide a library to others that does not depend on RequireJS? section of the Optimization guide:
If you are building a library for use on web pages that may not use RequireJS or an AMD loader, you can use the optimizer to combine all your modules into one file, then wrap them in a function and use an AMD API shim. This allows you to ship code that does not ship with all of RequireJS, and allows you to export any kind of API that works on a plain web page without an AMD loader.
almond is an AMD API shim that is very small, so it can be used in place of require.js when all of your modules are built into one file using the RequireJS optimizer. The wrap build config option will put a function wrapper around the code, or you can provide your own wrapper if you need to do extra logic.
I have a javascript project were most modules are using some third party libs as 'global' dependencies (in particular jquery and jquery plugins)
I would like to "clean" the project (to express all libraries as requirejs dependencies.), however this is in my case a large task (lots of files, lots of third-party libs).
How could I make the migration easier / quicker ?
Can I "fake" using amd dependencies by wrapping the third-party libs in modules that just load them (with the order! plugin ?)
Is it safe to mix modules that load third-party libs as modulesand modules that directly use the global ?
If I wanted to automate things, are there any tools could I use to 'parse' a requirejs module to tell me if a particular symbol is used ?
Edit : What I mean by my last question is "Would it be possible to automatically rewrite my js files so that hey explicitely import dependencies instead of relying on browser globals ?"
Can I "fake" using amd dependencies by wrapping the third-party libs in modules that just load them
Yes you can, RequireJS has a shim config that is designed just for that.
Take a look at this article it will help you organize your JavaScript code with RequireJS http://www.stefanprodan.eu/2012/09/intro-requirejs-for-asp-net-mvc/
I had a similar question about the need of wrapping third party code in AMD modules. My conclusion was, that there are no benefits in my case (large Backbone app). So you should ask yourself if you really need to import jquery for example per AMD. This will end in modules where you import jquery every time, which is a lot of error prone boilerplate code.
So in short it makes no sense to use AMD for code that you will use in any case.