SPA development experience on VueJS + Nuxt

    Our company is mainly engaged in the development of online stores and we want to share our experience in developing a project on the VueJS + Nuxt + Laravel bundle.

    The article will discuss how we decided to implement an online store as a SPA: how we came to this, difficulties, ease.

    The site, which will be discussed, is an almost classic online store with a catalog, filters, search, shopping cart, personal account ie. Almost anything can be in the store. The project has different logic, pricing and display for businesses and individuals.

    Why SPA


    Prior to the current project, our experience in developing one-page applications consisted of only a few internal projects. And in many respects the SPA for us remained in some sense a dark horse.

    There was no clear understanding of the problems associated with the growth of the project, its seo-promotion and stability, when, as experience and well-established processes in the creation of ordinary websites have not caused any problems in solving these problems.

    The choice of the approach caused rather heated debates in our company, both scales with arguments were filled and the decision was very difficult. Our developers decided to build a prototype of several pages of the project and see what difficulties would arise with each of the approaches. This approach helped us with the final decision. The prototypes helped to show that managing the state of the site (catalog, basket, ordering, etc.) is much more comfortable and causes less problems in the SPA version. The speed of development and interaction between layout designers and programmers has increased significantly due to the fact that there is no need to transfer the layout, it is enough just to add logic to the ready-made components. Also, problems with which we may encounter have become clearer and this has led to further actions. Before us was the choice of technology.

    Summer 2017 is outside the window. In twitter and on medium, disputes abate, which is still better, vue or react. Our office has not bypassed this trend. The developers were also divided into two camps, each with its own arguments. Before that, each of us had already worked with both technologies.
    Someone has become closer to jsx, someone prefers a more familiar html or pug, someone believes that immobility helps to better monitor and control the state of the application, for some it seems like an excessive complication. On the other hand, each framework provides us with the ability to create single-file components and for both there are already fairly stable libraries with a set of all the necessary functions for us (ssr, global state management, routing, meta-data management). For react, this is nextjs, and for vue, nuxtjs. Nuxt at the time of selection was still in the beta version, but quite stable. Because the development process was built in such a way that initially we had a layout, and then building the backend part and transferring the pages to frontend, the choice of the framework was quite simple. We chose vue and nuxtjs, because It was decided in parallel to typeset the site and run api. With this approach, it is convenient to typeset the components immediately and add logic to them. Our typesetters were closer to creating their usual html.

    Little backend


    In terms of server solutions and in general, the choice of technologies for building backend, we went the more usual way. The language was php, for which we use the laravel framework. This all turns on nginx. As a database solution, we have mysql.

    Start of development, used packages and problems


    Nuxt provides packages that completely satisfy us for managing application state (vuex) and routing (vue-router). Therefore, to start building a project and screwing the logic to the components could be started immediately, and then, as necessary, we should look for the packages we need. First of all, of course, it took a solution to communicate with the backend part. For this, the standard was already selected for all, axios, and the wrapper over it is nuxt-axios-module. We also immediately help the project not to get lost in environments and run in each environment with the desired configuration - select dotenv and nuxt-dotenv-module wrapper. To start developing this is enough and the layout process has begun.

    The first pause happened when it was necessary to add an image slider to the layout. “Where is my slick-slider, I want jquery” was heard from the imposition of the end of the room. A quick review of ready-made solutions revealed several suitable sliders. But almost all of the dependencies in the form of jquery, which did not want to add to the finished bundle, thereby increasing its size. Some packages did not support server rendering, which was also important for us. As a result, the choice fell on awesome-swiper, which fully complied with our requirements and even a little more. After the slider was bolted, our layout designers for a long time remained at a loss. “Is that all, do I have nothing more to do? Just specify a list of images and does it work? ”

    Next came the choice of the component to select dates. There was more luck because a wrapper for your favorite flatpickr makers found quickly. It remained only a little stylize it.

    In several places on the site there is a map. But, since we did not need perfect detailing and elaboration of the map, there was no choice between the services. Nevertheless, at the time of development, and even now, there are no solutions that perfectly cover all our needs. Based on all the pros and cons, google maps and vue2-google-maps wrapper were selected. The package is quite large and pulls a lot of unnecessary to us, but it solves its problems well.

    In some forms, we have phone entry fields. The user needs to help enter the phone, since the format options are too many, and then working with the data entered in a single format is easier in the future. Therefore, we need a mask. I wanted to use the already familiar text-mask, and then we were lucky; they already had a solution for vue - vue-text-mask.

    These packages covered almost all of our requirements. It remained only to track clicks outside the component, which was not helped by vue-click-outside. We scrolled up the page using vue-backtotop. To work with dates, use the moment.

    The total size of the bundle and where it came from 1 megabyte


    It should be borne in mind that an important criterion when choosing packages was their weight.

    In the middle of the project, we decided to analyze the final project and see the dimensions of the assembly. The results of us to say the least surprised. The size of the gang app.js was a little more than 950kb gzip. The npm run analyze command brought us a beautiful graph with the size of all modules, from which we realized that some modules were pulling the dependencies we didn't need in the form of jquery, lodash, etc. From these packages had to be abandoned and find them an alternative. Currently, the size of the entire bundle is 480kb gzip.



    Watch for dependencies and periodically check the size of your application.

    Initial download page and data obtained by api


    Nuxt provides a convenient opportunity to fill the store with data on the server side before loading the client. For this, the action nuxtServerInit is used. In our case, it looks like this:



    Since categories and some other entities are used in several components at once, it was more convenient for us to get them immediately and put them in the store.

    But then there is a problem with the size of json that you get. Since the server sends all received data to the client for the initial rendering, the html size may be too large. We faced this when in the categories we began to transmit images that we do not need on all pages, description and other fields belonging to each category. The json size was over 2mb. Fortunately, this is easily remedied by removing unnecessary fields from the data that the server gives.

    Memory leaks


    After some time of the application on our test server, we began to observe an unnatural increase in memory consumption. pm2 occupied up to 90% of all server memory and the application periodically crashed. On the github page, nuxt already had several issues with the same problem.

    The problem arose when we made several requests in the asyncData method of our pages.



    Fortunately, the nuxt developers quickly resolved this problem, and the process currently consumes about 40mb of memory.

    Interesting problems and solutions


    Articles with components
    In the control panel of the site it is possible to add articles and insert into the content of the article various blocks, for example, a block with a product.



    The HTML that comes from the server looks something like this:



    $ product-4 indicates that the Product.vue component with identifier 4 should be in place of this pointer. Vue provides us with a wide range of options for rendering the component using the render method. First, we search for all references to pointers to components in the incoming html and get api data needed to display this component. Next, we divide the entire html into a tree. This helped us library himalaya. And then we collect back html replacing pointers to ready-made components.

    ... And there was not enough power to write an article) The article began to be written in summer 2017 as the project was developed, and it was already summer 2018 outside, the project was launched, and the article was not released.
    Therefore, we publish what we have collected, but we still have many interesting topics, observations.
    If it is interesting - write, put likes) Well, what it would be interesting to hear more about what was missed.

    I want to say that the project has been working for about 4 months. There were no particular problems with it, and the site’s operation speed is impressive and makes it stand out favorably against other stores.

    Also popular now: