To do a good job, you must sharpen your tools first — Analects of Confucius

There are few people on the front end that don’t know about Vue in today’s big three frameworks. In 2014, former Google engineer Yu Yuci released the so-called Progressive front-end application framework Vue, whose simplified template binding and componentization ideas had a positive and profound impact on the front-end field in the era of jQuery. Vue was created to benefit front-end developers who were not used to TS or JSX syntax. Moreover, Vue’s low learning threshold also makes it very easy for beginners to get started. This is why Vue has been able to spread quickly in a short period of time. According to the State of JS survey, the popularity of Vue is close to 100%, and the overall user satisfaction is relatively high.

Vue is powerful and easy to learn. Does that mean Vue is a perfect framework? Sadly, the answer is no. Although Vue has a low barrier to entry and is flexible and easy to use, this advantage also becomes a double-edged sword, which brings certain limitations to the construction of large projects. Many front-end engineers who have worked on large projects with Vue 2 have a love-hate relationship with Vue. However, with the release of Vue 3, these disadvantages of developing large projects have been effectively addressed, making the Vue framework very versatile and potentially competitive with React. What important new features does Vue 3 bring? This article will cover this in detail.

Vue overview Vue is a front-end framework developed by former Google engineer Yu Yuxi in 2013 and released in 2014. For the specific definition of Vue, here is an excerpt from the introduction of Vue official website.

Vue (pronounced vju/curliest, similar to View) is a set of progressive frameworks for building user interfaces. Unlike other large frameworks, Vue is designed to be applied layer by layer from the bottom up. Vue’s core library focuses only on the view layer, making it easy to get started and integrate with third-party libraries or existing projects. On the other hand, when combined with modern toolchains and various supporting libraries, Vue is perfectly capable of providing drivers for complex, single-page applications.

Progressive Framework Many people may not understand what Progressive Framework means. Here’s a quick explanation. Gradualism is mainly for the project development process. Traditional software project development is usually Waterfall, that is to say, software design and development tasks usually have a clear time line, and there is a clear dependence between tasks, which means that the project’s tolerance to Uncertainty is low. This development model has become outdated in modern, increasingly complex and rapidly changing business scenarios, where requirements are often uncertain, which can put the project at great risk.

Progressive frameworks or incremental development patterns can solve this problem. Take Vue as an example: At the beginning of the project, the functional requirements were simple, and some relatively simple apis could have been used; As the project developed, some common components needed to be abstracted, so the componentization function of Vue was used; When the project becomes very large, modules such as Vue Router or Vuex can be referenced to further engineer the front-end system. See, this way the development process becomes very agile, you don’t have to design the entire system in advance, you just develop it on demand, so you can quickly prototype and scale into production systems.

The framework feature Vue uses template syntax to render pages, also known as declarative rendering. This is one of the main reasons why Vue is so easy to get used to, because it fits the conventions of front-end developers. Take the following example.

Copy the code

{{message}}

In addition, Vue integrates HTML, CSS and JS into the same file. Vue organizes code in the way of component-based application construction, encourages the design concept of “high cohesion and low coupling” in terms of syntax characteristics, and makes code organization more reasonable and improves readability and logicality. Here is an example of a basic.vue file from an official website.

Font-size: 2em; text-align: center; }

The skeleton (HTML), style (CSS), and data or operations (JS) of the copy code component are all in one place, and developers need to think about how to break the entire system down into smaller sub-modules, or components. This is very helpful for building large projects.

In addition to these two features, Vue has many other useful features that we won’t go into detail here for space reasons. Interested readers can go to the official website for in-depth understanding.

Framework flaws Nothing is perfect, nor is Vue. As Vue grew in popularity and usage, some front-end developers began to complain that the flexibility of Vue resulted in a lack of constraints when building large projects, leading to numerous bugs. Even using Vuex, the state management system in the Vue ecosystem, does not work. There has been a lot of debate online about whether Vue is suitable for large projects, and even UVU himself weighed in on the discussion on Zhihu.

To be fair, Vue has a low barrier to entry, but that doesn’t mean it’s not suitable for large projects. However, we must also acknowledge that large projects often require high stability and maintainability, and the flexibility and lack of constraints of the Vue framework make it easy for inexperienced front-end developers to abuse it, resulting in stinky, unreadable “mountain of crap” code. In fact, code maintainability does not require less flexibility and freedom, but such freedom may pose a risk to the overall stability of the project.

Vue author Yu Yu Creek has been aware of this problem for a long time, so he decided to refactor Vue from the ground up to better support TypeScript. This was Vue 3, released in September 2020.

Vue 3 has a number of useful new features, including TS support, composite apis, Teleport, and more. This article isn’t a reference for Vue 3, so we won’t cover all the new features. We’ll focus on the important ones, especially TypeScript (TS for short), which strengthens code constraints.

