1. Почему его следует преобразовать в модель разработки микроинтерфейса?
использовать фон
- Как команда я в основном делаю проект по обслуживанию в правительственной информационной технологии конструктивных, то есть мы часто говоримtoG. Этот проект завершен командой R & D, состоящей из почти дюжины компаний-победителей.Каждая компания отвечает за подсистему бизнеса, и каждая система сложна, проект, который я делал раньше. Подсистемы нашей компании заняли полтора года от проекта, такой огромный проект многие члены команды делают впервые. Таким образом, в опыте проекта и в начале недели каждый потребитель столкнулся с огромными проблемами для завершения стыковки, конечно, есть необходимость расти;
- Front-end архитектура проекта такова, что один из пакетов берет на себя роль единого портала, а затем подсистемы бизнеса других пакетов используютiframeОн каким-то образом встроен в систему портала, а стек технологий каждого пакета объединен на одной странице.Vue+ElementUI.
- Поскольку компания также выполняет рядSAASВ то же время также необходимо полностью отделить существующий набор проектов, обслуживающих правительство, от зависимости других подрядчиков, чтобы реализовать сотрудничество с компанией.SAASбесшовное соединение химических продуктов.
- этот наборSAASВсе подсистемы химического продукта совместно используют набор пользовательских систем, а затем проходятжилецОтправляйтесь в разные провинции и деловые места, чтобы приземлиться. Все наши подсистемыподелиться одной системой входа,такая же структура меню,тот же заголовок,тот же переключатель вкладок,Просто бизнес-логика каждой подсистемы разная. Что касается внешнего интерфейса, то если для разработки по-прежнему используется традиционная одностраничная модель, если необходимо реализовать 20 провинций, то нам необходимо разработать 20 наборов одностраничных проектов. некоторые общие меню, пользовательские системы, заголовок и т. д. необходимо многократно копировать, как стоимость разработки интерфейса, так и стоимость последующего обслуживания огромны. Поэтому, учитывая все аспекты, доступ к микроинтерфейсу может быть хорошим выбором.
Вот простой демонстрационный пример продукта SAAS компании.
Авторизоваться
Страница входа в систему
подсистема
2. Как построить микро-интерфейсный проект, подходящий для системы вашей компании?
рынок
В настоящее время многие крупные производители также используютqiankunЭто упакованный фреймворк, который работает из коробки.But, пакет, упакованный другими, не обязательно применим к нам;So, чтобы по-настоящему понять основную концепцию микро-интерфейса, вам все равно нужно сделать это самостоятельно. Прежде чем мы начнем, давайте посмотрим на разницу между микро-интерфейсом и традиционной одностраничной;
- В чем разница между микроинтерфейсом и традиционным одностраничным приложением?
традиционная одностраничная
микро интерфейс
- Как собрать набор микрофронтендов, подходящих для вашей компании от 0 до 1?
- Из приведенного выше рисунка ясно видно, что ядро микроинтерфейса на самом деле состоит иззагрузчик модулей(enter),
ОдинБазовый модуль (навбар) (логин + меню + шапка и другие публичные части),различные модули подсистемыЭти три части составляются. Здесь я также создал 4 фронтенд-проекта.
, соответственно:Вход (ввод), панель навигации (база), подсистема один, подсистема два.
- Входное приложение (enter)пройти черезsystemjsПо разным подсистемамидентификатор маршрутазагружать упакованные по требованиюapp.jsдокумент.
Модернизация приложения ввода
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="importmap-type" content="systemjs-importmap">
<link rel="stylesheet" href="/style/common.css">
<title>微前端入口</title>
<script type="systemjs-importmap">
{
"imports": <%= JSON.stringify(htmlWebpackPlugin.options.meta.all) %>
}
</script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<link rel="preload" href="/js/single-spa.min.js" as="script" crossorigin="anonymous" />
<link rel="preload" href="/js/vue.min.js" as="script" crossorigin="anonymous" />
<script src='/js/minified.js'></script>
<script src="/js/import-map-overrides.js"></script>
<script src="/js/system.min.js"></script>
<script src="/js/amd.min.js"></script>
<script src="/js/named-exports.js"></script>
<script src="/js/named-register.min.js"></script>
<script src="/js/use-default.min.js"></script>
</head>
<body>
<script>
(function() {
Promise.all([
System.import('single-spa'),
System.import('vue'),
System.import('vue-router'),
System.import('element-ui')]).then(function (modules) {
var singleSpa = modules[0];
var Vue = modules[1];
var VueRouter = modules[2];
var ElementUi = modules[3];
Vue.use(VueRouter)
Vue.use(ElementUi)
<% for (let app in htmlWebpackPlugin.options.meta.route) { %>
singleSpa.registerApplication(
'<%= app %>',
function () {
return System.import('<%= htmlWebpackPlugin.options.meta.route[app] %>')
},
function(location) {
<% if (app !== 'navbar') { %>
return location.pathname.split('/')[1] === '<%= app %>'
<% } else { %>
return true
<% } %>
})
<% } %>
singleSpa.start();
})
})()
</script>
<import-map-overrides-full show-when-local-storage="overrides-ui"></import-map-overrides-full>
</body>
</html>
- Во-первых, передайте плагины, от которых зависит микро-интерфейс.scriptПредставлять.
- Тогда мы сначала проходимsystem.jsПоместите в проект некоторые общедоступные плагины, такие какvue, vue-маршрутизатор, ElementUiДождитесь глобального представления.
- Наконец, с помощьюwebpackизhtmlWebpackPluginв плагинеmetaАтрибуты, пакет каждой подсистемы бизнесаapp.jsПройдите и разгрузитесь. Конечно, мы также можем напрямую передать метод обхода без использованияpromiseЧтобы ввести асинхронно, метод обхода используется для введения здесь в основном для лучшего постобслуживания и лучшей масштабируемости.
конфигурация веб-пакета
new HtmlWebpackPlugin({
filename: 'index.html',
template: resolve(__dirname, '../index.ejs'),
inject: false,
title: 'title',
minify: {
collapseWhitespace: false
},
meta: {
all: Object.assign(config[0], config[1]),
route: config[1],
outputTime: new Date().getTime()
}
})
- подсистемаapp.jsпройти черезconfigдля загрузки в разных средахapp.js, даже используяNodeпеременные среды, чтобы различатьразвивать,тестовое задание,Производствотри среды.
среда разработки
module.exports = {
"navbar": '//localhost:8002/navbar/app.js',
"children1": '//localhost:8003/children1/app.js',
"children2": '//localhost:8004/children2/app.js',
};
тестовая среда
const host = process.env.HOST;
module.exports = {
"navbar": host + '/navbar/app.js',
"children1": host + '/children1/app.js',
"children2": host + '/children2/app.js',
};
Производственная среда
const host = process.env.HOST;
module.exports = {
"navbar": host + '/navbar/app.js',
"children1": host + '/children1/app.js',
"children2": host + '/children2/app.js',
};
здесьhostТо есть доменное имя доступа тестовой и производственной среды, которое мы настраиваем в записи для упаковки и сборки.
"build": "rimraf dist && cross-env NODE_ENV=production HOST=//spa.caoyuanpeng.com:9001 webpack --config build/webpack.prod.config.js"
Выше приведено приложение для входа (enter) несколько шагов настройки ядра, конечно, нам нужно обратить внимание на упаковку входа здесь, мыlibraryTargetидти все вместеUMDрежим упаковки.
output: {
path: resolve(__dirname, '../dist'),
publicPath: '/',
filename: '[name].js',
chunkFilename: 'js/[name]-[chunkhash:6].js',
library: 'app',
libraryTarget: 'umd'
}
- О трансформации приложения navbar
Пакет webpack.base.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HappyPack = require('happypack');
// 通过os动态获取开启子进程的数量
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
const BasePlugins = require('./plugins');
const { resolve } = path;
const isDevMode = process.env.NODE_ENV === 'development';
module.exports = {
devtool: process.env.NODE_ENV !== 'production' ? 'source-map' : 'none',
// 入口
entry: {
app: ['webpack-hot-middleware/client', resolve(__dirname, main)]
},
// 出口
output: {
filename: 'app.js',
path: resolve(__dirname, '../dist'),
chunkFilename: 'js/[name]-[chunkhash:6].js',
publicPath: isDevMode ? '/' : '/navbar',
// library: 'navbar',
libraryTarget: 'umd'
},
externals: isDevMode ? {} : ['vue', 'vue-router', 'element-ui'],
plugins: [
...BasePlugins,
new MiniCssExtractPlugin({
filename: 'css/[name].[hash:6].css',
chunkFilename: 'css/[id].[hash:6].css'
}),
new HappyPack({
/*
* 必须配置
*/
// id 标识符,要和 rules 中指定的 id 对应起来
id: 'babel',
// 需要使用的 loader,用法和 rules 中 Loader 配置一样
// 可以直接是字符串,也可以是对象形式
loaders: ['babel-loader?cacheDirectory'],
// 使用共享进程池中的子进程去处理任务
threadPool: happyThreadPool
})
],
module: {
rules: [
{
test:/\.css$/,
use:[
{
loader: isDevMode ? 'style-loader' : MiniCssExtractPlugin.loader
},
'css-loader', {
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}
]
},
{
test: /\.less$/,
use:[
{
loader: isDevMode ? 'style-loader' : MiniCssExtractPlugin.loader
},
'css-loader',
'less-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ['happypack/loader?id=babel'],
},
{
test: /\.(jpg|jpeg|png|gif)$/,
loaders: 'url-loader',
exclude: /node_modules/,
options: {
limit: 8192,
outputPath: 'img/',
name: '[name]-[hash:6].[ext]'
}
},
{
test: /\.(woff|woff2|svg|eot|ttf)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'fonts/',
name: '[name].[ext]'
}
}
]
},
{
test: /\.vue$/,
use: ['vue-loader']
}
]
},
resolve: {
extensions: ['.js', 'json', '.less', '.css', '.vue'],
alias: {
vue$: 'vue/dist/vue.common.js',
'@': resolve(__dirname, '../src'),
'pages': resolve(__dirname, '../src/pages'),
}
}
};
- мы вПроизводственная средаа такжетестовое кольцоиспользуется при упаковкеexternalsБудуvue, vue-маршрутизатор, элемент-интерфейсудалены, т.к. эти плагины находятся в нашемenterбыл введен в , поэтому вnavbarОн используется только в среде разработки в системе, а тестовую и производственную среды не нужно вводить повторно.
- publicPath: '/navbar'Определите упакованный виртуальный путь, который должен быть указан здесь и не может иметь то же имя, что и каждая подсистема бизнеса;
- libraryTarget: 'umd', все еще используюUMDрежим упаковки
Входное преобразование системы навигации
base.js
import '@babel/polyfill';
import { setPublicPath } from 'systemjs-webpack-interop';
import Vue from 'vue';
import VueRouter from 'vue-router';
import Element from 'element-ui';
import singleSpaVue from 'single-spa-vue';
import routes from '../router';
const baseFn = () => {
// 默认控制台不输出vue官方打印日志
Vue.config.productionTip = false;
// 使用devtools调试
Vue.config.devtools = true;
// 注册navbar
setPublicPath('navbar');
// 生成vue-router实例
const router = new VueRouter({
mode: 'history',
routes
});
Vue.use(VueRouter);
Vue.use(Element);
// appOptions抽离
const appOptions = {
render: h => <div id="navbar">
<router-view></router-view>
</div>,
router
};
// 注册single-spa-vue实例
const vueLifecycles = singleSpaVue({
Vue,
appOptions
});
return vueLifecycles;
}
export default baseFn;
здесь черезsystemjs-webpack-interopсерединаsetPublicPathрегистрnavbar, затем поставьтеvueэкземпляр, за которым следуетrouter,vuexустановлены наsingleSpaVueначальство.
main.dev.js
import BaseFn from './base';
BaseFn();
main.prod.js
import BaseFn from './base';
const vueLifecycles = BaseFn();
export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;
производственная среда будетvueLifecyclesподняться набутстрап, монтировать, размонтироватьЭти три односпальных цикла находятся на крючке.
Преобразование маршрутизации страницы
import View from '@/pages/components/view';
const Template = () => import(/* webpackChunkName: "index" */ '@/pages/index');
const routes = [
{
path: '/navbar',
component: Template,
meta: {
title: '菜单'
},
children: [
{
path: '*',
component: View,
meta: {
title: ''
}
}
]
}
];
export default routes;
Нам нужно добавить единый префикс доступа к началу маршрута.navbar, цель - входenterВы можете получить доступ к префиксам через разные маршруты для загрузки различных по запросуapp.js. ==Здесь есть одна вещь, на которую следует обратить особое внимание, а именно: наша цель — всегдаnavbarПриложение загружается без разрушения,Здесь вам нужно установить путь под детьми к*==
- Преобразование приложения подсистемы
Трансформация подсистемы фактически аналогична трансформации вышеописанной панели навигации, за исключением того, что есть некоторые отличия в настройке вебпака и маршрутизации страниц.
output: {
filename: 'app.js',
path: resolve(__dirname, '../dist'),
chunkFilename: 'js/[name]-[chunkhash:6].js',
publicPath: isDevMode ? '/' : '/children2',
library: 'children2',
libraryTarget: 'umd'
}
publicPathбыть настроенным наchildren2,так же какlibraryбыть настроенным наchildren2.
Затем идет маршрутизация, которая должна установить префикс единого доступа страницы подсистемы наchildren2
import View from '@/pages/components/view';
const Template = () => import(/* webpackChunkName: "index" */ '@/pages/index');
const Detail = () => import(/* webpackChunkName: "detail" */ '@/pages/test');
const routes = [
{
path: '/children2',
component: View,
meta: {
title: '子应用'
},
children: [
{
path: 'index',
component: Template,
meta: {
title: '首页'
}
},
{
path: 'detail',
component: Detail,
meta: {
title: '详情'
}
}
]
}
];
export default routes;
- После загрузки app.js подсистемы single-spa-vue генерирует разные экземпляры vue в соответствии с разными маршрутами.
вот простоdemoДемонстрация, заинтересованные друзья могут щелкнуть эту ссылку, чтобы испытать ее.
- Прежде всего, в приведенной выше демонстрации мы ясно видим, что при первом доступе к доменному имени для загрузки панели навигации сначала будет сгенерирован экземпляр панели навигации (здесь две кнопки подсистема 1 и подсистема 2 используются для отображения содержимое навигационной панели), когда мы нажмем кнопку подсистемы 1, будет автоматически сгенерирован экземпляр Children1, страница будет отображать содержимое подсистемы 1, а экземпляр навигационной панели останется и не будет уничтожен.
- Затем, когда мы нажимаем кнопку подсистемы 2, автоматически создается экземпляр children2, и страница отображает содержимое подсистемы 2. В этот момент экземпляр children1 будет уничтожен, а экземпляр navbar останется без уничтожения.
- На этом этапе мы можем завершить создание микроинтерфейсного приложения от начала до конца.
3. В чем разница между развертыванием микроинтерфейсов в производственных средах и традиционным одностраничным развертыванием?
- Для традиционных одностраничных приложений нам просто нужно передатьjenkinsилиdockerчтобы упаковать нашу статику, а затем скопировать упакованный статический пакет на статический сервер через скрипт и, наконец, передатьNginxдля запуска агента.
- Развертывание микрофронтендов несколько отличается от нашего традиционного одностраничного, потому что мы по сути используем основное приложение для загрузки разных подприложений, то есть основное приложение и базовое приложение, главное приложение и подприложения взаимозависимый от. Поэтому при развертывании нам нужно найти способ очистить эти соответствия через скрипт сборки, прежде чем мы сможем плавно запустить микро-фронтенд.
- еслиjenkinsизpipelineДля сборки нам нужно обратить внимание на то, что каждый раз перед сборкой основного приложения следует удалять предыдущий старый каталог сборки, а затем копировать новый основной каталог приложения. Мы можем создатьмягкое соединениеВы можете связать каталог файлов основного приложения с тем же уровнем, что и каталог подприложения.
вот черезjenkinsУпаковывается и копируется в указанный нами каталог статических файлов.
Действуя на главном приложении Nginx
server {
listen 9001;
server_name spa.caoyuanpeng.com;
location / {
root /home/single-spa-vue;
try_files $uri $uri/ /index.html;
index index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
- Нашему nginx нужно только найти файл index.html в приложении ввода.
- Путь к файлу подсистемы на сервере должен совпадать с идентификационным именем маршрутизации нашей подсистемы, иначе файл не может быть загружен в систему.
- Подсистемы не требуют дополнительной отдельной настройкиnginx, вам нужно только настроить приложение для входа.
4. Каковы преимущества и недостатки преобразования в микро-интерфейс?
Преимущество
- Чтобы уменьшить объем упаковки системы, средний пакет подсистемы составляет менее нескольких сотен тысяч, а все общедоступные файлы js и файлы css необходимо загрузить только один раз.
- Благодаря совместимости с различными технологическими стеками мы можем использовать несколько технологических фреймворков (React, Vue, AngularJS) на одной странице, и нет необходимости обновлять страницу.
- Если есть подсистема, которая хочет получить доступ к микроинтерфейсу, стоимость доступа невелика, и нет необходимости рефакторить код.
- Код каждой подсистемы может быть загружен по требованию без траты дополнительных ресурсов.
- Каждая подсистема может быть отдельным проектом git и развертываться независимо.
- Между разными git-проектами можно собирать произвольные модули на основе каждого независимого маршрута страницы.
- Пользовательский опыт лучше, и пользователь может загружать несколько подсистем одновременно без восприятия.
недостаточный
- Поскольку в процессе загрузки будет сгенерировано несколько экземпляров Vue, необходимо сформулировать подробные спецификации глобального стиля, иначе это вызовет различные загрязнения стиля.
- Внешний используется в подсистеме для извлечения некоторых общих плагинов, в то же время нам нужно избегать загрязнения, вызванного такими конструкторами, как vue, vue-router, element-ui и т. д.
- Средства защиты маршрутизации подсистем не должны влиять друг на друга.
- Не все сценарии подходят для архитектуры микро-фронтенда, эти сценарии подходят, когда у вас есть достаточное количество проектов, все из которых представляют собой похожие одностраничные проекты, и вам нужно объединить различные функции подсистемы в большую систему.
5. Какие лучшие прорывы могут быть сделаны на основе микроинтерфейса в будущем?
- Позвольте задневскому микромущему партнеру в манере вывода сервиса, вывод переднего конца подмодулей в соответствии с функцией в соответствии с маршрутом, так что его можно сделать полностью произвольно собранными модулями в соответствии с функцией между различными подсистемами, Полная реализация микроспарного конца. Конечно, эта трудность относительно велика, взаимодействие данных между различными подсистемами - это большая проблема.
- Фронтальный интерфейс инкапсулирует вывод в соответствии с модулем, и формат данных, возвращаемый задней частью, остается равномерным среди различных подсистем.
6. Резюме
- С непрерывным развитием интерфейсной компонентизации и проектирования архитектура микроинтерфейса может становиться все более и более популярной.
- Если у вас есть тот же бизнес-сценарий, что и выше, с точки зрения технологических инноваций, я думаю, вы можете попытаться преобразовать его, и вы можете получить неожиданные сюрпризы и выгоды.