Техника теневого клонирования разработки мини-программ

Апплет WeChat

предисловие

Техника теневого клонирования, любой, кто видел Хокаге, знает, что у одного тела есть несколько клонов.

Все должны задаваться вопросом, может ли разработка небольших программ быть связана с техникой теневого аватара? Да, это естественно: набор кода, несколько небольших программ.

Не закатывайте глаза, все, и слушайте меня. . .

В настоящее время разработка небольших программ идет полным ходом. В сочетании с продвижением WeChat бизнес многих компаний постепенно переходит на небольшие программы. Это заставило меня, Android-разработчика, начать путь разработки небольших программ.

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

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

Поэтому для этого сценария есть решение: разработать технику теневого клонирования апплета.

Адрес Github: https://github.com/BakerJQ/WeAppBunXin

Проект основан наTaroкадр, поЛаборатория ударовОткрытый исходный код, большое спасибо за их тяжелую работу.

Я выбрал Taro главным образом потому, что он принимает стандарт синтаксиса React, и у меня есть предыдущий опыт разработки ReactNative.

Так как я давно не контактировал с front-end разработкой, если есть ошибка в тексте или есть лучшее решение, то приветствую вашу терпимость и исправление, большое спасибо.

Базовая конфигурация теневого клона

Способность теневого клона в основном исходит из способности компиляции, предоставленной Таро, поэтому необходимоКонфигурация сборкиа такжеСведения о конфигурации сборкипонимать.

Давайте сначала посмотрим на соответствующие каталоги файлов конфигурации:

Каталог config является каталогом конфигурации по умолчанию после инициализации Taro.Три файла (dev, index, prod) в синей рамке на рисунке — это файлы конфигурации, сгенерированные по умолчанию, а остальные файлы — это конфигурации, необходимые для клона. На рисунке настроено три аватара, в качестве примера возьмем канал 1, config — некоторая конфигурация аватара, а project.config.json — базовая конфигурация апплета аватара, например:

{
    "miniprogramRoot": "./",
    "projectname": "channel1",
    "description": "channel1",
    "appid": "wx8888888888888",
    ...
}

Файл channel.js используется для указания того, какой апплет в данный момент необходимо скомпилировать, например:

module.exports = {
  channel: 'channel1'
}

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

const channelInfo = require('./channel')
const config = {
    ...
    //输入目录为dist_channel1
    outputRoot: 'dist_' + channelInfo.channel,
    ...
    //讲config/channel1/project.config.json文件拷贝到dist_channel1下
    copy: {
    patterns: [
      {
        from: 'config/' + channelInfo.channel + '/project.config.json',
        to: 'dist_' + channelInfo.channel + '/project.config.json'
      }
    ],
    ...
    }
    ...
}

Казнить Тарокоманда компиляции апплетаПосле этого будет создана папка кода апплета dist_channel1, соответствующая клону, и вы можете напрямую использовать инструмент разработчика апплета, чтобы открыть этот каталог для предварительного просмотра апплета channel1.

С помощью этих конфигураций мы можем сгенерировать несколько разных небольших программ с помощью одного и того же набора кода! Конечно, содержание этих небольших программ абсолютно одинаковое, самое большее, имя и appid, настроенные в project.config.json, отличаются.

Затем давайте начнем смотреть, как создавать несколько дифференцированных апплетов.

Перед конкретной реализацией нам необходимо знать две важные конфигурации Таро:Глобальная переменная «defineConstants»а такжепсевдоним "псевдоним".

Клон в стиле теневого клона

Во-первых, давайте взглянем на одно из наиболее распространенных требований, которое заключается в различии стиля между различными программами-апплетами. Давайте сначала посмотрим на две картинки.

апплет А апплет Б

С точки зрения стиля, текущие различия между двумя апплетами:

  • разные основные цвета
  • Соответствующие ресурсы изображений отличаются
  • другое расположение

Установить каталог аватаров

Первый шаг — создать каталог для каждого апплета аватара в src, желательно с тем же именем, что и конфигурация в channel.js, как показано ниже:

Различия стилей места

Возьмем в качестве примера предыдущую «Мини-программу А»:

Папка assets — это ресурсный файл апплета, то есть различные синие значки.

app.less — это файл глобального стиля со следующим содержимым:

@main_color: #1296db;
.main_color_txt {
  color: @main_color
}

Файл ChannelStyle.ts — это стиль, который может понадобиться в коде:

const ChannelStyle = {
  mainColor: '#1296db'
}
export default ChannelStyle

Настроить псевдонимы

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

