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.
Related
I am learning ES6 modules at this current time. It took me so long to finally understand and be proficient in closures, IIFEs and scope using one script that I was almost upset to find ES6 modules bring about a different, more manageable way to organise modular code into various different scripts and then for a bundler like Webpack to bundle it all back into one (or only a few) scripts.
I get the normal cross origin error when I put script type = ‘module’ and try to run modules on my local file system which is different to when I run a normal script just simply specifying a src!
Wherever I look the solution is to use a local host to get round this which I have done! But at what point does Webpack work its bundling? Is it when I run it in the command line or when it’s loaded into the browser?
If installing Webpack via npm in my project and setting up the configuration, does this mean I wouldn’t have to use a local host because my distribution code during the runtime is now in one script file, so it doesn’t have to import scripts not on the same URL?
I know it’s only on my local file system, but I cannot request scripts in the same folder when using ES6 modules due to the cross origin policy as I could if just specifying a script src without using modules.
Each time I run Webpack from the command line, it bundles together the latest code taken from the entry point (specified during my configuration).
This means I can use the ES6 module syntax on my entry file without having to use a live server as I never intend to load this JavaScript entry file into the browser. It’s simply to be the controller of all other script exports by importing what I need from them.
Then this script will be the target of Webpacks bundling (the entry point) meaning the only script that is loaded into the browser is the bundled script, which has no other imports. This avoids the need to run a live server when testing ES6 modules!!
If not using Webpack, I would have to run a server because my main script would be importing other scripts and unless they have the same URL (they don’t even have one yet in my file system) then I will get a cross origin error. As soon as I run my local server 127.0.0.1 then it would work. I prefer testing with Webpack.
This is my problem: I created a library to use within Chrome extensions. This library exports two classes, one of which should be imported in the background script and one in the content scripts.
The background script (and other scripts that are used in the extension pages) can handle modules, so I would like to use the native "import"/"export" feature of ES6 Modules.
The content scripts do not support modules. That means that if I use the "export" keyword in my library script, that will throw an error, and I won't be able to use the library anymore.
Currently, I'm not implementing modules at all, and that solves the problem, but I would like to implement this functionality, so that it can be used when someone has access to it.
Is there a way to offer my library functionality as both a module and a non-module for both kind of scripts? Is that actually something that I should do?
In the end, I set up two git branches:
1 - In the first one, I just kept the file without the "export", so no ES6 modules capabilities
2 - This other branch, I decided to set it up to be published on NPM, and in this one I exported my classes. If you use NPM for your development, it's already very probable that you also have a bundler like webpack to keep track of modules and dependencies.
Whenever I do a change, I do it in the master (no exports) branch, and then I merge the changes in the npm branch, to avoid writing the same code twice
I really like using cdnjs to load up javascript on the client-side, it makes my project smaller and cleaner, and loads everything faster as well. I currently use require.js for module loading, which can load from cdnjs and shim traditional scripts to work with it easily. I've been looking more into browserify recently as an alternative, and while I did find browserify-shim, which can shim non-cjs modules much like require does, I'm curious if there is a way to load a script from a remote source with browserify, or if you have to install everything locally no matter what.
If the answer is that you would have to install everything locally through npm, this makes things a little weird. On one hand, you can add node_modules to the .gitignore file and not have to worry about keeping all the deps on version control if you are using a package.json, but on the other hand, you'd need to get the modules back in there on deploy, which means an additional post-deploy step that would run npm install and that node would need to be installed wherever you are deploying to, which also seems a little awkward to me for a static site especially.
Really, any ideas or discussion on this would be great : )
The way I think about it is this, you have three options: concat the JS files together locally (browserify) before deployment, load them in real-time (require.js), or a mix of both. To be fair, you can use require.js to concat your files with r.js too. For me at least, I like how browserify is designed to use the same syntax and mentality as npm modules. I think in the end the weirdness your experiencing doesn't really matter. If all the code is packaged together, you deploy, and there aren't any dependencies, seems like a win to me. Also, I think this is more in line with Java and similar compiled languages are doing, which is putting all the deps together in a deployable package. I know I mention Java but don't let that scare you because really we are all benefitting from the ideas of those around us even the languages we think we don't like. If I had to bet my money, I would bet on browserify since it's offering (what I consider) to be a more mature means of handling modules (organized by file based rather than syntax). The npm also gives us a great way to share our code so two thumbs up for them.
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.
If I have a node.js application that is filled with many require statements, how can I compile this into a single .js file? I'd have to manually resolve the require statements and ensure that the classes are loaded in the correct order. Is there some tool that does this?
Let me clarify.
The code that is being run on node.js is not node specific. The only thing I'm doing that doesn't have a direct browser equivalent is using require, which is why I'm asking. It is not using any of the node libraries.
You can use webpack with target: 'node', it will inline all required modules and export everything as a single, standalone, one file, nodejs module
https://webpack.js.org/configuration/target/#root
2021 edit: There are now other solutions you could investigate, examples.
Namely:
https://esbuild.github.io
https://github.com/huozhi/bunchee
Try below:
npm i -g #vercel/ncc
ncc build app.ts -o dist
see detail here https://stackoverflow.com/a/65317389/1979406
If you want to send common code to the browser I would personally recommend something like brequire or requireJS which can "compile" your nodeJS source into asynchronously loading code whilst maintaining the order.
For an actual compiler into a single file you might get away with one for requireJS but I would not trust it with large projects with high complexity and edge-cases.
It shouldn't be too hard to write a file like package.json that npm uses to state in which order the files should occur in your packaging. This way it's your responsibility to make sure everything is compacted in the correct order, you can then write a simplistic node application to reads your package.json file and uses file IO to create your compiled script.
Automatically generating the order in which files should be packaged requires building up a dependency tree and doing lots of file parsing. It should be possible but it will probably crash on circular dependencies. I don't know of any libraries out there to do this for you.
Do NOT use requireJS if you value your sanity. I've seen it used in a largish project and it was an absolute disaster ... maybe the worst technical choice made at that company. RequireJS is designed to run in-browser and to asynchronously and recursively load JS dependencies. That is a TERRIBLE idea. Browsers suck at loading lots and lots of little files over the network; every single doc on web performance will tell you this. So you'll very very quickly end up needing a solution to smash your JS files together ... at which point, what's the point of having an in-browser dependency resolution mechanism? And even though your production site will be smashed into a single JS file, with requireJS, your code must constantly assume that any dependency might or might not be loaded yet; in a complex project, this leads to thousands of async load barriers wrapping every interaction point between modules. At my last company, we had some places where the closure stack was 12+ levels deep. All that "if loaded yet" logic makes your code more complex and harder to work with. It also bloats the code increasing the number of bytes sent to the client. Plus, the client has to load the requireJS library itself, which burns another 14.4k. The size alone should tell you something about the level of feature creep in the requireJS project. For comparison, the entire underscore.js toolkit is only 4k.
What you want is a compile-time step for smashing JS together, not a heavyweight framework that will run in the browser....
You should check out https://github.com/substack/node-browserify
Browserify does exactly what you are asking for .... combines multiple NPM modules into a single JS file for distribution to the browser. The consolidated code is functionally identical to the original code, and the overhead is low (approx 4k + 140 bytes per additional file, including the "require('file')" line). If you are picky, you can cut out most of that 4k, which provides wrappers to emulate common node.js globals in the browser (eg "process.nextTick()").