Skip to content

[Bug]: unclear error and too general typing on externals field #8248

@ItamarGronich

Description

@ItamarGronich

System Info

  System:
    OS: macOS 14.6.1
    CPU: (10) arm64 Apple M2 Pro
    Memory: 174.80 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.16.0 - ~/.nvm/versions/node/v20.16.0/bin/node
    npm: 10.8.1 - ~/.nvm/versions/node/v20.16.0/bin/npm
    pnpm: 9.7.1 - ~/Library/pnpm/pnpm
  Browsers:
    Chrome: 130.0.6723.70
    Safari: 17.6
  npmPackages:
    @rspack/cli: ^1.0.14 => 1.0.14 
    @rspack/core: ^1.0.14 => 1.0.14 

Details

When compiling to a library with type 'umd' and using externals, Rspack will error out if you forgot to add the 'root' | 'commonjs' | 'commonjs2' properties to one of your externals.

for example:
Good ✅

export default {
  output: { library: { type: "umd" } },
  externals: {
    react: {
      commonjs: "react",
      commonjs2: "react",
      root: "React"
    }
  }
}

Bad ❌

export default {
  output: { library: { type: "umd" } },
  externals: {
    react: {
      commonjs: "react",
      commonjs2: "react" // Notice no 'root' property. But removing any of these three will result in an error.
    }
  }
}

This makes sense as critical information is missing for Rspack to be able to construct a correct UMD import of the react library.

The bad example will throw the following error:

[rspack-cli] [Error:   × Missing external configuration for type: root
] {
  code: 'GenericFailure'
}

How Webpack treats this

When you do this in webpack - webpack compiles successfully without any error. but the resulting code has errors in it.
So i think Rspack actually does the right thing here but fails to communicate this properly.
for example if you had this code:

import React from 'react'
console.log(React)

webpack would output something like this:

	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory(require("react"));
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else {
                // 🚧 notice the root[undefined] here which should have been root['React'] 
                // but because webpack doesn't have a 'root' property it just puts in undefined. 
                //                                                  This will throw in production👇🏻
		var a = typeof exports === 'object' ? factory(require("react")) : factory(root[undefined]); 
		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
	}

My Conclusion

I think Rspack does the right thing here I think that there's still some stuff missing in communication and DevX areas:

  1. The error that Rspack returns is quite vague and general. would be better to say what specific external is missing what properties.
  2. The types are too general (Record<string, string | string[]>) and don't let typescript users know that they are defining this configuration wrong. Would be better if when the library type is umd there was an actual interface that would let users know what properties should be required there (commonjs, commonjs2, amd & root).
  3. Documentation around externals doesn't enumerate the possible values and which are required in which case. https://rspack.dev/config/externals

Reproduce link

https://github.com/ItamarGronich/rspack-externals

Reproduce Steps

  1. clone the repo
  2. run nvm use
  3. run npm ci
  4. run npm run test:rspack to see the error printed out
  5. run npm run test:webpack to see no error printed out

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions