Skip to content

webpack——可选依赖打包实践 #7

@HexMox

Description

@HexMox

近期在维护一个Web侧的SDK,遇到一个可选依赖打包的场景颇为头疼,仅在此记录下探索过程。

前言

在Node中,我们常常会包一层try catch写出这样的代码来实现降级逻辑:

try {
  const a = require('a');
} catch(e) {
  // 模块a不存在的降级逻辑
}

但在前端存在webpack打包的场景中,也有几种方案可以实现类似效果

try-catch

将Node的代码原封不动的使用webpack打包也是可以实现这个效果的。不过会出现Warnings:

WARNING in ./src/pages/xxx/index.js
Module not found: Error: Can't resolve 'a' in '/workspace/projects/xx/src/pages/xxx'
 @ ./src/pages/xxx/index.js

当然如果你不包裹一层try-catch就会导致构建失败了,这一层try-catch的语义分析,webpack做到了什么程度呢?

假如现在有源码

[
  () => require('a'), 
  () => require('b')
].some(fn => {
  try {
    this.reportor = fn();
    return true;
  } catch (e) {}
});

那么webpack的语义分析就没用了...
如果需要尝试依赖超过3次的降级包,那为了避免嵌套地狱,try-catch包裹就只能这么写了:

function tryGet(x = 0) {
  try {
    switch(x) {
    case 0:
      return require('a');
    case 1:
      return require('b');
    case 2:
      return require('c');
    }
  } catch(e) {
    return x >= 2 ? null : tryGet(x + 1);
  }
}

require.resolveWeak

webpack提供了require.resolveWeak的API来实现弱依赖打包。

[
  // 兼容webpack,需要业务先行引入上报库
  () => __webpack_modules__[require.resolveWeak('a')],
  () => __webpack_modules__[require.resolveWeak('b')],
  // 兼容fis3
  () => jsRequire('a'),
  () => jsRequire('b'),
].some((fn, i) => {
  try {
    this.x = fn();
    return !!this.x;
  } catch (e) {
    console.warn('xxx');
  }
});

这种方式的缺陷就是业务代码中必须将模块ab先依赖进来,如果仅仅是node_modules中存在模块,则__webpack_modules__中不会有打包的模块,是一种相对较弱的optional require。

__non_webpack_require__

按照官方文档的说法,实际上会将源码:

__non_webpack_require__('a')

生成:

require('a')

以交由其他模块加载器处理,也有很大的局限性。

小结

以上是基于不动构建配置的前提下,实现可选依赖打包的实践,请多多指教!

如果不基于这个前提当然也有很多种实现,比如可以自行判断package.json的dependecies再结合externals配置来做、自行实现__webpack_require__的模板等等。

参考链接:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions