This document describes the high-level architecture of react-native-webpack-toolkit
.
If you want to familiarize yourself with the code base, you are just in the right place!
Before you start, make sure you've gone through the README.
Feel free to jump between this document and API documentation for an additional context on configuration, parameters and types.
There are 2 ways to look at the content of the react-native-webpack-toolkit
:
- by command that are exposed to React Native CLI
- by Webpack plugins and utilities
Here's a chart that represents both aspect of the codebase:
The following list describes the components that create react-native-webpack-toolkit
:
public/
— Public assets for Debugger UI.templates/
— Templates for files to initialize a new project.react-native.config.js
— React Native CLI plugin file with commands declarations.src/
client/
— Source code for Debugger UI.commands/
— Source code for React Native CLI commands.runtime/
— Source code for runtime code embedded into a final bundle.server/
— Source code for Development server, proxy and all related functionality.webpack/
— Source code for Webpack plugins and utilities.
The core of bundling functionality is to load platform-specific Webpack configuration file, then using Webpack API, create and run a compiler.
Depending on how code is run, the final Webpack configuration might be different, as the behavior of parseCliOptions
differs.
Please refer to a dedicated parseCliOptions
section for more information.
There's not much difference between in (webpack-)bundle
command and Webpack CLI logic, except that (webpack-)bundle
command
accepts React Native specific CLI options and Webpack CLI has its own set of options.
When running a development server, there is a wide difference in the functionality provided by (webpack-)start
command and Webpack CLI:
- Webpack CLI:
- Will create platform-specific Webpack configuration, so when the compiler calls
DevSeverPlugin
, a platform-specificDevServer
will be created. - The platform-specific
DevServer
has all the required features (debugging, symbolication, logging, message/events WebSocket server, HMR, Dev endpoints).
- Will create platform-specific Webpack configuration, so when the compiler calls
(webpack-)start
:- Uses
DevServerProxy
, which sole purpose is to allow running multiple Webpack compilers for multiple platforms. - Each platform will get its own compiler worker, which runs Webpack compiler in watch mode. For each compilation a platform-specific Webpack
configuration will be created, which will include platform-specific
DevServer
. - Each platform-specific
DevServer
will listen on randomly picked free-port. DevServerProxy
will handle the creation of said workers, as well as forwarding the requests based on?platform=<platform>
query param.- Additionally
DevServerProxy
has the same Dev endpoints asDevServer
(they both extendBaseDevServer
) and dedicatedPOST /symbolicate
endpoint.
- Uses
The overall architecture of DevServerProxy
is as follows:
`DevServerProxy`
├── <compiler worker platform=ios>
│ └── <webpack compilation>
│ └── `DevServerPlugin`
│ └── `DevServer`
├── <compiler worker platform=android>
│ └── <webpack compilation>
│ └── `DevServerPlugin`
│ └── `DevServer`
└── ...
Check parseCliOptions
section for details on configuration options that the DevServer
or DevServerProxy
will receive.
To support the common use-case, which is to run react-native-webpack-toolkit
using
React Native CLI, we need to be able to pass CLI options passed to the command (eg: when running
npx react-native webpack-start
) to the Webpack configuration. The problem is, that Webpack configuration
must be an object with all the required fields already filled in.
Based on that, the CLI options along with config object from React Native CLI is stored in a process.env
variable that parseCliOptions
then reads when evaluating Webpack configuration code.
However, this process.env
variable will not be set when running with Webpack CLI. To cover that case,
there's a fallback
property in configuration object for parseCliOptions
. If you run with Webpack CLI
all properties defined under fallback
will be used in place of CLI options from React Native CLI.
Additionally in both cases, some properties are optional and will default to values defined in DEFAULT_FALLBACK
constant.
To summarize the whole parseCliOptions
would perform the following actions:
- Merge
DEFAULT_FALLBACK
with providedfallback
values. - If CLI options in
process.env
are missing, return merged object from 1. - If CLI options are provided, and the command is
(webpack-)bundle
, return values based on CLI options (some fields might use values from merged object from 1.). - If CLI options are provided, and the command is
(webpack-)start
, return values from merged object from 1. anddevServer
configuration object based on the CLI options.
Please note that it's possible not to use parseCliOptions
at all and hard code all the necessary
values directly into Webpack configuration file or read it from somewhere else (eg: custom process.env
variables or a file).
Depending on how you run react-native-webpack-toolkit
the logging works slightly differently, but
the end destination for all logs is Reporter
instance — this is the place where all logs are
written to the terminal and/or file. The route that each log takes to get to the reporter instance
will differ.
The top-level Reporter
instance will also try to broadcast logs to the connected Flipper instance
under React Native -> Logs with tag rnwt_<type>
where type
can be debug
, info
, warn
or error
. Because of the Flipper tight integration with Metro all react-native-webpack-toolkit
logs will be reported as verbose
so make sure you sent the filter to include type Verbose
and use searching to filter logs e.g. by typing rnwt_debug
.
Bundling with (webpack-)bundle
command and Webpack CLI / Running with development server via Webpack CLI
Read as stack trace, from bottom to the top.
<terminal/file>
└── Reporter
└── LoggerPlugin
├── <webpack stats>
├── compilation.hooks.log
└── compiler.hooks.infrastructureLog
└── DevServerPlugin
└── DevServer
Read as stack trace, from bottom to the top.
<terminal>
└── Reporter
└── DevServerProxy
└── <compiler worker>
└── Reporter <file: if enabled> (format: json)
└── LoggerPlugin
├── <webpack stats>
├── compilation.hooks.log
└── compiler.hooks.infrastructureLog
└── DevServerPlugin
└── DevServer