Serverless Vue Micro Frontend
I’ve read a few articles recently explaining the implementation and benefits of Micro Front Ends (MFE) and recently had the opportunity to work on an MFE while on secondment at a company within the group I work for.
What is Micro Front End architecture?
The MFE’s that I have come across in work are used through Adobe Experience Manager (AEM). When AEM receives a request for a page that isn’t cached, it calls an MFE service for each component on the page. Once the entire page has been generated, it is cached in AEM for future requests and returned to the user. The stack contains a single application that generates a page (load balanced, scaled/auto-scaled) which calls an MFE for each component on the page. The main benefit of implementing MFE’s as an infrastructure standard within the frontend stack allows the team to rapidly develop, test and deploy components while minimising the risk of blocking the team at the development, QA or deployment stage as well as mitigating the risk of PR merge conflicts since not all developers are working in the same repository.
Maybe it’s just my search results but I’ve only come across MFE’s implemented as Docker containers which seems like not only a lot of resources but also a lot of setup and monitoring for such a simple task as generating component html. This got me thinking about whether I could get an MFE component service working as an AWS Lambda? The same functionality without the operational and monitoring cost or risk of a 24/7 running Docker container.
The Project Structure
Since I am developing a simple Vue component to be used in the MFE, it made sense to use Vue CLI to generate the project with the added benefit of Vue CLI providing the HelloWorld component. This would give me the component build and development environment out of the box with zero configuration. I say zero configuration but I did have to provide some custom configuration in a vue.config.js file to ensure that the html generated by the client side bundle matched the HTML returned by the MFE service. I would also need to bolt on the lambda build and development configuration but this wouldn’t be a largely complex task. All I had to do was provide a webpack configuration and a serverless.yml file to build and deploy the Lambda. I tend to use the Serverless framework for all of my AWS Lambda projects. After setup the project looks like this. Not too “busy”.
You will notice there is a ssrTemplate.html file in the root of the project which has been provided for local development. Locally, developers will be able to view the component in a web browser via the usual Vue cli serve command as well as a custom MFE SSR environment provided through the webpack dev server. The local MFE SSR environment generates a HTML page by calling the locally invoked AWS Lambda endpoint, replacing the html, css and javascript placeholders in the ssrTemplate.html file.
Configuration
The generated client side bundle in the project created for this blog has been configured through webpack to exclude the Vue framework. This decision has been made to reduce the size of the javascript bundle. In a production scenario, the web server would call multiple MFE services to generate HTML for multiple components and it therefore makes sense for Vue and any other frameworks such as Hypernova Vue etc to be provided globally in the browser.
The Lambda
The lambda has the simple task of generating the component HTML. This is achieved through Hypernove Vue which takes the packaged component (in this case the default hello world component that comes with the Vue CLI boilerplate project) and the params provided in the lambda request.
As you can see from the above screenshot of the handler.js file post function, the number of lines of code required to generate the component HTML is small. I firstly retrieve the body from the request and configure the Hypernova BatchManager, before calling the BatchManages render and getResult function to get the generated Hypernova response.
The Hypernova contract requires a getComponent function which is used to generate the HTML. The getComponent function of the handler.js file is provided to the BatchManager on line 30 of the handler.js file. A screenshot of the getComponent function is provided below:
You will notice the use of the CLIENT_MANIFEST global variable in the above screen shot. This is used to provide the client manifest file to the lambda which is generated through the webpack manifest plugin. This of course means that during the build process, the client bundle build needs to be performed before the lambda build since the lambda bundle requires the client manifest file. The main javascript and css asset URL’s are firstly retrieved from the client manifest file on line 16 and 17 which are then added to the Hypernova context. As well as the generated component HTML, the Hypernova response will contain the URL’s of any client side javascript and css files required to client side hydrate and render the Vue component. The final task performed by the getComponent function is to call the Hypernova Vue renderVue function providing the HelloWorld component name and component definition.
Running the Serverless MFE
Now that the project is configured to generate a client side bundle and a the lambda, I am able to run the lambda locally and view the SSR page in my browser. To do so, I run the yarn ssr command in a terminal.
You can see from the above screen shot that the page has been generated server side and hydrated client side which is evident by the presence of the Hypernova data attributes. The screen shot below shows the response returned by the HelloWrold MFE Lambda containing the generated HTML as well as the css and javascript URL’s within the meta block.
The code to accompany this blog post can be found on GitHub.