UNPKG

25.1 kBMarkdownView Raw
1<!-- TITLE/ -->
2
3<h1>@asset-pipe/client</h1>
4
5<!-- /TITLE -->
6
7
8<!-- BADGES/ -->
9
10<span class="badge-travisci"><a href="http://travis-ci.org/asset-pipe/asset-pipe-client" title="Check this project's build status on TravisCI"><img src="https://img.shields.io/travis/asset-pipe/asset-pipe-client/master.svg" alt="Travis CI Build Status" /></a></span>
11<span class="badge-npmversion"><a href="https://npmjs.org/package/@asset-pipe/client" title="View this project on NPM"><img src="https://img.shields.io/npm/v/@asset-pipe/client.svg" alt="NPM version" /></a></span>
12<span class="badge-daviddm"><a href="https://david-dm.org/asset-pipe/asset-pipe-client" title="View the status of this project's dependencies on DavidDM"><img src="https://img.shields.io/david/asset-pipe/asset-pipe-client.svg" alt="Dependency Status" /></a></span>
13<span class="badge-daviddmdev"><a href="https://david-dm.org/asset-pipe/asset-pipe-client#info=devDependencies" title="View the status of this project's development dependencies on DavidDM"><img src="https://img.shields.io/david/dev/asset-pipe/asset-pipe-client.svg" alt="Dev Dependency Status" /></a></span>
14
15<!-- /BADGES -->
16
17
18[![Greenkeeper badge](https://badges.greenkeeper.io/asset-pipe/asset-pipe-client.svg)](https://greenkeeper.io/)
19
20A client for reading an asset file entry point and uploading it as an asset feed
21to a [asset-pipe-build-server][asset-pipe-build-server] and for triggering
22builds of executable asset bundles in the said server.
23
24Creating asset bundles with [asset-pipe][asset-pipe] is a two step process. The
25first step is to upload an asset feed to the
26[asset-pipe-build-server][asset-pipe-build-server]. On upload the asset-feed
27will be persisted and the [asset-pipe-build-server][asset-pipe-build-server]
28will return the generated filename of the uploaded asset-feed.
29
30The second step is then to create a bundle out of one or multiple asset-feeds.
31This is done by providing the unique ID(s) of the asset-feeds one wants to use
32to build an asset bundle to the
33[asset-pipe-build-server][asset-pipe-build-server]. The build server will then
34create an executable asset bundle out of these asset-feeds and persist this. It
35will respond with the URL to the bundle.
36
37This client helps with remotely triggering these steps in the
38[asset-pipe-build-server][asset-pipe-build-server].
39
40## Optimistic Bundling
41
42The asset server can produce asset bundles in what we call an "optimistic"
43fashion. This means that asset bundles will be automatically produced and
44reproduced any time an asset changes or any time the definition of which assets
45should be included in a bundle changes.
46
47This works in the following way:
48
491. Any number of assets are uploaded to the asset server using the
50 `client.publishAssets` method.
512. Bundling instructions are uploaded to the asset server using the
52 `client.publishInstructions` method.
53
54Steps 1 and 2 can be performed in any order and the asset server will
55automatically bundle and rebundle as needed to produce up to date bundles for
56any instructions that have been published to the server.
57
58**Examples**
59
60We might begin by first we publishing some bundling instructions. (Though we
61could just as easily publish assets first):
62
63```js
64await client.publishInstructions('layout', 'js', ['podlet1', 'podlet2']);
65```
66
67At this point, the server will not have created any bundles as there are no
68corresponding assets for `podlet1` or `podlet2`.
69
70Next we upload the missing asset feeds for `podlet1` and `podlet2`.
71
72```js
73const { uri, id } = await client.publishAssets('podlet1', ['/path/to/file.js']);
74const { uri, id } = await client.publishAssets('podlet2', ['/path/to/file.js']);
75```
76
77Once both these asset feeds are in place, the asset server will generate a fresh
78bundle based on our earlier published instructions. Once finished, a new bundle
79file will be available from the asset server.
80
81### Calculating the location of produced bundle files
82
83When `publishAssets` is successfully called, a unique asset hash `id` property
84will be available on the returned object. sha256 hashing all asset hashes
85together (in the same order they are defined in the publish instructions) and
86appending the correct file extension to the result will give you the filename of
87the resulting bundle.
88
89**Example**
90
91First publish assets and instructions
92
93```js
94await client.publishInstructions('layout', 'js', ['podlet1', 'podlet2']);
95const result1 = await client.publishAssets('podlet1', ['/path/to/file.js']);
96const result2 = await client.publishAssets('podlet2', ['/path/to/file.js']);
97```
98
99Next, compute a hash and resulting filename
100
101```js
102const hash = sha256Somehow(result1.id, result2.id);
103const bundleFilename = `${hash}.js`;
104```
105
106Finally, the file can be retrieved from the asset server via the `/bundle`
107endpoint.
108
109```bash
110GET http://<asset-server-url>/bundle/<hash>.js
111```
112
113To make some of this a little easier, 2 helper methods exist on the client:
114
115- `bundleURL` - calculates the url location for a bundle based on a given array of asset hashes.
116- `bundlingComplete` - determines if bundling is complete for a given array of asset hashes.
117
118See API documentation below for more information.
119
120## Installation
121
122```bash
123$ npm install @asset-pipe/client
124```
125
126## Example I
127
128Read an [CommonJS module][commonjs] entry point and upload it as an asset-feed
129to the [asset-pipe-build-server][asset-pipe-build-server]:
130
131```js
132const Client = require('@asset-pipe/client');
133
134const client = new Client({
135 serverId: 'my-app-1',
136 server: 'http://127.0.0.1:7100'
137});
138
139client
140 .uploadFeed(['path/to/myFrontendCode.js'])
141 .then(content => {
142 // content contains filename of created the asset-feed
143 console.log(content);
144 })
145 .catch(error => {
146 console.log(error);
147 });
148```
149
150## Example II
151
152Read a CSS file entry point and upload it as an asset-feed to the
153[asset-pipe-build-server][asset-pipe-build-server]:
154
155```js
156const Client = require('@asset-pipe/client');
157
158const client = new Client({
159 server: 'http://127.0.0.1:7100'
160});
161
162client
163 .uploadFeed(['/path/to/styles.css'])
164 .then(content => {
165 // content contains filename of created the asset-feed
166 console.log(content);
167 })
168 .catch(error => {
169 console.log(error);
170 });
171```
172
173## Example III
174
175Build a javascript bundle out of two asset feeds:
176
177```js
178const Client = require('@asset-pipe/client');
179const client = new Client({
180 serverId: 'my-app-2',
181 server: 'http://127.0.0.1:7100'
182});
183
184bundle
185 .createRemoteBundle(
186 [
187 'f09a737b36b7ca19a224e0d78cc50222d636fd7af6f7913b01521590d0d7fe02.json',
188 'c50ca03a63650502e1b72baf4e493d2eaa0e4aa38aa2951825e101b1d6ddb68b.json'
189 ],
190 'js'
191 )
192 .then(content => {
193 // content contains URI to the created bundle
194 console.log(content);
195 })
196 .catch(error => {
197 console.log(error);
198 });
199```
200
201## Example IIII
202
203Build a CSS bundle out of two asset feeds:
204
205```js
206const Client = require('@asset-pipe/client');
207const client = new Client({
208 server: 'http://127.0.0.1:7100'
209});
210
211bundle
212 .createRemoteBundle(
213 [
214 'f09a737b36b7ca19a224e0d78cc50222d636fd7af6f7913b01521590d0d7fe02.json',
215 'c50ca03a63650502e1b72baf4e493d2eaa0e4aa38aa2951825e101b1d6ddb68b.json'
216 ],
217 'css'
218 )
219 .then(content => {
220 // content contains URI to the created bundle
221 console.log(content);
222 })
223 .catch(error => {
224 console.log(error);
225 });
226```
227
228## API
229
230Under the hood, when working with javascript, the [asset-pipe][asset-pipe]
231project builds on [browserify][browserify]. Multiple methods in this module are
232therefor underlaying Browserify methods where all features found in Browserify
233can be used. Such methods will in this documentation point to the related
234documentation in Browserify.
235
236When working with CSS the underlying POST CSS is used but the implementation is
237not exposed so there are no additional supported methods.
238
239This module has the following API:
240
241### constructor(options)
242
243Supported arguments are:
244
245- `options.server` - Required URI to the
246 [asset-pipe-build-server][asset-pipe-build-server]
247- `options.serverId` - An optional unique name to identify the deployed server
248 (required for runtime optimistic bundling)
249- `options.minify` - Use minification (optimistic bundling only) `true|false` Not providing this option will result in server default being used.
250- `options.sourceMaps` - (experimental) Use sourceMaps (optimistic bundling only) `true|false` Not providing this option will result in server default being used.
251- `options.logger` - An optional log4js compatible logger. See [abslog](https://www.npmjs.com/package/abslog) for more information
252- `options.development` - Puts the client in development mode. For use with the client.middleware() function (see below). Default `false`
253- `options.tag` - Optionally define a tag to be used when publishing assets to an asset server. For use with the client.middleware() function (see below). Required when `publish` is `true`.
254- `options.js` - Optionally define the full path to a JavaScript file. For use with the client.middleware() function (see below)
255- `options.css` - Optionally define the full path to a CSS style file. For use with the client.middleware() function (see below)
256
257### transform()
258
259Same as the [Browserify transform][browserify-transform] method. _NOTE:_ Only
260applicable when uploading javascript feeds.
261
262### plugin()
263
264Same as the [Browserify plugin][browserify-plugin] method. _NOTE:_ Only
265applicable when uploading javascript feeds.
266
267### uploadFeed(files)
268
269Read the [CommonJS module][commonjs] or CSS file entry point and uploads it as
270an asset feed to the [asset-pipe-build-server][asset-pipe-build-server].
271
272- `files` - Array - Either list of CommonJS module entry points - Same as
273 `files` in the [Browserify constructor][browserify-opts] OR list of paths to
274 CSS files
275
276Returns a promise.
277
278### createRemoteBundle(feeds, type)
279
280Creates an asset bundle on the
281[asset-pipe-build-server][asset-pipe-build-server].
282
283- `feeds` - Array - List of asset-feed filenames.
284- `type` - string - Either 'js' or 'css'
285
286### sync()
287
288Fetches centralised configuration information from the asset server.
289This should be called after creating a new client instance and before any calls to `.bundleURL()` or `.bundlingComplete()`
290
291**Example**
292
293```js
294const client = new Client(options);
295await client.sync();
296```
297
298### publishAssets(tag, entrypoints, options)
299
300Publishes assets to the asset server for use in optimisitic bundling. Bundles
301will be created according to bundle instructions published using the
302`publishInstructions` method.
303
304- `tag` - `string` - Alphanumeric string identifying the publisher. Should be
305 unique.
306- `entrypoints` - `Array|string` - Array of asset entrypoint filenames or single asset entrypoint filename string to be published to the asset server.
307- `options` - `object` - Bundling options. `{minify: true|false, sourceMaps: true|false}` Setting these options here will override the same options provided to the constructor
308
309`return` - `object` - An object with keys `id` (refering to the unique asset
310hash) and `uri` (referring to the location of the published asset on the
311server).
312
313**Examples**
314
315JavaScript
316
317```js
318const { uri, id } = await client.publishAssets('podlet1', '/path/to/file.js');
319```
320
321CSS
322
323```js
324const { uri, id } = await client.publishAssets('podlet1', '/path/to/file.css');
325```
326
327With minification
328
329```js
330const { uri, id } = await client.publishAssets('podlet1', '/path/to/file.js', {
331 minify: true
332});
333```
334
335### publishInstructions(tag, type, data, options)
336
337Publishes bundling instructions to the asset server for use in optimisitic
338bundling. Bundles are generated as specified by the `data` array. Anytime new
339instructions are published (via `publishInstructions`) or assets are published
340(via `publishAssets`), new bundles will be generated by the server.
341
342- `tag` - `string` - Alphanumeric string identifying the publisher. Should be
343 unique.
344- `type` - `string` - Asset type. Valid values are 'js' and 'css'
345- `data` - `array` - Array of tags to bundle together. Each tag must refer to
346 the tag property given when publishing assets using the `publishAssets`
347 method.
348- `options` - `object` - Bundling options. `{minify: true|false, sourceMaps: true|false}` Setting these options here will override the same options provided to the constructor
349
350`return` - 204 No Content is returned when publishing has successfully completed.
351
352**Examples**
353
354JavaScript
355
356```js
357await client.publishInstructions('layout', 'js', ['podlet1', 'podlet2']);
358```
359
360CSS
361
362```js
363await client.publishInstructions('layout', 'css', ['podlet1', 'podlet2']);
364```
365
366With minification
367
368```js
369await client.publishInstructions('layout', 'js', ['podlet1', 'podlet2'], {
370 minify: true
371});
372```
373
374### bundleURL(feedHashes, options)
375
376Calculates a bundle url string based on a given array of hashes which are asset feed content hashes. Each time an asset feed is published using `client.publishAssets` the resolved object will contain an `id` property which is the hash of the feed content and can be used with this method.
377
378Calculation is done by sha256 hashing together the given `hashes` and dropping the resulting hash into a url template.
379
380As such, this method does not perform any requests to the server and therefore cannot guarantee that the bundle exists on the server.
381
382**Note:** You should call `await client.sync();` one time after creating the client instance, before calling `bundleURL` to ensure the client has update information about the public location of bundle files.
383
384- `hashes` - `string[]` - array of asset feed content hashes as returned by `client.publishAssets`
385- `options` - `object`
386 - `options.prefix` - `string` url prefix to use when building bundle url. Defaults to `${client.server}/bundle/` which is the location on the asset server that a bundle can be located. Overwrite this if you use a CDN and need to point to that.
387 - `options.type` - `string` (`js`|`css`) - file type. Defaults to `js`
388
389`return` - `Promise<string>` - url for asset bundle on asset server.
390
391**Example**
392
393```js
394// publish instructions
395await client.publishInstructions('layout', 'js', ['podlet1', 'podlet2']);
396
397// publish necessary assets
398const { uri, id1 } = await client.publishAssets('podlet1', [
399 '/path/to/file.js'
400]);
401const { uri, id2 } = await client.publishAssets('podlet2', [
402 '/path/to/file.js'
403]);
404
405// calculate the url of the finished bundle
406const url = await client.bundleURL([id1, id2]);
407```
408
409### bundlingComplete(feedhashes, options)
410
411Calculates whether a bundling for the given `feedHashes` has been completed. The rules for this method are as follows:
412
413**Note:** You should call `await client.sync();` one time after creating the client instance, before calling `bundleURL` to ensure the client has update information about the public location of bundle files.
414
415- If `feedHashes` is an empty array, this method resolves to `true` as no bundle needs to be built.
416- Otherwise, if `feedHashes` is not an empty array then a bundle url will be computed and a request made to check if the file exists on the server.
417
418- `hashes` - `string[]` - array of asset feed content hashes as returned by `client.publishAssets`
419- `options` - `object`
420 - `options.prefix` - `string` url prefix to use when building bundle url. Defaults to `${client.server}/bundle/` which is the location on the asset server that a bundle can be located. Overwrite this if you use a CDN and need to point to that.
421 - `options.type` - `string` (`js`|`css`) - file type. Defaults to `js`
422
423`return` - `Promise<boolean>` - resolves to a boolean representing whether the bundling process for the given `feedHashes` is considered to be complete.
424
425**Example**
426
427```js
428// publish instructions
429await client.publishInstructions('layout', 'js', ['podlet1', 'podlet2']);
430
431// publish necessary assets
432const { uri, id1 } = await client.publishAssets('podlet1', [
433 '/path/to/file.js'
434]);
435const { uri, id2 } = await client.publishAssets('podlet2', [
436 '/path/to/file.js'
437]);
438
439// calculate the url of the finished bundle
440const isComplete = await client.bundlingComplete([id1, id2]);
441```
442
443### .middleware()
444
445This method returns a connect middleware that can be used to both support assets in local development and to ensure assets are published before the request completes.
446
447When `.middleware()` is called and the client flag `development` is set to `true` then assets
448will be provided at `/js` and `/css` on your app. Additionally, file system watching will be enabled for JavaScript.
449
450**N.B.** You must call `.publish()` and provide `js` and/or `css` options for development mode to work.
451
452_Example_
453
454```js
455const client = new Client({
456 ...
457 development: true,
458 ...
459});
460
461client.publish({
462 js: '/path/to/script.js',
463 css: '/path/to/style.js',
464});
465
466app.use(client.middleware());
467
468// curl http:<address>:<port>/js => bundled js scripts
469// curl http:<address>:<port>/css => bundled css styles
470```
471
472When `.middleware()` is called and the client flag `development` is `false` then the middleware will force requests to wait until `client.ready()` resolves to `true`. This will ensure that any publishing or bundling has completed before route handlers are invoked.
473
474_Example_
475
476```js
477const client = new Client({
478 ...
479 server: 'http://asset-server.com:1234',
480 tag: 'uniqueLabel',
481 development: false,
482 ...
483});
484
485client.publish({ ... });
486client.bundle({ ... });
487
488app.use(client.middleware());
489
490app.get('/', (req, res) => {
491 // publishing and bundling have completed before we get
492 // here
493})
494```
495
496### .js()
497
498Method for retrieving the id hash for JavaScript assets uploaded to an asset server
499
500```js
501const client = new Client({
502 ...
503 server: 'http://asset-server.com:1234',
504 tag: 'uniqueLabel',
505 development: false,
506 ...
507})
508
509client.publish({ ... });
510client.js() // => null
511
512app.use(client.middleware());
513
514app.get('/', (req, res) => {
515 client.js() // a2b2ab2a2b2b3bab4ab4aa22babab2ba2
516})
517```
518
519### .css()
520
521Method for retrieving the id hash for CSS assets uploaded to an asset server
522
523```js
524const client = new Client({
525 ...
526 server: 'http://asset-server.com:1234',
527 tag: 'uniqueLabel',
528 development: false,
529 ...
530})
531
532client.publish({ ... });
533client.css() // => null
534
535app.use(client.middleware());
536
537app.get('/', (req, res) => {
538 client.css() // b2b2ac2a2b4b3bab4ab2aa22babab2ba2
539})
540```
541
542### .ready()
543
544Method for waiting until assets have finished publishing to or bundling on an asset server.
545
546```js
547const client = new Client({
548 ...
549 server: 'http://asset-server.com:1234',
550 tag: 'uniqueLabel',
551 development: false,
552 ...
553});
554
555client.publish({ ... });
556
557client.css() // => null
558
559await client.ready();
560
561client.js() // a2b2ab2a2b2b3bab4ab4aa22babab2ba2
562client.css() // b2b2ac2a2b4b3bab4ab2aa22babab2ba2
563```
564
565### .publish(options)
566
567Method to publish JavaScript and/or CSS assets to an asset server. Returns a promise which resolves when publishing is done.
568
569```js
570const client = new Client({
571 server: 'http://asset-server.com:1234',
572 tag: 'uniqueLabel'
573});
574
575const { js, css } = await client.publish({
576 js: '/path/to/script.js',
577 css: '/path/to/styles.css'
578});
579// js => a2b2ab2a2b2b3bab4ab4aa22babab2ba2
580// css => b2b2ac2a2b4b3bab4ab2aa22babab2ba2
581```
582
583It is not necessary to wait for publish to complete. You can also call publish to kick off publishing and then wait for the `.ready()` method to resolve to know when publishing is complete.
584
585```js
586const client = new Client({
587 server: 'http://asset-server.com:1234',
588 tag: 'uniqueLabel'
589});
590
591client.publish({
592 js: '/path/to/script.js',
593 css: '/path/to/styles.css'
594});
595
596await client.ready();
597```
598
599If you use `.middleware()` in your connect based applications, waiting for publish completion will happen automatically.
600
601```js
602const client = new Client({
603 server: 'http://asset-server.com:1234',
604 tag: 'uniqueLabel'
605});
606
607client.publish({
608 js: '/path/to/script.js',
609 css: '/path/to/styles.css'
610});
611
612app.use(client.middleware());
613```
614
615### .bundle(options)
616
617Method to instruct an asset server to bundle JavaScript and/or CSS assets. Returns a promise which resolves when bundling is done.
618
619```js
620const client = new Client({
621 server: 'http://asset-server.com:1234',
622 tag: 'uniqueLabel'
623});
624
625await client.bundle({ js: ['tag1', 'tag2'], css: ['tag1', 'tag2'] });
626```
627
628It is not necessary to wait for bundle to complete. You can also call bundle to kick off bundling and then wait for the `.ready()` method to resolve to know when bundling is complete.
629
630```js
631const client = new Client({
632 server: 'http://asset-server.com:1234',
633 tag: 'uniqueLabel'
634});
635
636client.bundle({ js: ['tag1', 'tag2'], css: ['tag1', 'tag2'] });
637
638await client.ready();
639```
640
641If you use `.middleware()` in your connect based applications, waiting for bundle completion will happen automatically.
642
643```js
644const client = new Client({
645 server: 'http://asset-server.com:1234',
646 tag: 'uniqueLabel'
647});
648
649client.bundle({ js: ['tag1', 'tag2'], css: ['tag1', 'tag2'] });
650
651app.use(client.middleware());
652```
653
654### .scripts(hashes)
655
656Method to retrieve JavaScript bundle URLs once publishing and bundling are complete. Includes a best effort algorithm to try to return an optimally bundled solution, falling back to multiple individual bundles when an optimal bundle is not available.
657
658_Example: Requesting a bundling for 2 tags when only 1 has been published_
659
660```js
661const client = new Client({
662 server: 'http://asset-server.com:1234',
663 tag: 'tag1'
664});
665
666const { js } = await client.publish({ ... });
667await client.bundle({ js: ['tag1', 'tag2'] });
668
669const scripts = client.scripts([js]);
670// scripts => [http://<asset-server-url>/bundle/${js}.js]
671```
672
673This method will always return an array so you can iterate over it in your templates and create script tags
674
675```njk
676{% for script in scripts %}
677 <script src={{ script }}></script>
678{% endfor %}
679```
680
681### .styles(hashes)
682
683Method to retrieve css bundle URLs once publishing and bundling are complete. Includes a best effort algorithm to try to return an optimally bundled solution, falling back to multiple individual bundles when an optimal bundle is not available.
684
685_Example: Requesting a bundling for 2 tags when only 1 has been published_
686
687```js
688const client = new Client({
689 server: 'http://asset-server.com:1234',
690 tag: 'tag1'
691});
692
693const { css } = await client.publish({ ... });
694await client.bundle({ css: ['tag1', 'tag2'] });
695
696const styles = client.styles([css]);
697// styles => [http://<asset-server-url>/bundle/${css}.css]
698```
699
700This method will always return an array so you can iterate over it in your templates and create style tags
701
702```njk
703{% for style in styles %}
704 <link rel="stylesheet" href={{ style }} />
705{% endfor %}
706```
707
708### .metrics
709
710This module uses [@metrics/client](https://www.npmjs.com/package/@metrics/client) to expose metric objects for consumption via a stream.
711
712Available metric names are:
713
714- publish_assets_timer
715- publish_instructions_timer
716- asset_server_sync_timer
717
718**Example: piping metrics stream into a consumer**
719
720```js
721client.metrics.pipe(consumer);
722```
723
724See [@metrics/client](https://www.npmjs.com/package/@metrics/client) for more details including how to implement a consumer.
725
726## Transpilers
727
728Since [asset-pipe][asset-pipe] is built on [browserify][browserify] under the
729hood, its fully possible to take advantage of the different transpiers available
730for [browserify][browserify] when working with javascript.
731
732As an example, here is how Babel is applied:
733
734```js
735const babelify = require('babelify');
736const Client = require('@asset-pipe/client');
737
738const client = new Client({ server: 'http://127.0.0.1:7100' });
739
740client.transform(babelify, { presets: ['es2015'] });
741
742const { uri, id } = await client.publishAssets('podlet1', ['/path/to/file.js']);
743```
744
745## Contributing
746
747The contribution process is as follows:
748
749- Fork this repository.
750- Make your changes as desired.
751- Run the tests using `npm test`. This will also check to ensure that 100% code
752 coverage is maintained. If not you may need to add additional tests.
753- Stage your changes.
754- Run `git commit` or, if you are not familiar with [semantic commit
755 messages](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit),
756 please run `npm run cm` and follow the prompts instead which will help you
757 write a correct semantic commit message.
758- Push your changes and submit a PR.
759
760[commonjs]: https://nodejs.org/docs/latest/api/modules.html
761[asset-pipe]: https://github.com/asset-pipe
762[asset-pipe-build-server]: https://github.com/asset-pipe/asset-pipe-build-server
763[browserify]: https://github.com/substack/node-browserify
764[browserify-opts]: https://github.com/substack/node-browserify#browserifyfiles--opts
765[browserify-plugin]: https://github.com/substack/node-browserify#bpluginplugin-opts
766[browserify-transform]: https://github.com/substack/node-browserify#btransformtr-opts