Basis for a large modular SPA on Laravel + Vue + ElementUI with CRUD generator

image

In recent years, I managed to work on several large and not very projects using different back-end and front-end frameworks. Faced with various problems that arose as the application grew.

Now I can conclude from which solutions were successful and which were not very successful.
Using the accumulated experience, I set out to collect all the best solutions, in my opinion, and create my own foundation for SPA.

How to create a site on Laravel or what SPA is, I will not tell. There is enough such information on the Internet. This article is intended for more or less experienced developers, so I will miss some details.

Who can’t wait, at the end of the article is a link to my github repository.

The main technologies were selected by Laravel and Vue.js + Vuex as this is my main stack.

For quick development, I took the UI Kit - ElementUI .

the main objective


To create a foundation for a medium and large project that:

  • will help to avoid rigid cohesion of modules
  • understandable for a programmer with little experience
  • help avoid code duplication
  • will be easy to expand
  • reduce project start time
  • reduce the time of project support and code navigation

To make life as easy as possible, not to be confused in the project, you need to properly structure your ego. Initially, the application should be divided into levels of responsibility, such as user interface, database, business logic.

Further, each layer should be divided first by functionality, and then each functional module should be divided according to the selected pattern.

Inspired by the DDD philosophy, I decided to split the front-end and back-end into semantic modules. But these are not the classic domains that Evans describes. His model is also not perfect. In any application, over time, relationships between components always appear - the same relationships between models.

He left the models as a separate layer, because they seemed to duplicate the database, with all its connections.

Created a directory at the frontresources / js / modules , in which different modules will be located. Each will have api - methods for working with the back-end, components - all components and pages, store - storage, and routes .

{moduleName}/
β”‚
β”œβ”€β”€ routes.js
β”‚
β”œβ”€β”€ api/
β”‚   └── index.js
β”‚
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ {ModuleName}List.vue
β”‚   β”œβ”€β”€ {ModuleName}View.vue
β”‚   └── {ModuleName}Form.vue
β”‚
└── store/
    β”œβ”€β”€ store.js
    β”œβ”€β”€ types.js
    └── actions.js

In resources / js , the core folder is created , where the main components of the system are located.
There are also bootstrap and includes folders for configuring additional libraries and utilities, respectively.

The project uses dynamic loading of models. Namely, in core / routes and in core / states, we load the corresponding routing and storage files automatically (nothing needs to be registered).

Here is an example of how store.js were loaded from different modules automatically.

// Load store modules dynamically.
const requireContext = require.context('../../modules', true, /store\.js$/) 
 
let modules = requireContext.keys() 
    .map(file => 
        [file.replace(/(^.\/)|(\.js$)/g, ''), requireContext(file)] 
    )
    .reduce((modules, [path, module]) => { 
        let name = path.split('/')[0] 
        return { ...modules, [name]: module.store } 
    }, {})
 
modules = {...modules, core} 
 
export default new Vuex.Store({
    modules
})
 

On the backend in the app directory there will be similar modules. Each module will contain folders Controllers, Requests, Resources . The file with routes has also been moved here - routes_api.php .

{ModuleName}/
β”‚
β”œβ”€β”€ routes_api.php
β”‚
β”œβ”€β”€ Controllers/
β”‚   └──{ModuleName}Controller.php
β”‚
β”œβ”€β”€ Requests/
β”‚   └──{ModuleName}Request.php
β”‚
└── Resources/
    └── {ModuleName}Resource.php
 

Other design patterns like events, jobs, polices, etc. will not be included in the modules, as they are used less often and it’s more logical to keep them in a separate layer.

All manipulations with the dynamic loading of the modules are done so that minimal engagement beats between them. This allows you to add and remove modules without consequences. Now you can make the artisan make command to create such a module. With its help, we can quickly fill the project with the necessary entities along with CRUD functionality.

Having executed the command php artisan make:module {ModuleName}, we will have all the necessary files, including the model and migrations, for the full CRUD to work. You just have to complete the migrationphp artisan migrateand everything will work. Most likely you will need to add additional fields, so before migration, do not forget to add them to the model, migration, and also output to vue.



In this template, JWT-Auth technology was used for authentication , but it may be redundant and should be remade for Laravel Sanctum. In turn, vue-auth is used on the front-end , it makes it easy to manage user authorization and roles.

In the future, I would like to improve the system. Add a global event bus, connect websockets. Add tests. It is possible to create a role management option in separate branches or create branches with other UI Kit. It would be nice to hear recommendations, comments.

Initially, this template was developed for your needs, but now I hope it will be useful for other users.

All code can be viewed in my github repository .

All Articles