Replies: 5 comments
-
Code GenerationZendro is a project designed to bootstrap a fullstack application tailored to user-provided data models. Because certain parts of the frontend need to be generated at build time, a code-generator step is necessary. This allows us to create reusable code for queries, mutations, and more. In addition, part of this generated code should offer the possibility of customization with minimal effort, and successive builds should be able to re-import and use the modified code. Where editing of the generated core is impractical, overrides should be supported, so a certain degree of flexibility was required. Many of these aspects are already addressed by NEXT design philosophy, allowing us to focus on producing the application that we want to deliver. A page can be generated for each modelPage generation was one of the first aspects we needed to focus on. We wanted to avoid generating repetitive components for each data model, potentially bloating the application with almost identical code and exponentially increasing the complexity of the default application. Through the use of the These APIs proved invaluable in the early stages of development. In our case, the biggest benefit was keeping the core of the application contained to a few page components that could easily be overridden in later projects when necessary. Furthermore, because we had the ability to switch into a server-side rendering strategy by renaming the latter function as Static props are not always the solutionHowever, later on, we found that Because the application we are building is a CRUD interface, it is often required that a certain amount of interoperability exists between pages (models). For example, in the associations' management interface, where we needed to fetch the schemas from other models at build time. This scenario meant that building this data on a per page basis often led to code duplication by adding the same fetch logic in various pages or potentially having a burst of API calls during the build stage. We were concerned that this behavior would not be optimal in sites with a large count of generated pages. To address this use case, and until |
Beta Was this translation helpful? Give feedback.
-
RoutingOur use case required support for standard router features, such as dynamic routes, query parameters, and redirects. At the same time, we wanted to keep in mind potential later customizations, with the idea that the user should not require to modify core files much or at all. NEXT offered a very convenient file-base routing API, that for the most part simplified our job and laid out the groundwork for later customizations without resorting to extraneous code-generation strategies. Early, a hybrid of statically generated and client-side siteIn our CRUD interface frontend, dynamic routes (i.e. model pages) are known at build time and therefore can be easily generated via Because routes automatically mirror the structure of the However, in the early stages of a project, the contents of each page (i.e. the actual model records) are added and updated frequently, so it would not be optimal to statically generate this data. For Zendro, this meant that by default we could only pre-generate a scaffold of the models' layout (along with any other static pages in the application), while the actual content components (tables, forms) were fully client-side and imported via An simplified example can be seen below: # simplified for clarity
pages
├── [model]
│ ├── index.tsx
│ ├── details.tsx
│ ├── edit.tsx
│ └── new.tsx
└── index.tsx Later, even when statically generated, we can keep it dynamicWhen a data warehouse matures and is expected to receive less frequent or no updates, perhaps only additions, we can leverage the full power of static site generation. If we were to implement Zendro in a mature project, we could then statically generate the full pages using a fallback strategy, with potentially some revalidation interval set. This would open up new features, such as accessing cached content (via CDN) even if the main server is down, or the ability to keep using the site while the user is offline (e.g. as a PWA). For this, the site must be deployed using a Node.js server (e.g. by running Moreover, we could even build the application partially by generating only those most frequently requested models, then deploy via # simplified for clarity
pages
├── [model]
│ ├── index.tsx
│ └── details
│ └── [record].tsx
└── index.tsx |
Beta Was this translation helpful? Give feedback.
-
CustomizationAs we briefly mentioned in the routing section, because Zendro implements a generic user interface for CRUD requests, it is expected that in subsidiary projects we will want to at least modify pages to add visualizations or tailor the user experience for specific models. In these projects, feature requests and requirements may be quite different from what we initially conceived when designing the default Zendro experience. It was important for us to simplify customization as much as possible, to maintain a healthy developer experience. Route overrides simplify customizationHere is where overriding a dynamic route by simply creating a new file in the For example, by adding a # simplified for clarity
# overriding `index.tsx` for the `books` model
pages
├── [model]
│ ├── index.tsx
│ ├── details.tsx
│ ├── edit.tsx
│ └── new.tsx
├── books
│ └── index.tsx
└── index.tsx Non-developers can easily contribute contentIn the projects that we implement Zendro, many contributors may not be comfortable with This is often the case in scientific projects, where users are accustomed to analyze data and generate custom visualizations using |
Beta Was this translation helpful? Give feedback.
-
Private Data SourcesA reasonable use case for Zendro is to handle potentially sensible data, like patient history, or unpublished results. In these situations, this information may not be available via public APIs. Server-side rendering can be used to request from private APIs.Because NEXT supports server-side rendering out of the box, any page can be easily switched to query an internal resource not exposed to the public. Within the To further simplify the implementation, NEXT provides a special |
Beta Was this translation helpful? Give feedback.
-
Performance: Bundle Size, SEO, MetricsBuilding a fully static application that can be deployed to any static hosting site (e.g. Github Pages, Netlify), then cached and served by a CDN was an important feature for us. In fact, one of the requirements for Zendro was that by default it could be served statically (using Zendro may be more than a CRUD applicationNormally, projects that only use the CRUD interface provided with default Zendro should not necessarily benefit from pre-rendering pages. However, thanks to easy customization and extensibility, the normal use case of our platform could quickly evolve into a full project site that benefits from (and requires) improved SEO and accessibility. For us, at least some of our projects required a home page with the project overview, a list of partners, and useful links. To put it bluntly, it is a market where we want our partners to succeed over their competitors. Having our static pages pre-rendered by default facilitates this task. In the case of the content that is by default served as client-only (e.g. model data), we also realized that mature projects may switch to a different deployment strategy, as discussed in the Code Generator section, making this feature even more important. Any project benefits from code splittingCode-splitting is something we wanted to implement one way or another. Our concern was that, in our related projects, as feature requests grew, dependencies and bundle size could increase significantly, thus degrading the user experience. Code splitting each route by default into separate chunks, literally without our intervention, and additionally using an improved code-splitting strategy that could potentially reduce bundle size, was a big selling point for us. ReferencesPre-rendering is normally related to improved SEO and time to first contentful paint (FCP), while code-splitting usually improves time to interactive (TTI). More about these metrics at web.dev. Both pre-rendering and code-splitting, when properly implemented, can potentially reduce bundle size, as less JavaScript is required to be sent and run in the browser.
|
Beta Was this translation helpful? Give feedback.
-
Summary
The Zendro frontend, as part of our data warehouse platform, is a minimal implementation of a customizable user interface to send CRUD requests to our GraphQL endpoint. This discussion can be thought of as a development log, where I would like to describe the reasons why we chose NEXT.js and how it is working for us, in the context of this project.
Our original goal was to develop a versatile interface that could be adapted to the different use cases of our subsidiary projects. We wanted to use a framework or set of libraries capable of generating an application that was either:
In the following comments, I will try to outline the key aspects that were relevant to us during the design phase, and how NEXT helps us address them.
Table of Contents
Beta Was this translation helpful? Give feedback.
All reactions