Frontend-Entwicklung von Portalen für Open Source-Software: Erfahrungsaustausch

Im ersten Teil des Artikels darüber, wie wir Portallösungen für die größten Arbeitgeber in Russland erstellen, wurde die Architektur vom Backend beschrieben. In diesem Artikel werden wir zum Frontend übergehen.



Wie bereits im ersten Teil erwähnt, bestand unser Hauptziel darin, eine Plattform zu entwickeln, die einfach skaliert und gewartet werden kann.

Wiederverwendbarkeit Die

Vorderseite ist größtenteils in Vue.js geschrieben. Da das gesamte Portal in Portlets unterteilt ist, ist jedes von ihnen eine separate Vue-Instanz mit eigenem Vuex, Vue-Router und eigenen Komponenten. Jede solche Instanz wird in ein eigenes Repository verschoben.

Da sich das Portlet in seinem Repository befindet, stellt sich die Frage, wie nicht viel des gleichen Codetyps für verschiedene Portlets geschrieben werden kann. Um dieses Problem zu lösen, übertragen wir alles, was wiederverwendet werden kann, in ein separates Repository, das dann über Git-Module verbunden wird. Im Moment gibt es zwei solche Submodule.

Man speichert gemeinsame Funktionen: Dies sind gemeinsame Komponenten, Dienste, Konstanten usw. Wir haben dieses Modul namens Vue-common.

Das zweite Submodul enthält Einstellungen für die Montage, es speichert Konfigurationen für das Webpack sowie Lader und Helfer, die während der Montage benötigt werden. Dieses Modul heißt Vue-Bundler.

Zur Vereinfachung der Arbeit mit der API wurden die REST-Methoden auch in allgemeine und lokale Methoden unterteilt. In Vue-common wurden Methoden eingeführt, um eine Liste der Portalbenutzer, Verwaltungsmethoden, den Zugriff auf das Portal-Dateisystem und andere zu erhalten. Alle API-Endpunkte wurden in separate Dienste verschoben, die am Einstiegspunkt registriert und mit der Vue-Instanz verbunden waren. Dann können sie überall in der Anwendung verwendet werden.

Jeder einzelne Dienst ist im Plugin registriert. Vue verfügt über eine integrierte Verwendungsfunktion zum Verbinden von Plugins. Lesen Sie mehr über Plugins in Vue hier .

Das Plugin selbst wird folgendermaßen initialisiert:

class Api {
    constructor () {
        //  http ,   
        this.instance = instance

        //     
       //     this,      http 
        Object.keys(commonServices).forEach(name => commonServices[name](this))
        
        //     
	requireService.keys().forEach(filename => requireService(filename).default(this))
    }

    install () {
	Vue.prototype.$api= this
    }
}

export default new Api()

Zusätzlich zur Initialisierung:

  1. Die http-Client-Instanz wird erstellt. Das setzt die baseURL unseres Backends und der Header

    const instance = axios.create({
    	baseURL: '/example/api',
    	responseType: 'json',
    	headers: {
    		'Content-Type': 'application/json',
    		'Cache-Control': 'no-cache',
    		'Pragma': 'no-cache',
    	}
    })
                    backend   ,   axios.

  2. Es werden Dienste erstellt, die die Anforderungen selbst speichern

    // api -   http 
    export default api => {
    	api.exampleService= {
    		exampleGetRequest(params) {
    			return api.instance.request({
    				method: 'get',
    				url: `example/get`,
    				params
    			})
    		},
    		examplePostRequest(data) {
    			return api.instance.request({
    				method: 'post',
    				url: `example/post`,
    				data
    			})
    		},
    	}
    }
    

    In der Regel reicht es aus, nur einen solchen Dienst zu erstellen, und er ist bereits für jedes Portlet in der Api-Klasse registriert
  3. Allgemeine und lokale Dienste sind registriert

         const requireService = require.context('./service', false, /.service.js$/)
    

In Komponenten werden sie sehr einfach verwendet. Zum Beispiel:

export default {
	methods: {
		someMethod() {
    			this.$api.exampleService.exampleGetRequest()
}
}
}

Wenn Sie Anfragen außerhalb der Anwendung stellen müssen, können Sie dies tun:

//    (@ -     )
import api from ‘@/api’

//        
api.exampleService.exampleGetRequest()

Skalierung

Wie oben erwähnt, wird für jedes Portal ein separates Bundle gesammelt, und jedes Bundle verfügt über eigene Einstiegspunkte. In jedem von ihnen werden Komponenten und Assets registriert, die Autorisierung für die lokale Entwicklung konfiguriert und Plug-Ins verbunden.

Komponenten werden für jede Anwendung global registriert, sowohl lokal als auch allgemein.

Die Komponentenregistrierung sieht folgendermaßen aus:

import _ from “lodash”

const requireComponent = require.context('@/components', true, /^[^_].+\.vue$/i)

requireComponent.keys().forEach(filename => {
    const componentConfig = requireComponent(filename)

    // Get PascalCase name of component
    const componentName = _.upperFirst(
        _.camelCase(/\/\w+\.vue/.exec(filename)[0].replace(/^\.\//, '').replace(/\.\w+$/, ''))
    )

    Vue.component(componentName, componentConfig.default || componentConfig)
})

Manchmal muss das Portal, das wir entwickeln, einzigartige Funktionen hinzufügen. Dazu müssen Sie Komponenten schreiben, die für das Portal einzigartig sind, oder eine Komponente einfach auf eine andere Weise implementieren. Es reicht aus, eine Komponente in einem separaten Ordner zu erstellen, z. B. / components-portal / * portal name * / *. Vue, und sie am gewünschten Einstiegspunkt zu registrieren, wobei require.context nicht für einen Ordner, sondern für mehrere Ordner hinzugefügt wird.

const contexts = [
    require.context('@/components', true, /^[^_].+\.vue$/i),
   require.context('@/components-portal/example', true, /^[^_].+\.vue$/i)
]

contexts.forEach(requireComponent => {
    requireComponent.keys().forEach(filename => {
        const componentConfig = requireComponent(filename)

        // Get PascalCase name of component
        const componentName = _.upperFirst(
            _.camelCase(/\/\w+\.vue/.exec(filename)[0].replace(/^\.\//, '').replace(/\.\w+$/, ''))
        )

        Vue.component(componentName, componentConfig.default || componentConfig)
    })
})

Wenn Sie für die Komponente für ein bestimmtes Portal denselben Namen wie für die allgemeine Komponentenbibliothek festlegen, wird diese einfach als Eigenschaft des Objekts neu geschrieben und als Komponente für dieses Portal verwendet.

Assets wie SVG-Symbole werden ebenfalls global registriert. Wir verwenden svg-sprite-loader, um ein Sprite aus svg-Symbolen zu erstellen und sie dann über <use: xlink: href = "# * icon name *" /> zu verwenden.

Sie werden wie folgt registriert:

const requireAll = (r) => r.keys().forEach(r)

const requireContext = require.context('@/assets/icons/', true, /\.svg$/)

requireAll(requireContext)

Um nicht nur die Funktionalität, sondern auch die Komponentenstile zu skalieren, haben wir einen Mechanismus zum Ändern der Stile für ein bestimmtes Portal implementiert. Einzeldateikomponenten geben Stile im <style> -Tag an und werden standardmäßig verwendet. Um Stile für ein bestimmtes Portal zu implementieren, müssen Sie sie in einem anderen Tag registrieren

All Articles