Плагинная схема загрузки компонентов формы динамических форм

внешний интерфейс
Плагинная схема загрузки компонентов формы динамических форм

Это 88-я оригинальная статья без воды.Если вы хотите получить больше оригинальных статей, выполните поиск в общедоступном аккаунте и подпишитесь на нас~ Эта статья была впервые опубликована в блоге Zhengcaiyun:Плагинная схема загрузки компонентов формы динамических форм

предисловие

Про схему динамической формы мы уже однажды делились, студенты, которые не видели, могут прочитать предыдущую статьюZooTeam приглашает вас узнать, как создавать динамические формы. В статье упоминается, что с ростом дифференциации бизнеса мы приняли динамические формы для решения проблем повторного развития и логического стекирования. По мере того, как все больше и больше деловых сторон получают доступ к системе динамических форм, спрос на загрузку подключаемых модулей пользовательских компонентов начинает появляться и постепенно становится все сильнее.

Надеемся, что после добавления нового кастомного компонента нам не нужно будет переиздавать проект, нужно только опубликовать кастомный компонент отдельно, а затем зарегистрировать кастомный компонент в системе, что можно будет использовать непосредственно при настройке страницы формы. Затем это приводит к необходимости возможности загрузки подключаемых модулей и применения компонентов формы.

Текущее состояние схем загрузки компонентных плагинов

Что касается асинхронной загрузки, то большинство поисковых запросов на разных платформах связаны с разделением кода Webpack. И очень мало говорится о загрузке плагинов компонентов. Разберем подробно.

1. Ленивая загрузка Webpack

Отложенная загрузка Webpack, то есть функция загрузки Webpack для распаковки по запросу, в основном использует метод импорта для асинхронной загрузки статических ресурсов. Конкретный метод использования заключается в следующем. Код вводит файлы, которые необходимо распаковать, следующим образом:

import('./moduleA').then((moduleA) => {
  moduleA.add(1,2); // 3
})

На данный момент в пакете Webpack модуль A будет разделен как отдельный файл JS, проект был частью этой динамической загрузки ресурсов JS при реализации кода. Но если вы загружаете метод импорта удаленного ресурса напрямую, происходит ошибка процесса упаковки Webpack. Не соответствует спросу.

import('http://static.cai-inc.com/moduleA.js').then((moduleA) => {
   // ERROR,打包过程会出现报错
  moduleA.add(1,2);
})

Сообщение об ошибке:图片

2. Динамический импорт поддерживается существующими браузерами

Для этого метода проблема совместимости браузера с трудом соответствует требованиям, браузер IE вообще не поддерживает его и имеет ограничение на одно и то же доменное имя. Метод использования такой же, как отложенная загрузка Webpack:

import('http://static.cai-inc.com/moduleA.js').then((moduleA) => {
  moduleA.add(1,2); // 3
})

В-третьих, спецификация AMD require.js

Используйте require.js для загрузки JS-файла, совместимого с AMD. Конкретное использование заключается в следующем:

// 需要被动态加载的 moduleA.js
define('moduleA', [], function () {
  var add = function (x, y) {
    return x + y;
  };
  return {
    add: add
  };
});
// 加载和使用
require.config({
  paths: {
    "moduleA": "lib/moduleA"
  }
});
require(['moduleA'], function (moduleA){
    // 代码
    moduleA.add(1,2); // 使用被动态引入的插件的方法
});

В этом методе динамическим подключаемым модулем является модуль А. Чтобы использовать динамический подключаемый модуль, необходимо настроить путь к подключаемому модулю, а затем использовать require для ссылки на него. Для этого нам нужно сослаться на require.js в существующий проект, определить тег Script в HTML-коде проекта и установитьdata-main="scripts/main"как входной файл. Но в нашем проекте React также есть одна запись, что приводит к двум записям. Эти два использования плохо сосуществуют.

Требуйте разборки

Итак, теперь давайте разберем реализацию загрузки плагинов компонентовключевой вопрос:

1. Загрузка ресурсов

  • Поскольку плагин будет размещен в CDN после того, как будет выпущен отдельно, решение для загрузки статических ресурсов должно соответствовать условиям отсутствия междоменных ограничений.

Во-вторых, упаковка подключаемого модуля

  • Подключаемые модули предпочтительно должны использовать существующие стандарты модулей, такие как стандарты модулей CMD и AMD, чтобы мы могли использовать больше решений с открытым исходным кодом сообщества и снизить риск решения. При этом стоимость обучения и использования членов команды снижается.
  • Плагины должны иметь возможность внедряться в зависимости.Например, проект уже содержит пакеты библиотек компонентов Lodash или AntD.В настоящее время, если библиотеки компонентов Lodash или AntD используются в модуле плагина, мы, безусловно, надеемся, что сможем напрямую ссылайтесь на существующие в проекте, а не в модуле плагина.

анализ спроса

1. Статическая загрузка ресурсов

