The Daily TIL

July 25, 2019 by AndyAndyjavascriptgatsbynextjsserverlessframeworksreact

A Study in Javascript App Framework Entrypoints

I’m currently designing a new application framework that will help people code interactive user experiences in chat platforms that have rich UI capabilities, like Slack.

I decided to try thinking backwards, starting with the question, “What does code look like in a project built on my framework?” One of the first things to figure out is the Entrypoints. Those being the modules or files that bridge the gap between the framework code and my application’s code. When the framework or runtime environment figures out the intent of a user action, it has to find and execute a part of your application’s implementation, and an Entrypoint is the thing it finds and executes.

To get some inspiration, I put together a quick guide to how the Entrypoints are designed a few of my favorite Javascript app frameworks. I’m going to show examples of Entrypoints, how intents get routed to them, and how data gets passed from the intent to those Entrypoints.

Example

Gatsby

Routing
  • convention: paths are mapped to filenames in /pages. Default exports of each module in /pages becomes a routed entrypoint. eg. default export from /pages/media.js is executed when you visit http://mysite/media.
  • configuration: paths can be configured to map to any node at build time using the [createPages build lifecycle hook](https://www.gatsbyjs.org/docs/node-apis/#createPages). (example)
Entrypoint
  • Pages: default out-of-box entrypoints are Pages, which are top-level react components that live in /pages and are exported as default module exports (see convention routing above).
    const MediaPage = ({
      // from **pageQuery (see below)**
      data: {
        newsroomYaml: { personalNotes, clippings, videos },
        sourceImageFiles: { edges: sourceImages },
        sourceYaml: { edges: sources },
      },
      ...props
    }) => (
      <Layout>...</Layout>
    );
    
    export default MediaPage;
Entrypoint Arguments
  • pageContext: static context passed to a Page at the time of page creation/discovery.
    createPage({
      path: `/my-sweet-new-page/`,
      component: path.resolve(`./src/templates/my-sweet-new-page.js`),
      // The context is passed as props to the component as well
      // as into the component's GraphQL query.
      **context: {
        id: `123456`,
      },**
    })
    export default ({ **data** }) => (  <Layout>
        <h1>About {data.site.siteMetadata.title}</h1>     <p>
          We're the only site running on your computer dedicated to showing the best
          photos and videos of pandas eating lots of food.
        </p>
      </Layout>
    )
    
    **export const query = graphql`  
      query {
        site {
          siteMetadata {
            title
          }
        }
      }`**

Next.js

Routing
Entrypoint
  • Pages:
    const Index = ({ name }) => (
      <>
        <Head>
          <title>ALL THE SCREENS</title>
        </Head>
        <Main>
          <Viewer name={name} />
        </Main>
      </>
    );
Entrypoint Arguments
  • Page.getInitialProps:
    const Index = ({ name }) => (
      <>
        <Head>
          <title>ALL THE SCREENS</title>
        </Head>
        <Main>
          <Viewer name={name} />
        </Main>
      </>
    );
    
    Index.getInitialProps = ({ query: { name } }) => {
      return { name };
    };

Serverless

Routing
    # serverless.yml
    
    functions:
      hello:
        # `handler` refers to `handler.js` module
        # `hello` refers to the named export `hello` from `handler.js`
        handler: handler.hello 
        events:
          - http:
              path: hello
              method: get
Entrypoint
  • handler functions: exported event handler functions that return HTTP response structures.
    // handler.js 
    
    export const hello = function(event, context, callback) {
      // Contains incoming request data (e.g., query params, headers and more)
      console.log(event); 
    
      const response = {
        statusCode: 200,
        headers: {
          'x-custom-header': 'My Header Value',
        },
        body: JSON.stringify({ message: 'Hello World!' }),
      };
    
      callback(null, response);
    };
Entrypoint Arguments
  • Lambda events: arguments in this case are parsed from the HTTP request and passed as event to the handler entrypoint. In the case of HTTP events, event contains HTTP-specific request data, eg. query params, headers, body, etc.

References