Настройте способ работы «импорта» с веб-пакетом - PullRequest
0 голосов
/ 08 сентября 2018

Мне нужно настроить способ, которым веб-пакет обрабатывает импорт в моем приложении.

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

Обратите внимание, что мне нужны разные выходные файлы ("main.js" и "test.js"). Поэтому мне нужно убедиться, что test.js не включает в себя реальные реализации сервисов (недостаточно предотвращения выполнения, источник вообще не должен быть импортирован).

Папка Services содержит следующие файлы:

service-1.js
service-1.mock.js
service-2.js
index.js

услуги / index.js:

import service1 from ‘./service-1’
import service2 from ‘./service-2’
export {service1, service2}

Посоветуйте, пожалуйста, как мне настроить мой веб-пакет.

1 Ответ

0 голосов
/ 09 сентября 2018

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

Метод № 1

Создайте по одному .mobile и .desktop для каждого из ваших компонентов в главном файле (например, component.js, component.mobile.js, component.desktop.js) и используйте этот пользовательский загрузчик:

const targets = {
  desktop: 'desktop',
  mobile: 'mobile'
};
const source = `
    import Home from './components/home';
    import About from './components/about';
    import Header from './shared/Header';
    import Footer from './shared/about';
    import Categories from './category/categories';
    
    // rest of code
`;

const manipulated = manipulateSource(source, targets.mobile, ['components', 'shared']);
console.log(manipulated);


function manipulateSource(src, target = targets.desktop, pathMatches = []) {
  const paths = pathMatches.length ? `(${pathMatches.join('|')})` : '';
  const pattern = new RegExp(`(?<left>.*import.*${paths}.*\\\/)(?<name>[\\w\\-_]*)(?<rest>.*\\n)`, 'g');
  const manipulated = src.replace(pattern, (...args) => {
    const [{
      left,
      name,
      rest
    }] = args.slice(-1);
    return `${left}${name}.${target}${rest}`;
  });

  return manipulated;
}

Метод № 2

Для этих файлов предусмотрены различные реализации для .mobile и .desktop. Создайте третий файл (или четвертый, если вы хотите поместить разделяемый код в основной файл) с тем же именем и значимым расширением (например, component.platformAdaptive.js). который может быть обработан с помощью regular expresion (или любым другим способом манипулирования). В этом методе вам может потребоваться поместить базовую реализацию в последний файл, если вы используете strongTypes (например: Typescript):

const targets = {
  desktop: 'desktop',
  mobile: 'mobile'
};
const source = `
    import Home from './components/home';
    import About from './components/about';
    import Header from './shared/Header.platformAdaptive';
    import Footer from './shared/about.platformAdaptive';
    import Categories from './category/categories.platformAdaptive';
    
    // rest of code
`;

const manipulatedMob = manipulateSource(source, 'platformAdaptive', targets.mobile);
const manipulatedDesk = manipulateSource(source, 'platformAdaptive');

console.log(manipulatedMob);
console.log(manipulatedDesk);

function manipulateSource(src, replace, target = targets.desktop) {
  const pattern = new RegExp(`(?<left>.*\\\/)(?<name>[\\w\\-_]*\.)${replace}(?<rest>.*\\n)`, 'g');
  const manipulated = src.replace(pattern, (...args) => {
    const [{
      left,
      name,
      rest
    }] = args.slice(-1);
    return `${left}${name}${target}${rest}`;
  });

  return manipulated;
}

Оба вышеуказанных метода имеют некоторые ограничения в импорте, например, вы не можете использовать Barrel files (index.js), так как они предполагают, что последний фрагмент импорта является файлом компонента. В этом случае вы можете добавить несколько папок с barrel для обработки этого импорта. например, во втором методе вам понадобится такая структура:

|-- components.platformAdaptive
    |-- index.js
|-- components.mobile
    |-- index.js
|-- components.desktop
    |-- index.js

Или Вы можете использовать / вместо . для создания вложенной структуры (например: components/platformAdaptive):

|-- components
    |-- [+] platformAdaptive
    |-- [+] mobile
    |-- [+] desktop

Метод № 3

Еще один способ справиться с этой ситуацией - иметь разные классы с разными именами. Например, компонент List с различными реализациями для мобильных устройств и настольных компьютеров, тогда будут три компонента, такие как ListPlatformAdaptive, ListMobile, ListDesktop, в которых ListPlatformAdaptive может иметь базовые реализации, и barrel в папка компонентов, в которую экспортируются компоненты:

import * as ListPlatformAdaptive from './list.platformAdaptive';
import * as ListMobile from './list.mobile';
import * as ListDesktop from './list.desktop';

export {
    ListPlatformAdaptive,
    ListMobile,
    ListDesktop
}

Структура будет выглядеть так:

|-- components
    |-- list.platformAdaptive.js
    |-- list.mobile.js
    |-- list.desktop.js
    |-- index.js

Тогда манипуляция будет такой:

const targets = {
  desktop: 'Desktop',
  mobile: 'Mobile'
};
const source = `
    import Home from './components/home';
    import About from './components/about';
    import HeaderPlatformAdaptive as Header from './shared/Header';
    import FooterPlatformAdaptive as Footer from './shared/about';
    import CategoriesPlatformAdaptive as Categories from './category/categories';
    
    // rest of code
`;

const replace = 'PlatformAdaptive';
const manipulatedMob = manipulateSource(source, replace, targets.mobile);
const manipulatedDesk = manipulateSource(source, replace);

console.log(manipulatedMob);
console.log(manipulatedDesk);

function manipulateSource(src, replace, target = targets.desktop) {
  const pattern = new RegExp(replace, 'g');
  const manipulated = src.replace(pattern, target);

  return manipulated;
}

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


Метод № 4

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

const targets = {
  desktop: 'Desktop',
  mobile: 'Mobile'
};
const source = `
    import Home from './components/home';
    import About from './components/about';
    import Header from './shared/Header'; /* @adaptive */
    import Footer from './shared/about';  /* @adaptive: Desktop */
    import Categories from './category/categories'; /* @adaptive: Mobile */
                
    // rest of code
`;

const manipulatedMob = manipulateSource(source, targets.mobile);
const manipulatedDesk = manipulateSource(source);

console.log(manipulatedMob);
console.log(manipulatedDesk);

function manipulateSource(src, targetDevice = targets.desktop) {
  const pattern = /(?<left>.*import\s+)(?<name>\w+)(?<rest1>.*)\@adaptive(\:\s*(?<target>\w+))?(?<rest2>.*)/g
  const manipulated = src.replace(pattern, (matched, ...args) => {
    let [{
      left,
      name,
      rest1,
      target,
      rest2
    }] = args.slice(-1);
    target = target || targetDevice;
    return target == targetDevice ?
      `${left}${name}${target}$ as ${name}${rest1}${rest2}` :
      matched;
  });

  return manipulated;
}

В этом методе, как и в методе №2, имена импортируемых компонентов отличаются от оригинала, но отображаются на оригинальное имя, что совсем не хорошо, но мне оно больше всего нравится, так как при использовании его в barrel файлах и его можно изменить адрес импортированного файла. Другая забавная часть может состоять в том, чтобы передать адрес целевых файлов относительно target device и проанализировать его.

Заключение

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

...