Skip to content

Commit a6f2bdc

Browse files
robhoganfacebook-github-bot
authored andcommitted
runBuild: Support specifying bundleOut/sourceMapOut
Summary: Currently Metro's `runBuild` allows saving bundle and source maps to disk via a single `out` argument, which always appends a `.js` extension for bundles (unless `out` already ends with `.js`) and `.map` for source maps. This means it can't currently be used to implement React Native CLI's `bundle` command, because RN uses `.jsbundle` extension by convention (eg, [here](https://github.com/facebook/react-native/blob/5d7f35cd7c912333987ca82774734dba3bd48716/packages/react-native/scripts/react-native-xcode.sh#L108). This is an additive API change to allow `bundleOut` and `sourceMapOut` to specify full paths. This also allows us to fix the `react-native/core-cli-utils` todo [here](https://github.com/facebook/react-native/blob/5d7f35cd7c912333987ca82774734dba3bd48716/packages/core-cli-utils/src/private/app.js#L133). ``` - **[Feature]** `runBuild`: Add optional `bundleOut` and `sourceMapOut` arguments to exactly specify output paths. ``` Reviewed By: huntie Differential Revision: D74397776 fbshipit-source-id: a2cbe5df1a553447d60d6cca5138d318be78dc1f
1 parent 416c1ef commit a6f2bdc

3 files changed

Lines changed: 45 additions & 4 deletions

File tree

docs/GettingStarted.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,17 @@ Given a configuration and a set of options that you would typically pass to a se
129129
<!-- TODO(ives): Decide whether we need to show this to the user * `output (boolean)` -->
130130

131131
* `assets (boolean)`: Whether to include the assets in the result.
132+
* `bundleOut (string)`: Path to save the bundle. No extension will be added.
132133
* `dev (boolean)`: Create a development version of the build (`process.env.NODE_ENV = 'development'`).
133134
* `entry (string)`: Pointing to the entry file to bundle.
134135
* `onBegin (Function)`: Called when the bundling starts.
135136
* `onComplete (Function)`: Called when the bundling finishes.
136137
* `onProgress (Function)`: Called during the bundle, every time there's new information available about the module count/progress.
137138
* `minify (boolean)`: Whether Metro should minify the bundle.
138-
* `out (string)`: Path to the output bundle.
139+
* `out (string)`: Shorthand path to the output bundle and source map. A `.js` extension will be added (if not given) for the bundle and `.map` for the source map. Customize with `bundleOut` / `sourceMapOut`.
139140
* `platform ('web' | 'android' | 'ios')`: Which platform to bundle for if a list of platforms is provided.
140141
* `sourceMap (boolean)`: Whether Metro should generate source maps.
142+
* `sourceMapOut (string)`: Where to save the source map, if `sourceMap == true`. No extension will be added.
141143
* `sourceMapUrl (string)`: URL where the source map can be found. It defaults to the same same URL as the bundle, but changing the extension from `.bundle` to `.map`. When `inlineSourceMap` is `true`, this property has no effect.
142144

143145
```js

packages/metro/src/index.flow.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const {
5050
} = require('metro-config');
5151
const {Terminal} = require('metro-core');
5252
const net = require('net');
53+
const nullthrows = require('nullthrows');
5354
const {parse} = require('url');
5455

5556
type MetroMiddleWare = {
@@ -97,6 +98,8 @@ export type RunBuildOptions = {
9798
assets?: boolean,
9899
dev?: boolean,
99100
out?: string,
101+
bundleOut?: string,
102+
sourceMapOut?: string,
100103
onBegin?: () => void,
101104
onComplete?: () => void,
102105
onProgress?: (transformedFileCount: number, totalFileCount: number) => void,
@@ -394,6 +397,8 @@ exports.runBuild = async (
394397
minify = true,
395398
output = outputBundle,
396399
out,
400+
bundleOut,
401+
sourceMapOut,
397402
platform = 'web',
398403
sourceMap = false,
399404
sourceMapUrl,
@@ -437,10 +442,14 @@ exports.runBuild = async (
437442
onComplete();
438443
}
439444

440-
if (out) {
441-
const bundleOutput = out.replace(/(\.js)?$/, '.js');
445+
if (out || bundleOut) {
446+
const bundleOutput =
447+
bundleOut ?? nullthrows(out).replace(/(\.js)?$/, '.js');
448+
442449
const sourcemapOutput =
443-
sourceMap === false ? undefined : out.replace(/(\.js)?$/, '.map');
450+
sourceMap === false
451+
? undefined
452+
: sourceMapOut ?? out?.replace(/(\.js)?$/, '.map');
444453

445454
const outputOptions: OutputOptions = {
446455
bundleOutput,

packages/metro/src/integration_tests/__tests__/build-test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,36 @@ test('build a simple bundle with assets', async () => {
9090
]);
9191
});
9292

93+
test('allows specifying paths to save bundle and maps', async () => {
94+
const config = await Metro.loadConfig({
95+
config: require.resolve('../metro.config.js'),
96+
});
97+
const mockSave = jest.fn();
98+
99+
await Metro.runBuild(config, {
100+
entry: 'TestBundle.js',
101+
output: {
102+
...require('../../shared/output/bundle'),
103+
save: mockSave,
104+
},
105+
sourceMapOut: 'TestBundle.custommap',
106+
sourceMap: true,
107+
bundleOut: 'TestBundle.jsbundle',
108+
});
109+
110+
expect(mockSave).toBeCalledWith(
111+
{
112+
code: expect.any(String),
113+
map: expect.any(String),
114+
},
115+
expect.objectContaining({
116+
bundleOutput: 'TestBundle.jsbundle',
117+
sourcemapOutput: 'TestBundle.custommap',
118+
}),
119+
expect.any(Function),
120+
);
121+
});
122+
93123
test('(unstable) allows specifying a transform profile', async () => {
94124
const config = await Metro.loadConfig({
95125
config: require.resolve('../metro.config.js'),

0 commit comments

Comments
 (0)