Recommended way to share components between nextjs zones? - javascript

Context:
I'm building a portal with next and its multi zones feature. This allows us to have multiple NextJS applications running independently by different teams, but as a single app.
The problem:
I need to make sure header, navigation and footer, in all zones, are consistent. For that, I want to have a component in 1 place, and share it across the zones.
Unfortunately, webpack modules federation is not yet supported natively by nextjs so we can't benefit from it.
I am searching on ways to find out how people using this feature are dealing with shared components.
My research and thoughts are limited to one single solution:
Create npm module for components I want to share, and import it in the zones, and then pass the data I need in the zones. This comes with a price: For components like header and footer, at least, when a new version of the package is released, we need to make sure all zones are updated with the same version. So... it's not perfect but seems to be the way.
I tried to check NextJS GitHub discussions, but unfortunately, the community there doesn't seem to be very active (someone asked it already there, and the only answer you can find there about it is mine).
I decided to give it a try asking this here since the audience is wider and maybe you guys could shed me some lights if there are better ideas.

I am sure you figured it out by now but i just want to leave some suggestions for people who are also dealing with it.
You can create your own component library that does automatic NPM delploys with tools like Bit and Lerna which contains your shared components. However this leaves us with the problem of data fetching since we don't want to hardcode that into the component because the data fetching source or method can change in the future. Normally you could maybe provide a hook or pre-build wrapper component because we also don't want every team to re-invent the wheel. But Since we are using Next i want to statically generate the menu and footer by calling our CMS in getStaticProps.
A possible solution would be to also export the data fetching logic with the menu package so every team can just import it and use it in the getStaticProps. This way we can make sure that the different teams use the same logic to get the data for the menu.
Currently, I am looking into a different solution which is putting our front-end projects into a mono repo. Specifically, I am looking at Turbo-repo since it was acquired by Vercel last year and thus plays really well with Nextjs. Because all the code is in the same repo different teams can just import it in every project.

Webpack 5 is supported by Next.js through a top level flag, take a look at this documentation: https://nextjs.org/docs/messages/webpack5
Also, checkout this package that lets you achieve Module Federation for Next.js apps: https://www.npmjs.com/package/#module-federation/nextjs-mf
Lastly, be sure to checkout the provided dashboard to better manage module federation: https://www.npmjs.com/package/#module-federation/dashboard-plugin

Related

JavaScript Code-Splitting with hiding the code-endpoints

hey im not really familar with JavaScript or react.
So i hope i dont a too easy question:
i want to have a "one-page"-website, and want to change this page dynamically with ajax-request.
I have coded for example code for four visibility-levels (guest-user, normal user, moderator, administrator)
if you log in into my page and you are an admin, you get the JS-Code from all levels. For example in the json-response there is a list with URLs to the Javascriptcode destination.
If you log in as a normal user you should get only the normal-user js-code. The guest-user-js-code you already have; you got that at the time you entered the page.
So i guess the thing is clear, what i want.
But how i should implement this?
Are there some ready solutions out there?
https://reactjs.org/docs/code-splitting.html
maybe i have to adjust this here?
and maybe there are some good bundlers out there, that i can use, doing that splitting with hiding the endpoint urls (which i get if i have the rights from an ajax-request)?
lg knotenpunkt
As I said in the comments, I think that the question is very, very broad. Each one of the requests is a full standalone argument.
Generally speaking, I hope that this will led you to the right way.
You can split your code by using CommonJS or ES6 modules (read more here). That is to keep it "modular". Then, during the bundling process, other splitting techniques may be applied, but this will depend on your development environment and used tools.
Your best option for bundling would be Webpack without any doubt. However, directly dealing with Webpack or setting up a custom development environment is not an easy task. You'll certainly want to read about Create React App, which is a good place to start for a Single Page Application. It will allow you to write your code in a "modular" fashion and will bundle, split and process it automatically (uses Webpack under the hood).
Finally securing access must be done server-side (there is another world of available options there).

