├── .gitignore ├── code-of-conduct.md ├── contributing.md ├── license.md ├── package.json ├── prerender-dynamic.md ├── prerender-static.md ├── readme.md ├── readme.template.md ├── reframe.md └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | yarn-error.log 3 | package-lock.json 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at 59 | github.com/code-of-conduct@brillout.com. All 60 | complaints will be reviewed and investigated and will result in a response that 61 | is deemed necessary and appropriate to the circumstances. The project team is 62 | obligated to maintain confidentiality with regard to the reporter of an incident. 63 | Further details of specific enforcement policies may be posted separately. 64 | 65 | Project maintainers who do not follow or enforce the Code of Conduct in good 66 | faith may face temporary or permanent repercussions as determined by other 67 | members of the project's leadership. 68 | 69 | ## Attribution 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 72 | available at [http://contributor-covenant.org/version/1/4][version] 73 | 74 | [homepage]: http://contributor-covenant.org 75 | [version]: http://contributor-covenant.org/version/1/4/ 76 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | Note that this project is released with a [Contributor Code of Conduct](code-of-conduct.md). 4 | By participating in this project you agree to abide by its terms. 5 | 6 | - 7 | 8 | Contribution guidelines: 9 | 10 | - Make an individual pull request for each suggestion. 11 | - Use the following format for adding a tool: ` - [Project Name](https://github.com/owner/repo#readme) - Description without emojis.`. 12 | - There is no format for the learning section. 13 | - Your addition should be added to the bottom of the relevant section. 14 | - If it doesn't fit any category then open a new issue so we can discuss improving the categorization. 15 | - Check your spelling and grammar. 16 | - If you just created something, wait at least a couple of weeks before submitting it. 17 | - All texts should be translated to English. 18 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "docs": "mdocs" 5 | }, 6 | "devDependencies": { 7 | "@brillout/mdocs": "^0.1.20" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /prerender-dynamic.md: -------------------------------------------------------------------------------- 1 | #### Dynamic Pre-Rendering 2 | 3 | Automatically and regularly render your deployed website to HTML. 4 | 5 | ##### SaaS 6 | 7 | - [Prerender.io](https://prerender.io/) 8 | - [SEO4Ajax](https://www.seo4ajax.com/) 9 | - [Prerender.cloud](https://www.prerender.cloud/) 10 | - [SEO.js](http://getseojs.com/) 11 | - [BromBone](https://www.brombone.com/) 12 | 13 | ##### Libraries 14 | 15 | - [Prerender.io Node Server](https://github.com/prerender/prerender#readme) - The prerender.io Node Server is open source. 16 | -------------------------------------------------------------------------------- /prerender-static.md: -------------------------------------------------------------------------------- 1 | #### Static Pre-Rendering 2 | 3 | *Some static pre-renderers, instead of generating HTML upon a generated DOM, directly render your pages to HTML.* 4 | 5 | - [Prerender SPA Plugin](https://github.com/chrisvfritz/prerender-spa-plugin#readme) - Uses Puppeteer to crawl & render your pages. 6 | - [react-snap](https://github.com/stereobooster/react-snap#readme) - Uses Puppeteer to crawl & render your pages. 7 | - [prep](https://github.com/prismagraphql/prep#readme) - Uses Chromeless to crawl & render your pages. 8 | - [SSG webpack plugin](https://github.com/markdalgleish/static-site-generator-webpack-plugin#readme) - Directly render your pages to HTML. You provide render functions and routes. All routes are rendered at build-time using the render functions you provided. Also has a crawl mode to use a headless browser to automatically discover your website's URLs. 9 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 78 | # Awesome Universal Rendering [![Awesome](https://awesome.re/badge-flat.svg)](https://awesome.re) 79 | 80 | Awesome resources about universal rendering: 81 | - **Introduction** 82 |
83 | Explains why universal rendering is beneficial, 84 | the different techniques of doing universal rendering (SSR, SSG, pre-rendering) 85 | and when to use what technique. 86 | - **Learning Material** 87 | - SEO benefits of universal rendering 88 | - Performance benefits of SSR 89 | - How to implement SSR 90 | - **Tools** 91 | - SSR frameworks & libraries 92 | - Pre-rendering services & tools 93 | - Static site generators 94 | 95 |
96 | 97 | #### Contents 98 | 99 | - [Introduction](#introduction) 100 | - [Learning Material](#learning-material) 101 | - [Tools](#tools) 102 | 103 |
104 | 105 | ## Introduction 106 | 107 | Modern view libraries (React, Vue, Angular, etc.) render views to the DOM in the browser but they can as well render views to HTML on the server. 108 | This capability can be used to render the same view twice: 109 | First to HTML then again to the DOM. (Re-rendering the view in the browser is called *hydrating*.) 110 | This practice is called *universal rendering* (aka isomorphic rendering). 111 | 112 | Universal rendering leads to improvements in SEO, SMO and performance. 113 | 114 | There are several techniques to achieve universal rendering: 115 | 116 | - Server-Side Rendering (SSR) 117 | - Static Site Generators (SSG) 118 | - Pre-Rendering 119 | 120 | In the following we explain these techniques and the benefits of universal rendering. 121 | 122 | - [Benefits](#benefits) 123 | - [Techniques](#techniques) 124 | 125 | ### Benefits 126 | 127 | #### SEO 128 | 129 | Modern frontends (React, Vue, Angular, ...) use JavaScript to load and display content. 130 | Such JavaScript-generated-content is invisible to crawlers that don't execute JavaScript. 131 | Most crawlers (search engines and social sites) don't execute JavaScript. 132 | 133 | The Google crawler is 134 | the only one that can successfully index JavaScript-generated-content. 135 | But it has limitations. 136 | (Mainly around delayed indexing and client-side routing, 137 | see [Learning Material](#learning-material).) 138 | 139 | If you want your content to be crawled by all other search engines (Bing, Baidu, DuckDuckGo, etc.), then your content needs to be included in your website's HTML. 140 | 141 | #### SMO 142 | 143 | The crawler of social media sites (Facebook, Twitter, ...) don't execute JavaScript and rely on HTML exclusively. 144 | 145 | If you want your website to be correctly previewed when a user shares your website, then the corresponding information needs to be included in your website's HTML. 146 | 147 | (SMO means "Social Media Optimization".) 148 | 149 | #### Performance 150 | 151 | Rendering your website's pages to HTML decreases the perceived loading time: 152 | Once the HTML is loaded, content can already be displayed before any JavaScript is loaded/executed. 153 | 154 | The improvement is considerable on mobile 155 | where loading and executing JavaScript is much slower. 156 | 157 | ### Techniques 158 | 159 | Server-Side Rendering (SSR), Pre-Rendering, and Static Site Generators (SSG) are techniques to render JavaScript-generated-content to HTML. 160 | Making the content visible to crawlers and improving performance. 161 | 162 | There are two ways to render JavaScript-generated-content to HTML: 163 | 164 | - **Directly render to HTML** 165 |
166 | Modern view libraries (React, Vue, Angular, ...) can render views to HTML (in addition to be able to render views to the DOM). 167 | (E.g. a React component can be rendered to HTML with `require('react-dom/server').renderToStaticMarkup()`.) 168 | - **Render to HTML via headless browser** 169 |
170 | A headless browser runs your website's JavaScript, 171 | the website's pages are rendered to the DOM of the headless browser, 172 | and HTML is automatically generated from the resulting DOM. 173 | 174 | Leading to the following techniques: 175 | 176 | - **Server-Side Rendering (SSR)** 177 |
178 | Directly render your website's pages to HTML at request-time: 179 | Every time a user requests a page, the server renders the page directly to HTML. 180 |
181 | SSR is the most reliable option if your HTML changes frequently. 182 | (If your website's content may change after deploy-time, 183 | e.g. if you website's content is generated by users.) 184 | - **Pre-Rendering** 185 |
186 | A headless browser crawls your website, executes the website's JavaScript, and generates HTML upon the resulting DOM. 187 | - **Static Site Generators (SSG)** 188 |
189 | A static site is a website that doesn't have any server code: 190 | The website is composed of static browser assets only (HTML, CSS, JavaScript, images, fonts, etc.). 191 | Some SSG are able to render your views to HTML at build-time: 192 | When your website is built, each page is rendered to a HTML file that includes your page's content. 193 |
194 | If your content only changes at deploy-time, then using a SSG is an option. 195 | 196 | 197 | 198 |
199 |
200 | 201 | ## Learning Material 202 | 203 | ### SEO/SMO 204 | 205 | - [Hacker News Comment](https://news.ycombinator.com/item?id=12759605) - This HN comment explains the problem with SEO and search engines other than Google. 206 | - [Tweet from Google employee](https://twitter.com/Paul_Kinlan/status/1039852756113080320) - Tweet about delayed Google indexing for pure client-side. 207 | - [What's Server Side Rendering and do I need it?](https://medium.com/@baphemot/whats-server-side-rendering-and-do-i-need-it-cb42dc059b38) - Good summary about the issues of JavaScript-generated-content. 208 | - [Deliver search-friendly JavaScript-powered websites (Google I/O '18)](https://www.youtube.com/watch?v=PFwUbgvpdaQ) - Talk that mentions how the Google crawler executes JavaScript. Main take away: Google does index JavaScript-generated-content but with a delay. 209 | 210 | ### How to implement SSR 211 | 212 | - [The Complete Guide for SSR with Vue](https://ssr.vuejs.org/) - Official guide. 213 | - [Reactjs SSR Tips and Tricks](https://medium.com/@atahani/reactjs-ssr-tips-and-tricks-be9edff5b7bb) 214 | - [Server-side rendering with create-react-app, code-splitting, preloaded data, React Router, Helmet, Redux, and Thunk](https://medium.com/@cereallarceny/server-side-rendering-in-create-react-app-with-all-the-goodies-without-ejecting-4c889d7db25e) - Walkthrough of implementing a SSR app based on CRA (without having ejected). 215 | 216 | ### General discussion 217 | 218 | - [The Benefits of Server Side Rendering Over Client Side Rendering](https://medium.com/walmartlabs/the-benefits-of-server-side-rendering-over-client-side-rendering-5d07ff2cefe8) 219 | 220 | 221 | 222 |
223 |
224 | 225 | ## Tools 226 | 227 | #### Contents 228 | 229 | - [React](#react) 230 | - [SSR](#ssr) 231 | - [SSG](#ssg) 232 | - [Pre-Rendering](#pre-rendering) 233 | - [Vue](#vue) 234 | - [SSR](#ssr-1) 235 | - [SSG](#ssg-1) 236 | - [Pre-Rendering](#pre-rendering-1) 237 | - [Angular](#angular) 238 | - [SSR](#ssr-2) 239 | - [Pre-Rendering](#pre-rendering-2) 240 | - [View Library Agnostic](#view-library-agnostic) 241 | - [SSG](#ssg-2) 242 | - [Pre-Rendering](#pre-rendering-3) 243 | 244 | 245 | 246 | 247 |
248 | 249 | ### React 250 | 251 | #### SSR 252 | 253 | ##### Frameworks 254 | 255 | - [Next.js](https://github.com/zeit/next.js#readme) - The most popular SSR tool. 256 | - [After.js](https://github.com/jaredpalmer/after.js#readme) - Similar to Next.js but with routing based on React Router. 257 | - [React Server](https://github.com/redfin/react-server#readme) 258 | - [Reframe](https://github.com/reframejs/reframe#readme) - Flexible web framework. It does SSR by default and can be used as SSG. 259 | - [Fusion.js](https://github.com/fusionjs) - Plugin-based universal web framework maintained by Uber. 260 | 261 | ##### Libraries 262 | 263 | - [Goldpage](https://github.com/reframejs/goldpage) - A do-one-thing-do-it-well library that supports all app types; "SPA", "SSR", "Static Website", etc. 264 | - [Razzle](https://github.com/jaredpalmer/razzle#readme) - Handles the building. You do the rest. 265 | - [React Universal Component](https://github.com/faceyspacey/react-universal-component#readme) - Utility to code split your SSR app. 266 | - [Rogue.js](https://github.com/alidcastano/rogue.js#readme) - SSR utilities focused on flexibility. First-class support for React Router, Apollo GraphQL, Redux, Emotion, and Styled-Components. The build step is up to you (but you can use Razzle.) 267 | 268 | ##### Boilerplates 269 | 270 | - [cra-ssr](https://github.com/cereallarceny/cra-ssr#readme) - SSR app boilerplate based on CRA (without having ejected). 271 | 272 | #### SSG 273 | 274 | - [Gatsby.js](https://github.com/gatsbyjs/gatsby#readme) - SSG based on React and GraphQL. 275 | - [React Static](https://github.com/nozzle/react-static#readme) - SSG based on React and focused on simplicity. 276 | - [Goldpage](https://github.com/reframejs/goldpage) - A do-one-thing-do-it-well library that supports all app types; "SPA", "SSR", "Static Website", etc. 277 | - [Phenomic](https://github.com/phenomic/phenomic#readme) - SSG based on a flexible plugin system. 278 | - [Next.js](https://github.com/zeit/next.js#readme) - Although primarily focused on SSR, Next.js can also generate static sites. 279 | - [Reframe](https://github.com/reframejs/reframe#readme) - Flexible web framework. It does SSR by default and can be used as SSG. 280 | 281 | #### Pre-Rendering 282 | 283 | #### Dynamic Pre-Rendering 284 | 285 | Automatically and regularly render your deployed website to HTML. 286 | 287 | ##### SaaS 288 | 289 | - [Prerender.io](https://prerender.io/) 290 | - [SEO4Ajax](https://www.seo4ajax.com/) 291 | - [Prerender.cloud](https://www.prerender.cloud/) 292 | - [SEO.js](http://getseojs.com/) 293 | - [BromBone](https://www.brombone.com/) 294 | 295 | ##### Libraries 296 | 297 | - [Prerender.io Node Server](https://github.com/prerender/prerender#readme) - The prerender.io Node Server is open source. 298 | 299 | #### Static Pre-Rendering 300 | 301 | *Some static pre-renderers, instead of generating HTML upon a generated DOM, directly render your pages to HTML.* 302 | 303 | - [Prerender SPA Plugin](https://github.com/chrisvfritz/prerender-spa-plugin#readme) - Uses Puppeteer to crawl & render your pages. 304 | - [react-snap](https://github.com/stereobooster/react-snap#readme) - Uses Puppeteer to crawl & render your pages. 305 | - [prep](https://github.com/prismagraphql/prep#readme) - Uses Chromeless to crawl & render your pages. 306 | - [SSG webpack plugin](https://github.com/markdalgleish/static-site-generator-webpack-plugin#readme) - Directly render your pages to HTML. You provide render functions and routes. All routes are rendered at build-time using the render functions you provided. Also has a crawl mode to use a headless browser to automatically discover your website's URLs. 307 | - [React Snapshot](https://github.com/geelen/react-snapshot#readme) - Pre-renders React apps at build-time. Uses `require('react-dom/server').renderToString` to directly render the HTML. Uses JSDOM as headless browser to automatically discover your app's URLs. 308 | 309 | 310 | 311 | 312 | 313 |
314 | 315 | ### Vue 316 | 317 | #### SSR 318 | 319 | ##### Frameworks 320 | 321 | - [Nuxt](https://github.com/nuxt/nuxt.js#readme) - Similar to Next.js but for Vue. 322 | - [Reframe](https://github.com/reframejs/reframe#readme) - Flexible web framework. It does SSR by default and can be used as SSG. 323 | 324 | ##### Libraries 325 | 326 | - [vue-server-renderer](https://www.npmjs.com/package/vue-server-renderer) - Official library for SSR with Vue. 327 | - [Goldpage](https://github.com/reframejs/goldpage) - A do-one-thing-do-it-well library that supports all app types; "SPA", "SSR", "Static Website", etc. 328 | 329 | #### SSG 330 | 331 | - [Phenomic](https://github.com/phenomic/phenomic#readme) - SSG based on a flexible plugin system. 332 | - [Reframe](https://github.com/reframejs/reframe#readme) - Flexible web framework. It does SSR by default and can be used as SSG. 333 | 334 | #### Pre-Rendering 335 | 336 | #### Dynamic Pre-Rendering 337 | 338 | Automatically and regularly render your deployed website to HTML. 339 | 340 | ##### SaaS 341 | 342 | - [Prerender.io](https://prerender.io/) 343 | - [SEO4Ajax](https://www.seo4ajax.com/) 344 | - [Prerender.cloud](https://www.prerender.cloud/) 345 | - [SEO.js](http://getseojs.com/) 346 | - [BromBone](https://www.brombone.com/) 347 | 348 | ##### Libraries 349 | 350 | - [Prerender.io Node Server](https://github.com/prerender/prerender#readme) - The prerender.io Node Server is open source. 351 | 352 | #### Static Pre-Rendering 353 | 354 | *Some static pre-renderers, instead of generating HTML upon a generated DOM, directly render your pages to HTML.* 355 | 356 | - [Prerender SPA Plugin](https://github.com/chrisvfritz/prerender-spa-plugin#readme) - Uses Puppeteer to crawl & render your pages. 357 | - [react-snap](https://github.com/stereobooster/react-snap#readme) - Uses Puppeteer to crawl & render your pages. 358 | - [prep](https://github.com/prismagraphql/prep#readme) - Uses Chromeless to crawl & render your pages. 359 | - [SSG webpack plugin](https://github.com/markdalgleish/static-site-generator-webpack-plugin#readme) - Directly render your pages to HTML. You provide render functions and routes. All routes are rendered at build-time using the render functions you provided. Also has a crawl mode to use a headless browser to automatically discover your website's URLs. 360 | 361 | 362 | 363 | 364 | 365 | 366 |
367 | 368 | ### Angular 369 | 370 | #### SSR 371 | 372 | - [Angular Universal](https://github.com/angular/universal#readme) - Official packages for SSR with Angular. 373 | 374 | #### Pre-Rendering 375 | 376 | #### Dynamic Pre-Rendering 377 | 378 | Automatically and regularly render your deployed website to HTML. 379 | 380 | ##### SaaS 381 | 382 | - [Prerender.io](https://prerender.io/) 383 | - [SEO4Ajax](https://www.seo4ajax.com/) 384 | - [Prerender.cloud](https://www.prerender.cloud/) 385 | - [SEO.js](http://getseojs.com/) 386 | - [BromBone](https://www.brombone.com/) 387 | 388 | ##### Libraries 389 | 390 | - [Prerender.io Node Server](https://github.com/prerender/prerender#readme) - The prerender.io Node Server is open source. 391 | 392 | #### Static Pre-Rendering 393 | 394 | *Some static pre-renderers, instead of generating HTML upon a generated DOM, directly render your pages to HTML.* 395 | 396 | - [Prerender SPA Plugin](https://github.com/chrisvfritz/prerender-spa-plugin#readme) - Uses Puppeteer to crawl & render your pages. 397 | - [react-snap](https://github.com/stereobooster/react-snap#readme) - Uses Puppeteer to crawl & render your pages. 398 | - [prep](https://github.com/prismagraphql/prep#readme) - Uses Chromeless to crawl & render your pages. 399 | - [SSG webpack plugin](https://github.com/markdalgleish/static-site-generator-webpack-plugin#readme) - Directly render your pages to HTML. You provide render functions and routes. All routes are rendered at build-time using the render functions you provided. Also has a crawl mode to use a headless browser to automatically discover your website's URLs. 400 | 401 | 402 | 403 | 404 |
405 | 406 | ### View Library Agnostic 407 | 408 | #### SSG 409 | 410 | - [Phenomic](https://github.com/phenomic/phenomic#readme) - SSG based on a flexible plugin system. 411 | - [Reframe](https://github.com/reframejs/reframe#readme) - Flexible web framework. It does SSR by default and can be used as SSG. 412 | 413 | #### Pre-Rendering 414 | 415 | #### Dynamic Pre-Rendering 416 | 417 | Automatically and regularly render your deployed website to HTML. 418 | 419 | ##### SaaS 420 | 421 | - [Prerender.io](https://prerender.io/) 422 | - [SEO4Ajax](https://www.seo4ajax.com/) 423 | - [Prerender.cloud](https://www.prerender.cloud/) 424 | - [SEO.js](http://getseojs.com/) 425 | - [BromBone](https://www.brombone.com/) 426 | 427 | ##### Libraries 428 | 429 | - [Prerender.io Node Server](https://github.com/prerender/prerender#readme) - The prerender.io Node Server is open source. 430 | 431 | #### Static Pre-Rendering 432 | 433 | *Some static pre-renderers, instead of generating HTML upon a generated DOM, directly render your pages to HTML.* 434 | 435 | - [Prerender SPA Plugin](https://github.com/chrisvfritz/prerender-spa-plugin#readme) - Uses Puppeteer to crawl & render your pages. 436 | - [react-snap](https://github.com/stereobooster/react-snap#readme) - Uses Puppeteer to crawl & render your pages. 437 | - [prep](https://github.com/prismagraphql/prep#readme) - Uses Chromeless to crawl & render your pages. 438 | - [SSG webpack plugin](https://github.com/markdalgleish/static-site-generator-webpack-plugin#readme) - Directly render your pages to HTML. You provide render functions and routes. All routes are rendered at build-time using the render functions you provided. Also has a crawl mode to use a headless browser to automatically discover your website's URLs. 439 | 440 | 441 | 518 | -------------------------------------------------------------------------------- /readme.template.md: -------------------------------------------------------------------------------- 1 | # Awesome Universal Rendering [![Awesome](https://awesome.re/badge-flat.svg)](https://awesome.re) 2 | 3 | Awesome resources about universal rendering: 4 | - **Introduction** 5 |
6 | Explains why universal rendering is beneficial, 7 | the different techniques of doing universal rendering (SSR, SSG, pre-rendering) 8 | and when to use what technique. 9 | - **Learning Material** 10 | - SEO benefits of universal rendering 11 | - Performance benefits of SSR 12 | - How to implement SSR 13 | - **Tools** 14 | - SSR frameworks & libraries 15 | - Pre-rendering services & tools 16 | - Static site generators 17 | 18 |
19 | 20 | #### Contents 21 | 22 | - [Introduction](#introduction) 23 | - [Learning Material](#learning-material) 24 | - [Tools](#tools) 25 | 26 |
27 | 28 | ## Introduction 29 | 30 | Modern view libraries (React, Vue, Angular, etc.) render views to the DOM in the browser but they can as well render views to HTML on the server. 31 | This capability can be used to render the same view twice: 32 | First to HTML then again to the DOM. (Re-rendering the view in the browser is called *hydrating*.) 33 | This practice is called *universal rendering* (aka isomorphic rendering). 34 | 35 | Universal rendering leads to improvements in SEO, SMO and performance. 36 | 37 | There are several techniques to achieve universal rendering: 38 | 39 | - Server-Side Rendering (SSR) 40 | - Static Site Generators (SSG) 41 | - Pre-Rendering 42 | 43 | In the following we explain these techniques and the benefits of universal rendering. 44 | 45 | - [Benefits](#benefits) 46 | - [Techniques](#techniques) 47 | 48 | ### Benefits 49 | 50 | #### SEO 51 | 52 | Modern frontends (React, Vue, Angular, ...) use JavaScript to load and display content. 53 | Such JavaScript-generated-content is invisible to crawlers that don't execute JavaScript. 54 | Most crawlers (search engines and social sites) don't execute JavaScript. 55 | 56 | The Google crawler is 57 | the only one that can successfully index JavaScript-generated-content. 58 | But it has limitations. 59 | (Mainly around delayed indexing and client-side routing, 60 | see [Learning Material](#learning-material).) 61 | 62 | If you want your content to be crawled by all other search engines (Bing, Baidu, DuckDuckGo, etc.), then your content needs to be included in your website's HTML. 63 | 64 | #### SMO 65 | 66 | The crawler of social media sites (Facebook, Twitter, ...) don't execute JavaScript and rely on HTML exclusively. 67 | 68 | If you want your website to be correctly previewed when a user shares your website, then the corresponding information needs to be included in your website's HTML. 69 | 70 | (SMO means "Social Media Optimization".) 71 | 72 | #### Performance 73 | 74 | Rendering your website's pages to HTML decreases the perceived loading time: 75 | Once the HTML is loaded, content can already be displayed before any JavaScript is loaded/executed. 76 | 77 | The improvement is considerable on mobile 78 | where loading and executing JavaScript is much slower. 79 | 80 | ### Techniques 81 | 82 | Server-Side Rendering (SSR), Pre-Rendering, and Static Site Generators (SSG) are techniques to render JavaScript-generated-content to HTML. 83 | Making the content visible to crawlers and improving performance. 84 | 85 | There are two ways to render JavaScript-generated-content to HTML: 86 | 87 | - **Directly render to HTML** 88 |
89 | Modern view libraries (React, Vue, Angular, ...) can render views to HTML (in addition to be able to render views to the DOM). 90 | (E.g. a React component can be rendered to HTML with `require('react-dom/server').renderToStaticMarkup()`.) 91 | - **Render to HTML via headless browser** 92 |
93 | A headless browser runs your website's JavaScript, 94 | the website's pages are rendered to the DOM of the headless browser, 95 | and HTML is automatically generated from the resulting DOM. 96 | 97 | Leading to the following techniques: 98 | 99 | - **Server-Side Rendering (SSR)** 100 |
101 | Directly render your website's pages to HTML at request-time: 102 | Every time a user requests a page, the server renders the page directly to HTML. 103 |
104 | SSR is the most reliable option if your HTML changes frequently. 105 | (If your website's content may change after deploy-time, 106 | e.g. if you website's content is generated by users.) 107 | - **Pre-Rendering** 108 |
109 | A headless browser crawls your website, executes the website's JavaScript, and generates HTML upon the resulting DOM. 110 | - **Static Site Generators (SSG)** 111 |
112 | A static site is a website that doesn't have any server code: 113 | The website is composed of static browser assets only (HTML, CSS, JavaScript, images, fonts, etc.). 114 | Some SSG are able to render your views to HTML at build-time: 115 | When your website is built, each page is rendered to a HTML file that includes your page's content. 116 |
117 | If your content only changes at deploy-time, then using a SSG is an option. 118 | 119 | 120 | 121 |
122 |
123 | 124 | ## Learning Material 125 | 126 | ### SEO/SMO 127 | 128 | - [Hacker News Comment](https://news.ycombinator.com/item?id=12759605) - This HN comment explains the problem with SEO and search engines other than Google. 129 | - [Tweet from Google employee](https://twitter.com/Paul_Kinlan/status/1039852756113080320) - Tweet about delayed Google indexing for pure client-side. 130 | - [What's Server Side Rendering and do I need it?](https://medium.com/@baphemot/whats-server-side-rendering-and-do-i-need-it-cb42dc059b38) - Good summary about the issues of JavaScript-generated-content. 131 | - [Deliver search-friendly JavaScript-powered websites (Google I/O '18)](https://www.youtube.com/watch?v=PFwUbgvpdaQ) - Talk that mentions how the Google crawler executes JavaScript. Main take away: Google does index JavaScript-generated-content but with a delay. 132 | 133 | ### How to implement SSR 134 | 135 | - [The Complete Guide for SSR with Vue](https://ssr.vuejs.org/) - Official guide. 136 | - [Reactjs SSR Tips and Tricks](https://medium.com/@atahani/reactjs-ssr-tips-and-tricks-be9edff5b7bb) 137 | - [Server-side rendering with create-react-app, code-splitting, preloaded data, React Router, Helmet, Redux, and Thunk](https://medium.com/@cereallarceny/server-side-rendering-in-create-react-app-with-all-the-goodies-without-ejecting-4c889d7db25e) - Walkthrough of implementing a SSR app based on CRA (without having ejected). 138 | 139 | ### General discussion 140 | 141 | - [The Benefits of Server Side Rendering Over Client Side Rendering](https://medium.com/walmartlabs/the-benefits-of-server-side-rendering-over-client-side-rendering-5d07ff2cefe8) 142 | 143 | 144 | 145 |
146 |
147 | 148 | ## Tools 149 | 150 | #### Contents 151 | 152 | - [React](#react) 153 | - [SSR](#ssr) 154 | - [SSG](#ssg) 155 | - [Pre-Rendering](#pre-rendering) 156 | - [Vue](#vue) 157 | - [SSR](#ssr-1) 158 | - [SSG](#ssg-1) 159 | - [Pre-Rendering](#pre-rendering-1) 160 | - [Angular](#angular) 161 | - [SSR](#ssr-2) 162 | - [Pre-Rendering](#pre-rendering-2) 163 | - [View Library Agnostic](#view-library-agnostic) 164 | - [SSG](#ssg-2) 165 | - [Pre-Rendering](#pre-rendering-3) 166 | 167 | 168 | 169 | 170 |
171 | 172 | ### React 173 | 174 | #### SSR 175 | 176 | ##### Frameworks 177 | 178 | - [Next.js](https://github.com/zeit/next.js#readme) - The most popular SSR tool. 179 | - [After.js](https://github.com/jaredpalmer/after.js#readme) - Similar to Next.js but with routing based on React Router. 180 | - [React Server](https://github.com/redfin/react-server#readme) 181 | !INLINE ./reframe.md --hide-source-path 182 | - [Fusion.js](https://github.com/fusionjs) - Plugin-based universal web framework maintained by Uber. 183 | 184 | ##### Libraries 185 | 186 | - [Goldpage](https://github.com/reframejs/goldpage) - A do-one-thing-do-it-well library that supports all app types; "SPA", "SSR", "Static Website", etc. 187 | - [Razzle](https://github.com/jaredpalmer/razzle#readme) - Handles the building. You do the rest. 188 | - [React Universal Component](https://github.com/faceyspacey/react-universal-component#readme) - Utility to code split your SSR app. 189 | - [Rogue.js](https://github.com/alidcastano/rogue.js#readme) - SSR utilities focused on flexibility. First-class support for React Router, Apollo GraphQL, Redux, Emotion, and Styled-Components. The build step is up to you (but you can use Razzle.) 190 | 191 | ##### Boilerplates 192 | 193 | - [cra-ssr](https://github.com/cereallarceny/cra-ssr#readme) - SSR app boilerplate based on CRA (without having ejected). 194 | 195 | #### SSG 196 | 197 | - [Gatsby.js](https://github.com/gatsbyjs/gatsby#readme) - SSG based on React and GraphQL. 198 | - [React Static](https://github.com/nozzle/react-static#readme) - SSG based on React and focused on simplicity. 199 | - [Goldpage](https://github.com/reframejs/goldpage) - A do-one-thing-do-it-well library that supports all app types; "SPA", "SSR", "Static Website", etc. 200 | - [Phenomic](https://github.com/phenomic/phenomic#readme) - SSG based on a flexible plugin system. 201 | - [Next.js](https://github.com/zeit/next.js#readme) - Although primarily focused on SSR, Next.js can also generate static sites. 202 | !INLINE ./reframe.md --hide-source-path 203 | 204 | #### Pre-Rendering 205 | 206 | !INLINE ./prerender-dynamic.md --hide-source-path 207 | 208 | !INLINE ./prerender-static.md --hide-source-path 209 | - [React Snapshot](https://github.com/geelen/react-snapshot#readme) - Pre-renders React apps at build-time. Uses `require('react-dom/server').renderToString` to directly render the HTML. Uses JSDOM as headless browser to automatically discover your app's URLs. 210 | 211 | 212 | 213 | 214 | 215 |
216 | 217 | ### Vue 218 | 219 | #### SSR 220 | 221 | ##### Frameworks 222 | 223 | - [Nuxt](https://github.com/nuxt/nuxt.js#readme) - Similar to Next.js but for Vue. 224 | !INLINE ./reframe.md --hide-source-path 225 | 226 | ##### Libraries 227 | 228 | - [vue-server-renderer](https://www.npmjs.com/package/vue-server-renderer) - Official library for SSR with Vue. 229 | - [Goldpage](https://github.com/reframejs/goldpage) - A do-one-thing-do-it-well library that supports all app types; "SPA", "SSR", "Static Website", etc. 230 | 231 | #### SSG 232 | 233 | - [Phenomic](https://github.com/phenomic/phenomic#readme) - SSG based on a flexible plugin system. 234 | !INLINE ./reframe.md --hide-source-path 235 | 236 | #### Pre-Rendering 237 | 238 | !INLINE ./prerender-dynamic.md --hide-source-path 239 | 240 | !INLINE ./prerender-static.md --hide-source-path 241 | 242 | 243 | 244 | 245 | 246 | 247 |
248 | 249 | ### Angular 250 | 251 | #### SSR 252 | 253 | - [Angular Universal](https://github.com/angular/universal#readme) - Official packages for SSR with Angular. 254 | 255 | #### Pre-Rendering 256 | 257 | !INLINE ./prerender-dynamic.md --hide-source-path 258 | 259 | !INLINE ./prerender-static.md --hide-source-path 260 | 261 | 262 | 263 | 264 |
265 | 266 | ### View Library Agnostic 267 | 268 | #### SSG 269 | 270 | - [Phenomic](https://github.com/phenomic/phenomic#readme) - SSG based on a flexible plugin system. 271 | !INLINE ./reframe.md --hide-source-path 272 | 273 | #### Pre-Rendering 274 | 275 | !INLINE ./prerender-dynamic.md --hide-source-path 276 | 277 | !INLINE ./prerender-static.md --hide-source-path 278 | 279 | -------------------------------------------------------------------------------- /reframe.md: -------------------------------------------------------------------------------- 1 | - [Reframe](https://github.com/reframejs/reframe#readme) - Flexible web framework. It does SSR by default and can be used as SSG. 2 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@brillout/find-package-files@^0.1.0": 6 | version "0.1.1" 7 | resolved "https://registry.yarnpkg.com/@brillout/find-package-files/-/find-package-files-0.1.1.tgz#ee4e971af549b7bd4ab248c88c6b042b37aa4487" 8 | dependencies: 9 | find-up "^2.1.0" 10 | glob-gitignore "^1.0.6" 11 | ignore "^3.3.7" 12 | reassert "^1.1.8" 13 | 14 | "@brillout/format-text@^0.1.0": 15 | version "0.1.1" 16 | resolved "https://registry.yarnpkg.com/@brillout/format-text/-/format-text-0.1.1.tgz#13cd49bf966fc82727c0c62e003fcdc05fb052f8" 17 | 18 | "@brillout/mdocs@^0.1.20": 19 | version "0.1.20" 20 | resolved "https://registry.yarnpkg.com/@brillout/mdocs/-/mdocs-0.1.20.tgz#d04f74139b93876350d8137662a89bf8b756e7ae" 21 | dependencies: 22 | "@brillout/find-package-files" "^0.1.0" 23 | find-up "^2.1.0" 24 | reassert "^1.1.8" 25 | 26 | babel-runtime@^6.26.0: 27 | version "6.26.0" 28 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" 29 | dependencies: 30 | core-js "^2.4.0" 31 | regenerator-runtime "^0.11.0" 32 | 33 | balanced-match@^1.0.0: 34 | version "1.0.0" 35 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 36 | 37 | brace-expansion@^1.1.7: 38 | version "1.1.11" 39 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 40 | dependencies: 41 | balanced-match "^1.0.0" 42 | concat-map "0.0.1" 43 | 44 | concat-map@0.0.1: 45 | version "0.0.1" 46 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 47 | 48 | core-js@^2.4.0: 49 | version "2.5.7" 50 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" 51 | 52 | find-up@^2.1.0: 53 | version "2.1.0" 54 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" 55 | dependencies: 56 | locate-path "^2.0.0" 57 | 58 | fs.realpath@^1.0.0: 59 | version "1.0.0" 60 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 61 | 62 | glob-gitignore@^1.0.6: 63 | version "1.0.6" 64 | resolved "https://registry.yarnpkg.com/glob-gitignore/-/glob-gitignore-1.0.6.tgz#70e3554a257f1381df22ec56c77fe88075930d3a" 65 | dependencies: 66 | babel-runtime "^6.26.0" 67 | glob "^7.1.2" 68 | ignore "^3.3.7" 69 | lodash.difference "^4.5.0" 70 | lodash.union "^4.6.0" 71 | make-array "^1.0.2" 72 | util.inherits "^1.0.3" 73 | 74 | glob@^7.1.2: 75 | version "7.1.2" 76 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 77 | dependencies: 78 | fs.realpath "^1.0.0" 79 | inflight "^1.0.4" 80 | inherits "2" 81 | minimatch "^3.0.4" 82 | once "^1.3.0" 83 | path-is-absolute "^1.0.0" 84 | 85 | ignore@^3.3.7: 86 | version "3.3.10" 87 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" 88 | 89 | inflight@^1.0.4: 90 | version "1.0.6" 91 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 92 | dependencies: 93 | once "^1.3.0" 94 | wrappy "1" 95 | 96 | inherits@2: 97 | version "2.0.3" 98 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 99 | 100 | locate-path@^2.0.0: 101 | version "2.0.0" 102 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" 103 | dependencies: 104 | p-locate "^2.0.0" 105 | path-exists "^3.0.0" 106 | 107 | lodash.difference@^4.5.0: 108 | version "4.5.0" 109 | resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" 110 | 111 | lodash.union@^4.6.0: 112 | version "4.6.0" 113 | resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" 114 | 115 | make-array@^1.0.2: 116 | version "1.0.5" 117 | resolved "https://registry.yarnpkg.com/make-array/-/make-array-1.0.5.tgz#326a7635c756a9f61ce0b2a6fdd5cc3460419bcb" 118 | 119 | minimatch@^3.0.4: 120 | version "3.0.4" 121 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 122 | dependencies: 123 | brace-expansion "^1.1.7" 124 | 125 | once@^1.3.0: 126 | version "1.4.0" 127 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 128 | dependencies: 129 | wrappy "1" 130 | 131 | p-limit@^1.1.0: 132 | version "1.3.0" 133 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" 134 | dependencies: 135 | p-try "^1.0.0" 136 | 137 | p-locate@^2.0.0: 138 | version "2.0.0" 139 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" 140 | dependencies: 141 | p-limit "^1.1.0" 142 | 143 | p-try@^1.0.0: 144 | version "1.0.0" 145 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" 146 | 147 | path-exists@^3.0.0: 148 | version "3.0.0" 149 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 150 | 151 | path-is-absolute@^1.0.0: 152 | version "1.0.1" 153 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 154 | 155 | reassert@^1.1.8: 156 | version "1.1.13" 157 | resolved "https://registry.yarnpkg.com/reassert/-/reassert-1.1.13.tgz#0c65d70a80310ae63e172bef1781b714fa3906d6" 158 | dependencies: 159 | "@brillout/format-text" "^0.1.0" 160 | 161 | regenerator-runtime@^0.11.0: 162 | version "0.11.1" 163 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" 164 | 165 | util.inherits@^1.0.3: 166 | version "1.0.3" 167 | resolved "https://registry.yarnpkg.com/util.inherits/-/util.inherits-1.0.3.tgz#a9c626a0d06d34829d47ba56cab1278d745f9ce6" 168 | 169 | wrappy@1: 170 | version "1.0.2" 171 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 172 | --------------------------------------------------------------------------------