rollthecloudinc / quell

Climate aware CMS breaking web apps free from carbon emissions.
https://demo.carbonfreed.app/pages/create-panel-page
GNU General Public License v3.0
14 stars 1 forks source link

Serverside Rendering+ #58

Open windbeneathyourwings opened 3 years ago

windbeneathyourwings commented 3 years ago

Enable server side rendering to build pages and easily host static assets for things like landing pages. An example use case for this is for restaurant menus that would be accessed via QR code. Restaurant designers could build the menu using druid and host using optimized static minus assets instead of including entire angular application or even needing javascript.

This a two fold process.

1.) server side render panel page 2.) Provide process to easily deploy page or collection of pages as independent stand alone rendered assets.

We can also begin to talk about possibility of using this to build emails, PDFs, and other digital assets as well.

terminology:

server side+ : refers to taking server side rendering on step further and only hosting rendered assets ie. static html without javascript optionally.

static- : hosting optimized, minimal static assets like just html rather than gigantic javascript application as static site.

Stand alone interface could be created to manage panel pages as rendered asset collections or site of collections of these pages. Where the panel pages are analyzed for dependencies on other pages and all those pages are converted into a standalone static- site.

So panel pages/druid would effectively become a suite for multiple publishing outlets


cloud solutions

Options to deploy panel pages. deployment targets

The project remains open source but also provides cloud / sass model that adds the ability to use this in the cloud and deploy to suite of vendors like aws, azure, etc.

paid model could also provide stand alone build environments. Doing this would allow distribution managers to add source code and plugins.

The idea would be to "install" npm modules or perhaps plugins directory from npm or plugin repo perhaps.

There could be a plugin marketplace that would provide "plugins" basically angular modules that enhance and add functionality to the base platform though plugins, hooks, and other extension point without altering code or knowing how to code.

All interfaces related to the suite would be built using panel pages themselves. - cloud dashboard, marketplace, demo, etc.


What is the potential to further optimize rendered html and assets. Effectively a second phase of rendering that further optimizes the raw rendered page.


Universal angular builder can be feed a list of pages to pre-render. The pre-rendered pages could be deployed to s3. This might be perfect for stringing together all the pages for websites and/or landing pages.

Next steps for this are probably to look into some of the below issues a bit more with some pages like those that use virtual list and demo hitting the marvel api not rendering the list item content statically. Beyond debugging that though I think this can be loved into a lambda and deployed. Once that is done server-side rendering can be used in demo instead of hosting from s3.

windbeneathyourwings commented 3 years ago

https://samvloeberghs.be/posts/angular-v9-universal-ssr-and-prerendering-out-of-the-box/

windbeneathyourwings commented 3 years ago

SSR has been added. However, I noticed an issue. The rendering process is not waiting for dynamic content. Therefore, the rendered html does not include any real valuable data. The rendered html just includes the layout components right now.

  | <!DOCTYPE html><html lang="en"><head>
