Desarrollo frontal de portales en software de código abierto: comparta experiencia

En la primera parte del artículo sobre cómo creamos soluciones de portal para los empleadores más grandes de Rusia, el backend describió la arquitectura. En este artículo pasaremos a frontend.



Como ya se señaló en la primera parte, nuestro objetivo principal era desarrollar una plataforma que se pueda escalar y mantener fácilmente.

Reutilización El

frente está escrito principalmente en Vue.js, y dado que todo el portal está dividido en portlets, cada uno de ellos es una instancia de Vue separada con su propio Vuex, Vue Router y componentes. Cada una de esas instancias se mueve a su propio repositorio.

Dado que el portlet está en su repositorio, surge la pregunta de cómo no escribir mucho del mismo tipo de código para diferentes portlets. Para resolver este problema, transferimos todo lo que se puede reutilizar a un repositorio separado, que luego se conecta a través de .gitmodules. Por el momento hay dos submódulos de este tipo.

Uno almacena funcionalidades comunes: estos son componentes comunes, servicios, constantes, etc. Tenemos este módulo llamado Vue-common.

El segundo submódulo contiene configuraciones para el ensamblaje, almacena configuraciones para webpack, así como cargadores y ayudantes necesarios durante el ensamblaje. Este módulo se llama Vue-bundler.

Para la conveniencia de trabajar con la API, los métodos REST también se dividieron en generales y locales. En Vue-common, se introdujeron métodos para obtener una lista de usuarios del portal, métodos de administración, acceso al sistema de archivos del portal y otros. Todos los puntos finales API se movieron a servicios separados que se registraron en el punto de entrada y se conectaron a la instancia de Vue. Entonces podrían usarse en cualquier lugar de la aplicación.

Cada servicio individual se registra dentro del complemento. Vue tiene una función de uso incorporada para conectar complementos. Lea más sobre complementos en Vue aquí .

El complemento en sí se inicializa así:

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()

Además de la inicialización:

  1. Se crea la instancia del cliente http. Que establece la baseURL de nuestro backend y los encabezados

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

  2. Se crean servicios que almacenan las solicitudes mismas

    // 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
    			})
    		},
    	}
    }
    

    En vue-common es suficiente crear solo un servicio de este tipo, y ya está registrado para cada portlet en la clase Api
  3. Los servicios generales y locales están registrados.

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

En componentes, se usan de manera muy simple. Por ejemplo:

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

Si necesita realizar solicitudes fuera de la aplicación, puede hacer esto:

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

//        
api.exampleService.exampleGetRequest()

Escalado

Como se indicó anteriormente, se recopila un paquete separado para cada portal, y cada paquete tiene sus propios puntos de entrada. En cada uno de ellos, se registran componentes y activos, se configura la autorización para el desarrollo local y se conectan los complementos.

Los componentes se registran globalmente para cada aplicación, tanto local como general.

El registro de componentes se ve así:

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)
})

A veces se hace necesario que el portal que estamos desarrollando agregue una funcionalidad única, y para esto debe escribir componentes que son únicos para él, o simplemente implementar un componente de una manera diferente. Es suficiente crear un componente en una carpeta separada, por ejemplo / components-portal / * nombre del portal * / *. Vue, y registrarlo en el punto de entrada deseado, agregando require.context no para una carpeta, sino para varias.

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)
    })
})

Si establece el mismo nombre para el componente para un portal específico que el de la biblioteca general de componentes, simplemente se reescribirá como una propiedad del objeto y se usará como un componente para este portal.

Los activos como los iconos de svg también se registran globalmente. Usamos svg-sprite-loader para crear un sprite a partir de los iconos de svg y luego los usamos a través de <use: xlink: href = "# * icon name *" />

Se registran así:

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

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

requireAll(requireContext)

Para escalar no solo la funcionalidad, sino también los estilos de los componentes, hemos implementado un mecanismo para cambiar los estilos de un portal en particular. Los componentes de un solo archivo especifican estilos en la etiqueta <style> y se usan por defecto. Para implementar estilos para un portal específico, debe registrarlos en otra etiqueta

All Articles