TS support technically, TS support is not new to Vue 3, as Vue 2 already supports TS. But TS support in Vue 2 is implemented in a lame decorator way with vue-class-Component. The author of “bad” this evaluation have experience greatly, because the author once migration Vue 2 version of the production environment project, and finally found that income is not high, the grammar is very different, spent a lot of time to rebuild, found only promoted the standardization of the code, but the code as a whole becomes more bloated, readability is becoming worse.

In Vue 3, TS is supported natively, and since Vue 3 itself is written in TS, TS becomes a “first-class citizen” in Vue 3. TS support is in my opinion the most important feature in Vue 3, especially for building large front-end projects. Why is it important? Because TS effectively solves front-end engineering and scale problems, it greatly improves code quality in terms of code specifications and design patterns, thus enhancing system reliability, stability and maintainability. The importance of TS is covered in my previous post on the public account, “Why TypeScript is a Necessary language for developing large front-end projects,” for those who are interested.

Vue 3 defines a number of TS interfaces and types to help developers define and constrain variables, methods, and classes. Here is a very basic example.

Import {defineComponent} from ‘vue’

Interface Book {title: string author: string year: number}

// defineComponent defineComponent const Component = defineComponent({data() {return {book: {title: ‘Vue 3 Guide’, author: ‘Vue Team’, year: The above code defines the component type via defineComponent and defines the internal variable Book in data, which is defined via the interface Book. As a result, other components can automatically infer the type of the component, internal variable types, and so on when referring to it. TS will throw errors if the reference does not match any of the referenced interfaces or variable types, allowing you to avoid many errors ahead of time.

Although Vue 3 supports TS well in the traditional way of defining Vue instances (Options API), we recommend using TS in conjunction with a new way of defining Vue instances (Compositional API).

Composite apis Were born out of the inability to gracefully and efficiently reuse large numbers of components in large projects. If you already know about Vue, you probably know that previous versions of Vue instances included a number of fixed apis, including Data, computed, methods, and so on. One problem with this definition is that it locks the functionality of Vue instances into different apis by type, rather than by actual functionality, which can lead to very messy code in a complex component, as shown in the following figure.

In this traditional “Frankenstein” component, the code of the same color is responsible for the same function, but they are scattered in different areas according to the type, which makes it difficult for developers who are new to the component to quickly understand the functionality and logic of the entire component. A composite API allows developers to aggregate related functionality and variables in a component in one place and reference them externally on demand, avoiding the logic clutter of the traditional approach.

In Vue 3’s composite API, all functionality and logic need to be defined only in the setup method. Setup takes the props and context parameters and defines the required variables and methods inside the method. The return value is an object containing public variables and methods that can be used by other components and modules. Most of the apis for traditional Vue instances, such as Data, computed, methods, and so on, can be defined in SETUP. Here is an example of a composite API from the official website.

Copy code / / SRC/components/UserRepositories vue import {toRefs} from ‘vue’ import useUserRepositories the from ‘@/composables/useUserRepositories’ import useRepositoryNameSearch from ‘@/composables/useRepositoryNameSearch’ import useRepositoryFilters from ‘@/composables/useRepositoryFilters’

