marko-js / marko

A declarative, HTML-based language that makes building web apps fun
https://markojs.com/
MIT License
13.36k stars 643 forks source link

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

Closed sirceljm closed 8 months ago

sirceljm commented 7 years ago

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

patrick-steele-idem commented 7 years ago

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?

sirceljm commented 7 years ago

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!

patrick-steele-idem commented 7 years ago

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.

sirceljm commented 7 years ago

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:

I hope this clarifies my question more.

DylanPiercey commented 8 months ago

Closing since it's out of scope.