введение проблемы
Начнем с трудного вопроса:Многостраничное приложение MPA или архитектура микроинтерфейса, как работать с общими частями страниц.
Причина, по которой он острый, заключается в том, что с ним сталкивалась не только наша компания, но и многие передовые технические команды в стране и за рубежом, включая Tencent.
Например этот блог:Дилемма документов Tencent
Возьмем в качестве примера приложения MPA, такие как часть меню, когда отрисовывается традиционный внутренний шаблон,
// .NET
@Html.Partial("Header")
или
// Java
<%@ include file="header.jsp" %>
Внедрите общедоступные шаблоны, чтобы общедоступные части отображались непосредственно при доступе к странице.
Но если это современный проект (например, React), проект MPA с неразделенными интерфейсом и сервером (страница по-прежнему обрабатывается серверной частью, а рендеринг Dom берет на себя React), мы скопируем встроенные файлы ресурсов во внутренний проект. , добавив сценарий и стиль на страницу для рендеринга.
На данный момент проблема проявляется: для общей части заголовка страницы это компонент, отображаемый React.
Общепринятой практикой является встраивание общедоступной части в качестве компонента непосредственно в каждый проект уровня страницы, что ж, документы Tencent делают то же самое.
Это имеет следующие недостатки:
- Создайте избыточность, каждый проект на уровне страницы будет упакован в него при его сборке, что бесполезно тратит пропускную способность при загрузке.
Например
Header
Часть объема индивидуальной сборки составляет400KB
, то каждый результат сборки на уровне страницы будет увеличиваться по сравнению с существующим томом.400KB
(Игнорировать общие зависимости библиотек, предполагая унифицированное использованиеDllReferencePlugin
иметь дело с). Без малейшего преувеличения мыHeader
Есть много функций, плюсchunks
После этого действительно было почти500KB
.
- Если общественная часть внесена изменения, то все ссылки на его проект восстановить всю выпущенную версию!
особенно для
Header
Все приложения уровня страницы должны быть перестроены для распространения с минимальными изменениями в этой общей части, которую использует каждая страница.
Например, центр уведомлений документа Tencent на следующем рисунке:
Это казалось невозможным до выхода webpack5!
Передняя часть документов Tencent также изучала эту проблему, но из процесса исследования, описанного в статье, она в основном предназначена для упакованных__webpack_require__
В метод встроены крючки для поднятия шума, а эффективного решения предложено не было.
Если честно, нижний слой вебпака пока очень сложен, и степень кастомизации в случае незнакомости определить нельзя, так что мы этим давно особо не занимались.
- Выдержка из "Дилемма документов Tencent》
Однако, после серии исследований, мы отлично решили эту проблему в июле 2019 года, используя существующие функции webpack4! Так совпало, что команда Wepback также добавила в последней версии V5Module-Federation
Эта функция, используемая для этой сцены.
Начнем официальную галантерею!
решение webpack4
Причина, по которой друзья Tencent Docs не осмеливаются быть правыми__webpack_require__
Делаю это только потому, что это слишком сложно, и я боюсь, что это вызовет другие проблемы после изменения.
На самом деле, они с самого начала пошли не в том направлении, так наз.Ударь змею и ударь семь дюймов, Если вы пропустите семь дюймов, это вызовет ряд проблем, или вы не решитесь попасть.
Итак, обращаем внимание на «семь дюймов»Внешние расширения (externals)Заглянем в свойства (по умолчанию все уже знают его функцию).
Поскольку это мост между внутренними компонентами веб-пакета (npm + сборки) и внешними ссылками, я думаю, что это наиболее подходящее место для использования ножа!
рассмотрениеexternals
а такжеumd
Напомним, что мы используемexternals
Настройте сторонние библиотеки CDN, такие какReact
, настроенный следующим образом:
externals: {
'react-dom': 'ReactDOM',
'react': 'React'
}
Затем мы смотрим на React
Справочная ссылка CDN, обычно мы используемumd
версия сборки, она будет совместимаcommonjs
,commonjs2
,amd
,window
и т. д., в среде нашего браузера он свяжетReact
переменная кwindow
начальство:
externals
Роль такова: при сборке веб-пакета он встречаетimport React from 'react'
а такжеimport ReactDOM from 'react-dom'
будет избегаться при импорте операторовnode_modules
идтиexternals
Настроенное сопоставление найдено, и это значение сопоставления (ReactDOM
а такжеReact
) Этоwindow
найдено в переменной.
Следующие два рисунка демонстрируют это:
Почему я трачу так много места на то, чтобы заложить основу для этого?externals
Шерстяная ткань? Потому что это мост, мост для подключения внешних модулей!
Давайте сделаем смелую идею: В идеале моя общедоступная часть — это компонент заголовка! Если он построен самостоятельно какumd
пакет вexternals
настроен в видеimport Header from 'header';
Импортировать, потом использовать как компонент, как?
Я проверил это и не имею никаких проблем! ! !
Однако идеальной ситуации не существует, и вероятность так же мала, как выигрыш в благотворительной лотерее.
Большинство из нас такие:
import { PredefinedRole, PredefinedClient } from '@core/common/public/enums/base';
import { isReadOnlyUser } from '@core/common/public/moon/role';
import { setWebICON } from '@core/common/public/moon/base';
import ErrorBoundary from '@core/common/public/wrapper/errorBoundary';
import OutClick from '@core/common/public/utils/outClick';
import { combine } from '@core/common/entry/fetoolkit';
import { getExtremePoint } from '@core/common/public/utils/map';
import { cookie } from '@core/common/public/utils/storage';
import Header from '@common/containers/header/header';
import { ICommonStoreContainer } from '@common/interface/store';
import { cutTextForSelect } from '@common/public/moon/format';
import { withAuthority } from '@common/hoc';
......
Подобные ссылки встречаются в десятках проектов, особенно псевдонимы (alias
) используйте, есть десятки ситуаций цитирования!
ПС: мы
monorepo
архитектура,@core/common
Это общедоступный проект зависимостей. Здесь поддерживаются методы инструментов, перечисления, экземпляры axios, общедоступные компоненты, меню и т. д., поэтому мы испробовали все средства для независимой сборки этого проекта.
а такжеexternals
Приведенный выше метод конфигурации поддерживает преобразование только в следующих случаях, он просто точно соответствует имени модуля:
import React from 'react'; => 'react': 'React' => e.exports = React;
import ReactDom from 'react-dom'; => 'react-dom': 'ReactDOM' => e.exports = ReactDOM;
За именем сторонней библиотеки не может следовать/
Пути! Например, не поддерживается следующее:
import xxx from 'react/xxx';
Ивы и цветы
Я думал, маловероятно, что разработчики веб-пакетов будут настолько жесткими в отношении API, должны быть скрытые входы. как и ожидалось! Прочитав официальную документацию, я нашел подсказку:Он также поддерживает функции!
Функция функции состоит в том, чтобы:свободно распоряжаться любымimport
утверждение!
Мы можем попробовать напечатать входные параметры в этой функцииrequest
значение, результат показан на следующем рисунке:
всеimport
Цитаты все напечатаны! Итак, мы можем манипулировать по желанию@common
а также@core/common
Релевантные ссылки! Например:
function(context, request, callback) {
if (/^@common\/?.*$/.test(request) && !isDevelopment) {
return callback(
null,
request.replace(/@common/, '$common').replace(/\//g, '.')
);
}
if (/^@moon$/.test(request) && !isDevelopment) {
return callback(null, '$common.Moon');
}
if (/^@http$/.test(request) && !isDevelopment) {
return callback(null, '$common.utils.http');
}
callback();
}
Объясните здесь,callback
является callback-функцией (что также означает, что она поддерживает асинхронное суждение), ее первый параметр имеет неизвестное назначение и не указан в документации, второй параметр — это строка, которая будет отправлена вwindow
выполнить это выражение на$common.Moon
, он найдетwindow.$common.Moon
.
Таким образом, цель приведенного выше кода предельно ясна:@common
заменить$common
, который будет ссылаться на путь в/
заменить.
иди вместо этогоwindow
Найти на.
Имена переменных не могут начинаться с
@
символ, так что я будуlibrary
Значение заменяется на$common
Так,Теперь при создании проекта на уровне страницы можно удалить общую часть и оставить ее автоматически.window
искал на, но в это времяwindow
еще нет$common
объект!
Создавайте публичные проекты самостоятельно
Прежде всего, в конце предыдущего раздела наши потребности ясны, нам нужно построить$common
Объектыwindow
выше, для этого мы можем использоватьumd
,window
илиglobal
форма для построения. но,$common
Должен быть ряд податрибутов наimport
Путь для иерархического дизайна, например:
import $http, { Api } from '@http';
import Header from '@common/containers/header/header';
import { CommonStore } from '@common/store';
import { timeout } from '@packages/@core/common/public/moon/base';
import * as Enums2 from '@common/public/enums/enum';
import { Localstorage } from '@common/utils/storage';
Нам нужно$common
Имеет следующую структуру:
Итак, как построить эту иерархию$common
Что с объектом? Ответ очень прост, достаточно экспортировать объект соответствующей структуры для записи компиляции!
Вставьте код напрямую:
// webpack.config.js
output: {
filename: "public.js",
chunkFilename: 'app/public/chunks/[name].[chunkhash:8].js',
libraryTarget: 'window',
library: '$common',
libraryExport: "default",
},
entry: "../packages/@core/common/entry/index.tsx",
// @core/common/entry/index.tsx
import * as baseEnum from '../public/enums/base';
import * as Enum from '../public/enums/enum';
import * as exportExcel from '../public/enums/exportExcel';
import * as message from '../public/enums/message';
import commonStore from '../store';
import * as client from '../public/moon/client';
import * as moonBase from '../public/moon/base';
import AuthorityWrapper from '../public/wrapper/authority';
import ErrorBoundary from '../public/wrapper/errorBoundary';
import * as map from '../containers/map';
import pubsub from '../public/utils/pubsub';
import * as format from '../public/moon/format';
import termCheck from '../containers/termCheck/termCheck';
import filterManage from '../containers/filterManage/filterManage';
import * as post from '../public/utils/post';
import * as role from '../public/moon/role';
import resourceCode from '../public/moon/resourceCode';
import outClick from '../public/utils/outClick';
import newFeature from '../containers/newFeature';
import * as exportExcelBusiness from '../business/exportExcel';
import * as storage from '../public/utils/storage';
import * as _export from '../public/utils/export';
import * as _map from '../public/utils/map';
import * as date from '../public/moon/date';
import * as abFeature from '../public/moon/abFeature';
import * as behavior from '../public/moon/behavior';
import * as _message from '../public/moon/message';
import * as http from '../public/utils/http';
import Moon from '../public/moon';
import initFeToolkit from '../initFeToolkit';
import '../containers/header/style.less';
import withMonthPicker from '../public/hoc/searchBar/withMonthPicker';
import withDateRangePickerWeek from '../public/hoc/searchBar/withDateRangePickerWeek';
import withDateRangePickerClear from '../public/hoc/searchBar/withDateRangePickerClear';
import MessageCenterPush from '../public/moon/messageCenter/messageCenterPush';
import { AuthorityBusiness, ExportExcelBusiness, FeedbackBusinessBusiness,
FilterManageBusiness, HeaderBusiness, IAuthorityBusinessProps,
IExportExcelBusiness, IFeedbackBusiness, IFilterManageBusinessProps,
IHeaderBusinessProps, IMustDoBusinessProps, INewFeatureBusinessProps,
MustDoBusiness, NewFeatureBusiness } from '../business';
import {
Header, FeedBack, MustDoV1, MustDoV2, Weather,
withSearchBarCol, withAuthority,
withIconFilter, withExportToEmail, withSelectExport, withPageTable, withVisualEventLog
} from '../async';
const enums = {
base: baseEnum,
enum: Enum,
exportExcel,
message
};
const business = {
exportExcel: exportExcelBusiness,
feedback: FeedbackBusinessBusiness,
filterManage: { FilterManageBusiness },
header: { HeaderBusiness },
mustDo: { MustDoBusiness },
newFeature: { NewFeatureBusiness },
authority: { AuthorityBusiness },
};
const containers = {
map,
feedback: FeedBack,
newFeature,
weather: Weather,
header: { header: Header },
filterManage: { filterManage },
termCheck: { termCheck },
mustdo: {
mustdoV1: { mustDo: MustDoV1 },
mustdoV2: { mustDo: MustDoV2 },
}
};
const utils = {
pubsub,
post,
outClick,
storage,
http,
export: _export,
map: _map
};
const hoc = {
exportExcel: {
withExportToEmail: withExportToEmail,
withSelectExport: withSelectExport
},
searchBar: {
withDateRangePickerClear: withDateRangePickerClear,
withDateRangePickerWeek: withDateRangePickerWeek,
withMonthPicker: withMonthPicker,
withSearchBarCol: withSearchBarCol,
},
wo: {
withVisualEventLog: withVisualEventLog
},
withAuthority: withAuthority,
withIconFilter: withIconFilter,
withPageTable: withPageTable,
withVisualEventLog,
withSearchBarCol,
withMonthPicker,
withDateRangePickerWeek,
withDateRangePickerClear,
withSelectExport,
withExportToEmail,
};
export default {
enums,
utils,
business,
containers,
hoc,
initFeToolkit,
store: commonStore,
Moon: Moon,
wrapper: {
authority: AuthorityWrapper,
errorBoundary: ErrorBoundary,
},
public: {
enums,
hoc,
moon: {
date,
client,
role,
MessageCenterPush,
resourceCode,
format,
abFeature,
behavior,
message: _message,
base: moonBase,
}
}
};
Хотя код немного длинный, его нетрудно прочитать. Наша цель — построить объект экспорта, иерархия которого исчерпывает всеimport
Возможности Пути!
И как только мы добавим общедоступный файл для использования другими проектами, мы должны поддерживать этот файл, потому что это настоящая запись!
Этот файл такой длинный, с одной стороны, потому что там действительно много публичных функций, а с другой стороны, потому что мы используем веб-пакет
alias
функции, что приводит к разнообразию эталонных методов, а возможность их исчерпания несколько больше (например,withSearchBarCol
Есть два способа импорта, поэтому в структуре он появляется дважды). Поэтому, если вы хотите использовать эту программу, рекомендуется установить стандарт для ее управления.
использовать в сочетании
Самостоятельное построение публичных частей завершено, и приложение страницы тоже их извлекло, так как же использовать их вместе?
Просто обратитесь к нему по порядку!
Как отлаживать
Осторожная детская обувь может попросить, поэтому приложение подстраницы относится к упакованномуpublic.js
, Как отладить среду разработки во время реальной разработки?
Когда приложение страницы создается или запускается, я добавляюisDevelopment
Переменные контролируются и извлекаются только после создания рабочей среды. В противном случае звоните напрямуюcallback()
Возвращает как есть, ничего не делая.
Таким образом, при написании кода в среде разработки фактическая ссылка по-прежнему сохраняется.node_modules
по местному проекту.
для
monorepo
локальные проектные зависимости архитектуры,lerna
Устанавливается мягкое соединение.
На самом деле достичь этого уровня с существующими функциями webpack 4 непросто, ведь передовые технические команды в стране и за границей бьются над этим уже несколько лет!
Далее, давайте взглянем на webpack5, решение, которое заставило их сиять!
решение webpack5
Module Federation
webpack5 предоставляет нам встроенный плагин:ModuleFederationPlugin
Автор определяет его следующим образом:
Федерация модулей позволяет приложению JavaScript динамически загружать код из другого приложения — в процессе обмена зависимостями, если приложение, использующее федеративный модуль, не имеет зависимости, необходимой для федеративного кода — Webpack загрузит отсутствующую зависимость из этого источника федеративной сборки. .
Федерация модулей позволяет приложению JavaScript динамически загружать код из другого приложения JavaScript при совместном использовании зависимостей. Если приложение использует федеративный модуль, который не имеет необходимых зависимостей в федеративном коде, Webpack загрузит отсутствующие зависимости из федеративного источника сборки.
Терминология Объяснение
несколько терминов
-
Module federation
: а такжеApollo GraphQL federation
Идея та же, но для модулей JavaScript, работающих в браузере или Node.js. -
host
: первая сборка Webpack, которая будет инициализирована во время загрузки страницы (когда запускается событие onLoad); -
remote
: еще одна сборка Webpack, частично используемая «хостом»; -
Bidirectional(双向的) hosts
: когда пакет или сборка веб-пакета запускается как хост или удаленный, он либо потребляет, либо потребляется другими приложениями — как во время выполнения. -
Оркестрационный слой (
orchestration layer
): Это специально разработанная среда выполнения Webpack и точка входа, но это не обычная точка входа приложения и занимает всего несколько КБ.
Разбор конфигурации
Давайте сначала перечислим методы использования для всеобщего обозрения, а позже мы углубимся в детали:
// app1 webpack.config.js
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
...
plugins: [
new ModuleFederationPlugin({
name: "app1",
library: { type: "var", name: "app1" },
remotes: {
app2: "app2"
},
shared: ["react", "react-dom"]
}),
]
// app1 App.tsx
import * as React from "react";
import Button from 'app2/Button';
const RemoteButton = React.lazy(() => import("app2/Button"));
const RemoteTable = React.lazy(() => import("app2/Table"));
const App = () => (
<div>
<h1>Typescript</h1>
<h2>App 1</h2>
<Button />
<React.Suspense fallback="Loading Button">
<RemoteButton />
<RemoteTable />
</React.Suspense>
</div>
);
export default App;
// app2 webpack.config.js
...
plugins: [
new ModuleFederationPlugin({
name: "app2",
library: { type: "var", name: "app2" },
filename: "remoteEntry.js",
exposes: {
Button: "./src/Button",
Table: "./src/Table"
},
shared: ["react", "react-dom"]
})
]
Вот демонстрация того, как использовать общий доступ app2 в app1Button
а такжеTable
компоненты.
Небольшое пояснение значения этих элементов конфигурации:
-
ModuleFederationPlugin
Отwebpack/lib/container/ModuleFederationPlugin
,Являетсяplugin
. -
либо
host
илиremote
нужно инициализироватьModuleFederationPlugin
плагин. -
Можно использовать любой модуль
host
илиremote
или оба. -
name
Обязательно, не настроеноfilename
свойство будет использоваться в качестве уровня оркестровки текущего проекта (orchestration layer
)имя файла -
filename
Необязательно, имя файла слоя оркестровки, используется, если не настроеноname
стоимость имущества. -
library
Требуется, определите структуру модуля и имя переменной уровня оркестровки, а такжеoutput
изlibraryTarget
Функциональность похожа, но только для уровня оркестровки. -
exposes
Необязательные (требуются для общих модулей) внешние элементы, пары ключ-значение,key
значениеapp1
(общим модулем), на который ссылаетсяimport Button from 'app2/Button';
средняя и задняя половина пути,value
значениеapp2
Фактический путь в проекте. -
remote
пара ключ-значение, что означает что-то вродеexternal
,key
значениеimport Button from 'app2/Button';
первая половинаvalue
значениеapp2
настроен вlibrary -> name
, которое является именем глобальной переменной. -
shared
Общие модули для совместного использования сторонних библиотек. Напримерapp1
Загрузите сначала, поделитесьapp2
компонент вapp2
Этот компонент зависит отreact
. при загрузкеapp2
в этом компоненте он пойдет наapp1
изshared
найти вreact
Зависимость, если она есть, то она будет использоваться первой, не загружая свою (fallback
)
Наконец в app1index.html
введен в
<script src="http://app2/remoteEntry.js"></script>
Вот и все.
С приведенной выше конфигурациейapp1
могут быть свободно ввезены и использованы вapp2/Button
а такжеapp2/Table
.
Анатомия файла сборки
Так,ModuleFederationPlugin
Как возникла эта волшебная черная магия?
Ответ находится в следующем фрагменте встроенного кода:
__webpack_require__.e = (chunkId) => {
return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
__webpack_require__.f[key](chunkId, promises);
return promises;
}, []));
};
__webpack_require__.e(/* import() */ "src_bootstrap_tsx").then(__webpack_require__.bind(__webpack_require__, 601));
Этоapp1
код запуска,__webpack_require__.e
Для входа ищитеsrc_bootstrap_tsx
Зависимости модуля ввода, где их найти?
Object.keys(__webpack_require__.f).reduce((promises, key) => {
__webpack_require__.f[key](chunkId, promises);
return promises;
}, [])
пройдено здесьf
Все методы на объекте.
размещен нижеf
Все три метода привязаны к объектуoverridables
remotes
j
:
/******/ /* webpack/runtime/overridables */
/******/ (() => {
/******/ __webpack_require__.O = {};
/******/ var chunkMapping = {
/******/ "src_bootstrap_tsx": [
/******/ 471,
/******/ 14
/******/ ]
/******/ };
/******/ var idToNameMapping = {
/******/ "14": "react",
/******/ "471": "react-dom"
/******/ };
/******/ var fallbackMapping = {
/******/ 471: () => {
/******/ return __webpack_require__.e("vendors-node_modules_react-dom_index_js").then(() => () => __webpack_require__(316))
/******/ },
/******/ 14: () => {
/******/ return __webpack_require__.e("node_modules_react_index_js").then(() => () => __webpack_require__(784))
/******/ }
/******/ };
/******/ __webpack_require__.f.overridables = (chunkId, promises) => {
/******/ if(__webpack_require__.o(chunkMapping, chunkId)) {
/******/ chunkMapping[chunkId].forEach((id) => {
/******/ if(__webpack_modules__[id]) return;
/******/ promises.push(Promise.resolve((__webpack_require__.O[idToNameMapping[id]] || fallbackMapping[id])()).then((factory) => {
/******/ __webpack_modules__[id] = (module) => {
/******/ module.exports = factory();
/******/ }
/******/ }))
/******/ });
/******/ }
/******/ }
/******/ })();
/******/ /* webpack/runtime/remotes loading */
/******/ (() => {
/******/ var chunkMapping = {
/******/ "src_bootstrap_tsx": [
/******/ 341,
/******/ 980
/******/ ]
/******/ };
/******/ var idToExternalAndNameMapping = {
/******/ "341": [
/******/ 731,
/******/ "Button"
/******/ ],
/******/ "980": [
/******/ 731,
/******/ "Table"
/******/ ]
/******/ };
/******/ __webpack_require__.f.remotes = (chunkId, promises) => {
/******/ if(__webpack_require__.o(chunkMapping, chunkId)) {
/******/ chunkMapping[chunkId].forEach((id) => {
/******/ if(__webpack_modules__[id]) return;
/******/ var data = idToExternalAndNameMapping[id];
/******/ promises.push(Promise.resolve(__webpack_require__(data[0]).get(data[1])).then((factory) => {
/******/ __webpack_modules__[id] = (module) => {
/******/ module.exports = factory();
/******/ }
/******/ }))
/******/ });
/******/ }
/******/ }
/******/ })();
/******/ /* webpack/runtime/jsonp chunk loading */
__webpack_require__.f.j = (chunkId, promises) => {
...
/******/ })();
последнийf.j
Метод подробностей постить не буду, это в эпоху wepback4jsonp
нагрузка.
Наше основное вниманиеf.remotes
а такжеf.overridables
Два новых метода для webpack5.Zack Jackson
(Автор) решил использовать здесь нож, что очень тонко. а такжеexternal
разные(external
Это вход контакта с внешним миром во время строительства), вот вход контакта с внешним миром после строительства.
Как мы вскоре увидим, фактический способ работы с внешним миром точно такой же, как и способ, который я обсуждал в webpack4 в предыдущем разделе, а именно открытие ссылок через глобальные переменные.
Давайте поговорим о коде вышеreduce
роль: в основномПройдите по трем вышеуказанным методам, чтобы узнать, существует ли зависимость один за другим.!
overridables
общие общедоступные сторонние зависимости,react
а такжеreact-dom
Другие общедоступные зависимости будут разрешены здесь.app1
При сборке эти два файла будут создаваться независимо,app2
внутреннийexposes
Модули ищутся первыми, когда они загружаютсяapp1
внизshared
Зависимость, если есть, используйте ее напрямую, если нет — используйте свою.
remotes
удаленная зависимость, будет настроена вremotes
пары ключ-значение генерируются вidToExternalAndNameMapping
Среди переменных наиболее важным моментом является:
Разместите две картинки, разберем их по порядку:
Во-первых, это было сказано ранее__webpack_require__.e
будем искать один за другимoverridables
remotes
j
Три метода, когда они найденыremotes
Как показано на рисунке выше, введитеremotes
метод.
В настоящее времяchunkId
значение переменнойsrc_bootstrap_tsx
, то первый слой пройдет341
а также980
, а затем по этим двум значениям найтиidToExternalAndNameMapping
, чтобы найти341
ценность[731, "Button"]
,980
ценность[731, "Table"]
.
Выделенная строка кода на картинке__webpack_require__(data[0]).get(data[1])
Цель состоит в том, чтобы взять731
этот модуль, а затем вызвать егоget
метод, параметрыButton
| Table
, чтобы получить компонент Button или Table.
Итак, вот вопрос, это731
Что такое модуль? почему у него естьget
метод?
Продолжайте смотреть на вторую картинку выше, которую я выделил731
Этот модуль, его внутренняя ссылка907
модуль иoverride
охватыватьreact
react-dom
два модуля, указывающие на14
а также471
(эти два значения происходят именно изoverridables
определяется в методеidToNameMapping
отображение).
а также907
Модули ссылаются на глобальные переменныеapp2
!
Зачемapp2
Эта переменная будет существоватьget
метод? мы строимapp2
Этот метод пока не определен, давайте продолжим и посмотрим на него.app2
Результат сборки:
нажмите наremoteEntry.js
, ответ раскрывается:
ModuleFederationPlugin
На уровне оркестровки будут определены два метода.get
а такжеoverride
,в:
get
найти себяmoduleMap
карта (изexposes
конфигурация), это глобальная переменнаяapp2
+ егоget
Метод соединяет два несвязанных модуля!
override
используется, чтобы найтиshared
Зависимости от третьих лиц здесь тоже очень тонкие, почему вы так говорите? В опубликованном ранее коде мы фокусируемся наapp1
в слое оркестровки найдите__webpack_require__.O
объект, который определен вoverridables
Метод запущен, его начальное значение равно{}
, но в__webpack_require__.f.overridables
Он пуст при формальном исполнении. Это делаетapp1
используется непосредственно во время выполненияfallbackMapping
(то есть локальные сторонние зависимости).
в то время как вышеупомянутый731
точно используется в модулеapp2
который предоставилoverride
метод будетreact
а такжеreact-dom
изapp1
Цитаты в переопределеныapp2
Внутри мы смотрим наapp2
Уровень оркестрации (все коды уровня оркестровки согласованы),app2
серединаoverridables
просто используйте__webpack_require__.O
серединаreact
а такжеreact-dom
полагаться!
можно увидеть,app2
серединаoverride
метод будет вызываться извнеapp1
Сторонние зависимости в переопределенном__webpack_require__.O
Переменная!
Вот почему автор подчеркивает, что вряд ли существует избыточность зависимостей:
Дублирование зависимостей практически отсутствует.Через разделяемый вариант — удаленные устройства будут зависеть от зависимостей хоста, если у хоста нет зависимости, удаленный будет загружать свой собственный.Без дублирования кода, но встроенная избыточность.
По состоянию на 13 мая 2010 г. я обнаружил, что этот код плагина webpack5 все еще объединяет новые коммиты в основную ветку. Я взглянул на последние два представления и обнаружил, что уровень упаковки сильно изменился (элементы конфигурации пока не изменились), поэтому приведенный выше код результата упаковки приведен только для справки, и вы можете примерно понять Принцип. Код результата сборки, который я тестировал сегодня, отличается.
Суммировать
ModuleFederationPlugin
Это дает нам неограниченное пространство для воображения, и существует множество сценариев приложений, таких как совместное использование зависимостей микроприложений на микроинтерфейсах, совместное использование модулей и т. д.
Два недостатка, о которых я могу думать:
-
Во-первых, для раскрытия модулей требуются дополнительные модули.
exposes
Конфигурация (не подходит для нашего собственного сценария в предыдущем разделе этой статьи,entry
структура экспорта слишком сложная), и все используемые модули должны быть проинформированы о правильной конфигурации; -
Во-вторых, при отладке локальных зависимостей после настройки локальных зависимостей npm link или lerna вам также необходимо настроить таргетинг
remotes
настроить то же имяwebpack alias
а такжеtsconfig paths
, немного сложно.
Однако,wepback4
а такжеwebpack5
Когда эти два решения сочетаются и используются в соответствии со сценой, получается почти идеально!
О, забыл упомянуть, после использования обоих вариантов,Производительность компиляции значительно улучшена, поскольку общедоступная часть пропускается напрямую, нет необходимости ее компилировать, а отдельные общие файлы также можно кэшировать, а также повышается производительность загрузки. Данные не будут размещены, а сценарии их применения разные, так что вы сможете их понять в уме.
использованная литература
Webpack 5 Module Federation: A game-changer in JavaScript architecture