-- | --
  | <meta charset="utf-8">
  | <title>Ipe</title>
  | <base href="/">
  | <meta name="viewport" content="width=device-width, initial-scale=1">
  | <link rel="icon" type="image/x-icon" href="favicon.ico">
  | <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  | <!-- required for integration with public api bridge -->
  | <script type="text/javascript">var bridge;</script>
  | <style ng-transition="serverApp">.outlet-wrapper[_ngcontent-sc396] {
  | height: 100%;
  | }
  | /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInByb2plY3RzL2lwZS9zcmMvYXBwL2FwcC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQUE7QUFDRiIsImZpbGUiOiJwcm9qZWN0cy9pcGUvc3JjL2FwcC9hcHAuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyIub3V0bGV0LXdyYXBwZXIge1xuICBoZWlnaHQ6IDEwMCU7XG59XG4iXX0= */</style><style ng-transition="serverApp"></style><style ng-transition="serverApp">[_nghost-sc455]     gridster, [_nghost-sc455]     gridster-item{background-color:#fff}</style><style ng-transition="serverApp">.render-panel[_ngcontent-sc454], [_nghost-sc454]{height:100%}</style><style class="flex-layout-ssr">@media all {.flex-layout-0 {height:100%;min-height:100%;min-width:100%;width:100%;-webkit-flex-direction:column;box-sizing:border-box;display:flex;flex-direction:column;}.flex-layout-1 {height:100%;min-height:100%;min-width:100%;width:100%;-webkit-flex-direction:column;box-sizing:border-box;display:flex;flex-direction:column;}.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-3 {-webkit-flex-direction:row;box-sizing:border-box;display:flex;flex-direction:row;height:100%;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-5 {height:auto;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 600px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 960px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 1280px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 1920px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 1920px) and (max-width: 4999.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (max-width: 1919.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 1280px) and (max-width: 1919.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (max-width: 1279.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 960px) and (max-width: 1279.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (max-width: 959.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 600px) and (max-width: 959.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (max-width: 599.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}@media screen and (min-width: 0px) and (max-width: 599.9px) {.flex-layout-2 {-webkit-flex:  0.000000001px;box-sizing:border-box;flex:  0.000000001px;}.flex-layout-4 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:100%;}.flex-layout-6 {-webkit-flex:1 1 100%;box-sizing:border-box;flex:1 1 100%;max-width:50%;}.flex-layout-3 {height:100%;}.flex-layout-5 {height:auto;}.flex-layout-7 {height:auto;}}</style></head>
  | <body>
  | <app-root _nghost-sc396="" ng-version="10.1.5"><div _ngcontent-sc396="" fxlayout="column" fxfill="" ng-reflect-fx-layout="column" class="flex-layout-0"><div _ngcontent-sc396=""><!--bindings={
  | "ng-reflect-ng-if": "false"
  | }--><!--bindings={
  | "ng-reflect-ng-if": "false"
  | }--></div><div _ngcontent-sc396="" class="outlet-wrapper"><router-outlet _ngcontent-sc396=""></router-outlet><classifieds-ui-panel-page-router _nghost-sc457=""><classifieds-ui-panel-page _ngcontent-sc457="" _nghost-sc455="" class="panel-page" ng-reflect-id="633098ea-298e-11ec-a6c3-461d63"><!--bindings={
  | "ng-reflect-ng-switch-case": "grid"
  | }--><!--bindings={
  | "ng-reflect-ng-switch-case": "gridless"
  | }--><!--bindings={
  | "ng-reflect-ng-switch-case": "form"
  | }--><classifieds-ui-flex-layout-renderer><classifieds-ui-flex-layout _nghost-sc420="" ng-reflect-dashboard="[object Object],[object Object" ng-reflect-layout-setting="[object Object]" ng-reflect-row-settings="[object Object]" ng-reflect-column-settings="[object Object],[object Object"><div _ngcontent-sc420="" fxfill="" ng-reflect-fx-layout="column" class="flex-layout-1"><div _ngcontent-sc420="" ng-reflect-fx-flex="  " class="flex-layout-2"><div _ngcontent-sc420="" ng-reflect-fx-layout="row" ng-reflect-ng-style="[object Object]" style="height:100%;" class="flex-layout-3"><div _ngcontent-sc420="" ng-reflect-fx-flex="100" class="flex-layout-4"><p _ngcontent-sc420="" hidden="">row: 0 \| column: 0 \| size: 100</p><div _ngcontent-sc420="" class="grid-item-inner flex-layout-5" ng-reflect-ng-style="[object Object]" style="height:auto;"><classifieds-ui-render-panel _ngcontent-sc455="" _nghost-sc454="" ng-reflect-name="0" ng-reflect-panel="[object Object]" ng-reflect-nested="false" ng-reflect-contexts="[object Object],[object Object" ng-reflect-display-type="page" ng-reflect-index-position="0" ng-reflect-css="[object Object]" ng-reflect-ancestory="" data-index="0" class="panel-0 panel ng-untouched ng-pristine ng-valid"><div _ngcontent-sc454="" class="render-panel"><!--container--><!--ng-container--><!--bindings={}--></div></classifieds-ui-render-panel><!--bindings={
  | "ng-reflect-name": "panels"
  | }--><!--ng-container--><!--bindings={
  | "ng-reflect-ng-template-outlet-context": "[object Object]"
  | }--><!--bindings={
  | "ng-reflect-ng-template-outlet-context": "[object Object]"
  | }--></div></div><div _ngcontent-sc420="" ng-reflect-fx-flex="50" class="flex-layout-6"><p _ngcontent-sc420="" hidden="">row: 0 \| column: 1 \| size: 50</p><div _ngcontent-sc420="" class="grid-item-inner flex-layout-7" ng-reflect-ng-style="[object Object]" style="height:auto;"><classifieds-ui-render-panel _ngcontent-sc455="" _nghost-sc454="" ng-reflect-name="1" ng-reflect-panel="[object Object]" ng-reflect-nested="false" ng-reflect-contexts="[object Object],[object Object" ng-reflect-display-type="page" ng-reflect-index-position="1" ng-reflect-css="[object Object]" ng-reflect-ancestory="" data-index="1" class="panel-1 panel ng-untouched ng-pristine ng-valid"><div _ngcontent-sc454="" class="render-panel"><!--container--><!--ng-container--><!--bindings={}--></div></classifieds-ui-render-panel><!--bindings={
  | "ng-reflect-name": "panels"
  | }--><!--ng-container--><!--bindings={
  | "ng-reflect-ng-template-outlet-context": "[object Object]"
  | }--><!--bindings={
  | "ng-reflect-ng-template-outlet-context": "[object Object]"
  | }--></div></div><!--bindings={
  | "ng-reflect-loop": "2"
  | }--></div></div><!--bindings={
  | "ng-reflect-loop": "1"
  | }--></div></classifieds-ui-flex-layout></classifieds-ui-flex-layout-renderer><!--container--><!--ng-container--><!--ng-container--><!--bindings={
  | "ng-reflect-ng-switch-case": "page"
  | }--><!--ng-container--><!--ng-container--><!--bindings={
  | "ng-reflect-ng-switch-case": "split"
  | }--><!--ng-container--><!--container--></classifieds-ui-panel-page></classifieds-ui-panel-page-router><!--container--></div></div></app-root>
  | <script src="runtime.js" defer=""></script><script src="polyfills.js" defer=""></script><script src="styles.js" defer=""></script><script src="scripts.js" defer=""></script><script src="vendor.js" defer=""></script><script src="main.js" defer=""></script>
  |  
  | </body></html>
windbeneathyourwings commented 3 years ago

It appears render panels are all empty.

windbeneathyourwings commented 3 years ago

I think this issue is caused by the api url failing due to being a https request.

https://github.com/angular/universal/issues/856

windbeneathyourwings commented 3 years ago

This page renders properly once the virtual list style is removed.

http://localhost:4000/adlistv7/realestate

windbeneathyourwings commented 3 years ago

This does still appear to be a problem when a style like virtual list is used. The list is displayed without content.

windbeneathyourwings commented 3 years ago

Does not appear to be a problem using the tabs style and that uses the style handler.

http://localhost:4000/addetailv3/x/691733b2-a9d3-11ea-99f3-7e44960cbab9

I think it might be an issue isolated to the virtual list.

windbeneathyourwings commented 3 years ago

Thoughts regarding automated deployment of pre-rendered pages.

When panel page json object pushed to s3 kick off process to deploy page as stand alone site. This will probably be accomplished via event bridge to initiate a a docker in docker build for the panel page. Once built we need to figure out the best means of persisting the build assets to s3. Also possibly any post deployment steps necessary like automating cloud front distributions since these buckets will not be publicly accessible.

windbeneathyourwings commented 3 years ago

I wonder if its possible to deploy a group of pages as a website so that they share the same client side javascript can navigated without a page load, share state info between route changes.

windbeneathyourwings commented 3 years ago

I'm not necessarily sure the best way to kick of this process.

A year or so back I worked through most of the issues related to deploying the code. However, that work is for gitlab. So does it make sense to stick with gitlab. If sticking with gitlab what is the best way to kick off build processes without replicating s3 structure to trigger builds when adding/editing panel pages.

Investigate alternative solutions for ci/cd using docker-in-docker.

windbeneathyourwings commented 2 years ago

commands:

ng run ipe:build
ng run ipe:server --configuration="dev"
node bin/ipe.js

Application runs on localhost port 4000.