{"id":18940333,"url":"https://github.com/donejs/donejs-streaming-product-page","last_synced_at":"2026-03-23T08:30:17.867Z","repository":{"id":136943937,"uuid":"94110912","full_name":"donejs/donejs-streaming-product-page","owner":"donejs","description":"A product page that is super streaming fast!","archived":false,"fork":false,"pushed_at":"2019-06-20T16:46:06.000Z","size":37,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-12-31T22:28:56.572Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/donejs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-12T15:20:43.000Z","updated_at":"2018-03-08T01:36:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"e97cc38a-36d5-4b61-8fe6-b6e8bef1cbb2","html_url":"https://github.com/donejs/donejs-streaming-product-page","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donejs%2Fdonejs-streaming-product-page","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donejs%2Fdonejs-streaming-product-page/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donejs%2Fdonejs-streaming-product-page/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donejs%2Fdonejs-streaming-product-page/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/donejs","download_url":"https://codeload.github.com/donejs/donejs-streaming-product-page/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239939087,"owners_count":19721771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T12:22:06.706Z","updated_at":"2026-03-23T08:30:17.834Z","avatar_url":"https://github.com/donejs.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dog Things\n\n**Dog Things** is a [DoneJS](https://donejs.com/) application that allows users to view dog products like leashes and bones, and to add items to their cart. This application shows off the advantages of [streamable](https://www.bitovi.com/streamable) web applications and how DoneJS facilitates building them.\n\nThis readme walks through getting the project set up locally, and the features used to build the app.\n\n![app screen shot](https://user-images.githubusercontent.com/361671/29074136-2dff5cc2-7c1c-11e7-929a-1c77b19fda91.png)\n\n## Setting up\n\nTo get *Dog Things* set up locally, first clone the repository:\n\n```\ngit clone git@github.com:donejs/donejs-streaming-product-page.git\n```\n\nAnd then install the dependencies with [npm](https://www.npmjs.com/).\n\n```\ncd donejs-streaming-product-page\nnpm install\n```\n\n### SSL\n\nThis application uses [HTTP/2](https://http2.github.io/) to provide the fastest possible rendering. HTTP/2 requires SSL, so to debug the application locally you'll need to first create a [self-signed certificate](https://en.wikipedia.org/wiki/Self-signed_certificate).\n\nTo create the certificate and private key use the `openssl` command like so:\n\n```shell\nopenssl req  -nodes -new -x509  -keyout server.key -out server.cert\n```\n\nThis will create a `server.key` and `server.cert` file in the local directory. Since you don't want to include these in version control, move them somewhere else in the file system. I keep a directory for these certificates so that I can reuse them when working locally.\n\n```\nmkdir -p ~/.localhost-ssl\nmv server.key server.cert ~/.localhost-ssl\n```\n\n### Turning on incremental rendering\n\nNow that you have a certificate you can use for development, update the `develop` script in your package.json:\n\n```json\n{\n  \"scripts\": {\n    \"develop\": \"done-serve --develop --port 8080 --proxy http://localhost:8084 --key ~/.localhost-ssl/server.key --cert ~/.localhost-ssl/server.cert --strategy incremental\"\n  }\n}\n```\n\nThis app uses a locally hosted API. In your scripts also add this:\n\n```json\n{\n  \"scripts\": {\n    \"api\": \"node api/server.js\"\n  }\n}\n```\n\nFirst start the API server in one terminal window:\n\n```shell\ndonejs api\n```\n\nAnd in another terminal window start the server:\n\n```shell\ndonejs develop\n```\n\nAnd open the page in the browser at `https://localhost:8080`. The first time you open the page you will get a security error because the certificate is not signed by a CA the browser recognizes. Since you are using this for local development you can ignore this error, it will only happen the first time.\n\nIn Chrome first click on the link that says *ADVANCED*:\n\n![security advanced](https://user-images.githubusercontent.com/361671/29075035-37a59f5e-7c1f-11e7-90d1-6103f4c92687.png)\n\nAnd then click on the link saying *Proceed to localhost (advanced)*:\n\n![proceed to localhost](https://user-images.githubusercontent.com/361671/29075140-8e611922-7c1f-11e7-9a87-3c134324579b.png)\n\nWhich should load up the app.\n\n## Features\n\nThis demo application shows off some of the streaming capabilities of DoneJS. DoneJS utilizes HTTP/2 and the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to stream data from the server.\n\n### Incremental rendering\n\n*Incremental rendering* is a term we have come up with to describe a new streaming technique we've invented as part of DoneJS. Since *most* applications are made up of various dynamic parts, waiting for everything to load before rendering will result in a poor experience for your users. With the incremental rendering strategy DoneJS can provide many of the benefits of server-side rendering without forcing your users to wait on the slowest part.\n\nWhen you load this example app you'll see this to start:\n\n![app one thing loaded](https://user-images.githubusercontent.com/361671/29080326-7cc767a8-7c2d-11e7-8ab9-1508dcbce274.png)\n\nNotice that the cart shows **0** items. This is because the cart is still being loaded on the server. Meanwhile 1 product has already loaded.\n\nWhen implementing a traditional HTML streaming approach you would have to wait on the cart to load before streaming out any other content below it. Incremental rendering isn't biased in favor of top-down loading, so *the fastest parts of your app load first*.\n\nThis mirrors what happens in the real world, where often times something like a product listing will load fast from the database, and user profile things (that tend to be at the top of the page, like the cart) might require more complex database queries.\n\nWaiting a second or so longer and you should see this now:\n\n![more stuff loaded](https://user-images.githubusercontent.com/361671/29080696-76bd691a-7c2e-11e7-9781-6b4e3942a2f2.png)\n\nThe numbers demonstrate the loading order. First 2 product items load, then the cart, and finally more products.\n\nIf you open up your devtools you can see the stream of commands. It will come from a URL prefixed with `_donessr_instructions/`. It looks like:\n\n![devtools screen shot](https://user-images.githubusercontent.com/361671/29082002-3c733b1e-7c32-11e7-9416-d05bb60481a4.png)\n\n### NDJSON\n\nThe Dog Things app uses [NDJSON](https://davidwalsh.name/streaming-data-fetch-ndjson) to stream in the product list from the server. NDJSON is a format of data that delimits rows (from list queries) with newlines. It looks like this:\n\n```ndjson\n{ \"product\": \"Bones\", \"img\": \"https://...\" }\n{ \"product\": \"Treats\", \"img\": \"https://...\" }\n```\n\nIf you look in `src/models/products.js` you will see the import of [can-connect-ndjson](https://github.com/canjs/can-connect-ndjson):\n\n```js\nimport ndjson from \"can-connect-ndjson\";\n```\n\nand then the use:\n\n```js\nProduct.connection = connect([\n\tconstructor, connectMap, constructorStore,\n\tdataUrl, ndjson\n], {\n  url: loader.serviceBaseURL + '/api/product',\n\tndjson: loader.serviceBaseURL + '/api/product',\n  Map: Product,\n  List: Product.List,\n  name: 'product',\n  algebra\n});\n```\n\nNotice that this utilizes an **ndjson** property on the connection. In this case it is the same url as used for JSON, but if you wanted you could use different URLs. This would allow you to use ndjson streaming data for users with supported browsers and then to fallback to a JSON service for those that do not.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdonejs%2Fdonejs-streaming-product-page","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdonejs%2Fdonejs-streaming-product-page","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdonejs%2Fdonejs-streaming-product-page/lists"}