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 visithttp://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 asdefault
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
- 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.yml
has 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: 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.