Issue #2161505 by mr.j, mikeytown2: Aggregating JSMin compressed files can break JS.
[project/advagg.git] / README.txt
1
2 ----------------------------------
3 ADVANCED CSS/JS AGGREGATION MODULE
4 ----------------------------------
5
6
7 CONTENTS OF THIS FILE
8 ---------------------
9
10  * Fast 404
11  * Features & benefits
12  * Configuration
13  * Notes
14  * JavaScript Bookmarklet
15  * Technical Details & Hooks
16  * Single htaccess rules
17  * nginx Configuration
18
19
20 FAST 404
21 --------
22
23 Assuming that this guide was followed:
24 http://2bits.com/drupal-planet/reducing-server-resource-utilization-busy-sites-implementing-fast-404s-drupal.html
25 and your having issues with Advanced CSS/JS Aggregation. Advagg works similar
26 to imagecache, thus we need to add in an exceptions for the directories that
27 advagg uses. Replace this if statement
28
29     if (!strpos($_SERVER['QUERY_STRING'], 'imagecache')) {
30
31 with one like this:
32
33     if (!strpos($_SERVER['QUERY_STRING'], 'imagecache') && !strpos($_SERVER['QUERY_STRING'], '/advagg_')) {
34
35 This will most likely be in your settings.php file.
36
37 If using Nginx make sure there is a rule similar to this in your configuration.
38 http://drupal.org/node/1116618#comment-4321724
39
40 If this is still an issue you can try setting the
41 "IP Address to send all asynchronous requests to" setting on the
42 admin/settings/advagg/config page to -1. This will use the hostname instead of
43 an IP address when making the http request.
44
45 If you are still having problems, open an issue on the advagg issue queue:
46 http://drupal.org/project/issues/advagg
47
48
49 FEATURES & BENEFITS
50 -------------------
51
52 Advanced CSS/JS Aggregation Core Module:
53  * Imagecache style CSS/JS Aggregation. If the file doesn't exist it will be
54    generated on demand.
55  * Stampede protection for CSS and JS aggregation. Uses locking so multiple
56    requests for the same thing will result in only one thread doing the work.
57  * Zero file I/O if the Aggregated file already exists. Results in better page
58    generation performance.
59  * Fully cached CSS/JS assets making this module faster than drupal core.
60  * Smarter aggregate deletion. CSS/JS aggregates only get removed from the cache
61    if they have not been used/accessed in the last 3 days.
62  * Smarter cache flushing. Scans all CSS/JS files that have been added to any
63    aggregate; if that file has changed then rebuild all aggregates that contain
64    the updated file and give the newly aggregated file a new name. The new name
65    ensures changes go out when using CDNs.
66  * Works with Drupal's private file system. Can Use a separate directory for
67    serving aggregated files from.
68  * Footer JS gets aggregated as well.
69  * One can add JS to any region & have it aggregated.
70    drupal_add_js($data, 'module', 'left') is now possible; JS is appended to the
71    the end of that region.
72  * One can add external JS/CSS resources.
73     drupal_add_js('http://example.org/example.js', 'external');
74     drupal_add_css('http://example.org/example.css', 'external');
75    is now possible.
76  * Url query string to turn off aggregation for that request. ?advagg=0 will
77    turn off file aggregation if the user has the "bypass advanced aggregation"
78    permission. ?advagg=-1 will completely bypass all of Advanced CSS/JS
79    Aggregations modules and submodules.
80  * Button on the admin page for dropping a cookie that will turn off file
81    aggregation. Useful for theme development.
82  * Url query string to turn on advagg debugging for that request.
83    ?advagg-debug=1 will output a large debug string to the watchdog if the user
84    has the "bypass advanced aggregation" permission.
85  * Gzip support. All aggregated files can be pre-compressed into a .gz file and
86    served from Apache. This is faster then gzipping the file on each request.
87  * IE Unlimited CSS support. If using ?advagg=0 the CSS output will change
88    to use @import style in order to get around the 31 CSS files limit in IE.
89  * CDN support. Advagg integrates with this module.
90  * jQuery Update support. Advagg integrates with this module.
91  * LABjs support. Advagg integrates with this module.
92  * One year browser cache lifetimes for all aggregated files. This is a good
93    thing.
94  * Drush support. "cc advagg" will issue a smart cache flush.
95  * Admin menu support. Cache flushing Advanced CSS/JS Aggregation is available
96    in the "Flush all caches" menu.
97
98 Advanced CSS/JS Aggregation Submodules:
99  CSS:
100  * CSSTidy library support. Can compress the generated CSS files with the
101    CSSTidy library.
102  * CSS Compressor 3.0 support. https://github.com/codenothing/css-compressor
103  JS:
104  * JSMin+ library support. Can compress the generated JS files with the jsmin+
105    library.
106  * JSMin PHP Extension support. http://www.ypass.net/software/php_jsmin/
107  * Use Dean Edwards Packer on non gzipped files. .gz files will not be packed.
108  CDN:
109  * Google's CDN network. Load jquery.js & jquery-ui.js from using the Google
110    Libraries API. This is a good thing.
111  Bundler:
112  * Bundler. Will split up an aggregate into sub aggregates for better load
113    times throughout your site.
114
115 3rd Party modules:
116  CSS:
117  * Parallel CSS - AdvAgg Plugin. Have url()'s in css files reference different
118    CDN domains.
119
120
121 CONFIGURATION
122 -------------
123
124 Settings page is located at:
125 admin/settings/advagg
126  * Enable Advanced Aggregation. You can disable the module here. Same effect as
127    placing ?advagg=-1 in the URL.
128  * Use AdvAgg in closure. If enabled javascript files in the closure region will
129    be aggregated by advagg.
130  * Generate CSS/JS files on request (async mode). If advagg doesn't have a route
131    back to its self and this is enabled then you will have a broken site. With
132    this enabled one can expect much quicker page generation times after a cache
133    flush.
134  * Gzip CSS/JS files. For every Aggregated file generated, this will create a
135    gzip version of that and then serve that out if the browser accepts gzip
136    compression.
137  * Generate .htaccess files in the advagg_* dirs. If your using the rules
138    located at the bottom of this document in your webroots htaccess file then
139    you can disable this checkbox.
140  * Regenerate flushed bundles in the cache flush request. You can enable if your
141    server will not timeout on a request. This will call advagg_rebuild_bundle()
142    as a shutdown function for every bundle that has been marked as expired;
143    thus rebuilding that bundle in the same request as the flush.
144  * Use a different directory for storing advagg files. Only available if your
145    using a private file system. Allows you to save the generated aggregated
146    files in a different directory. This gets around the private file system
147    restrictions. If boost is installed, you can safely use the cache directory.
148  * Aggregation Inclusion Mode. Should the page wait for the aggregate to be
149    built before including the file, or should it send out the page with
150    aggregates not included.
151  * Disable page caching if all aggregates are not included on the page.
152  * File Checksum Mode. mtime is the file modification time. md5 is a hash of the
153    files contents.
154  * IP Address to send all asynchronous requests to. If you wish to have one
155    server generate all CSS/JS aggregated files then this allows for that to
156    happen.
157  * Smart cache flush button. Scan all files referenced in aggregated files. If any of
158    them have changed, increment the counters containing that file and rebuild
159    the bundle.
160  * Cache Rebuild button. Recreate all aggregated files. Useful if JS or CSS
161    compression was just enabled.
162  * Forced Cache Rebuild. Recreate all aggregated files by incrementing internal
163    counter for every bundle. One should never have to use this option.
164  * Master Reset. Clean slate; same affect as uninstalling the module.
165  * Rebuild htaccess files. Recreate the generated htaccess files.
166  * Aggregation Bypass Cookie. This will set or remove a cookie that disables
167    aggregation for the remainder of the browser session. It acts almost the same
168    as adding ?advagg=0 to every URL.
169
170 Additional information is available at:
171 admin/settings/advagg/info
172  * Hook Theme Info. Displays the preprocess_page order. Used for debugging.
173  * CSS files. Displays how often a files checksum has changed and any data
174    stored about it.
175  * JS files. Displays how often a files checksum has changed and any data
176    stored about it.
177  * Modules implementing advagg hooks. Lets you know what modules are using
178    advagg.
179  * Missing files. Lets you know the files that are trying to be added but are
180    not there.
181  * Asynchronous debug info. Outputs the the full object returned from
182    drupal_http_request() which is helpful when debugging async issues.
183
184
185 NOTES
186 -----
187
188 --Bundler Sub Module--
189 When using the bundler sub module, tools like Google Page Speed and YSlow will
190 complain that not all CSS/JS files are in one aggregate. This has to do with
191 how drupal_add_js/drupal_add_css works. You can get a better score on these
192 tools by placing all files into one aggregate, but the issue with doing that
193 is, different pages load different css/js files, thus on page 2 of the users
194 visit, you will get worse performance because the browser has to re-download a
195 whole new css & js aggregate rather then the smaller aggregate that only
196 changed. The bundler attempts to work around this issue by creating various
197 bundles, each one being chosen fairly smartly so that instead of downloading a
198 200KB js file you only have to download a 20KB file on the 2nd page.
199
200 The bundler sub module is all about balancing trade offs. You can make a site
201 that had really good performance stats according to the tools but you would
202 then have to re-download just about everything on a different page of your
203 site, because not all your pages are the same. If you don't care about this and
204 want a good score from pagespeed, disable the bundler sub-module. That will
205 give you a better score, but then you have to download a new (large) aggregate
206 on different parts of your website and already downloaded file reuse will be
207 lower.
208
209 --Cron--
210 The cron job for AdvAgg is there as a garbage collector. It only needs to run
211 once a week; running it every hour isn't going to be bad, it isn't necessary
212 though.
213
214
215 JAVASCRIPT BOOKMARKLET
216 ----------------------
217
218 You can use this JS code as a bookmarklet for toggling the AdvAgg URL parameter.
219 See http://en.wikipedia.org/wiki/Bookmarklet for more details.
220
221     javascript:(function(){var loc = document.location.href,qs = document.location.search,regex_off = /\&?advagg=-1/,goto = loc;if(qs.match(regex_off)) {goto = loc.replace(regex_off, '');} else {qs = qs ? qs + '&advagg=-1' : '?advagg=-1';goto = document.location.pathname + qs;}window.location = goto;})();
222
223
224 TECHNICAL DETAILS & HOOKS
225 -------------------------
226
227 Technical Details:
228  * There are two database tables and two cache table used by advagg.
229  * Files are generated by this pattern: css_[MD5]_[Counter].css
230  * Every JS file is tested for compressibility. This is necessary because jsmin+
231    can run out of memory on certain files. This allows us to catch these bad
232    files and mark them. Also allows us to skip files that are already
233    compressed.
234
235 Hooks:
236  * hook_advagg_css_alter. Modify the data before it gets written to the file.
237    Useful for compression.
238  * hook_advagg_css_inline_alter. Modify the data before it gets embedded in the
239    page. Useful for compression.
240  * hook_advagg_css_pre_alter. Modify the raw $variables['css'] before it gets
241    processed. Useful for file replacement.
242  * hook_advagg_css_extra_alter. Allows one to set the a prefix and suffix to be
243    added into the HTML DOM. Useful for CSS conditionals.
244
245  * hook_advagg_js_alter. Modify the data before it gets written to the file.
246    Useful for compression.
247  * hook_advagg_js_inline_alter. Modify the data before it gets embedded in the
248    page. Useful for compression.
249  * hook_advagg_js_pre_alter. Modify the raw $javascript before it gets
250    processed. Useful for file replacement.
251  * hook_advagg_js_extra_alter. Allows one to set the a prefix and suffix to be
252    added into the HTML DOM.
253  * hook_advagg_js_header_footer_alter. Allows one to move JS from the header to
254    the footer. Also one can look at both header and footer JS arrays before they
255    get processed.
256
257  * hook_advagg_filenames_alter. Allows for a one to many relationship. A single
258    request for a bundle name can result in multiple bundles being returned.
259  * hook_advagg_files_table. Allows for modules to mark a file as expired.
260  * advagg_master_reset. Allows other modules to take part in a master reset.
261  * advagg_disable_processor. Allows one to turn off advagg from a hook. See the
262    advagg_advagg_disable_processor() function for example usage.
263  * advagg_disable_page_cache. Allows 3rd party page cache plugins like boost or
264    varnish to not cache this page.
265  * advagg_bundler_analysis_alter. Give installed modules a chance to alter the
266    bundler's analysis array.
267
268 JS/CSS Theme Override:
269
270     $conf['advagg_css_render_function'] - advagg_unlimited_css_builder
271     $conf['advagg_js_render_function'] - advagg_js_builder
272
273 JS/CSS File Save Override:
274
275     $conf['advagg_file_save_function'] - advagg_file_saver
276
277 Public Functions:
278  * advagg_add_css_inline. Adds the ability to add in inline CSS to the page with
279    a prefix and suffix being set as well.
280
281
282 SINGLE HTACCESS RULES
283 ---------------------
284
285 If the directory level htaccess rules are interfering with your server, you can
286 place these rules in the Drupal root htaccess file. Place these rules after
287 "RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]" but before "</IfModule>"
288
289
290   # Rules to correctly serve gzip compressed CSS and JS files.
291   # Requires both mod_rewrite and mod_headers to be enabled.
292   <IfModule mod_headers.c>
293     # Serve gzip compressed CSS/JS files if they exist and client accepts gzip.
294     RewriteCond %{HTTP:Accept-encoding} gzip
295     RewriteCond %{REQUEST_URI} (^/(.+)/advagg_(j|cs)s/(.+)\.(j|cs)s) [NC]
296     RewriteCond %{REQUEST_FILENAME}\.gz -s
297     RewriteRule ^(.*)\.(j|cs)s$ $1\.$2s\.gz [QSA]
298
299     # Serve correct content types, and prevent mod_deflate double gzip.
300     RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1]
301     RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1]
302
303     <FilesMatch "\.(j|cs)s\.gz$">
304       # Serve correct encoding type.
305       Header set Content-Encoding gzip
306       # Force proxies to cache gzipped & non-gzipped css/js files separately.
307       Header append Vary Accept-Encoding
308     </FilesMatch>
309   </IfModule>
310
311
312 You also need to place these rules at the very end of your htaccess file, after
313 "</IfModule>".
314
315
316 # AdvAgg Rules Start.
317 <FilesMatch "^(j|cs)s_[0-9a-f]{32}_.+\.(j|cs)s(\.gz)?">
318   # No mod_headers
319   <IfModule !mod_headers.c>
320     # No mod_expires
321     <IfModule !mod_expires.c>
322       # Use ETags.
323       FileETag MTime Size
324     </IfModule>
325
326     # Use Expires Directive.
327     <IfModule mod_expires.c>
328       # Do not use ETags.
329       FileETag None
330       # Enable expirations.
331       ExpiresActive On
332       # Cache all aggregated CSS/JS files for 480 weeks after access (A).
333       ExpiresDefault A290304000
334     </IfModule>
335   </IfModule>
336
337   <IfModule mod_headers.c>
338     # Set a far future Cache-Control header to 480 weeks.
339     Header set Cache-Control "max-age=290304000, no-transform, public"
340     # Set a far future Expires header.
341     Header set Expires "Tue, 20 Jan 2037 04:20:42 GMT"
342     # Pretend the file was last modified a long time ago in the past.
343     Header set Last-Modified "Wed, 20 Jan 1988 04:20:42 GMT"
344     # Do not use etags for cache validation.
345     Header unset ETag
346   </IfModule>
347 </FilesMatch>
348 # AdvAgg Rules End.
349
350
351 Be sure to disable the "Generate .htaccess files in the advagg_* dirs" setting
352 on the admin/settings/advagg page after placing these rules in the webroots
353 htaccess file. This is located at the same directory level as Drupal's
354 index.php.
355
356
357 NGINX CONFIGURATION
358 -------------------
359
360 http://drupal.org/node/1116618
361
362     ###
363     ### advagg_css and advagg_js support
364     ###
365     location ~* files/advagg_(?:css|js)/ {
366       access_log off;
367       expires    max;
368       add_header ETag "";
369       add_header Cache-Control "max-age=290304000, no-transform, public";
370       add_header Last-Modified "Wed, 20 Jan 1988 04:20:42 GMT";
371       try_files  $uri @drupal;
372     }