如何使用 webpack-node-externals 将所有子依赖项列入白名单

125*_*748 7 javascript dependencies node.js webpack

我正在使用 webpack 使用该target属性来捆绑服务器资产。

这会产生一个可用的客户端包和一个可用的服务器,它运行良好。然而,似乎即使对于服务器代码,webpack 也将所有内容捆绑在node_modules. 我试图用来webpack-node-externals解决这个问题,见下图:

module.exports = [
  {
    name: "server code, output to ./server",
    entry: "./servertest.js",
    output: {
      filename: "./server/index.js"
    },
    target: "node",
    externals: [
      nodeExternals({
        includeClientPackages: false
      })
    ]
  },
  {
    name: "client side, output to ./public",
    entry: "./app.js",
    output: {
      filename: "./dist/app.js"
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

然而,这不起作用,因为它的默认行为是从捆绑中排除所有 node_modules,从而使服务器无用。有一个白名单选项,我已经包含了express,这是我的小测试用例的唯一依赖项。它不会在 express 上失败,但是它在 express, 的依赖上失败了merge-descriptors。当然,如果我将合并描述符添加到白名单中,则尝试启动服务器将因 express 的另一个依赖项而失败。我当然不能将每个依赖项和子依赖项(等等)添加到这个白名单数组中。

如何确保requiretarget: 'node'构建过程中 webpack 捆绑了给定ment 的所有依赖项?

Kev*_*vin 0

为了解决这个问题,我创建了一个小助手,datwd以获取特定包的所有子依赖项的列表:

// webpack.config.js
const nodeExternals = require('webpack-node-externals')
const includeSubdependencies = require('datwd')

module.exports = {
  // ...
  externals: [
    nodeExternals({
      // Will include "cookies" and its dependencies; for example:
      // `['cookies', 'depd', 'keygrip', 'tsscmp']`
      allowlist: includeSubdependencies(['cookies'])
    })
  ]
Run Code Online (Sandbox Code Playgroud)

它依赖于npm ls幕后。源代码:

/* eslint-disable global-require, import/no-dynamic-require */

const { execSync } = require('child_process')

/**
 * Returns a flat array of all Node module dependency names for the entire
 * dependency tree, optionally filtered by top-level modules. Requires NPM
 * and for dependencies to be installed.
 *
 * @param {Array} moduleFilter - An optional array of top-level module names
 *   whose dependencies should be included. If specified, any other modules'
 *   dependencies will be excluded.
 * @return {String[]} An array of module names
 */
const getAllDependencies = (moduleFilterInput = []) => {
  const moduleFilter = Array.isArray(moduleFilterInput)
    ? moduleFilterInput
    : [moduleFilterInput]

  // Get the full dependency tree using NPM, excluding dev dependencies
  // and peer dependencies.
  const dependencyTree = JSON.parse(execSync('npm ls --prod --json').toString())

  // Only get dependencies for specific top-level modules, if specified.
  const dependencyTreeFiltered = moduleFilter.length
    ? {
        ...dependencyTree,
        dependencies: Object.keys(dependencyTree.dependencies)
          .filter((key) => moduleFilter.includes(key))
          .reduce((obj, key) => {
            // eslint-disable-next-line no-param-reassign
            obj[key] = dependencyTree.dependencies[key]
            return obj
          }, {}),
      }
    : dependencyTree

  const allChildDeps = []
  const getAllChildDependencies = (depTree) => {
    const nextDeps = depTree.dependencies
    if (!nextDeps || !Object.keys(nextDeps).length) {
      return []
    }
    Object.entries(nextDeps).forEach(([childDep, childDepTree]) => {
      allChildDeps.push(childDep)
      getAllChildDependencies(childDepTree)
    })
    return allChildDeps
  }

  return getAllChildDependencies(dependencyTreeFiltered)
}
Run Code Online (Sandbox Code Playgroud)