如何使webpack编译 node_modules 中的 npm 包

发布时间 2023-09-15 18:19:19作者: 饭特稠

What

在项目开发过程中,我们会使用到大量第三方的npm包,这些包大部分使用了 es中新的语法编写 ,但是在发布的时候,它们有些是经过 babel,tsc, esbuild 等工具转换后发布的,有的则没有转换直接发布到 npm 中,

所以当我们在 webpack 中使用这样的包时,可能会看到如下报错:

Why

上面的截图中使用了一个叫 screenfull 的包,点进去一看,原来是代码中使用了?.运算符,而在 webpack.config.js 中,由于 exclude 被设置为整个 node_modules, 从而使 babel 跳过了对 screenfull 的转换:

module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env', { targets: "defaults" }]
          ]
        }
      }
    }
  ]
}

How

这时,我们需要修改 exclude 的配置,确保报错的 npm 中的包的代码被转换。exclude,include 作为一个 Condition, 可以是下面的形式:

  • 字符串:匹配输入必须以提供的字符串开始。是的。目录绝对路径或文件绝对路径。
  • 正则表达式:test 输入值,如/node_modules/
  • 函数:调用输入的函数,必须返回一个真值(truthy value)以匹配。
  • 条件数组:至少满足一个匹配条件, 如[/node_modules/, /lib/]
  • 对象:所有属性对应的 condition 都要满足。每个属性都有一个定义行为。

所以上面的问题可以这样来配置:

module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
+      exclude: {and: [/node_modules/], not: [/screenfull/] }, //screenfull是报错的npm 包
-      exclude: /node_modules/,
    }
  ]
}

除此以外,我们也可以定义一个condition函数,来完成同样的功能:


module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: (filepath) => {
        if (/node_modules/.test(filepath)) {
          if (/screenfull/.test(filepath)) {
             return false;
          }
          return true;
        }
        return false
      }
    }
  ]
}