Export default {// Reference child components: {RepositoriesFilters, RepositoriesSortBy, RepositoriesList}, // Properties props: {user: {type: String}}, setup(props) {// toRefs const {user} = toRefs(props).

// Get the repository public method, Define const {repositories, getUserRepositories} = useUserRepositories(user) // Search for repository public methods, Define const {searchQuery, in other modules, RepositoriesMatchingSearchQuery} = useRepositoryNameSearch (repositories)/filter/repository related public methods, Define const {filters, updateFilters, in other modules FilteredRepositories} = useRepositoryFilters (repositoriesMatchingSearchQuery) return {/ / because we don't care about unfiltered warehouse / / we can 'Repositories' under the name of exposed filtered repositories: filteredRepositories, getUserRepositories, searchQuery, filters, updateFilters }Copy the code

In this case, the variables or methods required by this component are all defined in other modules, exposed to external components through useXXX functions, and reused by other components. Does that make it look fresher?

You might be thinking about how to write a function like useXXX. It’s very simple. Here’s an example.

Copy code / / SRC/composables/useUserRepositories js

import { fetchUserRepositories } from ‘@/api/repositories’ import { ref, onMounted, watch } from ‘vue’

Export default function useUserRepositories(user) {// Internal list const repositories = ref([])

Const getUserRepositories = Async () => {repositories.value = await fetchUserRepositories(user.value)}

// Get the list for the first time, mount it and execute it. This is equivalent to mounted onMounted(getUserRepositories).

// Listen on user and get the latest list based on changes. Watch Watch (User, getUserRepositories)

Some of the apis in traditional components, such as Mounted and Watch, have become on-demand functions, which are exactly the same as before. Data, computed, and methods become internal variables in the SETUP function, and are exposed to the outside depending on whether they are returned.

It is important to note that Vue 3 introduced the concept of a reactive API. Previously, variables had to be defined using different reactive apis as required. Its specific principle is not introduced in depth, interested readers can go to the official documentation to continue in-depth study.

Other new features Vue 3 has several other new features that I won’t cover in detail for space reasons. Here are some useful new features and a brief introduction to them.

Teleport – Applies to Modal, Popover, and other components that need to be mounted in a global DOM element – Components support multiple root nodes to trigger component options – For a full list of API changes related to events, please refer to the official documentation.

So much theoretical knowledge has been introduced in front of large projects, which may not be enough for front-end engineers. In order to make the knowledge play a role in the work, it must be used in project practice, especially in large projects. Therefore, this section will focus on how to build enterprise projects with Vue 3. This section uses one of my Github repositories as a demonstration of how to build a large front-end project with Vue 3.

This repository is the front end of v0.6, the next version of my open source project, Crawlab. It is currently under development and is not finished; However, the code organization structure is in place and is sufficient for demonstration purposes. The previous version was written in Vue 2 using the traditional Vue API. This Vue 3 version will use TS and the composite API for refactoring and migration, and then add more utility on top of that. Anyone interested in the front-end project can visit the Github repository for details of the code, and anyone is welcome to talk to me about anything that doesn’t make sense or needs to be optimized.

Warehouse address: github.com/crawlab-tea…

Project Structure The code structure for this project is as follows. Some unimportant files or directories are ignored.

├─ SRC // Source directory │ ├─ Assets │ ├─ Components │ ├─ Constants // Constants │ ├─ i18n / / the internationalization │ ├ ─ ─ interfaces / / TS type declaration │ ├ ─ ─ layouts / / layout │ ├ ─ ─ the router / / routing │ ├ ─ ─ services / / service │ ├ ─ ─ store / / state management │ ├ ─ ─ Styles // CSS/SCSS Style │ ├─ Test │ ├─ utils │ ├─ views │ ├─ app.vue │ ├─ main.ts │ ├─ ├─ ├─ ├─.eslintrc.js // ESLint Config File ├─.eslintignore // ESLint Ignore file ├─ ├─ ├─ package.json // project ├─ ├─ ├.json // exercises ├── ├.json // exercises ├── ├.json // exercises As you can see by copying the code, the front-end project has many sub-modules, including components, layout, state management, and so on. There are more than ten subdirectories in the SRC directory, that is, more than ten modules, and this does not include the subdirectories under each module, so there are many modules and the structure is very complex. This is a typical project structure for a large front-end project. Enterprise-level projects, such as ERP, CRM, ITSM, or other back-end management systems, mostly have many functional modules and a clear project structure. These modules play their respective roles and cooperate with each other, which together constitute the whole front-end application.

This project structure doesn’t just apply to Vue. Other framework projects like React and Angular can be similar.

TS type declaration TS is almost standard in modern large front-end projects, and its powerful type system avoids many of the errors and risks that are common in large projects. Therefore, we also used TS as a type system in this front-end project.

In the previous project structure, we declared the TS type in the SRC /interfaces directory. The type declaration file is represented as.d.ts, and name indicates the type declaration associated with this module. For example, in the SRC/interfaces/layout/TabsView which s the file, we define the associated with TabsView the layout component type, content is as follows.

interface Tab { id? : number; path: string; dragging? : boolean; } is a more complex example of state management type declaration documents, such as the SRC/interfaces/store/spiders. Which s, this is the state management library Vuex Vue one module of the declaration documents, the content is as follows.

Import {GetterTree, Module, MutationTree} from ‘vuex’;

// If a third party type is introduced, // Inherit the base type of Vuex Module Interface SpiderStoreModule extends Module<SpiderStoreState, RootStoreState> { getters: SpiderStoreGetters; mutations: SpiderStoreMutations; }

// Status type // NavItem is a user-defined type. Interface SpiderStoreState {sidebarCollapsed: Boolean; actionsCollapsed: boolean; tabs: NavItem[]; }

// Getters // StoreGetter is a custom base type. Interface SpiderStoreGetters extends GetterTree<SpiderStoreState, RootStoreState> { tabName: StoreGetter<SpiderStoreState, RootStoreState, SpiderTabName>; }

// Mutations // StoreMutation is a customized base type interface SpiderStoreMutations extends MutationTree {setSidebarCollapsed: StoreMutation<SpiderStoreState, boolean>; setActionsCollapsed: StoreMutation<SpiderStoreState, boolean>; }} duplicate code where Angle brackets <… The content in > is the generic type in TS, which greatly improves the generality of the type and is often used as a base type.

Here are some examples of the type of reference TS SRC/store/modules/spiders. The TS.

Import router from ‘@/router’;

export default { namespaced: true, state: { sidebarCollapsed: false, actionsCollapsed: false, tabs: [ {id: ‘overview’, title: ‘Overview’}, {id: ‘files’, title: ‘Files’}, {id: ‘tasks’, title: ‘Tasks’}, {id: ‘settings’, title: ‘Settings’}, ], }, getters: { tabName: () => { const arr = router.currentRoute.value.path.split(‘/’); if (arr.length < 3) return null; return arr[3]; } }, mutations: { setSidebarCollapsed: (state: SpiderStoreState, value: boolean) => { state.sidebarCollapsed = value; }, setActionsCollapsed: (state: SpiderStoreState, value: boolean) => { state.actionsCollapsed = value; }, }, actions: {} } as SpiderStoreModule; The copy code uses an assertion as SpiderStoreModule. The TS static detector will automatically infer SpiderStoreModule elements and compare them to the actual variables. If there’s a discrepancy, you’re going to make a mistake.

Componentization componentization is a mainstay of modern front-end projects, and Vue 3 is no exception. The componentization of Vue 3 is similar to that of Vue 2 in that Vue instances are used to define various components. In this front-end project, components are grouped into different categories and grouped into folders, as shown below.

Copying code. └ ─ ─ the SRC └ ─ ─ components ├ ─ ─ the button / / button ├ ─ ─ the context menu / / right-click menu ├ ─ ─ drag / / drag ├ ─ ─ the file / / file ├ ─ ─ icon / / icon ├ ─ ─ nav / / navigation ├ ─ ─ the table / / form └ ─ ─… The copy code component file is defined for.vue. Here is an example of the right menu SRC /components/context-menu/ contextmenu.vue.

Copy the code

Copying code you might wonder: it doesn’t seem to use the type system in TS. In fact, this is a very simple component, and the following component contains a complete example of TS features.

SRC/file/FileEditor. Vue: github.com/crawlab-tea…

All other modules will not be covered in detail in this article for reasons of space. Here are just a few of them.

BasicLayout defines State Management for top, sidebar, bottom, and other elements Equivalent to global Routing – page Routing configuration Internationalization – multi-language configuration Styles – SCSS is used to define Services such as global Styles and style variables – including with the backend Vue 3 Utilities How to learn Vue 3 The way to learn Vue 3 is to read the official documentation to understand the basic concepts, advanced principles and engineering of Vue 3. Author You Yuxi has introduced all aspects of Vue in detail in the document, illustrated and simple to explain the concept and knowledge of Vue 3. All in all, the documentation for Vue 3 is very friendly for beginners. If you are familiar with English, it is recommended to read the official Documents in English, which are usually up to date.

In addition to reading the official documentation, I also recommend reading good Vue 3 open source projects, such as Element+, Ant Design Vue, vuE-Admin-Beautiful. There are many good Vue 3 projects on Github. Reading their source code will help familiarize you with how to use Vue 3 and how to organize code for building large projects.

Of course, getting your hands on a front-end project with Vue 3 can help you gain insight into how Vue 3 works and how it develops, especially when using the new features of Vue 3 for work projects. After understanding the basic syntax and new features of Vue 3, the author applied what he learned into his own open source project. By learning and doing, he quickly mastered the core knowledge of Vue 3.

This article focuses on the advantages of Vue 3 for large front-end projects, especially the new TS support and composite API, which can greatly improve the readability and maintainability of code. This makes the Vue framework, which is already easy to use, even more powerful for the design and development of large front-end projects. Native support for TS makes Vue 3 project code predictable. Composite apis, on the other hand, can bring order to the messy code logic. All of this helps make the Vue 3 front end project more robust, making it easier for the front end people to write stable and maintainable code. In addition, this article uses one of my Crawlab Frontend projects under development to demonstrate how to develop enterprise-level front-end projects with Vue 3, and shows the related project structure, TS type declaration, and componentization, etc.

More experienced front-end engineers might shrug off the new features in Vue 3, since the so-called TS support and composite apis were first introduced in other well-known frameworks under other names, such as React Hooks, Vue 3 seems to just borrow from the past. But this view is highly undesirable. In the face of technology, any scheme is not high or low, only suitable. Just like a blind date, only the right one is the best. You acknowledges that AngularJS and React have a lot of good technology, and Vue has borrowed some of it. But you can’t call it plagiarism. C# has similar syntax and features to Java, but you can’t prove that C# is a copy of Java (actually C# has many better features than Java, such as implicit type inference, which is one of the reasons I prefer C#). Vue’s success, by no means accidental, is a boon for front-end developers as its ease of use and relatively rich documentation make it easy for beginners to get started. We who do technology should be tolerant of new technology and treat problems dialectically and rationally, so as not to become extreme and go astray.