Closed mskorenkyi closed 1 week ago
What's the issue? Can you describe the scenario it is breaking so it can be addressed appropriately?
@satya164 Thanks for your question.
The scenario is next: I'm currently working on developing and publishing my private React Native material design package. To build the library and publish it, I'm using react-native-builder-bob
. For local development, I'm using webpack, and I have configured the webpack to point to the lib
directory rather than the src
folder. Occasionally, I need to bundle my code into a single bundle.js
file for the project's requirements, which is also done using webpack.
After updating react-native-builder-bob
to the latest version, webpack started throwing numerous errors, one of which is:
ERROR in ./lib/module/index.web.js
Module not found: Error: Can't resolve './components/Button' in '~/lib/module'
Did you mean 'Button.js'?
BREAKING CHANGE: The request './components/Button' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
As I described earlier, that this issue arises due to react-native-builder-bob
generating a package.json
file with the content {"type":"module"}
in the lib/module
directory, starting from version 0.28.0
and there are no any config option to avoid that.
Manually removing this file resolves the issue and allows webpack to work without errors.
I recommend setting fullySpecified
to false
in your loader options https://webpack.js.org/configuration/module/
While removing the type: module
may work for this specific case, modules with ESM basically break without it for React Native as without it platform specific extensions don't work.
I recommend setting
fullySpecified
tofalse
in your loader options https://webpack.js.org/configuration/module/While removing the
type: module
may work for this specific case, modules with ESM basically break without it for React Native as without it platform specific extensions don't work.
Unfortunately, fullySpecified
does not work for me. I'd tried it before creating this ticket.
ERROR in ./lib/module/index.web.js 120:0-66
Module not found: Error: Can't resolve './components/Button' in '~/lib/module'
Did you mean 'Button.js'?
BREAKING CHANGE: The request './components/Button' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
I completely agree that removing type: module
is risky and may cause some issues. My suggestion is to have an option (e.g., generatePackageType
or something similar) that would control the generation of type: module
. By default, this option would generate type: module
to avoid breaking changes. However, in my case, I would like to be able to turn this option off in order not to generate that.
I recommend setting
fullySpecified
tofalse
in your loader options https://webpack.js.org/configuration/module/While removing the
type: module
may work for this specific case, modules with ESM basically break without it for React Native as without it platform specific extensions don't work.Unfortunately,
fullySpecified
does not work for me. I'd tried it before creating this ticket.ERROR in ./lib/module/index.web.js 120:0-66 Module not found: Error: Can't resolve './components/Button' in '~/lib/module' Did you mean 'Button.js'? BREAKING CHANGE: The request './components/Button' failed to resolve only because it was resolved as fully specified (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request.
I completely agree that removing
type: module
is risky and may cause some issues. My suggestion is to have an option (e.g.,generatePackageType
or something similar) that would control the generation oftype: module
. By default, this option would generatetype: module
to avoid breaking changes. However, in my case, I would like to be able to turn this option off in order not to generate that.
The error says that fullySpecified
is enabled. It should be disabled. Can you share your configuration?
Adding an option specifically for this won't fix the actual issue - webpack isn't configured properly for React Native libs. Your configuration will still break for other React Native libraries.
Our goal is to have a consistent setup that works for all React Native libs - so we can standardize on the bundler configuration for everyone. Adding options that alter how the bundler needs to be configured makes this goal harder to achieve.
So we'd either remove this entirely if it's not possible to have a bundler configuration that works properly with this setup, or fix the bundler setups to be aligned.
If your library isn't for React Native specifically and hence you don't want to disable fullySpecified
, you can enable the esm
option in Bob's config which will output fully specified import paths. However, it will not work when using platform specific extensions. For platform specific extensions to work, fullySpecified
needs to be disabled.
I recommend setting
fullySpecified
tofalse
in your loader options https://webpack.js.org/configuration/module/While removing the
type: module
may work for this specific case, modules with ESM basically break without it for React Native as without it platform specific extensions don't work.Unfortunately,
fullySpecified
does not work for me. I'd tried it before creating this ticket.ERROR in ./lib/module/index.web.js 120:0-66 Module not found: Error: Can't resolve './components/Button' in '~/lib/module' Did you mean 'Button.js'? BREAKING CHANGE: The request './components/Button' failed to resolve only because it was resolved as fully specified (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request.
I completely agree that removing
type: module
is risky and may cause some issues. My suggestion is to have an option (e.g.,generatePackageType
or something similar) that would control the generation oftype: module
. By default, this option would generatetype: module
to avoid breaking changes. However, in my case, I would like to be able to turn this option off in order not to generate that.The error says that
fullySpecified
is enabled. It should be disabled. Can you share your configuration?Adding an option specifically for this won't fix the actual issue - webpack isn't configured properly for React Native libs. Your configuration will still break for other React Native libraries.
Our goal is to have a consistent setup that works for all React Native libs - so we can standardize on the bundler configuration for everyone. Adding options that alter how the bundler needs to be configured makes this goal harder to achieve.
So we'd either remove this entirely if it's not possible to have a bundler configuration that works properly with this setup, or fix the bundler setups to be aligned.
If your library isn't for React Native specifically and hence you don't want to disable
fullySpecified
, you can enable theesm
option in Bob's config which will output fully specified import paths. However, it will not work when using platform specific extensions. For platform specific extensions to work,fullySpecified
needs to be disabled.
My library is developing for react-native and react-native-web.
Below is my webpack config
// ~root/scripts/webpack.config.js
const appDirectory = path.resolve(__dirname, '../');
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
include: [
...
path.resolve(appDirectory, 'node_modules/react-native-vector-icons'),
...
],
resolve: {
fullySpecified: false,
},
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: ['module:@react-native/babel-preset'],
plugins: ['react-native-web'],
},
},
},
{
test: /\.(gif|jpe?g|png|svg)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
},
},
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
include: [
path.resolve(
appDirectory,
'node_modules/react-native-vector-icons/Fonts'
),
path.resolve(appDirectory, 'lib/module/assets/fonts'),
],
use: [
{
loader: 'url-loader',
},
],
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
resolve: {
// This will only alias the exact import "react-native"
alias: {
'react-native$': path.resolve(__dirname, 'rnw-alias.js'),
'react-native-linear-gradient': 'react-native-web-linear-gradient',
'react-native-svg': 'react-native-svg-web',
},
// If you're working on a multi-platform React Native app, web-specific
// module implementations should be written in files using the extension
// `.web.js`.
extensions: ['.web.js', '.js'],
},
};
and build config
// ~root/scripts/build.config.js
const baseConfig = require('./webpack.config');
const appDirectory = path.resolve(__dirname, '../');
const config = Object.assign(
{
mode: 'production',
entry: [path.resolve(appDirectory, 'lib/module/index.web.js')],
externals: {
react: 'react',
},
output: {
library: 'myLibrary',
libraryTarget: 'umd',
filename: 'bundle.web.js',
path: path.resolve(appDirectory, 'dist'),
},
},
baseConfig
);
module.exports = config;
@mskorenkyi I don't see your full include
statement but I assume that the folder containing the library code is not included, so fullySpecified: false,
doesn't get applied. You can try adding another rule under rules
:
{
test: /\.(js|jsx)$/,
include: regex_for_library_path,
resolve: {
fullySpecified: false,
},
},
For app code, webpack configs should include the following so libraries with ESM code can work:
{
test: /\.(js|jsx)$/,
include: /node_modules/,
resolve: {
fullySpecified: false,
},
},
Here is a repo with a minimal webpack config that demonstrates this https://github.com/satya164/bob-webpack-example
To test, run yarn prepare
, then yarn start
.
Description
After upgrading the version of the
react-native-builder-bob
to the latest version, I encountered an issue where the builder started generating apackage.json
file with content{"type":"module"}
in theoutput
directory (in my case, inlib
). Upon investigation, I discovered that these changes were responsible for this behavior.Unfortunately, I was unable to find any option to prevent the creation of the
package.json
in theoutput
directory. The only solution I found was to manually remove it from my end after the build was completed byreact-native-builder-bob
.Packages
Selected options
Below is my
react-native-builder-bob
config.Link to repro
https://github.com/mskorenkyi/BobIssue/
Environment
System: OS: macOS 14.2.1 CPU: (8) arm64 Apple M1 Pro
Binaries: Node: version: 20.12.2 path: ~/.nvm/versions/node/v20.12.2/bin/node Yarn: version: 1.22.22 path: ~/.nvm/versions/node/v20.12.2/bin/yarn npm: version: 10.8.1 path: ~/.nvm/versions/node/v20.12.2/bin/npm