Angular and Micro-Frontends

I am doing some research on how to split a huge single-page-monolith into a micro-frontend architecture.
The idea:
the page consists of several components which would be running autonomously
each component is managed by one dev-team
each team can change, update and deploy their components without breaking components of other teams
each team chooses its own toolstack
The reason
To efficiently develop large applications you need to have many people working on it. However the number of developers per app/team does not scale well. Parallel development of multiple independent apps by independent teams however can be scaled arbitrarily
With this in mind it is imperative that teams can choose their own toolstack and especially perform independent version-upgrades of third party-libraries (like angular, react, jquery). If this was not the case a framework-update would need to be compatible with every single component before you could deploy it to production.
Does this work with Angular?
While independent version-upgrades are necessary, it would be reasonable to restrict the teams to a few supported frameworks (Angular, React, Vue, Polymer...) and for now I try to build a demo purely consisting of Angular-Apps.
However even though Angular 5 is supposedly a platform-framework which supports huge multi-module apps, it seems to be almost impossible to have several independent angular-apps running in the same browser window.
I managed to bootstrap several Angular-Apps (different versions, each hosted on its own server) on a single webapp by utilizing HTML-Imports. However there are several global dependencies which need to be shared between apps
zone.js can only be started once
routing requires url-changes
Browser-stuff like cookies, sessionstorage, etc...
There are several articles in the net on how to bootstrap multiple angular-modules but they all refer to multiple modules in the same core-app, which in turn means they all are running on the same framework-version and an update means you have to rebuild and deploy the whole monolith.
Is there any solution other than "iframes" to get multiple Angular (5) Apps running on the same Page?
Instead of outright suggesting AGAINST this idea mainly due to separate stack requirements I will lay out the trade offs and provide some restrictions which will make this possible.
the page consists of several components which would be running autonomously
We all know this is offered out of box in Angular components with clear demarcation of inputs and output.
Small CAVEAT: When/If you pass objects for #Input and emit event objects with #Output() interacting components must agree on a defined interface upfront.
Workaround: Create another TypeScript project which just defines these artifacts. All other "component projects" would depend on a specific version of this.
each component is managed by one dev-team
Dev Teams can distribute the components just like other Angular projects in the opensource are doing. They can publish their artifacts to some npm repository. To develop attributable components I recommend you refer to Angular Material2 which may be overwhelming or you may use something like ngx-library-builder (based on Angular Team Member filipesilva/angular-quickstart-lib ) that each component team uses.
CAVEAT: Till this date angular team does not have a quick component library sharing project setup as evident in Angular CLI. But numerous developers have created some sort of library builders to fill the gap in Angular CLI.
each team can change, update and deploy their components without breaking components of other teams
Have your main project pull all the components and perform a periodic/change triggered build/deploy on some CI server. This is essentially producing AOT production builds with all the latest component releases.
As an added bonus you can have some abstract e2e tests built to do some automated integration testing ensuring side effects of one component does not break other components.
CAVEAT: It will be difficult to govern how each team develops the components i.e. they are doing optimal usage and disposition of memory, CPU, and other resources. e.g. what if one team starts creating subscriptions and does not remove them. Using some static code analysis can be useful but you will not have this source code available at this time - unless they also publish their source code.
each team chooses its own toolstack
This is a complete deal breaker unless if you mean "toolstack" as in developer tools such as IDEs and some of the "devDependencies". Although certain parts of "devDependencies" of each team must have the same exact versions of angular dev kits such as compilers etc.
At the least each team must use same Angular, RxJS etc.
Most importantly care should be taken that each of the team does not bootstrap any components - only the main projects will have a bootstrap module and that will bootstrap the root component. This will help answer your zone.js issue
Does this work with Angular?
If you recognize the limitations and provide governance I suggest go for it.
We asked ourselves the same question. Unfortunately, it seems that the answer to the question
Is there any solution other than "iframes" to get multiple Angular (5) Apps running on the same Page (edit: where each Angular app can use a different Angular version)?
currently is
No, unfortunately not, as long as you want to use Angular‘s change detection (which uses zone.js).
Due to zone.js Angular pollutes the global scope. Even worse zone.js patches an awful lot of browser APIs (https://github.com/angular/zone.js/blob/master/STANDARD-APIS.md) to detect when a zone is completed.
It’s only possible to use different versions of a framework in one page without side effects if the framework does not touch global scope (this seems to be true for React und Vue). Then you can bundle different framework versions with each application via Webpack (with separated scope and the downside that the size of each application bundle increases).
So, if you want to build a web page with Angular where different applications/modules should be integrated on one page, the only feasible solution currently is to create a deployment monolith (e.g. bundle different modules from different teams in one Angular application by a CI/CD system as bhantol explained in his answer).
It seems that the Angular team is also aware of the problem and that they might tackle it with following major versions. See robwormwald’s answer on the following Github issue regarding the Angular Elements roadmap: https://github.com/angular/angular/issues/20891
Hopefully there will be more information by the Angular team on that topic when the next major version Angular 6 is release at the end of march.
It seems that there has been a solution for your needs for a while now. Take a look at Single-SPA project HERE.
It's a wrapper SPA project for your micro SPA projects.
Take a look at Angular Elements (Custom Elements). https://moduscreate.com/blog/angular-elements-ngcomponents-everywhere/
The new Ionic version (4) is totally based on it to be able to be used on every version of Angular and on every JS frameworks.
For that, they created https://stenciljs.com/ that will help you to create Custom Elements.
But if all teams are using Angular, each of them can create a library using ngm for example.
Yes you can.
However you don't really want to get stuck in a framework when you are writing web components, because the whole point of a web component is to be reused possibly anywhere.
I share your vision, it's definitely better for the quality of the software as well as the productivity of developers to work on focused features rather than large apps when it comes to implementation.
Finally, what you are looking for right now is not Angular, but StencilJS. Stencil is a compiler for web components who also generate a virtual DOM inside your component to improve it's UI performances. Check it out ;-)
Other than Iframe there is one more option is currently available is SPA framework, you can get the sample code from here
https://github.com/PlaceMe-SAS/single-spa-angular-cli-examples
https://github.com/joeldenning/simple-single-spa-webpack-example
The only way to integrate different Angular Apps apart from IFrames and communication via postMessage is by "Deep-Linking" them and exchanging information using URL-Parameter. All Angular apps are then located on their own browser tab. But for common services and components you may want to implement a "Shared Kernel" used by all of your Angular apps, therefore your a stuck on a certain Angular version range. When you want this shared kernel the NGModule approach is the recommended way to go. You can mix Angular 2 and Angular 5 versions in one app because they are backward compatible. There ist no urgent need for the teams to stuck on the same version, until the Angular Team introduces breaking changes. Despite of that your technical debts grow, when you are not updating. The frequency for technical-updates is definitly higher in the Angular/Javascript area.

React Components - Extending, Customizing and reusing

We are developing React Components as part of product development.
Now we want that other teams can reuse these components and develop something for different clients.
for example
We developed a UserInfo component, published on NPM repository and other teams can use it for different clients.
We are done with all basict things like NPM publish, then developrs can point newly component in package.json and can use it effectively.
But the problem I'm facing in component architecture, how a component can be designed, so that these can easily be customized by other developers.
Like a developer can have requirement for different view, some extra methods, or override existing methods.
My Approach - I feel that more improvements can be done
Approach#1
We wrote Web pack plugin to replace existing file by newly created file during build time.
Problems - Its a complete replace, so we cannot reuse or extend the existing file
Approach#2 - Tried to use ES6 Extend
The problem here is We are extending JS Call not "React.Component" so some unwanted behavior of methods and functions are observed.
There is also problem on customizing internal components, you can visualize internal component from image. i.e How to extend/customize Image Component, Address Component etc.
I am working hard to find the optimal solutions since last 2 months, expecting some help from community.

How to write react / angular micro application that share the route based on redux?

Writing micro-services on back-end is not that much confusing, specially if we are building api endpoints. We can write separate project for users management, separate project for reporting, ..., and combine all their endpoint with AWS gateway api, or for smaller one acomplish this with nginx reverse proxy to provide a integrated api service.
The way I am suggesting the team for writing back-end is something like that:
localhost:8001/list <- reverse proxy to -> apiproxy.com/users/list
localhost:8003/transaction <- reverse proxy to -> apiproxy.com/transactions/create
So it seems simple, we write our projects by category in separate repos, and each team/person can work individualy on it. But here goes my question:
" How can we implement a solution, that a server rendered React app ( Or, angular, Vue ) can render, and developed with separate repositories, but in build time, they merge into each other, and their routing works well."
So, in this senario, each repository must be able to bootstrap independetly. The aim is not create a new framework.
Does anyone has any kind of suggestion?
Canopy Tax, a tech startup based in Utah that builds solutions for tax professionals, faced a similar situation about 2 years ago. They wanted to be able to implement some sort of microservice architecture in the front end, and guess what, they succeeded. The solution is not perfect yet, there's a lot of trade offs, but the objective is met and they are using this in production with their customers. I have seen it in action at some meet ups they have hosted.
Canopy Tax open sourced their framework last year, it is called Sofe. Here it is the link to the github project. Their solution, is used in production and is here to stay for a long time. They recently raised another 20 million in VC this year.
This sofe framework is what they call a Meta-framework. It is basically a main router that decides where to dispatch your routes. Then it dispatches to an angular, ember, react, angular2 app. And it gets even better, in the same page you can have pieces built in react, pieces in angular, etc. You get the idea. This allowed them to scale faster, get more talent as well as they are no longer limited to just one framework. And they can deploy anytime and their teams (squads) don't depend on each other as those pieces of the app are independent applications, like microservices in the front end.
It is still fairly new but definitively worth a look. I recently talked with them at a meet up and some other companies are using this as well in production. They also have an inspector tool an other tools that show you what framework that piece of the web app you select belongs to (e.g. react, angular, etc). Here it is the live demo of sofe in action.
Click on framework inspector there, then turn it on. It will show you.
There's trade offs on this approach, one is that this is not supported yet for mobile. It works great for their product but they are working on solutions for that as well.
Disclaimer: I do not work at Canopy Tax, I have never worked there and I do not have any relation with the company. I just like Sofe and what they are doing with the project.

Aurelia: Isomorphic?

As far as I know, Aurelia does not support server-side rendering as mentioned here.
But the question is: is it possible to do this with some hacks/workarounds?
The most obvious idea would be to use Phantom, Nightmare.js or whatever to simply render that page in Chrome on server and serve that to client, but this is very likely to cause big productivity issues.
Thanks!
UPD
According to Rob Eisenberg's response on FDConf today (16 Apr 2016), server-side rendering will be implemented in 2016, there's one core team member working on that and there's a deadline for this feature.
There is an open issue for Universal/Isomorphic Aurelia which you can monitor. In particular EisenbergEffect (who is Rob Eisenberg, the creator of Aurelia) states that they are gradually working towards providing Universal support for Aurelia. This post from him provides most of the detail:
EisenbergEffect commented on Aug 25
We are trying to lock things down within the next month. That doesn't
mean we won't add anything after that, but we need to work towards
stabilization, performance and solid documentation without
distractions of lots of new features for a little bit.
Primarily, "isomorphism" isn't a use case we want to tackle for the
initial v1 release. Again, that doesn't mean we won't do it later.
But, we want to have a solid framework for browser-based apps as well
as phone gap and electron/nwjs desktop apps first. That was our
original goal and we want to make sure we handle those scenarios
better than any other framework or library.
After that, we've got some other features we want to do, which are
valuable in their own right, but will also take us closer to
isomorphism.
Enable all aurelia libraries to run on the server. This enables some
new testing scenarios, so it's valuable if only from that perspective.
Once code can run on the server, we can then implement server view
compilation. This isn't isomorphic rendering, but rather the ability
to run Aurelia's view compiler as part of your build and bundle
process. This enables more work to be done ahead of time, as part of
your build, and then it doesn't need to be done in the browser at
runtime. So, this will improve the startup time for all apps and
reduce initial render times for all components. It also will make it
possible to store compiled views in browser local cache to improve
performance of successive runs of the application.
After both of those
things are in place, then we can look at doing a full server render
for each route. This isn't quite isomorphic in the truest sense, but
it solves the SEO problem without needing 3rd party libraries. So,
it's nice to have a solution there.
Finally, we can then "sync" a
server pre-rendered app with a stateful Aurelia app running in
browser, giving us 100% isomorphic support. So, those are the stages.
The first two would be beneficial to all developers, even those who
are not interested in isomorphic apps. The 3rd stage can be done today
with 3rd party libraries, so this is a nice to have for us, for those
who don't want an extra dependency. All of that leads into 4 which
adds the final pieces.
We have already begun some of the work on 1. That might get into our
first release. We aren't going to push it, but it's already in
progress and we're looking for the problem areas so we can make it
work. Steps 2-4 involve significant work. Really, we are talking about
a collection of features here, each one being rather complex. So,
those will probably come in stages after v1, as point releases.
We really don't want to do what Angular 2 has done. They have
massively complicated their architecture...to the point that very few
people will be able to understand it and developing applications with
it has become much more complicated, with many nuances. We really
don't want that, so we're focusing on the developer experience we want
first, then we'll come back and see about isomorphic support (yes, we
already have ideas how to do this cleanly, but want to give those
ideas some time to mature). In all of this, our goal is to be modular.
So, if you don't care about isomorphism, you don't have to think or
worry about it. If you do, you would install the necessary packages,
agree to the "constraints" of the system and be on your way.
So, to all who are interested in this topic, I would just ask you
kindly to be patient. For those who aren't interested in isomorphism,
don't worry, we aren't going to brake the developer experience on you.
For those of you who want it badly, you will have to wait longer and
it will come in stages and in modular pieces so as not to disrupt
others.
Just for now
The only way I can propose: render pages with phantomjs + use redis to speedup that process.
But you will have lots of trouble restoring the state at client side.
.......
Dirty solution
Load rendered page from server and at the client side render new one in the usual way, than switch UI's.
It won't be a truly isomorphic, but something like https://github.com/rails/turbolinks on first page load.
.....
I hope soon Aurelia team will provide simpler stuff for that case.
In the current Aurelia there is the possibility to enhance existing html.
The document says
So far you've seen Aurelia replacing a portion of the DOM with a root component. However, that's not the only way to render with Aurelia. Aurelia can also progressively enhance existing HTML.
Check out enhancement section # http://aurelia.io/docs.html#/aurelia/framework/1.0.0-beta.1.0.8/doc/article/app-configuration-and-startup
I'm looking forward to get a better documentation of this feature.
It seems to me like rendering the html on the Server and inject aurelia will work with it and google will like it as well.
a hack i just came up with is to put a static copy of the initial rendering into the index.html file:
<html>
<body aurelia-app="main">
<h1>static copy of the website here</h1>
<script src="scripts/vendor-bundle.js" data-main="aurelia-bootstrapper"></script>
</body>
</html>
this is of course completely manual and if the initial rendering contains any content from a database then the static copy may need to be updated
every time the database content changes. (which is of course what isomorphic rendering is supposed to solve)
however for my needs, which is a simple website with some information that is rarely updated, this solution is good enough. it will at least suffice until i am able to implement proper isomorphic rendering.

Categories

Resources