const config = {
  ...
  alias: {
    '@/channel': path.resolve(__dirname, '..', 'src/channel/' + channelInfo.channel),
    '@/assets': path.resolve(__dirname, '..', 'src/channel/' + channelInfo.channel + '/assets'),
    '@/app_style': path.resolve(__dirname, '..', 'src/channel/' + channelInfo.channel + '/app.less'),
  }
  ...
}

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

//代码中需要用到ChannelStyle中的样式
import ChannelStyle from '@/channel/ChannelStyle'
//app.tsx入口文件引用全局样式
import '@/app_style'
//引用资源图片
<Image src={require('@/assets/icon.png')} />

Кроме того, обратите внимание, что, поскольку Taro не поддерживает псевдонимы в файлах стилей, таких как .less, на него нельзя ссылаться способом, аналогичным @import '@/app_style', поэтому в настоящее время необходимо разместить полное количество разностных стилей. под каждым пакетом аватарки.

Настроить глобальные переменные

Поскольку конфигурация TabBar представлена ​​в виде чистых строк и не может быть настроена через псевдонимы, необходимо использовать другой метод настройки, то есть глобальные переменные Метод настройки в index.js выглядит следующим образом:

const config = {
  defineConstants: {
    ASSETS_PATH: 'channel/'+channelInfo.channel+'/assets'
  }
}

Однако у каждого клона основной цвет разный, поэтому его нужно настраивать в конфигурационном файле клона, то есть в базовой конфигурации config.js под папкой клона, в которую добавлена ​​конфигурация глобальных переменных :

module.exports = {
  ...
  defineConstants: {
    MAIN_COLOR: '#1296db'
  },
  ...
}

Глобальные переменные можно использовать прямо в коде, например, конфигурацию TabBar в app.tsx:

config: Config = {
    ...
    tabBar: {
      ...
      selectedColor: MAIN_COLOR,
      list: [
        {
          pagePath: 'pages/index/index',
          text: '首页',
          iconPath: ASSETS_PATH + '/home_u.png',
          selectedIconPath: ASSETS_PATH + '/home_s.png'
        },
        ...
      ]
    }
  }

слияние конфигураций

После завершения настройки в окончательный объединенный код файла index.js добавьте определенную нами конфигурацию аватара:

module.exports = function (merge) {
  ...
  //默认的原始代码为return merge({}, config, envConfig)
  return merge({}, config, envConfig, require('./' + channelInfo.channel + "/config"))
}

резюме стиля аватара

Таким образом, в соответствии с файлом ресурсов и цветовой конфигурацией темы «мини-программы B», эти две мини-программы могут быть сгенерированы путем изменения имени аватара компиляции в channel.js.

Мы также можем обнаружить, что разница в стиле между «Мини-программой A» и «Мини-программой B», помимо изображений ресурсов и цветов темы, макет страницы «Разработка» также отличается, как с этим бороться? Правильно, указать соответствующий файл стиля для каждой страницы, указав файл less по псевдониму.

Если в реальном бизнесе существуют очевидные различия в стилях тем и стилей между разными апплетами, рекомендуется создать пакеты тем, а затем настроить разные пакеты тем для разных апплетов, например:

//分身配置
module.exports = {
  ...
  alias: {
    '@/theme': path.resolve(__dirname, '..', '../src/theme/theme1'),
    ...
  }
  ...
}
//文件引用
import '@/theme/dev.less'

Клон функции теневого клонирования

В дополнение к различиям в стиле мини-программы с настраиваемыми атрибутами также должны иметь определенные функциональные различия.

Внимательные друзья могли обнаружить, что количество записей на странице разработки «Мини-программы А» и «Мини-программы Б» разное.

«Апплет А» не имеет FireWall, и порядок первых двух элементов Java и JSX у этих двух апплетов разный. Мало того, если вы запустите апплет и нажмете на каждый элемент, вы обнаружите, что когда вы нажимаете на элемент C++, «Applet B» перейдет на страницу сведений об элементе, а «Applet A» перейдет на « Вкладка «Управление».

Как мы справляемся с такими функциональными различиями?

Определить конфигурацию страницы

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

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

Для «разработки» страницы, например, в DevConfig.ts я определил следующие конфигурации:

import Taro from "@tarojs/taro";
//页面配置
export default {
  dev: {
    items: {//条目
      item1: {//条目1
        img: require('@/assets/jsx.png'),//图片
        txt: 'JSX',//文字
        onItemClick: () => {//点击跳转事件
          toPage('JSX', require('@/assets/jsx.png'))
        }
      },
      item2: {...},
      ...
    }
  }
}
//页面跳转
function toPage(title, img){
  Taro.navigateTo({url: '/pages/dev/DevInfo?title='+title+'&img='+img})
}

определить слияние различий

