【问题标题】:How to use webpack with a monorepo (yarnpkg workspaces)如何将 webpack 与 monorepo 一起使用(yarnpkg 工作区)
【发布时间】:2017-09-02 05:58:49
【问题描述】:

我正在使用yarn workspaces,其中根目录有一个包含我所有存储库的包目录。每个 repo 都有自己的 node_modules 目录,其中包含其依赖项。根 node_modules 目录包含整个项目的所有开发依赖项以及所有其他与开发相关的内容,例如 webpack.config 文件。 Webpack 使用热模块重新加载快速服务器包。

我遇到的问题是,如何配置 webpack externals 以排除整个项目中的所有 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

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'
  }
};

【问题讨论】:

  • Workspaces 在标题中拼写错误。

标签: node.js express webpack yarnpkg


【解决方案1】:

如果使用带有 webpack-node-externals 的 yarn 工作区比设置 modulesFromFile: true 更好的解决方案是在 webpack 配置中使用以下 externals 设置:

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

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

【讨论】:

  • 我尝试了两种方式,这种方式在构建时间上快了大约 1 秒(我使用的是非常弱的 chromebook)。我不确定moduleFromFiles 做了什么,但至少在我非常有限的测试中,这个解决方案更快。
  • 你在追了 9 个小时后救了我的命……虽然我不需要第一个 nodeExternals()
  • 如果我做对了,第一个 nodeExternal() 只会删除在本地 node_modules 中找到的包,所以在 Yarn 工作区的上下文中几乎什么都没有。第二个也将删除根 node_modules。
  • 找到了将其放入通用 webpack 配置的模式:externals: [ nodeExternals({ additionalModuleDirs: [path.resolve(__dirname, path/to/root/node_modules")] }) ]。它的工作原理与您的答案类似,但 additionalModuleDirs 更简洁。
【解决方案2】:

感谢@blackxored,我能够在我的项目中修复它。

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

import nodeExternals from 'webpack-node-externals'

然后添加

externals: [
  nodeExternals({
    modulesFromFile: true,
  }),
],

【讨论】:

  • 您能详细说明一下这样做的后果吗?如果我做对了,作为默认 nodeExternals 将排除它在根 node_modules 和您的代码中找到的任何内容。但是,使用此选项,您会强制他阅读您的本地 package.json。我说的对吗?
【解决方案3】:

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

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

我会尝试using a function with webpack's external option。系统会向您传递 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();
    }
]

【讨论】:

    猜你喜欢
    • 2020-10-28
    • 1970-01-01
    • 2019-11-04
    • 2020-05-24
    • 2018-11-03
    • 2018-04-09
    • 2018-09-08
    • 2015-09-15
    相关资源
    最近更新 更多