如何使用webpack与monorepo(yarnpkg工作区)

oti*_*ssv 19 node.js express webpack yarnpkg

我正在使用 纱线工作区,其中根目录具有包含所有我的存储库的包目录.每个repo都有自己的node_modules目录,其中包含其依赖项.根node_modules目录包含整个项目的所有dev依赖项以及所有其他dev相关的东西,例如webpack.config文件.Webpack使用热模块重新加载Express服务器包.

我遇到的问题是,如何配置webpack外部以通过整个项目排除所有node_modules目录,而不仅仅是在根目录中?

在这种情况下,webpack-node-externals似乎不起作用.

错误信息:

WARNING in ./packages/servers/express/node_modules/colors/lib/colors.js
127:29-43 Critical dependency: the request of a dependency is an expression

WARNING in ./packages/servers/express/node_modules/express/lib/view.js
79:29-41 Critical dependency: the request of a dependency is an expression
Run Code Online (Sandbox Code Playgroud)

Webpack配置:

const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const StartServerPlugin = require('start-server-webpack-plugin');

module.exports = {
  entry: [
    'babel-polyfill',
    'webpack/hot/poll?1000',
    path.join(__dirname, '../packages/servers/express/server/index.js')
  ],
  watch: true,
  target: 'node',
  externals: [
    nodeExternals({
      whitelist: ['webpack/hot/poll?1000']
    })
  ],
  resolve: {
    alias: {
      handlebars: 'handlebars/dist/handlebars.js'
    }
  },
  module: {
    rules: [
      {
        test: /\.js?$/,
        use: 'babel-loader',
        exclude: /node_modules/
      }
    ]
  },
  plugins: [
    new StartServerPlugin('server.js'),
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env': { BUILD_TARGET: JSON.stringify('server') }
    })
  ],
  output: {
    path: path.join(__dirname, '../packages/servers/express/.build'),
    filename: 'server.js'
  }
};
Run Code Online (Sandbox Code Playgroud)

小智 9

如果使用webpack-node-externals比设置更好的解决方案的纱线工作区modulesFromFile: trueexternals在Webpack配置中使用以下设置:

externals: [
  nodeExternals(),
  nodeExternals({
    modulesDir: path.resolve(__dirname, 'path/to/root/node_modules'),
  }),
],
Run Code Online (Sandbox Code Playgroud)

本质上使用两个nodeExternals实例。1个用于包node_modules,一个用于根node_modules

  • 你花了 9 个小时寻找这个,救了我的命……不过我不需要第一个 `nodeExternals()` (2认同)

Ant*_*iad 7

感谢@blackxored,我得以将其修复到我的项目中。

在您的webpack配置文件中,执行以下操作:

import nodeExternals from 'webpack-node-externals'
Run Code Online (Sandbox Code Playgroud)

然后加

externals: [
  nodeExternals({
    modulesFromFile: true,
  }),
],
Run Code Online (Sandbox Code Playgroud)

  • 您能详细说明一下这样做的后果吗?如果我做对了,默认的nodeExternals将排除在根node_modules和代码中找到的任何内容。然而,使用此选项,您会强制他读取本地 package.json。我对吗? (2认同)

mor*_*ney 5

Yarn 工作空间将兼容的模块提升到根 node_modules 目录,将任何不兼容的(不同的 semver 等)模块保留在依赖工作空间的 node_modules 目录中。如果在不使用相对路径的情况下请求包,则该包可能是来自 node_module 的本机包,也可能是来自您的工作空间之一的符号链接包。您可能希望所有这些包都是外部的。

如何配置 webpack externals 以排除整个项目中的所有 node_modules 目录,而不仅仅是在根目录中?

我会尝试使用带有 webpack 外部选项的函数。您将收到 require 的上下文、所请求的模块的名称以及指示此特定导入(require)是否应被视为外部的回调。

externals: [
    (ctx, req, cb) => {
        if (!/node_modules/.test(ctx) && req[0] !== '.') {
            // Assumes you have defined an "entries" variable
            let notAnEntry = (path) => {
                return Object.keys(entries).every((entry) => {
                    return entries[entry] !== path
                });
            };

            if (notAnEntry(require.resolve(req))) {
                // This module is external in a commonjs context
                return cb(null, `commonjs ${req}`);
            }
        }

        cb();
    }
]
Run Code Online (Sandbox Code Playgroud)