Устали писать страницы активности? Приходите и получите конструктор страниц!

Node.js внешний интерфейс сервер Vue.js

предисловие

Если вы часто обращаетесь к страницам активности некоторых компаний, у вас часто могут быть следующие головные боли: у этих проектов короткие циклы, частые требования, быстрые итерации, низкие технические требования и мало возможностей для роста. Тем не менее, мы все еще спешим удовлетворить спрос на продукцию.С увеличением масштаба компании мы не можем неограниченно увеличивать количество людей и постоянно повторять эти действия. Здесь я не буду вводить некоторые понятия, которых нет или нет, потому что их слишком много.В качестве внешнего интерфейса мы можем просто перейти непосредственно к коду! ! ! ! Чтобы узнать больше, посетите:

blogs

Цель

Наша цель — реализовать фон производства страницы, в котором мы можем组件选择 --> 布局样式调整 --> 发布上线 --> 编辑修改Такой технологический процесс.

Архитектурный дизайн

Во-первых, мы можем предоставить компоненты для выбора пользователями.组件库, а затем нужно настроить стиль макета выбранных компонентов, поэтому нам нужен页面编辑后台Затем нам нужно отобразить данные, сгенерированные путем редактирования, в реальную страницу, поэтому нам нуженnode服务и для заполненияtemplate 模板. Релиз находится в режиме on-line.Хорошо иметь прямую связь с системой релизов внутри каждой компании.Мы не будем здесь подробно останавливаться. Последняя функция редактирования и модификации заключается в изменении конфигурации, поэтому нам нужна база данных, здесь я предпочитаю использоватьmysql. Конечно, вы также можете сделать управление правами, управление страницами и т. Д. Кстати. Спустя столько времени нарисуем картинку, чтобы понять общий процесс:

открытым

Реализация компонента

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

В соответствии с приведенным выше рисунком наши компоненты будут разделены и опубликованы по отдельности дляnpmСклад, почему он устроен именно так? На самом деле, я также рассматривал возможность разработки библиотеки компонентов раньше, и все компоненты включены в библиотеку компонентов, так что необходимо выпустить только один пакет библиотеки компонентов, и его можно будет загрузить по запросу, когда он будет использоваться. Позже, в процессе практики, я обнаружил, что это не подходит для совместной разработки.Если другие фронтенды хотят внести компоненты, стоимость доступа к трансформации также очень велика. Например 🌰: Сяо Мин написал письмо в свой бизнесButtonКомпонент, этот компонент часто повторно используется другими проектами. Он хочет внести этот компонент в нашу систему и использовать шаблоны. Если это библиотека компонентов, он должен сначала вытащить код нашей библиотеки компонентов, а затем следовать библиотеке компонентов. , представлены в каноническом формате. Таким образом, ленивый Сяо Мин может не захотеть это делать.Самый крутой способ, конечно, собрать npm-библиотеку локально, а выбор разработчиков — использоватьTypeScriptНас не волнуют другие вещи, нас не волнует выбранный препроцессор Css, даже стандарт кодированияESLintНам тоже все равно. Наконец, просто нужно скомпилировать. Это позволяет избежать ограничения библиотеки компонентов. Опираясь на идеальный механизм выпуска/растяжки и контроля версий NPM, мы можем выполнять меньше дополнительной работы, или вы можете быстро настроить платформу.

Сказав все это, как насчет кода? , мы беремButtonНапример, мы предоставляем этот компонент формы извне:

<template>
  <div :style="data.style.container" class="w_button_container">
    <button :style="data.style.btn"> {{data.context}}</button>
  </div>
</template>
<script>

export default {
  name: 'WButton',
  props: {
    data: {
      type: Object,
      default: () => {}
    }
  }
}
</script>

Видно, что мы выставили только одинprops, преимущество этого подхода заключается в том, что данные, предоставляемые компонентом, могут быть унифицированы, и могут использоваться внутренние компоненты компонента. Обратите внимание, что мы также можем представить здесь некоторые сторонние библиотеки компонентов, такие какmint-uiкакой-то тип.

Реализация фонового редактирования

Перед записью кода давайте подумаем о том, какие функции должны быть реализованы:

  1. Область редактирования атрибута, предоставляющая компоненты редактирования пользователей внутриpropsфункция
  2. Область выбора компонентов, предоставляющая пользователям возможность выбора необходимых компонентов.
  3. Область предварительного просмотра компонентов, предоставляющая пользователям функцию перетаскивания и сортировки предварительных просмотров страниц.
Реализация области редактирования

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

image

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

[
  {
    "blockName": "按钮布局设置", 
    "settings": {
      "src": {
        "type": "input",  
        "require": true,
        "label": "按钮文案"
      }
    }
  }
]

