webpack: Problems with pnpm and the way loaders are resolved

Do you want to request a feature or report a bug?

bug?

What is the current behavior?

I can’t create libs which use webpack and loaders, install these libs with pnpm and try to use them, because the modules can’t be found.

It looks like pnpm installs my lib here: /Users/foo/test/ws-pnpm-test/node_modules/.registry.npmjs.org/@mercateo/ws/1.0.2/node_modules/@mercateo/ws.

The loader is here /Users/foo/test/ws-pnpm-test/node_modules/.registry.npmjs.org/string-replace-loader and here /Users/foo/test/ws-pnpm-test/node_modules/.registry.npmjs.org/@mercateo/ws/1.0.2/node_modules/string-replace-loader.

I think webpack only looks here for loaders: /Users/foo/test/ws-pnpm-test/node_modules/string-replace-loader, but this does not exist.

I think webpack resolves loaders in node_modules relative to process.cwd(), but not relative to my lib.

I can’t just rewrite my config to something like this:

{
  resolveLoader: {
    modules: [
       // goes up '@mercateo/ws/dist' to match `'/Users/foo/test/ws-pnpm-test/node_modules/.registry.npmjs.org/@mercateo/ws/1.0.2/node_modules/string-replace-loader'`
       // this could lead to different directories, if my lib isn't installed with pnpm
       join(__dirname, '..', '..', '..'),
       // this would match `'/Users/foo/test/ws-pnpm-test/node_modules/.registry.npmjs.org/string-replace-loader'`
       // but I can't be sure, that my users use the official registry and not a private mirror or something like that
       join(process.cwd(), 'node_modules/.registry.npmjs.org'),
      'node_modules'  // default
    ]
  }
}

What is the most robust way to solve this? Can I specify something like that? resolveLoaders.basedir: __dirname, so all loaders can be resolved relative to my lib?

// cc @zkochan

If the current behavior is a bug, please provide the steps to reproduce.

package.json:

{
  "name": "ws-pnpm-test",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "ws": "ws"
  },
  "ws": {
    "type": "browser"
  },
  "dependencies": {
    "@mercateo/ws": "^1.0.2"
  }
}

tsconfig.json:

{}

src/index.ts:

console.log('hello');
$ pnpm install
$ npm run -s ws -- build
ERROR in Entry module not found: Error: Can't resolve 'string-replace-loader' in '/Users/foo/test/ws-pnpm-test'

What is the expected behavior?

Build without error.

If this is a feature request, what is motivation or use case for changing the behavior?

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.

Node LTS, Webpack 2.6, pnpm 0.71, Mac OS X.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 29
  • Comments: 48 (12 by maintainers)

Commits related to this issue

Most upvoted comments

This issue had no activity for at least half a year.

It’s subject to automatic issue closing if there is no activity in the next 15 days.

This issue had no activity for at least three months.

It’s subject to automatic issue closing if there is no activity in the next 15 days.

@sokra any ideas? This issue is still prevalent and old. pnpm is very promising and this is blocker.

cc @yegor-sytnyk, @max-devjs

Ref https://github.com/pnpm/pnpm/issues/801

We have issues in lots of applications because webpack can’t resolve packages in the node_modules created by pnpm. I think it is because webpack doesn’t resolve dependencies the way Node does. Node resolves requires from the real path of a module. That is why the symlink approach pnpm uses works with all Node apps. However, it seems to confuse webpack and some other tools like browserify and eslint.

It’s a shame this hasn’t been resolved yet. I love using pnpm because it treats dependencies in a sane way and it’s fast. I also like the simplicity of vue-cli and the power of webpack.

Could we attempt to fix this somehow? I don’t even know who should change.

This caught my eye in pnpm/pnpm#1678

I think the best/cleanest/most portable solution is to use resolveLoader.alias and require.resolve to map loaders directly to absolute paths. (i.e. config.resolveLoader.alias.set(‘babel-loader$’, require.resolve(‘babel-loader’)))

Any help is appreciated here @evilebottnawi .

I think the way to solve this, if you intend to use a config package that provides a webpack config for you, is to use require.resolve for all of your loader references, like for example require.resolve('babel-loader') instead of plain babel-loader as a string in the webpack config.

I don’t have these issues anymore, as long as I use the above.

If you don’t have control over the package you get the configuration from, you should probably open an issue with them, because require.resolve makes more sense to do from their side rather than webpack’s side. Webpack only reads loaders from working directory, changing that would be quite a breaking change, I believe.

webpack should have a peeDependency to events, because hot module loading requires it

https://github.com/webpack/webpack/blob/81cf088cd6a0231b94fa2399bd29294eccee1907/hot/emitter.js#L1

make sure you have resolve.symlinks set to true

Have you tried to put a file .npmrc in your project root folder? The content is just like this:

shamefully-hoist=true

I think I’m hitting this issue or something similar in this React project:

https://github.com/dirtprotocol/dirt/tree/master/sampleprojects/sample-web-react

If I install with npm or yarn, everything is fine when I run npm start. If I install with pnpm, I get this error:

/Users/sendrecv/sproj/dirt/packages/lib/dist/services/StaticContractProvider.js
Module not found: Can't resolve '@dirt/contracts' in '/Users/sendrecv/sproj/dirt/packages/lib/dist/services'

Confirmed. If you git clone this repository, it will cause this problem:

https://github.com/mdn/kuma

Maybe I can just use resolveLoaders.modules: [ join(__dirname, '..', '..', '..'), 'node_modules' ]?

If my lib is installed with pnpm the path matches '/Users/foo/test/ws-pnpm-test/node_modules/.registry.npmjs.org/@mercateo/ws/1.0.2/node_modules. For npm and yarn it would match '/Users/foo/test/ws-pnpm-test/node_modules'. Looks okay I guess?

Feel free to close this issue, if this is the intended way.

Without using shamefully-hoist, this still seems like a problem when using a packager that depends on webpack behind the scenes, like Rails’ webpacker. Loaders don’t seem to, well load, without manually resolving them via require.resolve('babel-loader'), etc in the resolve config.

This is a major roadblock for rails/webpacker/issues/2467.

@evilebottnawi

  1. it all started with this error https://github.com/vuejs/vue-cli/issues/4571
  2. i update pnpm to 3.8.1 and solve it
  3. after build I found an error Module not found: Error: Can't resolve 'ts-loader' and same errors for tslib and @types/node.
  4. after forse install tslib and @types/node in package.json my app started
  5. but failed in runtime with Module not found: Error: Can't resolve 'ts-loader'
  6. after install ts-loader same as in vue-cli deps, i found Module build failed (from ../common/temp/node_modules/.registry.npmjs.org/babel-loader/8.0.6_@babel+core@7.6.0+webpack@4.12.0/node_modules/babel-loader/lib/index.js):
  7. I gave up and switched to rush + npm.