marko icon indicating copy to clipboard operation
marko copied to clipboard

Include backend section into .marko template to compile into AWS Lambda function

Open sirceljm opened this issue 7 years ago • 4 comments

New Feature

Compile .marko components into AWS Lambda function

Description

class {
    --> get data from backend {} here somehow
    sayHi() {
        alert(`Hi!`);
    }
}
 
backend {
var AWS = require("aws-sdk");

AWS.config.update({
  region: "us-west-2",
  endpoint: "http://localhost:8000"
});

var docClient = new AWS.DynamoDB.DocumentClient()

var table = "Movies";

var year = 2015;
var title = "The Big New Movie";

var params = {
    TableName: table,
    Key:{
        "year": year,
        "title": title
    }
};

docClient.get(params, function(err, data) {
    if (err) {
        console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
    } else {
        console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
    }
});
}

<button on-click('sayHi')>Click me!</button>

Write a backend section inside .marko template. This section then gets compiled and executed in AWS Lambda function before AWS Lambda function renders the static content. Multiple such sections of marko components included into one webpage could also get combined and optimized. For example caching same API calls would be a simple optimization.

Context

Instead of just generating static files we could generate AWS lambda function which would first execute the backend code and then serve the generated HTML. This way users could call backend services separetely inside each .marko component template which would simplify development a lot.

Possible Implementation

Open Questions

I would like to start working on this feature but would need general guidance and pointers. Is it possible to do this with a plugin or would it be wiser to change the markojs core.

Is this something you're interested in working on?

Yes

sirceljm avatar Jul 12 '17 11:07 sirceljm

If I am understanding you correctly then that is already supported since Marko supports async rendering (and thus fetching data from the backend asynchronously during rendering):

import AWS from "aws-sdk";

static {
  // This code will run one when the template is loaded
  AWS.config.update({
    region: "us-west-2",
    endpoint: "http://localhost:8000"
  });
}

class {
  sayHi() {
    alert(`Hi!`);
  }

  getMovieData() {
    return new Promise((resolve, reject) => {
      var docClient = new AWS.DynamoDB.DocumentClient()

      var table = "Movies";

      var year = 2015;
      var title = "The Big New Movie";

      var params = {
        TableName: table,
        Key: {
          "year": year,
          "title": title
        }
      };

      docClient.get(params, function(err, data) {
        if (err) {
          console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
          return reject(err);
        } else {
          return resolve(data);
        }
      });
    });
  }
}

<div>
  <await(movieData from component.getMovieData())>
    <ul>
      <li>Director: ${movieData.director}</li>
    </ul>
  </await>
  
  <button on-click('sayHi')>Click me!</button>
</div>

Does that work for you?

patrick-steele-idem avatar Jul 12 '17 13:07 patrick-steele-idem

Hi, this is really great. One more question. Would the code in static show up in frontend - for example could I put my AWS keys in there.

Thanks!

sirceljm avatar Jul 12 '17 14:07 sirceljm

Yes, the entire component's code is sent to the browser in the above usage since it will be compiled into a single JavaScript module so you would not want to hard code keys into the JavaScript sections. You can use a split component or the browser field in package.json to control what gets sent to the browser, but a better strategy would be to put secret keys in environment variables (e.g. process.env.MY_SECRET_KEY) so that they will never get bundled up with code.

patrick-steele-idem avatar Jul 12 '17 15:07 patrick-steele-idem

Now I gave it a second thought and also did some experimenting and I don't believe this will work. I forked the ui-components-playground repository to https://github.com/sirceljm/ui-components-playground and I use marko starter to build the distribution files. This works perfectly but it doesn't handle tag. When I serve dist folder in the browser with koa I get an error "Not allowed".

I believe that to use async server side rendering I would actually have to run the server but in AWS Lambda you just have a function which in the end has to return something. I cannot run start the server in lambda and parse the .marko templates there because I wouldn't be able to get the generated .css files and probably it also wouldn't be very optimised.

What I would like to do is:

  • compile the marko templates in advance to get the .js file
  • make that compiled .js file an AWS Lambda function which would run the backend code inject the data that it gets from services and server side rendered the marko compiled code.

I hope this clarifies my question more.

sirceljm avatar Jul 16 '17 17:07 sirceljm

Closing since it's out of scope.

DylanPiercey avatar Jan 17 '24 22:01 DylanPiercey