Для загрузки статических ресурсов во время выполнения, независимо от того, какое из существующих решений используется, это реализуется путем динамической вставки тегов Script или Link. И это решение не будет иметь ограничений на доменное имя. Конкретная реализация примерно такова:

export default function (url) {
  return new Promise(function (resolve, reject) {
    const el = document.createElement('script'); // 创建 script 元素
    el.src = url; // url 赋值
    el.async = false; // 保持时序
    const loadCallback = function () { // 加载成功回调
      el.removeEventListener('load', loadCallback);
      resolve(result);
    };
    const errorCallback = function (evt) { // 加载失败回调
      el.removeEventListener('error', errorCallback);
      var error = evt.error || new Error("Load javascript failed. src=" + url);
      reject(error);
    };
    el.addEventListener('load', loadCallback);
    el.addEventListener('error', errorCallback);
    document.body.appendChild(el); // 节点插入
  });
}

2. Внедрить зависимости для загрузки модулей

В этом отношении мы можем видеть, как require.js следует спецификации AMD. Код:

// require.js
const modules = {};
const define = function(moduleName, depends, callback){
  modules[moduleName] = { // 将模块存起来,等待后续调用
    depends,
    callback,
  };
}
// moduleA.js
define('moduleA', [], ()=>{
  // code
})

Поскольку ресурсы JS импортируются путем вставки Script, JS будет выполняться немедленно, поэтому все модули JS, загруженные в require.js, обертываются методом определения, а код, который необходимо выполнить, ожидает последующих вызовов в функции обратного вызова. Когда moduleA.js успешно загружается, немедленно вызывается метод определения, и выполняемое здесь содержимое предназначено для сохранения модулей проекта и ожидания вызова. Внедрение зависимостей — это внедрение зависимостей в качестве параметров обратного вызова.

На самом деле, независимо от того, на какой спецификации основана стратегия динамической загрузки статических ресурсов, она примерно одинакова. Функция A используется в модуле для переноса кода объекта. Возьмем функцию A в качестве аргумента функции D. Когда модуль загружен, функция A, содержащая целевой блок кода, может быть получена из определенной функции D в браузере. Тогда звони куда хочешь. Введите любую переменную, которую вы хотите ввести.

  • Примечание:
    • Вот примерное объяснение принципов AMD.В конкретной реализации много деталей.Если хотите узнать больше, то можете найти в Интернете много анализов исходного кода.Я не буду здесь вдаваться в подробности.
    • Метод управления модулями кода, упакованного Webpack, представляет собой набор вещей, похожих на спецификацию CommonJS, реализованную самим Webpack. Если вы посмотрите на код, сгенерированный пакетированием, вы обнаружите, что есть некоторые ключевые слова, такие как webpack_modules__, webpack_require и webpack_exports, которые соответствуют модулям, требуют и экспортируют спецификацию CommonJS.

3. Стандарт упаковки модулей

Поскольку наша команда использует систему упаковки Webpack, если мы хотим поддерживать единый технологический стек, мы должны начать с упаковки Webpack. Давайте попробуем все модульные пакеты Webpack и посмотрим, что у нас получится.

Есть 5 способов упаковать библиотеку Webpack.

  • переменная: как глобальная переменная, черезscriptтег для доступа (libraryTarget:'var').
  • это: пройтиthisДоступ к объекту (libraryTarget:'this').
  • окно: пройтиwindowДоступ к объекту в браузере (libraryTarget:'window').
  • UMD: на AMD или CommonJSrequireдоступен после (libraryTarget:'umd').
  • AMD: Упаковка основана на спецификации AMD (libraryTarget:'amd').

Первые три можно исключить, мы не хотим вешать модуль под оконные или глобальные переменные. Так что нам нужно попробовать только два последних.

Блоки кода, которые необходимо упаковать:

export default {
  test: ()=>{
    console.log('测试模块打包!');
  }
};

После упаковки спецификации AMD:

define(["lodash"], (__WEBPACK_EXTERNAL_MODULE__92__) => (() => {
  // code ...
  // return funciton
})());

После упаковки спецификации UMD:

(function webpackUniversalModuleDefinition(root, factory) {
    if(typeof exports === 'object' && typeof module === 'object')
        module.exports = factory(require("lodash")); // cmd
    else if(typeof define === 'function' && define.amd)
        define(["lodash"], factory); // amd
    else { // 
        var a = typeof exports === 'object' ? factory(require("lodash")) : factory(root["_"]);
        for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
    }
})(self, function(__WEBPACK_EXTERNAL_MODULE__92__) {
    // code
});

Можно видеть, что после того, как спецификация AMD упакована, код выполняет метод определения. Инъекция зависимости вводится через параметры метода обратного вызова. Таким образом, мы можем повесить метод определить под окном перед загрузкой файла JS, и когда файл загружен и выполняет метод определения, мы можем сделать то, что мы хотим в методе определения. Аналогичным образом, спецификация упаковки UMD также может достичь нашей цели через аналогичные операции. Таким образом, оба варианта в порядке. Учитывая необходимость в более поздних страницах динамических форм, которые будут преобразованы в локальный код, я надеюсь, что плагин все еще может быть установлен и используется NPM. Спецификация UMD используется здесь.

