Передняя многопроектная модульная практика

внешний интерфейс Webpack

Я работаю сверхурочно уже почти три месяца подряд, и недавно я нашел время, чтобы записать некоторые из своих переживаний, которые можно рассматривать как резюме!

предыстория истории

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

  • Несколько параллельных проектов, что приводит к нехватке человеческих ресурсов (эта обезьяна находится в городе третьего уровня, брата с двумя кистями нелегко нанять)
  • Низкий уровень повторного использования кода и слишком много дублирования работы (даже проекты с 50% сходства, возможно, придется переделывать, что слишком мало)
  • Качество разработки трудно контролировать, а затраты на тестирование высоки.
  • Проекты трудно завершить вовремя, часто задерживая

Так что поиск доступного решения, подходящего для ситуации нашей команды, неизбежен!

Технологический стек этой команды ape — vue+webpack, поэтому мое решение может не подойти для других технологических стеков.

Решение первое

На самом деле это провальный план. Позвольте мне сначала представить его здесь и презирать себя!

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

<component-a v-if="projectId === 10000"></component-a>
<component-a v-if="projectId === 10001"></component-a>

Трагедия такого подхода очевидна:

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

Решение второе

В настоящее время это решение находится на практике, и оно может удовлетворить текущие потребности бизнеса на данный момент!

1. Структура каталогов компонентов и страниц

Компоненты каталога компонентов аналогичны страницам каталога страниц, так что вот TabBar (нижняя панель навигации) в компонентах в качестве примера.

Мы видим, что под TabBar есть три файла 0.vue, 29006.vue и index.js:

  • 0.vue — стандартный компонент нижней панели навигации.
  • 29006.vue — это нижняя панель навигации, настроенная для проекта номер 29006.
  • index.js — это вход для всего компонента TabBar. Как сгенерировать этот файл, см. следующее введение.

По аналогии, в pages/Home (главная) мы также можем видеть стандартную домашнюю страницу, домашнюю страницу, настроенную под номер проекта 29006, и файл входа домашней страницы index.js

Во-вторых, структура файлов ресурсов

Файлы стилей и изображений такие же, как и компоненты, представленные ранее, с использованием номера элемента в качестве имени файла, чтобы различать их.

3. Компоненты ссылки на страницу и страницы загрузки маршрута

Каждый компонент имеет index.js в качестве записи, поэтому, если вы добавляете компонент на страницу, просто:

import TabBar from '../../components/TabBar';

Точно так же каждая страница также имеет index.js в качестве записи, поэтому, если вы добавляете компоненты в маршрут, просто:

{
      path: '/home',
      name: 'home',
      title: '首页',
      component(resolve) {
        require.ensure(['../pages/Home'], () => {
          resolve(require('../pages/Home'));
        });
      },
      meta: {requiresAuth: false}
}

В-четвертых, конфигурация проекта

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

Нижний колонтитул генерации проекта create-platform.js выглядит следующим образом:

const glob = require('glob');
const fsExtra = require('fs-extra')
const platform = process.argv[2]; // 项目号
const vueFile = `${platform}.vue`; // 与项目匹配的vue文件
const defaultVueFile = `0.vue`; // 标准的vue文件
const fs = require('fs');

// 获取指定路径下的入口文件
function getEntries(globPath) {
  let files = glob.sync(globPath);
  let paths = [];
  files.forEach((filepath) => {
    let split = filepath.split('/');
    let path = split.slice(0, split.length - 1);
    path = path.join('/');
    paths.push(`${path}`);
  });
  paths = dedupe(paths);
  return paths;
}

// 数组去重
function dedupe(array){
  return Array.from(new Set(array));
}

// 写入index.js入口文件
async function writeIndexJS (path, fileName) {
  let split = path.split('/');
  let componentName = split[split.length - 1];
  let f = `${path}/index.js`
  try {
    await fsExtra.outputFile(f, `import ${componentName} from './${fileName}';\r\nexport default ${componentName};`);
  } catch (err) {
    console.error(err)
  }
}

async function copyFile (src, dest) {
  try {
    await fsExtra.copy(src, dest, { overwrite: true })
  } catch (err) {
    console.error(err)
  }
}

