It's quite sad I have to ask this question in April 2012, but I know quite few approaches to the problem.
So, I want a tool for statically compiling javascript files, resolving dependencies.
To be more precise I want such tool (let's call it sometool) which can do following:
scan a folder, find all *.js files
parse this files and find some very simple synchronous and 100% js-compliant directive. By synchronous I mean that there is no such thing like passing onload handler - it's only about static text preprocessing. By 100% js-compliant I mean that it looks it's looks like a comment from js point of view - something like // #include
resolve paths used in include directive, using some config which can be customized.
substitute all include with real output and put it into a separate folder.
I do realize that all this sounds obvious to most of you, but javascripters nowadays understand something slightly different while talking about dependency managing - see require.js, for example.
You should have a look at sprockets. It can bundle and pack JavaScript files and supports includes. You might have to write some boilerplate code though. There seems to be a script that allows sprocket to be run from command line bundled with it. And it's in Ruby. Don't know if this is a problem.
There actually is one answer, its name is: Apache ANT
ANT like Make, is a tool which can do almost any job for you. Concatenating files, stripping, reading files/foldes, minifiying, etc. etc. Instructions are done via .xml files, many jobs are already present but of course you can write your own jobs.
That way, you can have a perfect static build process. Personally I use it on severval bases. Have a look as example: https://github.com/jAndreas/typeof-NaN-2.0/tree/master/build
I'm not resolving javascript dependencies the way you described, but I do it with stylesheet dependencies there (replacing #import lines with actual files). So its a fairly easy task to do the same with javascript files. Also, last step in those build scripts are to copy the fresh generated files into my Apache website directory, its indeed one static build process and you're done.
Don't be scared about the filesize, I modified an existent config file from the HTML5 boiler plate there. I actually could shrink that file to 10% size, removing all optional builds.
Related
I'm hoping to find a way to have alternate versions of the same file available from the same webpack run and same output url, with a different chunk/bundle being dynamically loaded after a service call determines which group a user falls into.
Background:
Putting alpha/beta changes into production in the same build and output url lets us develop and test features with external users, but sticking conditionals everywhere (and later removing them) that needs can change is error-prone and generates more complicated code.
My thought was to have alternate versions of the same files in specially named subdirs - e.g. foo/file.js and foo/flagged--special/file.js - and then when something does import blah from 'foo/file' it will automatically get the correct version for that user.
This avoids conditionals in the code itself, and making a feature available for all is just overwriting the base file with the alternate. It also doesn't involve huge changes to our existing codebase and webpack config, nor does it involve a lot of funky and product-specific syntax to replace all our import statements. (After I put the idea together, someone pointed me to Mendel, where Yahoo did much the same thing, albeit as their own framework that is not friendly with webpack, so I'm assuming the base idea isn't crazy)
Problems:
I see examples of feature-flagging a build to one version or the other, but not any examples of having both in one build.
I could write a custom loader or plugin to wrap each file load to do this (I think - not sure about how the output of webpack works in terms of runtime evaluation), but that would result in adding both versions to the bundle.
I'm thinking I can create a base output chunk that does little more than fetch the user's options, then dynamically load one of two alternate chunks that have the different versions...but I have no idea if that will work, or if I'm fighting a losing war vs the webpack internals.
Can this work?
Has someone already done this?
Is there a better way?
Thanks in advance!
I'm developing a modular framework in javascript and am looking for a way to automatically optimize/combine a set of javascripts as a precompile step.
I'm already using grunt so a grunt-task would probably make sense.
The framework consists of modules in their own files (as in the rectangular 'widgets' we're all used to) that in turn may require other javascripts.
All this is wired using Require.js which works great.
However, I came across the following constraint when trying to use r.js which comes with require.js
The optimizer will only combine modules that are specified in arrays
of string literals that are passed to top-level require and define
calls, or the require('name') string literal calls in a simplified
CommonJS wrapping. So, it will not find modules that are loaded via a
variable name:
The thing is: modules may inherit from eachother, and even composition of other modules is possible through configuration (with the technical need to load the referenced modules sitting in their own js-files).
This doesn't work with the mentioned constraint above.
I'm sure I could cook up something myself with enough time, but perhaps someone has already done something like this. (r.js but more flexible).
A doable solution imho would be to:
let the precompile-task run the page for which the js needs to be optimized once (but on the server in Node instead of on the client, the framework is able to do this)
and somehow track all the libraries loaded in by require.js
read out require.js somehow and voila there's your list of js-scripts to load.
hand this to r.js through the include it provides and r.js handles it from there.
there are more pagetypes btw. But in r.js it seems possible to define common libraries, so they don't get included in the per-page-optimized file.
Does this sound plausible? Anyone ever tried something like this?
This seems overly complicated. In r.js build there is option onBuildRead, where you can modify source so that it would be acceptable to optimizer. Also you may look into Internal API: onResourceLoad. Where you can capture all loaded dependencies and then make a call to do custom build.
To load your page you would have to use PhantomJS, so that it acts as a browser and executes JS. Then signal node to produce custom build for that page. But then need to switch resources on that page to use custom build. I guess you can make it configurable and do that when in production.
It does sound that it is possible, not sure if it is feasible.
The documentation for tinymce notes that one can compress all the javascript and components (which I assume includes plugins) into a single file. They do note reasons why one might not want to that as well.
Compressing into a static file
It's also possible to simply concatenate the necessary components and some boilerplate code into a single .js file. However you will always have to recreate this file if you want to use other TinyMCE plugins, or you upgrade TinyMCE. You will also probably want to configure your webserver to compress javascript files.
But assuming one actually did want to do it, how does one actually go about it? Build.xml does does not provide an appropriate task it seems. At least when I tried it the plugins did not seem to be included when I loaded tiny_mce.js.
There are some really excellent command line tools for this, but you can also do this easily with just a text editor. The simplest way is to just open each file, copy the contents, and paste the contents into a single JS file ("everything-all-together.js", say). You'll need to make sure you paste the files into the single file in the same order you would've put the script tags into the HTML doc. Once you have all the files all together, you can use tools like JSXMin, YUI Compressor, or Google Closure. There are also some tools online that do this, like http://www.minifyjavascript.com/. You can paste in the uncompressed JS and copy back out the compressed JS. This makes the build process really cumbersome, but if you just need to do this once, that will get you there.
The best way to do this is to do it as a build step for the site. That means when you make changes to the JS files, you rebuild the compressed JS file to include the changes as well. This can be a cumbersome step if you're iterating quickly and changing files over and over again. You don't want to have to rebuild the compressed file with each save. You can solve this by setting up development and production modes of the site. When being loaded in development mode, the JS files aren't grouped together. When all the necessary changes are made, you'd rerun the build step to generate the single compressed JS file. To do the minification from the command line, you'd probably want to use Google Closure: https://developers.google.com/closure/compiler/. If you download the compiler app, you can do the following:
java -jar compiler.jar some-file.js some-other-file.js > compiled.js
That will generate a file called compiled.js that includes the contents of some-file.js and some-other-file.js in a minified format. You can specify as many files to compile as you need to. Actually, I'm selling Closure a bit short to say it's just minified. It's also extremely optimized code. Pretty much every site should be doing this to all of there JS all the time unless they're already doing something better.
I hope I'm getting you (and the tinymce docs) right, but this sounds a lot like combining JavaScript files on the server side. This means taking the contents of all of your JS files, putting them into one file and returning that one to the client.
Why would you do that? Well, this should be obvious, but.. you reduce the number of HTTP requests to your server, which is always a good thing.
How do you do that? There are many solutions out there for all server-side languages and frameworks, I suggest doing a Google search for "[your language] javascript minifier" or something similar.
Hope this helps.
I've been using yuicompressor.jar on my test server for on-the-fly minimisation of changed JavaScript files. Now that I have deployed the website to the public server, I noticed that the server's policies forbid the use of exec() or its equivalents, so no more java execution for me.
Is there a decent on-the-fly JS compressor implemented in PHP? The only thing resembling this that I was able to find was Minify, but it's more of a full-blown compression solution with cache and everything. I want to keep the files separate and have the minimised files follow my own naming conventions, so Minify is a bit too complex for this purpose.
The tool, like yuicompressor, should be able to take either a filename or JavaScript as input and should either write to a file or output the compressed JavaScript.
EDIT: To clarify, I'm looking for something that does not have to be used as a standalone (i.e. it can be called from a function, rather than sniffing my GET variables). If I just wanted a compressor, Minify would obviously be a good choice.
EDIT2: A lot has changed in the five years since I asked this question. Today I would strongly recommend separating the front-end workflow from the server code. There are plenty of good tools for JS development around and except for the most trivial jQuery enhancements it's a better idea to have a full workflow with automated bundling, testing and linting in place and just deploy the minified bundles rather than the raw files.
Yes there is, it's called minify.
The only thing in to worry about in the way of complexity is setting up a group, and there's really nothing to it. Edit the groupsConfig.php file if you want multiple JS/CSS in one <script> or <link> statement:
return array(
'js-common' => array('//js/jquery/jquery-1.3.2.min.js', '//js/common.js', '//js/visuals.js',
'//js/jquery/facebox.js'),
'css-common' => array('//css/main.css', '//css/layout.css','//css/facebox.css')
);
To include the above 'js-common' group, do this:
<script type="text/javascript" src="/min/g=js-common"></script>
(i know i was looking for the exact same thing not knowing how to deal directly with the jar file using php - that's how i ended up here so i'm sharing what i found)
Minify is a huge library with tons of functionalities. However the minifying part is a very tiny class : http://code.google.com/p/minify/source/browse/trunk/min/lib/Minify/YUICompressor.php
& very very easy to use :
//set the path to the jar file
Minify_YUIcompressor::$jarFile=_ROOT.'libs/java/yuicompressor.jar';
//set the path to a writable temp folder
Minify_YUIcompressor::$tempDir=_ROOT.'temp/';
//minify
$yourcssminified=Minify_YUIcompressor::minifyCss($yourcssstringnotminified,$youroptions)
same process for js, if you need more functionalities just pick from the library & read the source to see how you can make direct call from your app.
I didn't read the question well, since minify is based on using the jar files, the op can't use it anyway with his server config
Minify also include other minifying methods than yui, for example:
http://code.google.com/p/minify/source/browse/trunk/min/lib/JSMinPlus.php?r=443&spec=svn468
Try Lissa:
Lissa is a generic CSS and JavaScript loading utility. Lissa is an extension of the YUI PHP Loader aimed at solving one of the current loader limitations; combo loading. YUI PHP Loader ships with a combo loader that is capable of reducing HTTP requests and increasing performance by outputting all the YUI JavaScript and/or CSS requirements as a single request per resource type. Meaning even if you needed 8 YUI components which ultimately boil down to say 13 files you would still only make 2 HTTP requests; one for the CSS and another for the JavaScript. That's great, but what about custom non-YUI resources. YUI PHP Loader will load them, but it loads them as separate includes and thus they miss out on benefits of the combo service and the number of HTTP requests for the page increases. Lissa works around this limitation by using the YUI PHP Loader to handle the loading and sort of YUI and/or custom resource dependencies and pairs that functional with Minify.
Nowadays, we have tons of Javascript libraries per page in addition to the Javascript files we write ourselves. How do you manage them all? How do you minify them in an organized way?
Organization
All of my scripts are maintained in a directory structure that I follow whenever I work on a site. The directory structure normally goes something like this:
+--root
|--javascript
|--lib
|--prototype.js
|--scriptaculous
|--scriptaculous.js
|--effects.js
|--..
|--myOwnScript.js
|--myOwnScript2.js
If, on the off chance, that I'm working on a team uses an inordinate amount of scripts, then I'll normally create a custom directory in which we'll organize scripts by relationship. This doesn't happen terribly often, though.
Compression
Though there are a lot of different compressors and obfuscators out there, I always come back to YUI Compressor.
Inclusion
Unless a site is using some form of a master page, CMS, or something that dictates what can be included on a page beyond my control, I only included the scripts necessarily for the given page just for the small performance sake. If a page doesn't require any script, there will be no script inclusions on that page.
First of all, YUI Compressor.
Keeping them organized is up to you, but most groups that I've seen have just come up with a convention that makes sense for their application.
It's generally optimal to package up your files in such a way that you have a small handful of packages which can be included on any given page for optimal caching.
You also might consider dividing your javascript up into segments that are easy to share across the team.
Cal Henderson (of Flickr fame) wrote Serving JavaScript Fast a while back. It covers asset delivery, not organization, but it might answer some of your questions.
Here are the bullet points:
Yes, you ought to concatenate JavaScript files in production to minimize the number of HTTP requests.
BUT you might not want to concatenate into one giant file; you might want to break it into logical pieces and spread the transfer cost over several pages.
gzip compression is good, but you shouldn't serve gzipped assets to IE <= 6, so you might also want to minify/compress your JavaScript.
I'll add a few bullet points of my own:
You ought to come up with a solution that works for both development and production. In development mode, it should pull in extra JavaScript files on demand; in production it should bundle everything ahead of time. Switching from one behavior to the other should be as easy as setting a flag.
Rails 2.0 handles all this through an asset cache; other web app frameworks might offer similar solutions.
As another answer suggests, placing third-party libraries in a lib directory is a good start. You can also divide your own JS files into sub-directories if it makes sense. Ideally, you'll be able to arrange them in such a way that the files in a given sub-directory can be concatenated into one file.
I will have a folder for all javascript, and a sub folder of that for 3rd party/shared libraries, and sub folders for each component of the site to keep everything organized.
For example:
/
+--/javascript/
+-- lib/
+-- admin/
+-- compnent1/
+-- compnent2/
Then run everything through a minifier/obfuscator during the build process.
I'v been using this lately:
http://code.google.com/apis/ajaxlibs/
And then have a "jscripts" folder where I keep my custom code.
In my last project, we had three kinds of JS files, all of them inside a JS folder.
Library code. A bunch of functions used on most all of the pages, so they were put together in one or a few files.
Classes. These had their own files, organized in folders as needed, but not necessarily so.
Ad hoc JS. Code that was specific to that page. These were saved in files that had the same name as the JSP pages they were supposed to run in.
The biggest effort was in having most of the code on the first two kinds, having custom code only know what to call, and when.
This might be a different approach than what you're looking for, but I've been playing around with the idea of JavaScript templates in our blog engine. In a nutshell, you assign a Javascript template to a page id using the database and it will dynamically include and minify all the JavaScript files associated with that template and create a file in a server-side cache with the template id as a file name. When a page is loaded, it calls the template file which first checks if the file exists in the cache and loads it if it does. If it doesn't exist, it creates it on the fly and includes it. I also use the template file to gzip the conglomerate JavaScript file.
The template idea would work well for site-wide JavaScript (like a JavaScript library), but it doesn't cover page-specific JavaScript. However, you can still use the same approach for page specific JavaScript by including a second file that does the same as above.