Replies: 4 comments
-
I think it's time to give a little update on the UF6 project since things have been moving since the last post. As a reminder, the purpose of this thread is to keep you informed on the progress, share my thoughts on the design of UserFrosting 6, and document the process that led to some decisions. This update should be quicker, as I have less to say but more to show. Progress is slow, but I'm happy with the current pace considering I always spend less time coding during the summer and the technical challenges that come with developing new software while learning new frameworks. Previously onLast time, I went through the design principles of UF6, the choice of Vue.js and Vite for the frontend framework, and choosing UiKit for the new custom frontend template. The Pink Cupcake repository was up and running, and development was progressing in the demo-vue repository. The next steps were creating a custom Vite Twig integration, testing Vue i18n, and beginning work on the final product. Since then, most of these tasks have been completed, except Vue i18n testing. First, the custom Twig-Vite integration has been released. This can be found on Github: userfrosting/vite-php-twig. This code could have been published on the Framework repo; however, I decided to release it in its own repository in the hopes it could help others with an increase in visibility. Next, the proper development has been successfully migrated from the As for the account sprinkle, it now hosts the account-related features, such as the code logic for processing the login and registration forms (more on that later), the basic authGuard (more on that later also), and common object interfaces. The Pink Cupcake repository, of course, continues to be updated with the related Vue components to create the new pages and UI elements. Finally, the skeleton (aka Validating previous design choicesWhat I'm most happy with so far is that the design choices discussed in the last update have paid off. Since version 4, UserFrosting has a modularity system built in the form of sprinkles. This system was greatly enhanced with UF5. Every design element of the new frontend for UF6 takes the sprinkle system into account. It was difficult to get everything in place, especially TypeScript. The efforts to get it right with Pink Cupcake and demo-vue paid off, as the transition to Implemented UI and FeaturesEnough talking; it's time to brag a little and show you the result of the work done in the last two months. Unit TestingI'll start with the boring part. This one I'm proud of. I've always been a big fan of unit testing with PHPUnit. While UF5 achieved 100% test coverage of the backend PHP code, automated testing of the frontend Javascript code was still missing. Hence, one goal of UF6 is to also have full test coverage of the JavaScript code. While this wasn't on my to-do list from the last update, it became clear I needed to work on that front right away. Vitest was chosen for the frontend testing framework, and after a bit of learning, Core and Account Sprinkles both already have 100% test coverage for the code written so far. Work is ongoing on the Pink Cupcake code, and Skeleton will follow. Login PageThe login page is now 90% done. The missing elements are frontend form validation (more on that later) and adding a link to the registration form. Registration PageThe registration page is similar to the login page: 90% done with form validation and a link to the login form. The available locales are displayed according to the main configuration, and the old captcha is functional. AuthGuardUserFrosting 4 and 5 use Twig and PHP to generate each front-end page. Thus, a unified authentication guard is used for both API routes and frontend routes. Since the UF6 frontend is genreated by Vue and Vue-Router, two distinct auth guards will be required. After all, you don't want to show the login page to someone who's already logged in and the "profile settings" page to someone who isn't. Plus, everything needs to follow Vue reactivity principles. After much research, I came up with a simple For example, the {
path: '/login',
name: 'login',
meta: {
guest: {
redirect: { name: 'home' }
}
},
component: () => import('../views/LoginView.vue')
} Same principle for pages you want to require a logged-in user, this time with the {
path: '/about',
name: 'about',
meta: {
auth: {
redirect: { name: 'login' },
}
},
component: () => import('../views/AboutView.vue')
} The plan for the future version is to add roles and permissions definitions along with the redirect key. These will be the same roles and permission keys as the PHP code. The user object in Vue will eventually know which permissions the user has and handle everything accordingly. This will work for whole page guards as well as fine-grained objects inside pages (for example, showing an "edit" button only to users who have permission to edit stuff). {
path: '/about',
name: 'about',
meta: {
auth: {
permission: ['uri_about']
redirect: { name: 'login' },
}
},
component: () => import('../views/AboutView.vue')
} Next stepsAgain, the release of UF6 is still months, if not more, away. The work continues, and the next steps in the development of UF6 are:
Getting involved with UF6If you're interested in UF6, you can start by trying out the current code, giving your opinion on the visual theme so far, and sharing your ideas for UF6. Don't hesitate to engage with me on the chat, leave a comment below, and follow updates on the chat #github-activity channel. The best way you can still help UserFrosting is by contributing your time and knowledge to the project. It is definitely possible to build UF6 together! Contact me in the chat if you're interested. |
Beta Was this translation helpful? Give feedback.
-
I stumbled on this page while looking into updating my UF install to AdminLTE 4. Rather than shoe-horn that in now, and have that work undone by UF6, I guess I will wait to see what the rewritten front-end looks like. I don't have any Vue experience, but looking forward to giving it a go! |
Beta Was this translation helpful? Give feedback.
-
Work has progressed on UF6, and it's time for another quick update! This one should be more of a show than tell, as the UI has been moving along! Scroll down a bit if you only want to see the new UI of UserFrosting 6. Previously onLast update, login and registration pages were functional. Since then, the "Forgot Password" and "Resend Verification Email" pages have been added. There are still some issues with the email logic since the old routes defined in PHP were moved to Vue, but the email is still sent by PHP. This system where a link was sent to the user to click on has always been troublesome. It is, in fact, outdated now in this era of constant phishing attempts. The end goal for UF6 (and maybe UF5) will be to replace these links with one-time use codes. This will be more secure and remove the technical constraint of that link working perfectly. I left aside the unit testing for now to focus on the interesting part, aka the UI. The Admin Sprinkle has been integrated into UF6, and all the basic pages from Admin were added. This leads me to the next part... Ladies and Gentlemen, the SprunjerA big part of UserFrosting has always been our custom Sprunje. The PHP was solidified with UF5, but the frontend was still lacking. The JavaScript code is not unit tested, depends on a third-party library, and is super complex. This is why I was eager to work on the UI, because I knew the Sprunje would be a big challenge to get right due to its complexity. After all, each table needs to support filters, sorts, columns, etc. It was even more complex as UIkit nor Vue support pagination out of the box. I tried to find a good library to use for the Sprunje and didn't find any. So I dove in and started working on a fully custom Sprunjer. In the end, I literally got the Sprunje working in a matter of hours. This is a statement to the power and versatility of Vue.js. What used to be 700+ lines of JavaScript spaghetti code wrapping the TableSorter library is now a 155 line TypeScript class, plus a couple of Vue (HTMLish) templates. Mind-freaking-blown 🤯. And everything is highly customizable using Vue templates and variables. Adding a custom search field is as easy as assigning the correct variable to an input field. Anyone who created a custom "UF Table" with UF4 or UF5 knows how complicated it can be. This is the full Vue code (minus the PHP part) used to create the Sprunje table shown in the screenshot above. No additional JavaScript required! <UFSprunjeTable dataUrl="/api/users" searchColumn="name">
<!-- Header Template -->
<template #header>
<UFSprunjeHeader sort="name">User</UFSprunjeHeader>
<UFSprunjeHeader sort="last_activity">Last Activity</UFSprunjeHeader>
<UFSprunjeHeader sort="status">Status</UFSprunjeHeader>
<UFSprunjeHeader>Actions</UFSprunjeHeader>
</template>
<!-- Row Template -->
<template #body="{ item }">
<UFSprunjeColumn>
<strong>
<RouterLink
:to="{
name: 'admin.user',
params: { user_name: item.user_name }
}">
{{ item.full_name }} ({{ item.user_name }})
</RouterLink>
</strong>
<div class="uk-text-meta">{{ item.email }}</div>
</UFSprunjeColumn>
<UFSprunjeColumn>
<div>{{ moment(item.last_activity.occurred_at).format('dddd') }}</div>
<div>
{{ moment(item.last_activity.occurred_at).format('MMM Do, YYYY h:mm a') }}
</div>
<i>{{ item.last_activity.description }}</i>
</UFSprunjeColumn>
<UFSprunjeColumn>
<UFLabel :severity="Severity.Danger" v-if="item.flag_enabled == false">
Disabled
</UFLabel>
<UFLabel :severity="Severity.Warning" v-else-if="item.flag_verified == false">
Unactivated
</UFLabel>
<UFLabel :severity="Severity.Success" v-else>Active</UFLabel>
</UFSprunjeColumn>
<UFSprunjeColumn>
<!-- Row Action Slot -->
<button class="uk-button uk-button-default uk-button-small" type="button">
Actions <font-awesome-icon icon="caret-down" fixed-width />
</button>
<div uk-dropdown>
<ul class="uk-nav uk-dropdown-nav">
<li><a href="#">Edit User</a></li>
<li><a href="#">Change User Password</a></li>
<li><a href="#">Disable User</a></li>
<li><a href="#">Delete User</a></li>
</ul>
</div>
</UFSprunjeColumn>
</template>
</UFSprunjeTable> Notice how there is zero code to set up the Filter panel? Since the Sprunje API (that is, the PHP code) already knows which columns are filterable and which are listable, the filter panel is created automatically. And I believe the code could be simplified even more in the future. For example, the header portion could be defined in the row template, and sorts set up automatically. It's hard for me to communicate how excited I am for this new feature. Making it easier for everyone to include a data table in their project is really important, and Vue provides the perfect tools to make this easier than ever. The code is now super clean and simple. I can't wait to have feedback on this feature. The other pagesSo far most pages from the Admin Sprinkle have been created for UF6. Each Sprunje is also present on these pages. Again, adding a Sprunje table to a page takes minutes! Detail pages for each element were also added. Group creation is done, and group delete and edit modals are in the works. The rest of the CRUD (Create, Read, Update, Delete) actions for the other pages are next. Next stepsWith this moving on quickly, the next steps in the development of UF6 are:
I expect to release a first alpha version of UF6 without i18n support, form validation, and permission checks by the end of the year or January 2025. This will be the first functioning version of UF6, and its goal will be to get feedback on the UI so far. Once all features are locked in, the first beta will be released. I expect this to happen in summer 2025. Getting involved with UF6If you're interested in UF6, you can start by trying out the current code, giving your opinion on the visual theme so far, and sharing your ideas for UF6. Don't hesitate to engage with me on the chat, leave a comment below, and follow updates on the chat #github-activity channel. The best way you can help UserFrosting is by contributing your time and knowledge to the project. It is definitely possible to build UF6 together! Contact me in the chat if you're interested. |
Beta Was this translation helpful? Give feedback.
-
Here's a couple more screenshots of the Group CRUD ! 😁 |
Beta Was this translation helpful? Give feedback.
-
UserFrosting's main mission, as defined by @alexweissman, has always been to educate PHP developers and make them better developers, especially for indie, non-professional, and hobbyists like myself. This is the reason I wanted to take a moment and share my thoughts on the process of designing the next version of UserFrosting, UF6, and document the process that led to some decisions. I see this as an opportunity not only to document my work but also as a teaching tool for anyone working on a similar project.
Plus, I'm not an expert! I started contributing to UF around 2015 or 2016, back when the stable release was UF3. Since then, the team has worked on UF4, and I released UF5 in November 2023 after more than a year of work. But I still have much to learn. UserFrosting is an exemplary tool for learning, whether you're working on a personal project or working on UserFrosting itself. I've learned so much since "joining" UF, and it has definitely made me a better developer. This is only possible because of the foundation on which open source stands: collaboration.
So this post is also a way to bring collaboration into the UF6 design process. UF6 does bring new ideas and techniques to the table, using tools I'm learning as I go. Anyone with experience with these tools, ideas, and suggestions is welcome to share. Everyone is also welcome to contribute to UF6. Just hit me in the chat or in the comments below. I'll also use this conversation to update the process as I go, so don't forget to come back to check on the progress made on UF6.
The design principles
The goal of UF5 was to rewrite the backend PHP code while maintaining the same frontend. The changes to the backend were already extensive, and I felt like forcing a new frontend would discourage existing users from upgrading to UF5. Hence, the primary goal of UF6 is to completely rewrite the frontend.
I've set myself four key points to address with this redesign:
Simple enough? Let's go through some decisions and experiments made to achieve these design principles.
Vue.js
The first design principle for UF6 is to replace aging frontend dependencies. Replace JQuery for frontend interactivity and Handlebar for the frontend template.
Both are still usable and somewhat maintained, but they were also created a long time ago
in a galaxy far, far away. Today, other libraries and tools are used to achieve the same goal in a more modern way. I find it important for UserFrosting to showcase these new tools. What's the point of teaching an old ape a new trick if the tricks are already outdated? Plus, newer tools are generally easier to use and understand!Vue.js is one of those new libraries. Vue is an open-source model–view–viewmodel front end JavaScript framework for building user interfaces and single-page applications. It serves as a perfect replacement for both. It provides frontend interactivity, templating in an integrated and performant way, and so much more. I recommend you check out Vue.js website and examples if you're not already familiar with Vue!
So now, why Vue and not React or anything else? Well, because... I used it before (in a project based on Laravel, I know...). That's the only reason!
Using Vue as a foundation for the UF6 frontend does have some cost: the frontend will need to be rewritten from scratch. While it will have a major impact on existing UF users, I truly believe it's a necessary cost. The current (i.e., UF 4 and UF5) frontend is messy. It contains many complex vanilla-ish javascript components, tightly coupled with the UI and Jquery. These need replacement anyway. Replacing them with Vue components will make it possible to achieve the second design principle of UF6:
Vue will enable modularity and customization via a complete separation of concern between the backend and frontend. All of this while still preserving the ability to use JQuery on your own project if you wish so.
Webpack Encore vs. Vite
UserFrosting 5 introduced Webpack Encore as the frontend dependency manager, replacing the custom Gulp solution introduced with UserFrosting 4. I chose Webpack Encore back then as it was simple to use (or at least looked this way) and was relatively easy to integrate with Twig (both Encore and Twig were created by Symfony). Webpack can handle Vue and other frontend Javascript frameworks natively, which is future proof for UserFrosting.
However, there's a new guy in town... Since Vue 3 release, Vite has become the de facto tool for building Vue applications. Vite, which is the French word for fast, is indeed really fast. It's more modern than the old Webpack and has an awesome Hot Module Replacement feature.
So here is the problem: UF5 just introduced Webpack. Are we going to switch to Vite this fast?
Well, that's a good question... The current plan is to allow both. In fact, the bakery commands to build assets were changed in UF 5.1 in preparation for this. While UF5.0 used "webpack" in the command name, UF5.1 changed this to "assets" instead. This means that in the background, UF can use a config or env variable to switch to the right tool.
However, while this is the plan, Webpack has proven difficult to work with, especially when Typescript is involved. I've ironed out the kinks, but it is not a guarantee that Webpack might not get the boot before UF6 ships. One thing is for sure: Vite will most likely be the default in UF6.
Oh, and while we're here, a note about Typescript... It's awesome. Frustrating, but awesome. I set myself a goal with UF5 to achieve high code quality on the PHP side with the help of PHPStan. Typescript will help achieve the same goal on the frontend with UF6, which will be configured out of the box to use Typescript (so you don't have to experience the same frustration I did, I hope).
UiKIt vs. AdminLTE
The second design principle means that the default theme should be able to be switched as easily as possible. This was the initial goal when UF4 was designed, i.e., to have multiple templates, but it never really materialized. The frontend code is tightly coupled with AdminLTE, and while the Sprinkle system and Twig make it easy to replace the HTML or CSS, the Javascript code is complex and outdated. Replacing AdminLTE with a custom Bootstrap theme in UF5 would be very tedious right now.
Another aging dependency is the AdminLTE theme itself. UF4 and UF5 both use AdminLTE 2. This version is outdated and, in fact, includes dependencies with known security issues. AdminLTE 3.2 has been released since February 2022, and AdminLTE 4 is coming soon, with Beta 1 released in May 2024. However, updating to AdminLTE 3 is not a simple task, and there's a risk that AdminLTE 4 will be released in the meantime—or not if we base the UF6 theme on the AdminLTE 4 Beta.
AdminLTE was chosen when UF4 was being developed for its design and features. It still works, but it does feel a bit dated, in my opinion. Plus, while it's still MIT-licensed, the AdminLTE business model is weird, Webpack/Vue support is not official, it has infrequent releases, etc.
From the start, I looked at different open source alternatives, particularly one that would integrate directly with Vue.js, i.e., a theme or template that would provide Vue components out of the box. However, there is no real product that provides feature-complete Vue components and is up-to-date. For example, BootstrapVue is still based on Bootstrap 4, while the latest version of Bootstrap is 5.3.
I finally selected UiKit. UiKit is fully open source, has more frequent updates than AdminLTE, is feature-complete, and (in my opinion) is more modern, both in look and technology. It is lightweight, modular, and doesn't depend on any external JS code (e.g., jQuery).
However, its biggest advantage is that it's more easily customizable. AdminLTE provides predefined layouts and widgets, while UiKit provides individual components that let you create anything from scratch. Finally, since it's built with Less, it is super easy to customize, both for the default theme UF will ship with and for any custom theme a UserFrosting user would like to create.
Finally, it's important to note that the design principle put forward for UF6 means the default theme might be built with UiKit, but it should be easy to replace it with your custom theme, even AdminLTE, if you wish so.
Web component
I wanted to talk about web components... For those who don't know what web components are, think of custom HTML blocks that can be interactive and built on web standards (no external framework). Web components sound like the perfect fit for the second design principle:
Howerver, I found out that building them from scratch would be more complex than using Vue. After all, UserFrosting's mission is also to teach web developers. While it's important to teach the basis, it must still be accessible knowledge.
Vue does support Web components natively. However, there's a big caveat. Each web component uses its own CSS. If you use a global CSS stylesheet, each component will ignore it. This is from a process called "Shadow DOM", and it is not possible to turn it off with Vue. This caveat could be solved with vue-web-component-wrapper, but I found this would add yet another level of complexity. Hence the decision to stick only with Vue for UF6.
Pink Cupcake Theme
Now comes the third design principle. While it's easy to code a new theme, it's difficult to find out what it should look like. However, the last principle helped solve this question.
UserFrosting already has a distinct visual identity on its website and documentation (learn). This theme, especially the documentation portion, is based on the Learn2 Grav theme, with a custom pink navbar. And thus Pink Cupcake was born. The Pink Cupcake template is built with UiKit and styled to look like the current learn documentation.
I think it's the perfect choice for the new UF6 default theme and will serve the next version of the website. The theme provides the necessary
.less
files for generating the final CSS and various Vue components that will be used to build the final UI. These components have been designed with common names, and a global import technique means dependencies don't even have to know which theme you're using. This means any UF6 app that uses Pink Cupcake could easily switch to another theme, say Chocolate Cupcake. Even if the app uses the Account or Admin sprinkles as dependencies, these will call the globalUFUserCard
component and not "UserCard
from PinkCupcake", dissociating them from any one theme/template.While the Pink Cupcake repository only contains the source code (with the compiled one available on npm), pink cupcake example is a repository with a basic vue app used to test and preview the templates (I didn't use a monorepo structure for simplicity).
Oh, and this one will definitely have a dark mode!
Note that Pink Cupcake already has some releases on NPM. However, these are under the "major version zero" (
0.y.z
) semver development rule for initial development. Not all components or features are complete yet.Demo-vue
The last piece of the puzzle some might have spotted on GitHub is the demo-vue repository. This was actually started before the UF5 release as a way to test and experiment with Vue integration with Webpack and UserFrosting 5. This repo is used to experiment, test, and do proof of concept before going all in with Vue and UF6. You can actually clone the repo and set it up for a very early look at the Pink Cupcake theme and Vue.js potential.
Next steps
The release of UF6 is still months, if not more, away. The next steps in the development of UF6 are:
This doesn't mean UF5 won't get any love. For example, in preparation to integrate translations on the front side (either from Vue i18n, another package, or a custom package), it is planned for UF 5.2 to rework the i18n package to switch the language dictionaries from PHP arrays to yaml / json files.
Conclusion
That's it for the not so short first update on UF6. As I mentioned in the beginning, I'm not an expert at this. I've learned about Vue and the new frontend framework since I started on the UF6 journey and still have a lot to learn.
Open-source software is built on collaboration. That means the best way you can help the UserFrosting mission at this point is by contributing your time and knowledge to the project. It is definitely possible to build UF6 together! I'm definitely not looking for money here (I have a six-figure-day job!). The paycheck I get from UserFrosting is the feedback from people using UF, engaging with me, and seeing your contributions and projects, whatever form they may take. If you've read everything I've written here, you've already made a great contribution.
Don't be shy to engage with me on the chat and follow updates on the chat #github-activity channel. Star the different repo, leave comments, clone the project, fork the repo, send a PR, send ideas, and create something. Be awesome.
Beta Was this translation helpful? Give feedback.
All reactions