В фоновом режиме редактирования мы можем запросить эти конфигурации через интерфейс, а затем отрисовать правила:

    /**
     * 根据类型,选择创建对应的组件
     * @param {VNode} vm
     * @returns {any}
     */
    createEditorElement (vm: VNode) {
      let dom = null
      switch (vm.config.type) {
        case 'align':
          dom = this.createAlignElement(vm)
          break;
        case 'select':
          dom = this.createSelectElement(vm)
          break;
        case 'actions':
          dom = this.createActionElement(vm)
          break;
        case 'vue-editor':
          dom = this.createVueEditor(vm)
          break;
        default:
          dom = this.createBasicElement(vm)
      }
      return dom
    }
Область выбора компонентов

Первое, что нам нужно рассмотреть, это как зарегистрировать компоненты? Поскольку, когда компонент выбран пользователем, нам нужно отобразить компонент, поэтому мы можем предоставить скрипт узла для обхода необходимых компонентов, а также для установки и регистрации компонентов:

// 定义渲染模板和路径
var OUTPUT_PATH = path.join(__dirname, '../packages/index.js');
console.log(chalk.yellow('正在生成包引用文件...'))
var INSTALL_COMPONENT_TEMPLATE = '    {{name}}';
var IMPORT_TEMPLATE = 'import {{componentName}} from \'{{name}}\'';
var MAIN_TEMPLATE = `/* Automatic generated by './compiler/build-entry.js' */

{{include}}

const components = [
{{install}}
]

const install = function(Vue) {
    components.map((component) => {
        Vue.component(component.name, component)
    })
}

/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
    install(window.Vue)
}

export {
    install,
{{list}}
}
`;
// 渲染引用文件
var template = render(MAIN_TEMPLATE, {
  include: includeComponentTemplate.join(endOfLine),
  install: installTemplate.join(`,${endOfLine}`),
  version: process.env.VERSION || require('../package.json').version,
  list: listTemplate.join(`,${endOfLine}`)
});

// 写入引用
fs.writeFileSync(OUTPUT_PATH, template);

Окончательный отрендеренный файл выглядит так:

import WButton from 'w-button'
const components = [
    WButton
]
const install = function(Vue) {
    components.map((component) => {
        Vue.component(component.name, component)
    })
}
/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
    install(window.Vue)
}
export {
    install,
    WButton
}

Это также распространенный способ написания библиотек компонентов, поэтому идея здесь состоит в том, чтобы публиковать вnpmКомпоненты выше агрегированы и объединены в ссылку на пакет компонентов.Когда мы редактируем в фоновом режиме, нам нужно импортировать их полностью:

import * as W_UI from '../../packages'

Vue.use(W_UI)

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

  1. Пользователь включает dev-сервер для тестов написания кода
  2. серверный скрипт с использованием инструментов Chromepuppeteer, переведите страницу в мобильный режим и сделайте скриншот текущего dev-сервера.
  3. Создание файлов снимков экрана, загрузка в службу узла и связывание компонентов

Таким образом, вы можете прикрепить миниатюру к компоненту при загрузке области выбора компонента.

Область предварительного просмотра компонента

Когда пользователь выбирает компонент в области выбора, нам нужно отобразить его в области предварительного просмотра, так как мы узнаем, какие компоненты выбрали пользователь? Всегда невозможно писать все компоненты в зону рендеринга заранее.v-ifДавайте судить по выбору? Конечно, это не так глупо, Vue обеспечил функциональность динамических компонентов:

<div 
   :class="[index===currentEditor ? 'active' : '']" 
   :is="select.name" 
   :data="select.data">
</div>

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

дополнительный вопрос

Сказав так много, кажется, что все идет хорошо, но на практике я обнаружил, что есть очевидная проблема: область предварительного просмотра посередине нас на самом деле должна максимально имитировать эффект мобильных страниц. Но если мы добавим что-то вродеposition: fixedСтилизованные компоненты, вы обнаружите, что со стилем существуют очевидные проблемы. Типичные, такие какDialog LoadingЖдать. Итак, мы ссылаемся наm-uiДизайн библиотеки компонентов показывает промежуточный контейнер операции предварительного просмотра какiframe. Будуiframeизменен размер на375 * 667, который имитирует мобильный телефон iPhone 6. Таким образом, не будет проблем со стилем. Однако возникла другая трудность, а именно, как своевременно реагировать на данные редактирования слеваiframeсередина? Вот такpostMessgae, общая идея такова:

использоватьvuexДелать пулы хранения данных, все изменения, черезpostMessgaeСинхронизировать, чтобы мы должны были только для того, чтобы изменения в пуле данных могут быть сопоставлены с изменениями в изменении слоя рендера. Например, мы выбрали компоненты и перетаскивали и отсортированные в зоне предварительного просмотра, то нам нужно только пройтиvuexИнформация о синхронизации отправления может быть:

