javascript - 自定义 “import” 使用 webpack 的方式

标签 javascript webpack import es6-module-loader

我需要自定义 webpack 在我的应用中处理导入的方式。

我的一些服务有模拟实现。 在测试模式下,如果服务旁边存在带有“.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}

请告知如何配置我的 webpack。

最佳答案

根据评论,我可以使用自定义加载器建议这些解决方法:

方法#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),可以使用正则表达式(或任何其他操作方式)处理。在此方法中,如果您使用 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 文件 (index.js),因为它们假设导入的最后一 block 是组件文件。 在这种情况下,您可以使用 barrel 添加多个文件夹来处理这些导入。例如在第二种方法中你需要这样的结构:

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

或者您可以使用 / 而不是 . 来创建嵌套结构(例如:components/platformAdaptive):

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

方法#3

处理这种情况的另一种方法是使用不同名称的不同类。例如,一个 List 组件具有不同的移动和桌面实现,那么将有三个组件,如 ListPlatformAdaptiveListMobileListDesktop - 其中 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 文件,这种方法的缺点是所有组件都已经导入,因此导入成本是 Not Acceptable 。


方法#4

我能想到的另一种方法是添加一些注释作为注释,并在该行中对它的存在作出 react :

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 文件中使用它并且可以更改导入的文件地址。另一个有趣的部分是传递关于目标设备的目标文件地址并解析它。

结论

如您所见,我的所有回答都是关于处理源代码而不检查文件是否存在,并假设开发人员对此有把握。顺便说一句,你可以搜索看看是否有找到文件绝对路径,然后检查目标替代品的可用性。

关于javascript - 自定义 “import” 使用 webpack 的方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52236515/

相关文章:

python - 存储和调用数据的最有效方法是什么?

python - 导入错误:cannot import name '_methods'

javascript - 使用 MSAL 和 JS 检测到 multiple_matching_tokens_Detected

javascript - 如何获取jquery中的datepicker类值?

javascript - 从Django传递值到Ajax,如何识别变量类型?

运行 webpack 后 Javascript 函数未定义

javascript - Webpack 排除 CommonsChunkPlugin 的条目

sass - .scss 文件未找到流模块

mysql - 计划将 .MDB 文件从 ftp 服务器导入 MySQL

javascript - 如何使用 jQuery 查找具有电子邮件地址作为类名的元素?