UNPKG

27.7 kBMarkdownView Raw
1# AssetGraph
2
3[![NPM version](https://badge.fury.io/js/assetgraph.svg)](http://badge.fury.io/js/assetgraph)
4[![Build Status](https://travis-ci.org/assetgraph/assetgraph.svg?branch=master)](https://travis-ci.org/assetgraph/assetgraph)
5[![Coverage Status](https://img.shields.io/coveralls/assetgraph/assetgraph.svg)](https://coveralls.io/r/assetgraph/assetgraph?branch=master)
6[![Dependency Status](https://david-dm.org/assetgraph/assetgraph.svg)](https://david-dm.org/assetgraph/assetgraph)
7
8AssetGraph is an extensible, <a href="http://nodejs.org/">node.js</a>-based
9framework for manipulating and optimizing web pages and web
10applications. The main core is a dependency graph model of your entire website, where all assets are treated as first class citizens. It can automatically dicsover assets based on your declarative code, reducing the configuration needs to a minimum.
11
12If you just want to get started with the basics, read [Peter Müller - Getting started with Assetgraph](http://mntr.dk/2014/getting-started-with-assetgraph/).
13
14If you are looking for a prepackaged build system take a look at <a
15href="https://github.com/assetgraph/assetgraph-builder">Assetgraph-builder</a>.
16
17## Tools built with AssetGraph
18
19- [assetgraph-builder](https://www.npmjs.com/package/assetgraph-builder) - A static web page build system that post-processes your website with extremely little configuration
20- [subfont](https://www.npmjs.com/package/subfont) - A tool that supercharges your webfont loading by automatically applying all best practice loading techniques and generating optimal font subsets
21- [hyperlink](https://www.npmjs.com/package/hyperlink) - A link checker tool that will ensure all your internal and external links are intact and up to date
22- [seespee](https://www.npmjs.com/package/seespee) - A Content-Security Policy generator. Point it at a webpage and it will tell you what policy you need as a minimum
23- [trackingdog](https://github.com/papandreou/trackingdog) - cli for finding the original source location of a line+column in a generated file, utilizing the source map
24
25# Assets and relations
26
27All web build tools, even those that target very specific problems,
28have to get a bunch of boring stuff right just to get started, such
29as loading files from disc, parsing and serializing them, charsets,
30inlining, finding references to other files, resolution of and
31updating urls, etc.
32
33The observation that inspired the project is that most of these
34tasks can be viewed as graph problems, where the nodes are the
35assets (HTML, CSS, images, JavaScript...) and the edges are the
36relations between them, e.g. anchor tags, image tags, favorite
37icons, css background-image properties and so on.
38
39![An example illustration of an asset graph representing a web page](illustration.png)
40
41An AssetGraph object is a collection of assets (nodes) and the
42relations (edges) between them. It's a basic data model that allows
43you to populate, query, and manipulate the graph at a high level of
44abstraction. For instance, if you change the url of an asset, all
45relations pointing at it are automatically updated.
46
47Additionally, each individual asset can be inspected and massaged
48using a relevant API: <a
49href="https://github.com/tmpvar/jsdom">jsdom</a> for HTML, <a href="https://github.com/postcss/postcss">PostCSS</a> for CSS, and an <a
50href="http://esprima.org/">Esprima</a> AST for Javascript.
51
52AssetGraph represents inline assets the same way as non-inline ones,
53so eg. inline scripts, stylesheets, and images specified as `data:`
54urls are also first-class nodes in the graph. This means that you
55don't need to dig into the HTML of the containing asset to manipulate
56them. An extreme example would be an Html asset with a conditional
57comment with an inline stylesheet with an inline image, which are
58modelled as 4 separate assets:
59
60```html
61<!DOCTYPE html>
62<html>
63 <head>
64 <!--[if !IE]> -->
65 <style type="text/css">
66 body {
67 background-image: url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==);
68 }
69 </style>
70 <!-- <![endif]-->
71 </head>
72 <body></body>
73</html>
74```
75
76These are some of the supported assets and associated relation types:
77
78#### HTML
79
80`<a>`, `<link rel="stylesheet|shortcut icon|fluid-icon|alternate|serviceworker">`, `<script>`, `<style>`,
81`<html manifest="...">` `<img>`, `<video>`, `<audio>`, `<applet>`,
82`<embed>`, `<esi:include>`, `<iframe>`, `<svg>`, `<meta property="og:...">`
83
84#### SVG
85
86`<style>`, inline `style=...` attributes, event handlers, `<?xml-stylesheet href=...>`, `<font-face-src>`
87
88#### CSS
89
90`//# sourceMappingURL=...`, `background-image: url(...)`, `@import url(...)`, `behavior: url(...)`,
91`filter: AlphaImageLoader(src='...')`, `@font-face { src: url(...) }`
92
93#### JavaScript
94
95`//# sourceMappingURL=...`, homegrown `'foo/bar.png'.toString('url')` syntax for referencing external files
96
97#### Web manifest
98
99Icon urls, `related_applications`, `start_url`, etc.
100
101#### Cache manifest (appcache)
102
103Entries in the `CACHE`, `NETWORK` and `FALLBACK` sections
104
105#### JSON, XML, PNG, GIF, JPEG, ICO
106
107(none)
108
109# Features
110
111- Build an AssetGraph programmatically or load it from disk or a
112 remote server via http.
113- Find explicit dependencies between JavaScript and CSS and roll them
114 out as `<script>` and `<link rel='stylesheet'>` tags in your
115 HTML.
116- Bundle and inline CSS and JavaScript.
117- Create a cache manifest with references to all the assets your web
118 app needs to be usable offline.
119- Move all CSS, JavaScript, image assets etc. to a static dir and
120 rename them to md5.extension so the web server can be configured to
121 set a far-future Cache-Control.
122- Help getting your static assets on a CDN by allowing you to easily
123 rewrite all references to them.
124- Use Graphviz to visualize your dependencies at any step.
125- Using the separate <a
126 href="https://github.com/assetgraph/assetgraph-sprite">assetgraph-sprite
127 transform</a>: Optimize CSS background images by creating sprite
128 images. The spriting is guided by a set of custom CSS properties
129 with a `-ag-sprite` prefix.
130
131# Installation
132
133Make sure you have <a href="http://nodejs.org/">node.js</a> and <a
134href="http://npmjs.org/">npm</a> installed, then run:
135
136```
137$ npm install assetgraph
138```
139
140## Querying the graph
141
142AssetGraph supports a flexible syntax for finding assets and relations
143in a populated graph using the `findAssets` and `findRelations`
144methods. Both methods take a query object as the first argument.
145The query engine uses MongoDB-like queries via the
146[sift module](https://github.com/crcn/sift.js). Please consult that
147to learn about the advanced querying features. Below are some basic examples.
148
149Get an array containing all assets in the graph:
150
151```javascript
152var allAssets = assetGraph.findAssets();
153```
154
155Find assets by type:
156
157```javascript
158var htmlAssets = assetGraph.findAssets({ type: 'Html' });
159```
160
161Find assets of different named types:
162
163```javascript
164var jsAndCss = assetGraph.findAssets({ type: { $in: ['Css', 'JavaScript' ] });
165```
166
167Find assets by matching a regular expression against the url:
168
169```javascript
170var localImageAssets = assetGraph.findAssets({
171 url: { $regex: /^file:.*\.(?:png|gif|jpg)$/ }
172});
173```
174
175Find assets by predicate function:
176
177```javascript
178var orphanedJavaScriptAssets = assetGraph.findAssets(function(asset) {
179 return (
180 asset.type === 'JavaScript' &&
181 assetGraph.findRelations({ to: asset }).length === 0
182 );
183});
184```
185
186Find all HtmlScript (`<script src=...>` and inline `<script>`) relations:
187
188```javascript
189var allHtmlScriptRelations = assetGraph.findRelations({ type: 'HtmlScript' });
190```
191
192Query objects have "and" semantics, so all conditions must be met for
193a multi-criteria query to match:
194
195```javascript
196var textBasedAssetsOnGoogleCom = assetGraph.findAssets({
197 isText: true,
198 url: { $regex: /^https?:\/\/(?:www\.)google\.com\// }
199});
200```
201
202Find assets by existence of incoming relations:
203
204```javascript
205var importedCssAssets = assetGraph.findAssets({
206 type: 'Css',
207 incomingRelations: { $elemMatch: { type: 'CssImport' } }
208});
209```
210
211Relation queries can contain nested asset queries when querying the
212`to` and `from` properties.
213
214Find all HtmlAnchor (`<a href=...>`) relations pointing at local images:
215
216```javascript
217assetGraph.findRelations({
218 type: 'HtmlAnchor',
219 to: { isImage: true, url: { $regex: /^file:/ } }
220});
221```
222
223# Transforms and workflows
224
225AssetGraph comes with a collection of premade "transforms" that you
226can use as high level building blocks when putting together your build
227procedure. Most transforms work on a set of assets or relations and
228usually accept a query object so they can be scoped to work on only a
229specific subset of the graph.
230
231Usually you'll start by loading some initial assets from disc or via
232http using the `loadAssets` transform, then get the related assets
233added using the `populate` transform, then do the actual
234processing. Eventually you'll probably write the resulting assets back
235to disc.
236
237Thus the skeleton looks something like this:
238
239```javascript
240var AssetGraph = require('assetgraph');
241
242const assetGraph = new AssetGraph({ root: '/the/root/directory/' });
243
244await assetGraph.loadAssets('*.html'); // Load all Html assets in the root dir
245await assetGraph.populate({ followRelations: { type: 'HtmlAnchor' } }); // Follow <a href=...>
246// More work...
247await assetGraph.writeAssetsToDisc({ type: 'Html' }); // Overwrite existing files
248
249// Done!
250```
251
252In the following sections the built-in transforms are documented
253individually:
254
255## assetGraph.addCacheManifest([queryObj])
256
257Add a `CacheManifest` asset to each `Html` asset in the graph (or
258to all `Html` assets matched by `queryObj` if provided). The cache
259manifests will contain relations to all assets reachable by traversing
260the graph through relations other than `HtmlAnchor`.
261
262## assetGraph.bundleRelations(queryObj[, strategyName])
263
264Bundle the `Css` and `JavaScript` assets pointed to by the
265relations matched by `queryObj`.
266
267The `strategyName` (string) parameter can be either:
268
269#### `oneBundlePerIncludingAsset` (the default)
270
271Each unique asset pointing to one or more of the assets being
272bundled will get its own bundle. This can lead to duplication if
273eg. several `Html` assets point to the same sets of assets, but
274guarantees that the number of http requests is kept low.
275
276#### `sharedBundles`
277
278Create as many bundles as needed, optimizing for combined byte size
279of the bundles rather than http requests. Warning: Not as well
280tested as `oneBundlePerIncludingAsset`.
281
282Note that a conditional comment within an `Html` asset conveniently
283counts as a separate including asset, so in the below example
284`ie.css` and `all.css` won't be bundled together:
285
286```html
287<!--[if IE]><link rel="stylesheet" href="ie.css"/><![endif]-->
288<link rel="stylesheet" href="all.css" />
289```
290
291The created bundles will be placed at the root of the asset graph with
292names derived from their unique id (for example
293`file://root/of/graph/124.css`) and will replace the original
294assets.
295
296## assetGraph.compressJavaScript([queryObj[, compressorName[, compressorOptions]]])
297
298Compresses all `JavaScript` assets in the graph (or those specified by
299`queryObj`).
300
301The `compressorName` (string) parameter can be either:
302
303#### `uglifyJs` (the default and the fastest)
304
305The excellent <a href="https://github.com/mishoo/UglifyJS">UglifyJS</a>
306compressor. If provided, the `compressorOptions` object will be
307passed to UglifyJS' `ast_squeeze` command.
308
309#### `yuicompressor`
310
311Yahoo's YUICompressor though Tim-Smart's <a
312href="https://github.com/Tim-Smart/node-yui-compressor">node-yuicompressor
313module</a>. If provided, the `compressorOptions` object will be
314passed as the second argument to `require('yui-compressor').compile`.
315
316#### `closurecompiler`
317
318Google's Closure Compiler through Tim-Smart's <a
319href="https://github.com/Tim-Smart/node-closure">node-closure
320module</a>. If provided, the `compressorOptions` object will be
321passed as the second argument to
322`require('closure-compiler').compile`.
323
324## assetGraph.convertCssImportsToHtmlStyles([queryObj])
325
326Finds all `Html` assets in the graph (or those specified by
327`queryObj`), finds all `CssImport` relations (`@import url(...)`) in inline and external CSS and converts them to
328`HtmlStyle` relations directly from the Html document.
329
330Effectively the inverse of `assetGraph.convertHtmlStylesToInlineCssImports`.
331
332Example:
333
334```html
335<style type="text/css">
336 @import url(print.css) print;
337 @import url(foo.css);
338 body {
339 color: red;
340 }
341</style>
342```
343
344is turned into:
345
346```html
347<link rel="stylesheet" href="print.css" media="print" />
348<link rel="stylesheet" href="foo.css" />
349<style type="text/css">
350 body {
351 color: red;
352 }
353</style>
354```
355
356## assetGraph.convertHtmlStylesToInlineCssImports([queryObj])
357
358Finds all `Html` assets in the graph (or those specified by
359`queryObj`), finds all outgoing, non-inline `HtmlStyle` relations
360(`<link rel='stylesheet' href='...'>`) and turns them into groups of
361`CssImport` relations (`@import url(...)`) in inline
362stylesheets. A maximum of 31 `CssImports` will be created per inline
363stylesheet.
364
365Example:
366
367```html
368<link rel="stylesheet" href="foo.css" />
369<link rel="stylesheet" href="bar.css" />
370```
371
372is turned into:
373
374```html
375<style type="text/css">
376 @import url(foo.css);
377 @import url(bar.css);
378</style>
379```
380
381This is a workaround for <a
382href="http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/ad1b6e88-bbfa-4cc4-9e95-3889b82a7c1d/">the
383limit of 31 stylesheets in Internet Explorer <= 8</a>. This transform
384allows you to have up to 31\*31 stylesheets in the development version
385of your HTML and still have it work in older Internet Explorer
386versions.
387
388## assetGraph.drawGraph(fileName)
389
390Uses the Graphviz `dot` command to render the current contents of the
391graph and writes the result to `fileName`. The image format is
392automatically derived from the extension and can be any of <a
393href="http://www.graphviz.org/doc/info/output.html">these</a>. Using
394`.svg` is recommended.
395
396Requires Graphviz to be installed, `sudo apt-get install graphviz` on
397Debian/Ubuntu.
398
399## assetGraph.executeJavaScriptInOrder(queryObj[, context])
400
401Experimental: For each JavaScript asset in the graph (or those matched by
402queryObj), find all reachable `JavaScript` assets and execute them
403in order.
404
405If the `context` parameter is specified, it will be used as <a
406href="http://nodejs.org/docs/latest/api/vm.html#vm.runInContext">the
407execution context</a>. Otherwise a new context will be created using
408<a
409href="http://nodejs.org/docs/latest/api/vm.html#vm.createContext">vm.createContext</a>.
410
411## assetGraph.externalizeRelations([queryObj])
412
413Finds all inline relations in the graph (or those matched by
414`queryObj`) and makes them external. The file names will be derived
415from the unique ids of the assets.
416
417For example:
418
419```html
420<script>
421 foo = 'bar';
422</script>
423<style type="text/css">
424 body {
425 color: maroon;
426 }
427</style>
428```
429
430could be turned into:
431
432```html
433<script src="4.js"></script>
434<link rel="stylesheet" href="5.css" />
435```
436
437## assetGraph.inlineCssImagesWithLegacyFallback([queryObj[, options]])
438
439Finds all `Html` assets in the graph (or those matched by
440`queryObj`), finds all directly reachable `Css` assets, and
441converts the outgoing `CssImage` relations (`background-image`
442etc.) to `data:` urls, subject to these criteria:
443
4441. If `options.sizeThreshold` is specified, images with a greater byte size
445 won't be inlined.
446
4472. To avoid duplication, images referenced by more than one
448 `CssImage` relation won't be inlined.
449
4503. A `CssImage` relation pointing at an image with an `inline` GET
451 parameter will always be inlined (eg. `background-image: url(foo.png?inline);`). This takes precedence over the first two
452 criteria.
453
4544. If `options.minimumIeVersion` is specified, the `data:` url length
455 limitations of that version of Internet Explorer will be honored.
456
457If any image is inlined an Internet Explorer-only version of the
458stylesheet will be created and referenced from the `Html` asset in a
459conditional comment.
460
461For example:
462
463```javascript
464await assetGraph.inlineCssImagesWithLegacyFallback(
465 { type: 'Html' },
466 { minimumIeVersion: 7, sizeThreshold: 4096 }
467);
468```
469
470where `assetGraph` contains an Html asset with this fragment:
471
472```html
473<link rel="stylesheet" href="foo.css" />
474```
475
476and `foo.css` contains:
477
478```css
479body {
480 background-image: url(small.png);
481}
482```
483
484will be turned into:
485
486```html
487<!--[if IE]><link rel="stylesheet" href="foo.css"/><![endif]-->
488<!--[if !IE]>--><link rel="stylesheet" href="1234.css" /><!--<![endif]-->
489```
490
491where `1234.css` is a copy of the original `foo.css` with the
492images inlined as `data:` urls:
493
494```css
495body {
496 background-image: url(data;image/png;base64, iVBORw0KGgoAAAANSUhE...);
497}
498```
499
500The file name `1234.css` is just an example. The actual asset file
501name will be derived from the unique id of the copy and be placed at
502the root of the assetgraph.
503
504## assetGraph.inlineRelations([queryObj])
505
506Inlines all relations in the graph (or those matched by
507`queryObj`). Only works on relation types that support inlining, for
508example `HtmlScript`, `HtmlStyle`, and `CssImage`.
509
510Example:
511
512```javascript
513await assetGraph.inlineRelations({ type: { $in: ['HtmlStyle', 'CssImage'] } });
514```
515
516where `assetGraph` contains an Html asset with this fragment:
517
518```html
519<link rel="stylesheet" href="foo.css" />
520```
521
522and `foo.css` contains:
523
524```css
525body {
526 background-image: url(small.png);
527}
528```
529
530will be turned into:
531
532```html
533<style type="text/css">
534 body {
535 background-image: url(data;image/png;base64, iVBORw0KGgoAAAANSUhE...);
536 }
537</style>
538```
539
540Note that `foo.css` and the `CssImage` will still be modelled as
541separate assets after being inlined, so they can be manipulated the
542same way as when they were external.
543
544## assetGraph.loadAssets(fileName|wildcard|url|Asset[, ...])
545
546Add new assets to the graph and make sure they are loaded, returning a promise
547that fulfills with an array of the assets that were added. Several
548syntaxes are supported, for example:
549
550```javascript
551const [aHtml, bCss] = await assetGraph.loadAssets('a.html', 'b.css'); // Relative to assetGraph.root
552await assetGraph.loadAssets({
553 url: 'http://example.com/index.html',
554 text: 'var foo = bar;' // The source is specified, won't be loaded
555});
556```
557
558`file://` urls support wildcard expansion:
559
560```javascript
561await assetGraph.loadAssets('file:///foo/bar/*.html'); // Wildcard expansion
562await assetGraph.loadAssets('*.html'); // assetGraph.root must be file://...
563```
564
565## assetGraph.mergeIdenticalAssets([queryObj])
566
567Compute the MD5 sum of every asset in the graph (or those specified by
568`queryObj`) and remove duplicates. The relations pointing at the
569removed assets are updated to point at the copy that is kept.
570
571For example:
572
573```javascript
574await assetGraph.mergeIdenticalAssets({ type: { $in: ['Png', 'Css'] } });
575```
576
577where `assetGraph` contains an `Html` asset with this fragment:
578
579```html
580<head>
581 <style type="text/css">
582 body {
583 background-image: url(foo.png);
584 }
585 </style>
586</head>
587<body>
588 <img src="bar.png" />
589</body>
590```
591
592will be turned into the following if `foo.png` and `bar.png` are identical:
593
594```html
595<head>
596 <style type="text/css">
597 body {
598 background-image: url(foo.png);
599 }
600 </style>
601</head>
602<body>
603 <img src="foo.png" />
604</body>
605```
606
607and the `bar.png` asset will be removed from the graph.
608
609## assetGraph.minifyAssets([queryObj])
610
611Minify all assets in the graph, or those specified by
612`queryObj`. Only has an effect for asset types that support
613minification, and what actually happens also varies:
614
615#### `Html` and `Xml`
616
617Pure-whitespace text nodes are removed immediately.
618
619#### `Json`, `JavaScript`, and `Css`
620
621The asset gets marked as minified (`isPretty` is set to
622`false`), which doesn't affect the in-memory representation
623(`asset.parseTree`), but is honored when the asset is serialized.
624For `JavaScript` this only governs the amount of whitespace
625(<a href="https://github.com/estools/escodegen">escodegen</a>'s
626`compact` parameter); for how to apply variable renaming and
627other compression techniques see `assetGraph.compressJavaScript`.
628
629Compare to `assetGraph.prettyPrintAssets`.
630
631## assetGraph.moveAssets(queryObj, newUrlFunctionOrString)
632
633Change the url of all assets matching `queryObj`. If the second
634argument is a function, it will be called with each asset as the first
635argument and the assetGraph instance as the second and the url of the
636asset will be changed according to the return value:
637
638- If a falsy value is returned, nothing happens; the asset keeps its
639 current url.
640- If a non-absolute url is returned, it is resolved from
641 `assetGraph.root`.
642- If the url ends in a slash, the file name part of the old url is
643 appended.
644
645Move all `Css` and `Png` assets to a root-relative url:
646
647```javascript
648await assetGraph.moveAssets({ type: 'Css' }, '/images/');
649```
650
651If the graph contains `http://example.com/foo/bar.css` and
652`assetGraph.root` is `file:///my/local/dir/`, the resulting url will
653be `file:///my/local/dir/images/bar.css`.
654
655Move all non-inline `JavaScript` and `Css` assets to either
656`http://example.com/js/` or `http://example.com/css/`, preserving
657the current file name part of their url:
658
659```javascript
660await assetGraph.moveAssets(
661 { type: { $in: ['JavaScript', 'Css'] }, isInline: false },
662 (asset, assetGraph) =>
663 `http://example.com/${asset.type.toLowerCase()}/${asset.fileName}`
664);
665```
666
667The assets are moved in no particular order. Compare with
668`assetGraph.moveAssetsInOrder`.
669
670## assetGraph.moveAssetsInOrder(queryObj, newUrlFunctionOrString)
671
672Does the same as `assetGraph.moveAssets`, but makes sure that the
673"leaf assets" are moved before the assets that have outgoing relations
674to them.
675
676The typical use case for this is when you want to rename assets to
677`<hashOfContents>.<extension>` while making sure that the hashes of
678the assets that have already been moved don't change as a result of
679updating the urls of the related assets after the fact.
680
681Here's a simplified example taken from `buildProduction` in
682<a href="http://github.com/assetgraph/assetgraph-builder">AssetGraph-builder</a>.
683
684```javascript
685await assetGraph.moveAssetsInOrder(
686 { type: { $in: ['JavaScript', 'Css', 'Jpeg', 'Gif', 'Png'] } },
687 asset => `/static/${asset.md5Hex.substr(0, 10)}${asset.extension}`
688);
689```
690
691If a graph contains an `Html` asset with a relation to a `Css` asset
692that again has a relation to a `Png` asset, the above snippet will
693always move the `Png` asset before the `Css` asset, thus making it
694safe to compute the md5 of the respective assets when the function is
695invoked.
696
697Obviously this only works for graphs (or subsets of graphs)
698that don't contain cycles, and if that's not the case, an error will
699be thrown.
700
701## transforms.populate(options)
702
703Add assets to the graph by recursively following "dangling
704relations". This is the preferred way to load a complete web site or
705web application into an `AssetGraph` instance after using
706`assetGraph.loadAssets` to add one or more assets to serve as the
707starting point for the population. The loading of the assets happens
708in parallel.
709
710The `options` object can contain these properties:
711
712#### `from`: queryObj
713
714Specifies the set assets of assets to start populating from
715(defaults to all assets in the graph).
716
717#### `followRelations`: queryObj
718
719Limits the set of relations that are followed. The default is to
720follow all relations.
721
722#### `onError`: function (err, assetGraph, asset)
723
724If there's an error loading an asset and an `onError` function is
725specified, it will be called, and the population will continue. If
726not specified, the population will stop and pass on the error to its
727callback. (This is poorly thought out and should be removed or
728redesigned).
729
730#### `concurrency`: Number
731
732The maximum number of assets that can be loading at once (defaults to 100).
733
734Example:
735
736```javascript
737const assetGraph = new AssetGraph();
738await assetGraph.loadAssets('a.html');
739await assetGraph.populate({
740 followRelations: {
741 type: 'HtmlAnchor',
742 to: { url: { $regex: /\/[bc]\.html$/ } }
743 }
744});
745```
746
747If `a.html` links to `b.html`, and `b.html` links to `c.html`
748(using `<a href="...">`), all three assets will be in the graph
749after `assetGraph.populate` is done. If `c.html` happens to link
750to `d.html`, `d.html` won't be added.
751
752## assetGraph.prettyPrintAssets([queryObj])
753
754Pretty-print all assets in the graph, or those specified by
755`queryObj`. Only has an effect for asset types that support pretty
756printing (`JavaScript`, `Css`, `Html`, `Xml`, and `Json`).
757
758The asset gets marked as pretty printed (`isPretty` is set to
759`true`), which doesn't affect the in-memory representation
760(`asset.parseTree`), but is honored when the asset is
761serialized. For `Xml`, and `Html`, however, the existing
762whitespace-only text nodes in the document are removed immediately.
763
764Compare to `assetGraph.minifyAssets`.
765
766Example:
767
768```javascript
769// Pretty-print all Html and Css assets:
770await assetGraph.prettyPrintAssets({ type: { $in: ['Html', 'Css'] } });
771```
772
773## assetGraph.removeRelations([queryObj, [options]])
774
775Remove all relations in the graph, or those specified by `queryObj`.
776
777The `options` object can contain these properties:
778
779#### `detach`: Boolean
780
781Whether to also detach the relations (remove their nodes from the
782parse tree of the source asset). Only supported for some relation
783types. Defaults to `false`.
784
785#### `removeOrphan`: Boolean
786
787Whether to also remove assets that become "orphans" as a result of
788removing their last incoming relation.
789
790## assetGraph.setHtmlImageDimensions([queryObj])
791
792Sets the `width` and `height` attributes of the `img` elements
793underlying all `HtmlImage` relations, or those matching
794`queryObj`. Only works when the image pointed to by the relation is
795in the graph.
796
797Example:
798
799```javascript
800const AssetGraph = require('assetgraph');
801
802const assetGraph = new AssetGraph();
803await assetGraph.loadAssets('hasanimage.html');
804await assetGraph.populate();
805
806// assetGraph.findAssets({type: 'Html'})[0].text === '<body><img src="foo.png"></body>'
807
808await assetGraph.setHtmlImageDimensions();
809
810// assetGraph.findAssets({type: 'Html'})[0].text === '<body><img src="foo.png" width="29" height="32"></body>'
811```
812
813## assetGraph.writeStatsToStderr([queryObj])
814
815Dumps an ASCII table with some basic stats about all the assets in the
816graph (or those matching `queryObj`) in their current state.
817
818Example:
819
820```
821 Ico 1 1.1 KB
822 Png 28 196.8 KB
823 Gif 145 129.4 KB
824 Json 2 60.1 KB
825 Css 2 412.6 KB
826JavaScript 34 1.5 MB
827 Html 1 1.3 KB
828 Total: 213 2.2 MB
829```
830
831## assetGraph.writeAssetsToDisc(queryObj, outRoot[, root])
832
833Writes the assets matching `queryObj` to disc. The `outRoot`
834parameter must be a `file://` url specifying the directory where the
835files should be output. The optional `root` parameter specifies the
836url that you want to correspond to the `outRoot` directory (defaults
837to the `root` property of the AssetGraph instance).
838
839Directories will be created as needed.
840
841Example:
842
843```javascript
844const AssetGraph = require('assetgraph');
845
846const assetGraph = new AssetGraph({root: 'http://example.com/'});
847await assetGraph.loadAssets(
848 'http://example.com/bar/quux/foo.html',
849 'http://example.com/bar/baz.html'
850);
851
852// Write the two assets to /my/output/dir/quux/foo.html and /my/output/dir/baz.html:
853await assetGraph.writeAssetsToDisc({type: 'Html'} 'file:///my/output/dir/', 'http://example.com/bar/');
854```
855
856## assetGraph.writeAssetsToStdout([queryObj])
857
858Writes all assets in the graph (or those specified by `queryObj`) to
859stdout. Mostly useful for piping out a single asset.
860
861## License
862
863AssetGraph is licensed under a standard 3-clause BSD license -- see the
864`LICENSE`-file for details.