При этом файл ChannelConfigDiff.ts в составе пакета diff, как файл разностной конфигурации, имеет следующее содержимое:

export default (config, merge)=>{
  return merge([{}, config])
}

Видно, что это фактически возвращает входящий конфиг как есть, потому что для основной части проекта конфиг менять не нужно, конкретное использование будет объяснено ниже.

А MultiChannelConfig.ts — это окончательная конфигурация каждой страницы, содержание которой следующее:

import merge from 'deepmerge'
import ChannelConfigDiff from '@/diff/ChannelConfigDiff'
//开发页面配置
import DevConfig from './pages/DevConfig'
//合并基本页面配置
const baseConfig = Object.assign({}, DevConfig)
//合并差异页面配置
const config = ChannelConfigDiff(baseConfig, merge.all)
//开发页面最终配置
export const devConfig = config.dev

Определить конфигурацию различий

В приведенном выше определении мы обнаружили, что ChannelConfigDiff ссылается на псевдоним Теперь все должны понимать роль файла ChannelConfigDiff.ts, верно? Правильно, добавив этот файл в каждый клон и прописав конфигурацию.

Взяв в качестве примера «Мини-программу A», каталог diff выглядит следующим образом:

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

const dev = {
  dev: {
    items: {
      item1: {//定义第一个item为java内容
        img: require('@/assets/java.png'),
        txt: 'Java',
        onItemClick: () => {
          toPage('Java', require('@/assets/java.png'))
        }
      },
      item2: {...},//第二个item为jsx内容
      item5: null,//第五个item(FireWall)为空
      item8: {
        onItemClick: () => {//最后一个item(C++)点击后跳转TAB
          Taro.switchTab({url: '/pages/index/Manage'})
        }
      }
    }
  }
}
//将dev配置合并到原始整体配置
export default (config, merge) => {
  return merge([{}, config, dev])
}

Видно, что в этой конфигурации содержимое item1 (оригинальный jsx) и item2 (оригинальный java) поменяно местами, item5 (оригинальный FireWall) оставлен пустым, а событие click для item8 (оригинальный C++) изменено. Благодаря этим конфигурациям могут быть достигнуты функциональные различия в «Мини-программе А».

Наконец, не забудьте определение псевдонима, в index.js псевдоним настроен как:

    '@/diff': path.resolve(__dirname, '..', 'src/config/diff'),

В config.js канала 2 псевдоним настроен как:

    '@/diff': path.resolve(__dirname, '..', '../src/channel/channel2/diff'),

Обзор функциональных аватаров

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

В это время, после компиляции, сгенерированная «мини-программа А» имеет страницу «разработки» с дифференцированными стилями и функциями.

Такая дифференцированная конфигурация требует хорошего понимания бизнеса, разумного разделения компонентов и определения разумных элементов конфигурации.

Большая разница теневых клонов

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

Если это произойдет, ей придется сломать руку, чтобы выжить — то есть подмену всей страницы.

Давайте взглянем на «Страницы администратора» «Мини-программы А» и «Мини-программы Б»:

апплет А апплет Б

написать новую страницу

Мы предполагаем, что страницу «Администрирование» «Мини-программы B» трудно отличить с помощью конфигурации, поэтому в настоящее время нам нужно только написать новую страницу со следующим каталогом:

Среди них страница под страницами - это страница, посвященная каналу 3.

замена страницы

Способ замены страниц на самом деле через глобальные переменные.

index.js:

defineConstants: {
  PAGE_MANAGE: 'pages/index/Manage',
}

config.js для канала 3:

defineConstants: {
  PAGE_MANAGE: 'channel/channel3/pages/index/Manage'
},

Конфигурация страницы app.tsx:

  config: Config = {
    pages: [
      ...
      PAGE_MANAGE
    ],
    ...
    tabBar: {
      ...
      list: [
        ...
        {
          pagePath: PAGE_MANAGE,
          ...
        }
      ]
    }
  }

Таким образом, после компиляции, канал 3 генерирует страницу «Управление» «Апплета Б», которая является уникальной страницей канала 3.

Суммировать

То, что представлено в этой статье, - это просто метод, который я могу придумать для решения дилеммы «несколько небольших программ с похожими основными функциями должны поддерживать несколько наборов кодов». Если есть лучший метод, я надеюсь, что вы можете сказать мне, спасибо ты очень.

Так как я только новичок во фронтенд-разработке под Android, мне еще многому предстоит научиться, если в тексте есть ошибки, прошу меня поправить и покритиковать.

Конкретный код можно просмотреть на Github, и вы также можете пометить его звездочкой и поднять вопрос.

Наконец, снова опубликуйте адрес Github: https://github.com/BakerJQ/WeAppBunXin.