// action.ts
const action = {
  setCurrentPage ({commit, state}, page: number) {
      // 更新当前store
      commit('setCurrentPage',page)
      // 对应postMessage
      helper.postMsgToChild({type: 'syncState', value: state})
    },
  // ...
}

Реализация шаблона шаблона

Дизайн и реализация шаблона, я имею в видуVue-cli 2.xВариант идеи, шаблон тут, есть соответствующийgitна складе. Когда пользователям необходимо создать страницы, они могут напрямую получить соответствующие шаблоны из репозитория git. Разумеется, после извлечения копия также будет закэширована локально, а после рендеринга ее можно будет прочитать прямо из локального кеша. Теперь сосредоточимся на формате и спецификации шаблона. Неважно, какой синтаксис мы используем для шаблона, здесь я просто использую иVue-cliтоже самоеHandlerbarsдвигатель. Здесь идет непосредственно к дизайну нашего шаблона:

<template>
  <div class="pg-index" :style="{backgroundColor: '{{bgColor}}'}">
      <div class="main-container" :style="{
        backgroundColor: '{{bgColor}}',
        backgroundImage: '{{bgImage}}' ? 'url({{bgImage}})' : null,
        backgroundSize: '{{bgSize}}',
        backgroundRepeat: 'no-repeat'
      }">
        {{#components}}
          <div class="cp-module-editor {{className}} {{data.className}}">
            <{{name}} class="temp-component" :data="{{tostring data}}" data-type="{{upcasefirst name}}"></{{name}}>
          </div>
        {{/components}}
      </div>
  </div>
</template>

<script>
    {{#noRepeatCpsName}}
  import {{upcasefirst this}} from '{{this}}'
    {{/noRepeatCpsName}}
export default {
  name: '{{upcasefirst repoName}}',
  components: {
    {{#noRepeatCpsName}}
      {{upcasefirst this}},
    {{/noRepeatCpsName}}
  }
}
</script>

Чтобы упростить логику, мы разрабатываем шаблоны в виде потокового макета, и все компоненты располагаются один за другим и располагаются в порядке убывания. Этот файл нашvue-webpack-simpleв шаблонеApp.vue. Мы переписали его. Таким образом, когда данные заполнены, можно отобразить один файл Vue. Здесь я привожу только пример, мы также можем реализовать сложные шаблоны, такие как многостраничные шаблоны, и подтягивать разные шаблоны в соответствии с требованиями.

Служба рендеринга узлов

Когда запрос на рендеринг отправляется в фоновом режиме, наша служба узла в основном выполняет следующие действия:

  1. Вытащите соответствующий шаблон
  2. визуализировать данные
  3. компилировать

Тянуть - это пойти на указанный склад, чтобы пройтиdownload-git-repoПлагин подтягивает шаблон. Компиляция на самом деле черезmetalsmithГенератор статических шаблонов принимает шаблон в качестве входных данных и данные в качестве заполнения в соответствии сhandlebarsсинтаксис для обычного рендеринга. конечный результатbuildСозданный каталог. На этом шаге компоненты, которые нам были нужны ранее, будут преобразованы вpackage.jsonдокумент. Давайте посмотрим на основной код:

// 这里就像一个管道,以数据入口为生成源,通过renderTemplateFiles编译产出到目标目录
function build(data, temp_dest, source, dest, cb) {
  let metalsmith = Metalsmith(temp_dest)
    .use(renderTemplateFiles(data))
    .source(source)
    .destination(dest)
    .clean(false)

  return metalsmith.build((error, files) => {
    if (error) console.log(error);
    let f = Object.keys(files)
      .filter(o => fs.existsSync(path.join(dest, o)))
      .map(o => path.join(dest, o))
    cb(error, f)
  })
}


function renderTemplateFiles(data) {
  return function (files) {
    Object.keys(files).forEach((fileName) => {
      let file = files[fileName]
      // 渲染方法
      file.contents = Handlebars.compile(file.contents.toString())(data)
    })
  }
}

В итоге мы получили проект Vue, который в настоящее время не может быть запущен непосредственно на стороне браузера, здесь используется форма, поддерживаемая текущей системой публикации. Как сказать? Если систему выпуска вашей компании необходимо скомпилировать онлайн, вы можете загрузить исходные файлы непосредственно в репозиторий git, запустить WebHook репозитория и позволить системе выпуска выпустить проект для вас. Если ваша система публикации требует от вас отправки скомпилированных файлов для публикации после компиляции, вы можете использовать команду узла для локальной сборки для создания HTML, CSS и JS. Отправить напрямую в издательскую систему. На данный момент наша задача почти такая же ~ Большинство конкретных основных твердых тел были четко объяснены.Если есть какие-либо проблемы или несоответствия в реализации, пожалуйста, обсудите и обменяйтесь вместе! !

Не по теме

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