{"_id":"external","_rev":"267401","name":"external","description":"Fittings for BigPipe which allows you to use the BigPipe as a third party/external content provider.","dist-tags":{"latest":"1.0.0"},"maintainers":[{"name":"3rdeden","email":""},{"name":"indexzero","email":"charlie.robbins@gmail.com"},{"name":"jcrugzz","email":""}],"time":{"modified":"2023-06-28T11:49:31.000Z","created":"2015-09-16T09:25:56.343Z","1.0.0":"2015-09-16T09:25:56.343Z"},"users":{},"author":{"name":"Arnout Kazemier"},"versions":{"1.0.0":{"name":"external","version":"1.0.0","description":"Fittings for BigPipe which allows you to use the BigPipe as a third party/external content provider.","main":"index.js","browser":"extern.js","scripts":{"100%":"istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100","test":"node test/index.js","node":"mocha test/extern.test.js","watch":"mocha --watch test/extern.test.js","coverage":"istanbul cover ./node_modules/.bin/_mocha -- test/extern.test.js","compile":"mkdir -p dist && NODE_ENV=production browserify -s Extern -g envify -g uglifyify index.js -o dist/extern.min.js","prepublish":"npm run compile","dev":"mkdir -p dist && NODE_ENV=development browserify -s Extern -g envify index.js -o dist/extern.dev.js","static":"node test/static.js"},"keywords":["external","fittings","remote","loading","third","party","third-party","bigpipe"],"author":{"name":"Arnout Kazemier"},"license":"MIT","dependencies":{"async-asset":"0.0.x","async-each":"0.1.x","demolish":"1.0.x","diagnostics":"1.0.x","emits":"3.0.x","fittings":"1.2.x","intl":"1.0.x","react":"0.13.x","react-intl":"1.2.x","recovery":"0.2.x","requests":"0.1.x","serve-static":"1.10.x","url-parse":"1.0.x"},"devDependencies":{"access-control":"0.0.x","argh":"0.1.x","assume":"1.2.x","browserify":"10.2.x","envify":"3.4.x","istanbul":"0.3.x","mocha":"2.2.x","mochify":"2.10.x","mochify-istanbul":"2.3.x","node-jsx":"0.13.x","pre-commit":"1.0.x","uglifyify":"3.0.x"},"testling":{"files":"test/*.browser.js","harness":"mocha-bdd","browsers":["ie/6..latest","chrome/22..latest","firefox/16..latest","safari/latest","opera/11.0..latest","iphone/latest","ipad/latest","android-browser/latest"]},"gitHead":"c523969a861706e8d36080a0129f080b60d74efa","_id":"external@1.0.0","_shasum":"119e186c6a88780eb64398735250feae65f75d11","_from":".","_npmVersion":"2.14.3","_nodeVersion":"0.12.3","_npmUser":{"name":"3rdeden","email":"npm@3rd-Eden.com"},"maintainers":[{"name":"3rdeden","email":""},{"name":"indexzero","email":"charlie.robbins@gmail.com"},{"name":"jcrugzz","email":""}],"dist":{"shasum":"119e186c6a88780eb64398735250feae65f75d11","size":449512,"noattachment":false,"key":"/external/-/external-1.0.0.tgz","tarball":"http://name.csiicloud.com:7001/external/download/external-1.0.0.tgz"},"directories":{},"_cnpmcore_publish_time":"2021-12-23T10:09:05.854Z","publish_time":1442395556343,"_cnpm_publish_time":1442395556343}},"readme":"# external\n\nExternal is a dual purpose library. It ships with a client-side framework renders\nthird party or external pages in the most optimal way as possible. This is done\nusing various of techniques:\n\n- The payload is downloaded using a fully async streaming XHR request. This way\n  we can continuously update and render our placeholder while data flows and\n  therefor reducing the time to render.\n- All assets of the page are loaded async, this includes the CSS.\n- The received client code is wrapped before execution so client code can re-use\n  our dependencies while keeping a sandboxed approach.\n- While the client was specifically written for the [BigPipe] framework it\n  should work against any back-end as long as it returns the same data\n  structure.\n- Templates are rendered using React so it's easy to compose and update.\n\nBut we also ship with a server-side framework implementation for [BigPipe] which\nmakes it possible to serve the client and automatically format all the output in\nthe expected HTML structure.\n\n## Table of Contents\n\n- [Installation](#installation)\n  - [Building](#building)\n  - [Serving](#serving)\n  - [Listening](#listening)\n- [Extern](#extern)\n- [BigPipe](#bigpipe)\n- [Wire Format](#wire-format)\n- [License](#license)\n\n## Installation\n\nThe client-side component is composed from various of tiny modules and can be\nbuild using [Browserify]. It can be build-in to other browserify components by\nsimply requiring the `external` module in your client-code.\n\nThe server side part of this framework can be installed through npm:\n\n```\nnpm install external\n```\n\nIn addition to providing a browserify-able client-side script there is also a\ncompiled version of this code which lives in the `dist` folder called\n`extern.js`. This pre-compiled library exposes it self using the `Extern` global\nand therefor does not introduced `require` statement as globals. In all the code\nexamples in documentation we assume that you have an `Extern` global. If you use\nthe `dist` build you can skip the following example:\n\n```js\nvar Extern = require('extern');\n```\n\n### Building\n\nIf you want to generate new stand alone bundles of the Extern library you can\nrun our `prepublish` and `dev` scripts using the `npm run` command. These\ncommands do assume that you've installed the `devDependencies` of this project.\nTo generate a new production build, `dist/extern.min.js` run:\n\n```\nnpm run prepublish\n```\n\nAs this is a `prepublish` script, it means that every release to npm will have\nthe `dist/extern.js` included. So if browserify isn't your think, you can just\ninclude the `extern/dist/extern.min.js` instead.\n\nTo generate an un-minified build for development purposes you can run:\n\n```\nnpm run dev\n```\n\nThis will generate a new `dist/extern.dev.js` file.\n\n### Serving\n\nNow that you know how to install it and what type of bundles there are you can\ndecide how to serve the library. When this module is used as plugin in [BigPipe]\nit will automatically serve the browserify and plugin combined bundle from:\n\n```\nhttp(s)://domain.com/extern.js\n```\n\nWe also mount our `dist` folder on the server so the static assets in this\nfolder can also be served:\n\n```\nhttp(s)://domain.com/extern.min.js\n```\n\nNow that you've picked your build, and know how the files are served you can\nsimply put the script tag in your page and your ready to display external\npages/apps.\n\n```html\n<script src=\"https//yourdomain.com/extern.min.js\"></script>\n<script>\nvar extern = new Extern(document.body, 'http://whateverurlyouwantousehere.com/path/name');\n</script>\n```\n\n### Listening\n\nThe easiest way to have `Extern` load your remote pages is by using the\n`Extern.listen` method in combination with the `rel=\"extern\"` attributes on\n`<a>` elements:\n\n```html\n<a href=\"http://my-remote-server.com/optional/path\" rel=\"extern\">Remote</a>\n```\n\nThe `Extern.listen` method will gather all `<a>` elements and search for a `rel`\nthat is set to `extern` and uses the set `href` of the element as URL that needs\nto be remotely loaded.\n\n```js\nExtern.listen(document.body, {});\n```\n\n## Extern\n\nThe following options are supported:\n\n- **`timeout`** Timeout for dependency loading. If assets take longer we should\n  render and error template instead. The timeout is in milliseconds.\n- **`document`** Reference to the `document` global can be useful if assets need\n  to be loaded in iframes instead of the global document.\n- **`className`** If a link has this className we will automatically load it in\n  the placeholder. This className will also automatically be add and removed\n  once the link is clicked. Defaults to `extern-loads`.\n\n```js\nvar extern = new Extern('http://my.example.com/page', document.body, {\n  timeout: 10000\n});\n```\n\n### Events\n\nThe returned `extern` instance is actually an `EventEmitter3` instance so you\ncan listen to the various of events that we're emitting:\n\n- **error** Emitted when something went so horribly wrong that we decided to\n  show the error template. This event receives the actual `error` as argument.\n- **done** The streaming XHR is finished with loading.\n- **name:render** Called when a fragment is about to render in to the\n  placeholder. The `name` part in the event should be name of the fragment you\n  want to listen for.\n- **name:loaded** All the assets are loaded for the given placeholder name.\n\n## Wrapping\n\nThe client code for each fragments are loaded through an XHR connection. This\nway we can safely executed third party code by wrapping the execution in a\n`try/catch` statement. But not only does this allow us to wrap code, it also\nallows us to introduce variables in the function. The following variables are\nintroduced as \"globals\":\n\n- `React`, This is the `react/addons` reference.\n- `require`, Reference to our `require` statement so you can re-use all the\n  bundled things.\n\n## API\n\nThe following properties and methods are exposed on the Extern instance.\n\n#### Extern.listen\n\n**Exposed on the constructor**\n\nScan the current document for all `<a rel=\"extern\">` elements and attach click\nlisteners to it so we can automatically update the supplied placeholder with the\ncontents of the set URL. This method accepts one argument and that is the\n`placeholder` DOM element where all pages should loaded in\n\n```js\nExtern.listen(document.body);\n```\n\n#### Extern.merge\n\n**Exposed on the constructor**\n\nMerge the object of the second argument in to the first argument. It returns the\nfully merged first argument.\n\n```js\nvar x = Extern.merge({ foo: 'foo' }, { bar: 'bar' });\n```\n\n#### Extern.requests\n\n**Exposed on the constructor**\n\nA reference to the `requests` module that we're using for our XHR requests.\n\n```js\nvar requests = Extern.requests.\n```\n\nSee [unshiftio/requests](https://github.com/unshiftio/requests) for more\ninformation.\n\n## BigPipe\n\nThis library ships with a custom [Fittings] framework implementation for\n[BigPipe] which allows us to control how everything is processed inside of\n[BigPipe]. Adding it to your BigPipe instance is just as simple as passing a\ncustom `framework` option while creating a new instance:\n\n```js\n'use strict';\n\nvar BigPipe = require('bigpipe')\n  , Extern = require('external');\n\nvar app = BigPipe.createServer({\n  framework: Extern,\n  port: 8080\n});\n```\n\nBut the framework can also be set _after_ the construction using the `framework`\nmethod:\n\n```js\napp.framework(Extern);\n```\n\n**Please do note that the current Fittings implentation is in the BigPipe master\nbranch but will out in the release that follows 0.9**\n\nOnce the fittings are installed on the application, it will start spitting out\nresponses based on the specified [Wire Format](#wire-format) below. The\nprocessing instructions can be found in the [instructions](/instructions) folder\nin the root of this repository. But before fiddling with these files I would\nsuggest giving the [README.md][Fittings] of Fittings a read so you know how the\ndata formatting works.\n\n## Wire Format\n\nIn order to have the broadest support within this framework we came up with a\ndedicated wire-format in order to have the server-side and client-side\ncomponents interact with each other. While this wire-format is mostly catered to\nthe needs of an application that is build using the [BigPipe] framework it\nshould be relatively easy to produce exactly the same output in different\nframeworks and programming languages. This wire format is also required in order\nto make streaming data as simple as possible as we can trigger buffer flushes\nbased on this.\n\nThe format that we're using is `\\u1337` separated `JSON`. Every time we\nencounter the `\\u1337` character on the client-side we assume it's the end of\nchunk that requires processing. The JSON payload that is send should contain the\nfollowing properties:\n\n- **`_id`** A unique id for the payload that is flushed.\n- **`name`** Name of the payload that is flushed. This is used to track\n  potential child->parent references throughout the flushed payload.\n- **`details`** An object that contains:\n  - **`js`** Array with path names for the JavaScript files that need to be\n    loaded on the page. We will automatically prepend the server address to\n    these assets.\n  - **`css`** Array with path names for the CSS files that need to be\n    loaded on the page. We will automatically prepend the server address to\n    these assets.\n- **`state`** Additional state that will be spread on the component when we\n  render it.\n- **`template`** An initial HTML template that should be rendered in the given\n  placeholder.\n\n### CSS Assets\n\nIn order to be able to load CSS assets fully async in every browser we need to\nknow when the styles are applied. This is done by Extern client by adding a DOM\nelement to the page that has an `id` attribute which contains `_` and the filename of\nthe asset that is being downloaded (`#_yourfilename`). We therefor **require**\nthat the CSS file contains CSS selector and sets the `height` property to\n`42px`. This allows us to poll the element for height changes to know when the\nCSS is fully loaded. So if we have a file called `1aFafa801jz09.css` it should\nhave the following selector in the source:\n\n```css\n#_1aFafa801jz09 { height: 42px }\n```\n\n## License\n\nThis project has been released under the MIT license, see [LICENSE].\n\n[Fittings]: https://github.com/bigpipe/fittings\n[Browserify]: http://github.com/substack/node-browserify\n[BigPipe]: https://github.com/bigpipe/bigpipe\n","_attachments":{},"license":"MIT"}