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/pagesbecomes a routed entrypoint. eg. default export from/pages/media.jsis executed when you visithttp://mysite/media. - configuration: paths can be configured to map to any
nodeat build time using the[createPagesbuild 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
/pagesand are exported asdefaultmodule 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
- convention: https://nextjs.org/docs/#routing
- configuration (with now.json): https://zeit.co/guides/custom-next-js-server-to-routes#step-3:-defining-routes-configuration
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
- configuration:
[serverless.ymlhas routing configuration](https://serverless.com/framework/docs/providers/aws/events/apigateway#http-endpoint-with-extended-options) for HTTP handler functions. HTTP paths are explicitly defined and mapped to files that contain named exports that are Lambda function handlers.
# 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: getEntrypoint
- 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
eventto the handler entrypoint. In the case of HTTP events,eventcontains HTTP-specific request data, eg. query params, headers, body, etc.