// 创建index.js
function createIndexJS(paths) {
  paths.forEach(async (path) => {
    let exists = await fsExtra.pathExists(`${path}/${vueFile}`);
    if (exists) {
      writeIndexJS(path, vueFile);
    } else {
      writeIndexJS(path, defaultVueFile);
    }
  });
}

// copy懒加载所需图片
async function copyLazyLoad() {
  let exists = await fsExtra.pathExists(`./src/assets/images/lazy-load/list/${platform}.png`);
  if (exists) {
    copyFile(`./src/assets/images/lazy-load/list/${platform}.png`, `./static/lazy-load/list.png`);
  } else {
    copyFile(`./src/assets/images/lazy-load/list/0.png`, `./static/lazy-load/list.png`);
  }
  exists = await fsExtra.pathExists(`./src/assets/images/lazy-load/thumbnail/${platform}.png`);
  if (exists) {
    copyFile(`./src/assets/images/lazy-load/thumbnail/${platform}.png`, `./static/lazy-load/thumbnail.png`);
  } else {
    copyFile(`./src/assets/images/lazy-load/thumbnail/0.png`, `./static/lazy-load/thumbnail.png`);
  }
}

// copy样式文件
async function copyLess() {
  let exists = await fsExtra.pathExists(`./src/assets/css/main/${platform}.less`);
  if (exists) {
    copyFile(`./src/assets/css/main/${platform}.less`, `./src/assets/css/main.less`);
  } else {
    copyFile(`./src/assets/css/main/0.less`, `./src/assets/css/main.less`);
  }
  exists = await fsExtra.pathExists(`./src/assets/css/theme/${platform}.less`);
  if (exists) {
    copyFile(`./src/assets/css/theme/${platform}.less`, `./src/assets/css/theme.less`);
  } else {
    copyFile(`./src/assets/css/theme/0.less`, `./src/assets/css/theme.less`);
  }
}

let paths = getEntries('./src/components/**/*.vue'); // 获得入口components目录下的文件
createIndexJS(paths);
paths = getEntries('./src/pages/**/*.vue'); // 获得入口pages目录下的文件
createIndexJS(paths);
copyLazyLoad();
copyLess();

Команда запуска скрипта:

node create-platform.js 29006

Описание сценария

const platform = process.argv[2]; // 以命令行的第三个参数项目号
const vueFile = `${platform}.vue`; // 根据项目号生成匹配的vue文件
const defaultVueFile = `0.vue`; // 标准的vue文件
// 获取指定路径下的入口文件
function getEntries(globPath) {
  .........
}
// 创建index.js
function createIndexJS(paths) {
  // 遍历目录
  paths.forEach(async (path) => {
    // 判断目录中是否存在和项目号匹配的vue文件,如果有就使用该文件,如果没有则使用标准的0.vue
    let exists = await fsExtra.pathExists(`${path}/${vueFile}`);
    if (exists) {
      writeIndexJS(path, vueFile);
    } else {
      writeIndexJS(path, defaultVueFile);
    }
  });
}
// 写入index.js入口文件
async function writeIndexJS (path, fileName) {
  let split = path.split('/');
  let componentName = split[split.length - 1]; // 以目录名作为组件和页面名称
  let f = `${path}/index.js`
  try {
    await fsExtra.outputFile(f, `import ${componentName} from './${fileName}';\r\nexport default ${componentName};`);
  } catch (err) {
    console.error(err)
  }
}

Здесь представлено лишь несколько основных методов, другие методы copyLazyLoad и copyLess имеют те же принципы, поэтому они не будут представлены один за другим!

5. Результаты

Команда выполнения

node create-platform.js 29006

Содержимое файла index.js в TabBar выглядит следующим образом:

import TabBar from './29006.vue';
export default TabBar;

Это связано с тем, что существует файл компонента 29006.vue, который соответствует номеру проекта на вкладке TabBar.

Содержимое файла index.js в HomeCategoryColumn выглядит следующим образом:

import HomeCategoryColumn from './0.vue';
export default HomeCategoryColumn;

Это связано с тем, что в HomeCategoryColumn нет файла, соответствующего элементу 29006, поэтому используется стандартный 0.vue.

6. Резюме

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

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

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