In the normal course of development assets are best loaded individually rather than in one merged file. And assets definitely should not be minified or mangled. This all makes for easier debugging and for speedier compile and load times. But when an application is taken to production, all the performance improvements that come with merging, optimizing, and minifying assets should be included.
For both the
watch commands, Mimosa provides
--minify flags that combine to provide both the ability to fully optimize an application, and to have a more control over what gets optimized.
mimosa-require module that comes with Mimosa by default, Mimosa uses the r.js optimizer which is perfect for optimizing RequireJS applications. Underneath the hood, that optimizer is using Uglify2 to shrink a codebase down as tiny as possible. Mimosa bundles Uglify2, and can use it to individually shrink assets. And Mimosa's Uglify and the r.js optimizer can be combined to provide more fine-grained control over a minification strategy.
Out-of-the-box Mimosa supports RequireJS based optimization. But if browserify is your favorite build tool, then check out the mimosa-browserify module. The GitHub page has details on its use and the author has put an example app up show how to use it.
But if RequireJS is your thing...
Mimosa's RequireJS optimization support comes courtesy of the
mimosa-require module, a default Mimosa module that comes with Mimosa when it is installed.
For both the
watch commands, Mimosa provides an
--optimize flag that will turn on optimization. Mimosa wraps the r.js optimizer and runs it with a default configuration gleaned from the setup of the application.
When a codebase is optimized and pulled together into one file, the RequireJS library is no longer necessary. Mimosa will wrap r.js optimized code in Almond, a replacement AMD loader for RequireJS that provides the minimal functionality necessary for optimized files. (If you are loading modules/resources from a CDN, Almond does not support that. See this Mimosa issue for help dealing with CDN resources.)
Mimosa will infer the following default settings for the r.js optimizer.
baseUrl: set by combining the mimosa-config
mainConfigFile: set to the file path of the main module unless a common config (
require.commonConfigsetting) is detected. If a common config is found,
mainConfigFileis set to that.
logLevel: set to
3which is the r.js error logging level
optimize: set to
uglify2unless both the
--minifyflags are used, in which case it is set to
For single file runs without
modules, the following will also be inferred.
out: optimized files are output into the
include: set to the name of the module being compiled
insertRequire: set to the name of the module being compiled
name: set to
For runs that involve the
optimize.modules config, the following in inferred.
keepBuildDir: Keeps the build directory between builds.
modules: This isn't inferred, rather it is taken without modification from the
require.optimize.modulesconfig. It is the presence of
optimize.modulesthat triggers the different group of inferred properties.
watch< config. This is where all the outputs from the run will be deposited.
These settings will package up each individual module into its own optimized file wrapped with Almond.
Any of the other RequireJS optimizer configuration options can be included in the mimosa-config. Just uncomment the
require.optimize.overrides setting and include those settings there. Settings can be both overridden and removed. To override a Mimosa setting, put the override in
overrides. To remove a default setting, set it to
require.optimize.overrides can also be configured as a function. That function is passed the full inferred r.js config for the module being optimized. This provides the opportunity to amplify the inferred config rather than just replace it.
Mimosa can also be configured to not infer anything and to go entirely with a custom config. Set
false and Mimosa will run r.js with only the settings provided in
requirejs method calls) are in script tags on an HTML page, Mimosa will not find any modules to compile for optimization and therefore will not run optimization, so a custom configuration will need to be provided in
inferConfig set to
As noted above, Mimosa has specific support in place for configuring and running require.js builds involving a
modules config. As of Mimosa version
1.0.8 source maps are disabled by default for r.js builds that involve the
modules config. Source maps are only generated when using
mimosa watch, so when running
watch with the
optimize flag and a
modules config, Mimosa turns off source maps. Source maps do not cause any issues with the first r.js optimize run, but they do cause trouble with subsequent ones. Source maps can be forced on by adding
generateSourceMaps: true to the
require.optimize.overrides. Just know the 2nd+ runs will not output proper files.
This should be remedied in future Mimosa releases.
Mimosa can't know all the intricacies of a project. It can make a lot of educated guesses and put together a really good base r.js config, but there are times when complicated alterations must be made to the r.js config.
overrides allows static changes to the r.js configuration, but that isn't always ideal.
require.optimize.inferConfig:false loses all of the smarts Mimosa puts into building a r.js config. Ideally a project can take advantage of the work Mimosa puts into building the r.js config, and dynamically alter it as well.
Mimosa's building of the inferred r.js config, and the execution of the r.js optimization are pulled apart in two separate steps in Mimosa's workflows. Config building executes during the
beforeOptimize step, and execution during the
optimize step. This means a custom module can programmatically and dynamically alter the Mimosa-prepared r.js configs before r.js execution occurs.
For instance, maybe there are files to include in the r.js execution that are not pulled in as dependencies by r.js, maybe all .html files via the requirejs text plugin, and rather than listing them one by one in the overrides, they could be dynamically added so a list need not be maintained. A module could do this, executing during the
beforeOptimize step, but after the configs have been built. In that module the codebase could be scanned for .html files and push them onto the r.js config
Doing this provides both Mimosa's smarts, and the intelligence Mimosa can't provide by way of a custom module. To get started building such a module, check out the long-named example mimosa-requirebuild-textplugin-include which performs just the task mentioned above.
mimosa watch is used with
--optimize (and not also
--minify which does minification outside of requirejs), Mimosa will generate source maps for easy debugging in browser dev tools.
mimosa build does not generate source maps. All cleans performed by various Mimosa tasks will clean up the generated
.map files. Because generation of source maps is configured via the r.js config, which can already be overridden in the
require config, no additional config settings have been added to change the default behaviors.
Mimosa's Minification support comes courtesy of the
mimosa-minify-css modules which are both default modules that come with Mimosa when it is installed.
For both the
watch commands, Mimosa provides an
minifyCSS.exclude settings. By default any file already possessing
.min. in the path name will be excluded as it is assumed to already be minified.
For either the
watch commands, using the
--optimize flags together provides increased control over the optimization workflow.
The r.js optimizer by itself is often good enough to handle minifying, compressing and pulling modules into single files; however, the occasional file does not take kindly to being run through Uglify and will be broken when compressed. The r.js optimizer is all or none. It does not allow omitting a file from compression if it is not compressing correctly.
When both minifying and optimizing, r.js minification is turned off. Specifically the
optimize setting of r.js is set to
none. The optimizer is still used to pull all of an application's files together into the same file and wrap it in Almond. But Mimosa will Uglify files first, before calling the optimizer, and Mimosa provides the opportunity to not Uglify whatever files are not making it through Uglifying in working order.
If a project has many pages, and therefore many optimized files that need to be written, using both flags at the same time will also speed up the build. If Mimosa writes minified files, then the files are minified once and the minified versions are used to build the many optimized files. If Mimosa writes un-minified files, then those files have to be minified by the r.js optimizer. The optimizer is going to minify each file every time it is used. So if the unminified jQuery source is in a project's codebase, and it is used on 10 pages and therefore is bundled into 10 optimized files, then r.js will minify it 10 times, which can slow the build. So, if a build is running slow, try using both flags at once to speed it up.
The AngularFunMimosa demo project is a perfect example of a project that benefits from this functionality. This commit from that project shows the effect of the minify+optimize feature being added to Mimosa. Previously optimization was turned off via Mimosa's r.js overrides, because when r.js Uglified the code, it also broke the application. When this Mimosa feature was added, the r.js override was removed, and the file that was not surviving Uglifying,
main.js, was simply omitted from minification. What comes out the other side is a fully r.js optimized and zipped up file that is fully compressed with the exception of the file that cannot be minified.
--optimize flag is used, Mimosa will minify CSS files too.
The external mimosa-combine module can be used to do things like pull compiled or vendor CSS files together...or anything really. All mimosa-combine wants is a folder to merge and a place to put the result, but it also allows assets to be excluded and an order to be provided.
Just tack the string
"combine" onto the
modules array and Mimosa will fetch the module for immediate use.