Выбор схемы

1. Схема загрузки ресурсов

  • Загрузка ресурсов JS осуществляется путем динамической вставки Script.

Во-вторых, схема упаковки модуля

  • Как упакована спецификация UMD.

Окончательная ссылка на код реализации:

// importScript.js
export default function (url, _) {
  const defineTemp = window.define; // 将 window 下的 define 方法暂存起来。
  let result; // 结果
  window.define = (depends, func) => { // 自定义 define 方法,
    result = func(_); // 包依赖注入 
  }
  window.define.amd = true; // 伪装成 amd 的 define。
  return new Promise(function (resolve, reject) {
    const el = document.createElement('script'); // 创建 script 元素
    el.src = url;
    el.async = false; // 保持时序
    const loadCallback = function () { // 加载完成之后处理
      el.removeEventListener('load', loadCallback);
      window.define = defineTemp;
      resolve(result);
    };
    const errorCallback = function (evt) { // 加载失败之后处理
      el.removeEventListener('error', errorCallback);
      window.define = defineTemp;
      var error = evt.error || new Error("Load javascript failed. src=" + url);
      reject(error);
    };
    el.addEventListener('load', loadCallback); // 绑定事件
    el.addEventListener('error', errorCallback); // 绑定事件
    document.body.appendChild(el); // 插入元素
  });
}

метод вызова

import importScript from './importScript.js';
import _ from 'lodash';
importScript('http://static.cai-inc.com/app.bundle.js', _).then((mod)=>{
   // code mod.xxx
})

3. Сочетание с пользовательскими формами

Внедрение компонентов подключаемым модулем решено, но возникает новая проблема. Если на странице формы есть 10 настраиваемых компонентов, должна ли она динамически загружать 10 статических ресурсов? Если каждый компонент имеет JS, CSS. Это 20. Это неосуществимо.

Таким образом, существует необходимость в объединении компонентов.

При настройке страницы формы, когда пользователь публикует страницу, сервер создает временный проект, устанавливает в проект все пользовательские компоненты, задействованные на странице, и экспортирует ее. Скомпилируйте и упакуйте для создания файловых модулей, соответствующих спецификации UMD. Затем импортируйте так же, как указано выше. Это решает проблему слияния нескольких файлов.

Суммировать

Окончательное решение на самом деле очень простое, просто гибкое применение упаковки спецификации UMD. Код компонента упаковывается на основе спецификации UMD, а код JS компонента вводится путем динамической вставки тегов Script. Перед импортом определите метод window.define. После успешной загрузки JS-кода компонента будет вызван определенный нами метод window.define. Таким образом, мы можем внедрить модуль плагина и сохранить его для последующего использования.

Рекомендуемое чтение

В сочетании с исходным кодом React вам потребуется пять минут, чтобы освоить приоритетную очередь.

[Flutter Skills] Поставщик управления состоянием, о котором вы должны знать

Карьера

ZooTeam, молодая, увлеченная и творческая команда, связанная с отделом исследований и разработок продукции Zhengcaiyun, базируется в живописном Ханчжоу. В настоящее время в команде более 40 фронтенд-партнеров, средний возраст которых составляет 27 лет, и почти 30% из них — инженеры полного стека, настоящая молодежная штурмовая группа. В состав членов входят «ветераны» солдат из Ali и NetEase, а также первокурсники из Чжэцзянского университета, Университета науки и технологий Китая, Университета Хандянь и других школ. В дополнение к ежедневным деловым связям, команда также проводит технические исследования и фактические боевые действия в области системы материалов, инженерной платформы, строительной платформы, производительности, облачных приложений, анализа и визуализации данных, а также продвигает и внедряет ряд внутренних технологий. Откройте для себя новые горизонты передовых технологических систем.

Если вы хотите измениться, вас забрасывают вещами, и вы надеетесь начать их бросать; если вы хотите измениться, вам сказали, что вам нужно больше идей, но вы не можете сломать игру; если вы хотите изменить , у вас есть возможность добиться этого результата, но вы не нужны; если вы хотите изменить то, чего хотите достичь, вам нужна команда для поддержки, но вам некуда вести людей; если вы хотите изменить установившийся ритм, это будет "5 лет рабочего времени и 3 года стажа работы"; если вы хотите изменить исходный Понимание хорошее, но всегда есть размытие того слоя оконной бумаги.. , Если вы верите в силу веры, верьте, что обычные люди могут достичь необыкновенных вещей, и верьте, что они могут встретить лучшего себя. Если вы хотите участвовать в процессе становления бизнеса и лично способствовать росту фронтенд-команды с глубоким пониманием бизнеса, надежной технической системой, технологиями, создающими ценность, и побочным влиянием, я думаю, что мы должны говорить. В любое время, ожидая, пока вы что-нибудь напишете, отправьте это наZooTeam@cai-inc.com