Summary:
**Summary**
Metro crashed with "Allocation failed - JavaScript heap out of memory" when trying to build a project with a lot of assets. (Repro: https://github.com/fson/metro-out-of-memory, `yarn start` and open the app.)
By looking at a heap snapshot, I found out the reason was that `node-haste` was reading the contents of asset files and parsing them in search of the `providesModule` docblock field, although it should only do this for source files. I fixed this by checking that `isHaste()` evaluates to `true` before attempting to read the docblock. (`AssetModule` always returns `false` for `isHaste()`.)
**Test plan**
* Ran the [repro](https://github.com/fson/metro-out-of-memory) before the fix. It crashed with `FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory`
* Heap snapshot: <img width="1440" alt="screen shot 2018-01-03 at 17 31 53" src="https://user-images.githubusercontent.com/497214/34571809-33ee8dfc-f178-11e7-93f9-3fd80e62c188.png">
* After implementing the fix, ensured that the process didn't crash anymore and the heap didn't grow significantly during the build:
![screen shot 2018-01-04 at 17 39 26](https://user-images.githubusercontent.com/497214/34571848-622818aa-f178-11e7-9972-9f54146a83ee.png)
Closes https://github.com/facebook/metro/pull/112
Reviewed By: jeanlauliac
Differential Revision: D6660719
Pulled By: rafeca
fbshipit-source-id: d4d8d4445e75274c65f6a52027d878041f1c9a33
Summary:
As reported in https://github.com/facebook/metro/issues/109, the sourcemaps generated by metro are including the binary data of all the assets, which adds a lot of overhead and is not useful at all.
This commit removes the assets contents from the sourcemaps to fix https://github.com/facebook/metro/issues/109
Reviewed By: jeanlauliac
Differential Revision: D6649741
fbshipit-source-id: 8b09d429a1aa8d487557c22440bfa73ae55d03bd
Summary: Finally we can extract this function out, that remove any remaining dependency on the `TModule` generics and the like. Next steps are to push Metro-specific concepts out of the `resolveDependency` function and out of the module completely, after which the module will be ready to have its own unit tests, and be split into a `metro-resolve`.
Reviewed By: cpojer
Differential Revision: D6645333
fbshipit-source-id: a7915d646f888c29b410bf211f2e2bc4ec157676
Summary: This changeset alters the Haste resolution logic to be in sync with the new refactored pieces (resolveFile, etc.) Next steps involve extracting this function outside of the class so as to reduce the surface API and promote composability.
Reviewed By: cpojer
Differential Revision: D6645302
fbshipit-source-id: 6ee00fb52025cc0d332e57f837b46e8323faf6f4
Summary: In a further diff, I'll add cases where this error may be thrown at a higher level than the `resolveFileOrDir` function. So we need to move the handler and wrapping logic up the stack, that doesn't have any difference in practice.
Reviewed By: cpojer
Differential Revision: D6642475
fbshipit-source-id: 6b746386a170bfc167a9b50d9786fbb98c920c6d
Summary:
This is part of the efforts to clean up and extract the resolution logic. In this diff, the haste resolution is moved as part of the main resolution function rather than having 2 separate top-level functions. The reason for doing this is that logic is duplicated otherwise, making the already complex code harder to follow still. An example of duplicated logic is the call to `isRelativeImport`, that is done both in ResolutionRequest and ModuleResolution's node resolver. In that case, we never want to use Haste. Another duplication is the redirect of requires of package/haste names. With this changeset it is done in a single place at the beginning of the algo.
This changeset causes slight changes in behaviors. For example, consider `require('Foo/')`. A lookup of `Foo` would be done in the package `browser` field for a potential redirect. With this new code, we'll only look for `Foo/` in the redirect map. My opinion is that this is for the better, as this uniformize the way it works with Node.js `node_module` packages, making resolution more predictable. We should, additionally, actively strive to get rid of trailing slashes anywhere they might be in RN as they bring no apparent technical feature, but more confusion (I might be missing context, naturally).
Next steps will be to clean up `_resolveHasteDependency` completely, removing the callsite `try..catch` in favor of saner conditionals, and enforcing Haste packages to resolve if they exist (right now if a Haste package is found but corrupted, we just continue merrily trying to resolve the module with the rest of the logic; we should hash-crash instead, same as has been done for `resolvePackage`).
Reviewed By: cpojer
Differential Revision: D6642347
fbshipit-source-id: 2f40575b35916b644f342e0267c465a89bee202c
Summary: This improves the error message by providing line/column so we can identify errors encountered in https://github.com/facebook/metro/issues/65 easier. Also provide additional fields so we can better format that later on.
Reviewed By: cpojer
Differential Revision: D6641909
fbshipit-source-id: 0372da6b2fb51010b42ab906fc40b528b1483532
Summary:
The spec doesn't say the `browser` field should actually generate a replacement for the main *file*, just that it provides an alternative main: https://github.com/defunctzombie/package-browser-field-spec#alternate-main---basic
We also don't have any test covering this behavior. Any package relying on this behavior should be fixed to have a redirection of the main *file* in addition to their `main` *field*.
This is part of an effort to cleanup the way we do redirections. Eventually this will be part of the resolution module, not `Package.js`.
Reviewed By: davidaurelio
Differential Revision: D6611894
fbshipit-source-id: 0186aa23df2a9183d895ea02b5fd3b2b7339dc76
Summary: This is one of the first step towards a generic and composable resolution algorithm. We shall get rid of `TModule` as it's an abstraction that doesn't bring us any benefit in the resolution algo, and we actually want to get rid of `Module.js` eventually. This changeset gets rid of `TModule` up to the place where I already got rid of the exception-based control flow mechanism. Next steps are to push the boundaries higher up both for error handling, and for removing `TModule`.
Reviewed By: mjesun
Differential Revision: D6603157
fbshipit-source-id: 551e9ccd93628f45452148ed40a817bdde3740ea
Summary: I want to get rid of `TModule` and stuff so that we can eventually reunite this with `jest-resolve`. This is a continuation of the cleanup I started a long time ago.
Reviewed By: davidaurelio
Differential Revision: D6601657
fbshipit-source-id: 62c1806783323ee50e9a09146c73006c721eb891
Summary:
On D6248242, runBeforeMainModule was changed to `getModulesRunBeforeMainModule`, but the entry point used by opensource to build prod bundles was not updated. We couldn't catch this since we don't use this codepath internally
Fixes https://github.com/facebook/metro/issues/73
Reviewed By: mjesun
Differential Revision: D6556097
fbshipit-source-id: 889eaf825c7c3cdebe1ca4fc9831020a4a7d56dc
Summary:
Addresses a performance regression introduced by automatic linting: Compound assignment operators are much slower than keeping assignment separate on `let` bindings in certain versions of v8.
This reverts the relevant changes and configures eslint to *disallow* these operators explicitly in `metro-source-map`.
Reviewed By: mjesun
Differential Revision: D6520485
fbshipit-source-id: 16f35f5cd691ce6b1924480cbc30fbaa1275f730
Summary:
**Summary**
`createModuleIdFactory` is already used in `metro` internally, but is currently always a fixed function.
This enables `metro.runBuild()` to be run with a custom module ID factory.
One use case: building a base bundle, on top of which other application-specific bundles could reference modules in the base. The application-specific IDs need to not conflict with those in the base bundle, and all references to modules in the base must resolve to the correct ID in the base bundle. A custom ID factory can make all this possible.
**Test plan**
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. -->
Using `metro.runBuild(...)` with these changes, I was able to substitute in a custom ID factory
```javascript
const fs = require('fs')
const metro = require('metro')
const baseManifestFileContents = JSON.parse(fs.readFileSync('./baseManifest.json'))
// baseManifest looks like:
// { "modules": { ...
// "react/index.js": { "id": 12 },
// "react/cjs/react.production.min.js": { "id": 13 }, ... } }
const opts = {
dev: false,
entry: 'index.js',
out: './out.bundle',
platform: 'ios',
projectRoots: ['.', 'node_modules'],
config: {
createModuleIdFactory: createModuleIdFactory(baseManifestFileContents)
}
}
metro.runBuild(opts)
// Creates a sample custom ID factory
function createModuleIdFactory(manifestFileContents) {
return function createModuleIdFactory() {
const fileToIdMap = new Map()
let nextId = manifestFileContents ? getNextIdAfterBaseManifest(manifestFileContents) : 0
return path => {
const sourcePath = path
.replace(process.cwd() + '/node_modules/', '')
.replace(process.cwd(), '.')
// If module is in the base manifest, return its ID
if (manifestFileContents && manifestFileContents.modules[sourcePath]) {
return manifestFileContents.modules[sourcePath].id
}
// Otherwise, get it from the map or create a new ID
if (!fileToIdMap.has(path)) {
fileToIdMap.set(path, nextId)
nextId += 1
}
return fileToIdMap.get(path)
}
}
function getNextIdAfterBaseManifest(manifestFileContents) {
return Object.keys(manifestFileContents.modules).reduce((id, key) => {
if (manifestFileContents.modules[key].id > id) {
return manifestFileContents.modules[key].id
}
return id
}, 0) + 1
}
}
```
With the sample module ID factory above, the output looks like the following, where defined module IDs start at a higher number to avoid the base module IDs, but may depend on modules in the base bundle (lower numbers).
```javascript
...
__d(function(r,o,t,i,n){t.exports=r.ErrorUtils},551,[]);
__d(function(n,t,o,r,u){'use strict';var e,c=t(u[0]);e=c.now?function(){return c.now()}:function(){return Date.now()},o.exports=e},552,[553]);
...
__d(function(e,t,r,s,l){'use strict'; ...},564,[18,565,27]);
...
```
Closes https://github.com/facebook/metro/pull/100
Reviewed By: mjesun
Differential Revision: D6508351
Pulled By: rafeca
fbshipit-source-id: f2cfe5c373a6c83c8ae6c526435538633a7c9c2a
Summary:
With this, we do all the transformation and wrapping of files inside the workers, which mean faster initial builds (because parallelization and caching), and more legacy code that can be removed (see the following diff).
I've done some tests locally, and while the initial builds are slightly faster, the increase is not super substantial (the big win was in the diff were I moved the wrapping of JS files, in this diff only the assets transformation has speed up).
The most important thing that this diff enables is the possibility of doing the minification of modules also in the worker. This will mean that we can cache minified files and prod builds will get significantly faster - almost as fast as development builds (this will be relevant mainly for the opensource community).
Reviewed By: davidaurelio
Differential Revision: D6439144
fbshipit-source-id: ba2200569a668fcbe68dbfa2b3b60b3db6673326
Summary: This fixes https://github.com/facebook/metro/issues/99, which causes issues when metro tries to build files that are ignored by babel (if babel transformer ignores a file, it returns a null AST, which makes the collectDependencies logic break).
Reviewed By: mjesun
Differential Revision: D6466878
fbshipit-source-id: b5030e03775b982958a0b9204f4efccc8940ae4d
Summary: I'm working on getting CI to pass. As a first step, I'll upgrade the lerna setup to use Yarn's workspaces (when yarn is run from the Metro root) as well as upgrading Flow to the same version we use in xplat. I also copied over the Jest type definitions. This should fix all type errors for a start.
Reviewed By: davidaurelio
Differential Revision: D6361276
fbshipit-source-id: 4e8661b7d5fe4e3f6dd1e6923891bd2d23c9b4db
Summary:
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. The two fields below are mandatory. -->
**Summary**
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
It is currently not possible to resolve specific module imports (such as `react-native/Libraries/Image/AssetRegistry` using forward slashes as folder separators) using a custom mapping defined in `extraNodeModules` on Windows. This PR solves this issue by normalizing module names to use platform-specific folder separators before splitting the module name using `path.sep` as separators.
**Test plan**
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. -->
We use `extraNodeModules` to create a mapping between `react-native` and a forked and scoped version of react-native (i.e. `scope/react-native`). If we import a specific file from react-native (such as [`react-native/Libraries/Image/AssetRegistry`](https://github.com/facebook/react-native/blob/master/local-cli/core/Constants.js), which gets referenced when importing image assets), `ModuleResolution.js` is not able to extract the first folder name on Windows. This first folder name is the name of the module (`react-native` in the previous example) and is used to query `extraNodeModules` for possible matches. It is not able to find this folder name because the module name is split using `path.sep` as a separator, which is `'\\'` on Windows. Most module names use forward slashes as folder separators. The solution is to normalize `toModuleName` before we split on `path.sep`.
Closes https://github.com/facebook/metro-bundler/pull/89
Differential Revision: D6312391
Pulled By: jeanlauliac
fbshipit-source-id: 920c52633e8c9584ecb2bdd309dc4a8516c3199b
Summary:
Uglify@3.1.7 is causing some perf issues (more specifically, this commit: 5b4b07e9a7) that are impacting TTI on RN views and increased memory usage.
More specifically, code like:
```
function nonTrivialFn(pre) {
return pre + Math.random();
}
function hotFunctionCalledALotOfTimes(num) {
return nonTrivialFn(num + Math.random());
}
hotFunctionCalledALotOfTimes(3);
hotFunctionCalledALotOfTimes(5);
```
in v3.1.7 gets converted to:
```
function hotFunctionCalledALotOfTimes(num){
return function(pre) {
return pre + Math.random();
}(num + Math.random())
}
hotFunctionCalledALotOfTimes(3);
hotFunctionCalledALotOfTimes(5);
```
This causes a function creation each time `hotFunctionCalledALotOfTimes` is called.
By comparison, in v3.1.6, that previous code was converted to:
```
function nonTrivialFn(pre){
return pre + Math.random()
}
function hotFunctionCalledALotOfTimes(num){
return nonTrivialFn(num + Math.random())
}
hotFunctionCalledALotOfTimes(3);
hotFunctionCalledALotOfTimes(5);
```
Reviewed By: jeanlauliac, alexeylang
Differential Revision: D6296740
fbshipit-source-id: b3988d886e607103ec3ae6b9763b2f0411a8aa3c
Summary:
`metro-bundler` v0.21 contains a rewritten bundling mechanism, with simplified logic and much faster rebuild times, called delta bundler. This release contains a couple of breaking changes:
* Now, when using a custom transformer, the list of additional babel plugins to apply are passed to the `transform()` method. These are used in non-dev mode for optimization purposes (Check 367a5f5db8 (diff-40653f0c822ac59a5af13d5b4ab31d84) to see how to handle them from the transformer).
* Now, when using a custom transformer outputting `rawMappings`, the transformer does not need to call the `compactMappings` method before returning (check d74685fd1d (diff-40653f0c822ac59a5af13d5b4ab31d84) for more info).
* We've removed support for two config parameters: `postProcessModules` and `postProcessBundleSourcemap`.
Reviewed By: davidaurelio
Differential Revision: D6186035
fbshipit-source-id: 242c5c2a954c6b9b6f339d345f888eaa44704579
Summary:
**Summary**
Minification fails or minified bundle may crash due to uglify-es bugs which have been fixed recently. See https://github.com/facebook/react-native/issues/16689
**Test plan**
Try to production bundle a project using ex-navigation, which fails with:
```
Maximum call stack size exceeded
```
Use this patch and see that bundling suceeds. There are also minified runtime errors solved by this change, see https://github.com/facebook/react-native/issues/16689 for more information.
Closes https://github.com/facebook/metro-bundler/pull/85
Reviewed By: mjesun
Differential Revision: D6259177
Pulled By: rafeca
fbshipit-source-id: 55987eb338b06938181c0da74d104d23eeb135b6
Summary:
This diff migrates Metro Bundler from `worker-farm` to `jest-worker`:
* Fully removes the custom patched `worker-farm` fork.
* Removes //a lot// of non-clear Flow types used to cast functions from callbacks to promises.
* Reduces cyclomatic complexity of the `Transformer` class by using `async`/`await`.
* Cleans all additional methods inside `JSTransformer/index.js`, by moving them to a single class and properly scoping them.
**Note:** this diff does not still enable the ability to bind files to workers by using `computeWorkerKey`; this will come at a later stage.
Reviewed By: davidaurelio
Differential Revision: D6247532
fbshipit-source-id: 51259360a5c15117996777a3be74b73b583f595e
Summary: To determine whether segment boundaries are properly covered by async imports rather than requires, we need to get knowledge about it higher up in the stack. This changeset exposes which of the dependencies are async as an array of indices within the `dependencies` array (I'd prefer avoiding duplicating the strings because they could get inconsistent, and I don't want to have 2 separate arrays of names either because we'd have to modify a bunch of stuff across the stack to support that).
Reviewed By: davidaurelio
Differential Revision: D6220236
fbshipit-source-id: 1ee36bc7c59f7f27e089f7771a24c45c8bd57b5d
Summary: Having types in tests ensure that we're testing what the API is supposed to process and not something else. In that case, adding type revealed that we were mistakenly passing strings instead of `Buffer` objects to the transform and optimize functions, but it would still work because `toString` was called over it. Passing proper `Buffer` objects as expected ensures that it doesn't just work with strings, and that the integration of these files in the rest of the application works as expected. This changeset fixes these callsites and add a few invariants here and there. We use `invariant` instead of `expect()` because Flow understands only the former as a type refinement, even though `expect` would also be a form of possible refinement. I don't think it's a big deal.
Reviewed By: davidaurelio
Differential Revision: D6160019
fbshipit-source-id: cbcbb05d7bccf9e1b9f6bb3ea30b0bb2925aef1b
Summary: Here's a good example why Flow "exact types" are useful: there are a few place where we were adding unusused fields in the objects. As these fields end up in JSON files used to communicate with Buck, this can amount to a waste of resources. This changeset make the type exact and removes the unused fields.
Reviewed By: mjesun
Differential Revision: D6159350
fbshipit-source-id: 8cdf29d5729253f119778943ad961eacb8990c04
Summary: This is the last step remaining before enabling the `import()` syntax to use `require.async()` (for now that function is just doing a simple `require()` in behind).
Reviewed By: davidaurelio
Differential Revision: D6147030
fbshipit-source-id: 5cd8ee6cc550816ae3cdea0b457dc2419c99e7a7
Summary:
After checking more deeply, there were still situations where the delta bundler could generate different bundles between runs: when a module is required by two different modules (it has two or more inverse dependencies), that module would not always be inserted after the first inverse dependency in the bundle, which would cause some bundling order discrepancies.
In order to fix that, the bundler now re-traverses synchronously the dependency graph using a DFS traversing algorithm to guarantee the same order. This will add some small runtime overhead (specially when generating the initial bundle), but it's not worrying (from benchmarks in my macbook pro it'll add ~10ms of initial build for every 1000 modules traversed, being this overhead linear).
Reviewed By: mjesun
Differential Revision: D6124993
fbshipit-source-id: 9bc7cb329f01a7860c7d3b52c3376c643ea5cf3b
Summary:
The `formatBanner.js` file is requiring the `wordwrap` package, but it was not defined in the package.json. Somehow this was working before (maybe the package was being downloaded by another depdendency or maybe `formatBanner` was not used).
This fixes https://github.com/facebook/metro-bundler/issues/79
Reviewed By: mjesun
Differential Revision: D6136865
fbshipit-source-id: 722dd61cb936fca893453f4cfc3248718a329779
Summary: This diff fixes https://github.com/facebook/metro-bundler/issues/78 by adding the `runBeforeMainModule` server parameter to the bundler. This is not the cleanest solution, but will be fixed once we use the Delta Bundler for builds from the CLI
Reviewed By: davidaurelio
Differential Revision: D6074469
fbshipit-source-id: 068926ef671d9f897ad9f1bd0540036a97340c00
Summary:
Adds module size as `fb_`-prefixed node attributes to the digraph output of dependencies.
The list of edges is now followed by a list of node declarations, that use the `fb_size` attribute to expose the module size in bytes.
E.g:
```
digraph {
"a" -> "b";
"b" -> "c";
"a"[fb_size=123];
"b"[fb_size=456];
"c"[fb_size=789];
}
```
Reviewed By: fkgozali
Differential Revision: D6064861
fbshipit-source-id: 73127e08c5e38075b5112053de12f9abac1102ee
Summary:
Resolves https://github.com/facebook/metro-bundler/issues/27
**Summary**
There is an edge case where tools like react-primitives need to assign to `Platform.OS`,
but the inline transformation results in an invalid AST.
When Platform.OS is unconditionally inlined, the following scenario:
````
Platform.OS = 'ios';
````
Is transformed to:
```
"ios"="ios"
````
And results in error `Property left of AssignmentExpression expected node to be of a type ["LVal"] but instead got "StringLiteral"**`.
See issue in react-primitives: https://github.com/lelandrichardson/react-primitives/issues/79
This patch checks whether the current node is on the left hand side of an AssignmentExpression
and skips the inlining when this is the case.
It also does the same for `process.env.NODE_ENV`, which suffers from the same problem. See related closed issue https://github.com/facebook/react-native/issues/7607#issuecomment-221425153 which was resolved by using bracket notation `process.env["NODE_ENV"]` instead.
**Test plan**
Unit tests included.
**Notes**
This is my first contribution to Metro, and haven't worked with Babel AST a lot, so constructive feedback on the implementation is welcome.
Closes https://github.com/facebook/metro-bundler/pull/45
Reviewed By: cpojer
Differential Revision: D5974615
Pulled By: mjesun
fbshipit-source-id: 224e63cef24f450b33e17ff9c0e0c0cea46bc70e
Summary:
In order to aid with debugging inline requires we add a method that
will give us the modules.
**Summary**
I was looking for a way to see what modules had been loaded when I was working with inline requires. I had tried using beginEvent on Systrace, but I was worried that there were modules that I might have missed (I'm not certain if all the loaded files are polyfills before the entryFile is invoked for instance). By adding getModules() it simplifies seeing what modules are loaded.
**Test plan**
At the root of my app `index.ios.js`:
```
import App from './App';
import { AppRegistry } from 'react-native';
AppRegistry.registerComponent('App', () => App);
// after 3 seconds the initial app data should have loaded, so lets take a look:
setTimeout(() => {
console.log(require.getModules());
}, 3000);
```
**NOTE**
If there is a way to get to this easily (via the debugger or some other mechanism) I would be happy to use that instead and add documentation for it.
Closes https://github.com/facebook/metro-bundler/pull/37
Differential Revision: D6008180
Pulled By: cpojer
fbshipit-source-id: 850103bbce166bf65a0cbd710582198c66273db5
Summary:
**Summary**
This is the workaround that cpojer suggested in #65 and should resolve the biggest pain point that developers are experiencing in that issue: using moment.js in React Native. Hopefully this at least serves as a starting point to reaching a decent solution for libraries using non-static `require()` statements.
**Test plan**
- Expected error when non-static-argument-based `require()` is nested more than one level deep within a `try` statement
- Expected no error when non-static-argument-based `require()` is nested directly within a `try` statement
```bash
ip-192-168-1-10:trueflipapp richard$ react-native bundle --entry-file index.js --platform ios --bundle-output /tmp/test.js --reset-cache
Scanning folders for symlinks in /repo/trueflip/sandbox/code/trueflipapp/node_modules (8ms)
Scanning folders for symlinks in /repo/trueflip/sandbox/code/trueflipapp/node_modules (8ms)
Loading dependency graph, done.
warning: the transform cache was reset.
bundle: start
bundle: finish
bundle: Writing bundle output to: /tmp/test.js
bundle: Done writing bundle output
```
Closes https://github.com/facebook/metro-bundler/pull/69
Differential Revision: D6008567
Pulled By: cpojer
fbshipit-source-id: f9be328cf50dc47c7433ffeb5eb053b398c92122
Summary:
Hi,
**Summary**
This fixes#40 where bundler cannot resolve a file starting with `.` from the root package directory.
it just adds a check to see if the absolute path filename is the same as the localpath filename then lets it through.
**Test plan**
- Steps to reproduce have been written up in #40
Thanks!
Closes https://github.com/facebook/metro-bundler/pull/54
Reviewed By: cpojer
Differential Revision: D5974618
Pulled By: mjesun
fbshipit-source-id: 4b7113c3bed20f2c908739881d61410d651e6ed7
Summary:
Whitelist node opt `--max-old-space-size` for JSTransformer.
Bundling can choke on the default node memory settings for those of us generating large index.js files. This change allows supplied node options to make it through to the node processes spawned by the JSTransformer worker farm.
Closes https://github.com/facebook/metro-bundler/pull/70
Differential Revision: D6008141
Pulled By: cpojer
fbshipit-source-id: 1ef3b436ea30baf3f255a4fd718fe4d958d70c65
Summary:
Addresses https://github.com/facebook/metro-bundler/issues/62
Apparently with some versions of `jest-haste-map`, the nested source file returns the module wrapped with `default` instead of the exports themselves (due to some ES6 babel transform, I am guessing). I wasn't able to reproduce this myself yet, but I think a good first step is to avoid using nested library files in the first place, ie. only use what's exported at the top-level.
Reviewed By: rafeca
Differential Revision: D5890757
fbshipit-source-id: 1196264b5626eda65c4aae222db2a1620f901c55
Summary: Upgrades uglify to version 3 with (experimental) ES6 support turned on.
Reviewed By: jeanlauliac
Differential Revision: D5842410
fbshipit-source-id: 1c8ccea15785bc5bb1c68d7a83b75881432d0ce2
Summary:
This replaces `async/queue` with a hand-rolled queue that does not yield to the event loop if a unit of work can be run synchronously.
Anecdotally, this leads to a > 11x speedup for the graph traversal when all data is available synchronously, e.g. from an in-memory cache.
Reviewed By: jeanlauliac
Differential Revision: D5861763
fbshipit-source-id: f7cf5f916a13adf9ca418d7522cd2f19df596fba
Summary: Changes `GraphFn` to return a promise rather than taking a callback. This is more in line with call sites, which so far have been using `denodeify`.
Reviewed By: jeanlauliac
Differential Revision: D5857192
fbshipit-source-id: 61bbbef4fbf24b0b91c4a3008541eaa5a1af0f7a
Summary:
Changes `LoadFn` to be synchronous or return a promise, and `ResolveFn` to be synchronsous.
This makes for a nicer API, without losing the property of not yielding to the event loop for synchronous work.
Reviewed By: jeanlauliac
Differential Revision: D5855963
fbshipit-source-id: 4b3c3363f4e49a9890586462925e8e400872feb2
Summary: When running with node 8, the babel plugins `async-to-generator` and `syntax-trailing-function-commas` are unnecessary. Removing them makes runtime transpilation faster, and the resulting code is closer to the original (useful with debugging: less unmapped code areas, better breakpoint support, less renamed variables).
Reviewed By: mjesun
Differential Revision: D5842305
fbshipit-source-id: d99f719794e4a8f48fd10b0349fbb36f2994666e
Summary:
This copies the basic loading mechanism and default config from the RN local cli into Metro and exposes it under `metro-bundler`, and switches internal scripts over to it.
davidaurelio: I changed the packager-worker-for-buck to hardcode the rn.cli file, like we do in other files. I would like to pull the "find" mechanism that traverses up to find a config into Metro at some point, but for now I'd prefer to keep it lean until we need it. Let me know if that doesn't work for you.
The next diff will switch the RN cli over to these functions also.
Reviewed By: davidaurelio
Differential Revision: D5832596
fbshipit-source-id: a3e167644d96c8831e5a83378e8ba143e62426db
Summary: As a first step in defining a new public API and CLI for Metro, I'd like to pull the generally useful pieces from the RN cli into Metro. This diff makes it as a non-breaking change (so we don't have to bump the version of Metro for RN) by updating only the imports outside of the react-native-github folder.
Reviewed By: davidaurelio
Differential Revision: D5832464
fbshipit-source-id: 11b00b5517665441763c2207d577ae0e110c681b
Summary: Fixed the UNBUNDLE magic file location to match what JniJSModulesUnbundle.cpp expects.
Reviewed By: sahrens
Differential Revision: D5821637
fbshipit-source-id: 4342e4bb4d139b4eba77dd92a53b1683041fc7e9
Summary:
This diff renames all the stragglers in comments and strings from variations of "packager" to "Metro Bundler". I did one of three:
* Rename "packager" to "Metro Bundler"
* Rename "react-native-packager" to "Metro Bundler"
* Remove "packager" when code inside of Metro implies that it's about Metro
I also removed `Glossary.md` because it is unmaintained and very old. mjesun is currently starting to write documentation for Metro which will supersede whatever was there before.
Reviewed By: mjesun
Differential Revision: D5802993
fbshipit-source-id: ba99cb5ed04d84b0f7b7a8a0bf28ed99280a940a
Summary: When starting to use `metro-bundler` as a standalone server, I found quite complicated the fact that it needs a transformer by default. Moreover, the transformer is not passed as a reference to a JS object, but as a path to a required file. I removed the need to be required, and defaulted to a dummy, basic transform, that does nothing by default. This avoids having to create an extra file and linking to it (potentially needing to involve `path` and other extra modules).
Reviewed By: cpojer
Differential Revision: D5622906
fbshipit-source-id: 0c2b1bec86fa542b3c05de42c89d4b5bb4384b34
Summary:
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. The two fields below are mandatory. -->
**Summary**
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
I am sending this PR to fix an error in TransformCaching module. See this issue [TransformCaching module try to collect cache every time I build bundle #46](https://github.com/facebook/metro-bundler/issues/46).
**Test plan**
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. -->
```
/**
* When restarting packager we want to avoid running the collection over
* again, so we store the last collection time in a file and we check that
* first.
*/
_collectCacheIfOldSync() {
const {_rootPath} = this;
const cacheCollectionFilePath = path.join(_rootPath, 'last_collected');
const lastCollected = Number.parseInt(
tryReadFileSync(cacheCollectionFilePath) || '',
10,
);
if (
Number.isInteger(lastCollected) &&
Date.now() - lastCollected < GARBAGE_COLLECTION_PERIOD
) {
return;
}
const effectiveCacheDirPath = path.join(_rootPath, CACHE_SUB_DIR);
mkdirp.sync(effectiveCacheDirPath);
collectCacheSync(effectiveCacheDirPath);
fs.writeFileSync(cacheCollectionFilePath, Date.now().toString());
}
```
Steps:
1. Create a new react-native project.
2. Put your breakpoint at this sentence `collectCacheSync(effectiveCacheDirPath);`.
3. Bundle the project, program will break at `collectCacheSync(effectiveCacheDirPath);`
4. Resume the program, finish the first time bundle.
5. Bundle again, this time program won't break.
Closes https://github.com/facebook/metro-bundler/pull/48
Differential Revision: D5726161
Pulled By: jeanlauliac
fbshipit-source-id: 0865f1bf25d6eb36f067ac3dc7764df9fd5026dc
Summary:
The HMR logic used to try to calculate the dependencies of every new added (or modified) file, including assets. This resulted in a TransformError.
This commit adds a check that stops the HMR bundling once it finds out that the updated file is an asset
Reviewed By: cpojer
Differential Revision: D5697391
fbshipit-source-id: faf7ccad76ac4922b70ed1c7ce8ce32b03c4e8ee
Summary: We were not using the timeout at all, so we decided to remove it. Also, the current value is pretty high, so it should never fail unless there's something really bad.
Reviewed By: jeanlauliac
Differential Revision: D5640839
fbshipit-source-id: 3eaa567a6828902376fe5df9fe3f4e96b83a23bd
Summary:
We'll revert when the root problem is fixed, that should mitigate for now.
What might be the root problem, I believe, is that when there are some cached files already on the machine, we immediately try to build all the dependencies, but the worker farm is queuing these and it takes a long time to finish. The timeout should include only the transformation time, not the queuing. I'll fix that separately.
Reviewed By: mjesun
Differential Revision: D5650380
fbshipit-source-id: f4b045876cc822caee3998f69ca98ea986709bf4
Summary: It might be that Metro bundler is getting used directly with the `http` module and not within an express app. If that's the case, the `next` method will not exist, so we have to guard against it.
Reviewed By: davidaurelio
Differential Revision: D5639944
fbshipit-source-id: bcee4a70f6a7b643218b11af0d8aedbc7762eead
Summary: This is the last piece of work to make all the clients do a single request for both HMR/non-HMR modes. I'm not completely sure how this URL is used by the client, but it does not need the `hot` param.
Reviewed By: davidaurelio
Differential Revision: D5639946
fbshipit-source-id: a76f9ba7b9ace625352a156761d3ee2809f80c92
Summary:
This diff enables the HMR transforms for any bundle requested through the metro-bundler HTTP server, so it ignores the `hot` parameter passed in the URL.
This allows much faster switches when enabling/disabling HMR, since metro-bundler does not need to re-compile each single file again, while not impacting substantially build times when HMR is off.
I've done some lightweight benchmarks on my machine and these are the results (all the tests have been done after running metro-bundler with a clean cache and restarting the app).
**Before**
Time to build (HMR off): 1x (baseline)
Time to build (HMR on): 1.90x
**This diff**
Time to build (HMR off): 1.009x
Time to build (HMR on): 1.036x
(The reason why now it takes double the time to load the HMR bundle than the non-HMR bundle after launching the app is because the device after a restart always asks for the non-HMR bundle and afterwards the HMR bundle, causing the server to have to build both bundles).
**Bundle size**
In terms of bundle size, adding the HMR transforms increases the size by around 3-4% (this regression is due to the wrappers added around React components, and will depend on the app).
**Next steps**
There are two improvements to do after this diff:
1. Remove the `hot=true` parameter from the clients when they request the bundle. This will reduce by half the memory used by metro-bundler when switching from non-HMR to HMR (or when opening the app with HMR enabled), since metro-bundler caches the bundles based on url.
2. After this diff, the `hot` parameter in the various options objects will not make much sense, so my suggestion is to just remove it from everywhere and instead of checking for that parameter in the transformer, check for `dev=true` there.
Reviewed By: davidaurelio
Differential Revision: D5623623
fbshipit-source-id: cb76b9182e55f442e2987fcf59eee2ba2571578e
Summary: now that `ResolutionRequest.resolveDependency` is synchronous, we can also make `ResolveFn` synchronous.
Reviewed By: fkgozali
Differential Revision: D5528094
fbshipit-source-id: 0b40df29024b809a99b7e577716b24e9fa499578
Summary: Adds filtering to the assets written from a Buck build, so that we don’t write all assets present in libs, but rather only the ones included in the bundle.
Reviewed By: cpojer
Differential Revision: D5522844
fbshipit-source-id: fcca3567b726dfab1ecf9560932fd6e1a174b31f
Summary: makes flow typing for the entry point more sound and fixes two issues
Reviewed By: BYK
Differential Revision: D5507650
fbshipit-source-id: 6b03f7de792ffcece4d0d61950e136a61ea7db2e
Summary: Format everything, one subdir at a time.
Reviewed By: mjesun
Differential Revision: D5481590
fbshipit-source-id: 6d9157e6857d61b8116bcf9285bd4be415c5ba01
Summary:
By default, when Babel transforms a file, it looks for .babelrc in the file's directory and all parent directories until it finds a .babelrc file. This means that when Metro tries to transform `<PROJECT_ROOT>/node_modules/dep/mod.js`, it searches for `<PROJECT_ROOT>/node_modules/dep/.babelrc`. If that .babelrc actually exists, Babel will try to apply it.
In practice, this often causes problems because packages that include .babelrc often do so unintentionally -- they don't intend for the package consumer to look at that .babelrc file. One thing we've done a lot is `rm` all .babelrc files under node_modules -- this commit effectively achieves the same in a less destructive way by telling Babel not to look up .babelrc files. (To clarify, Metro will still apply the .babelrc file in the project root.)
Since the current behavior is to look at .babelrc files, this commit keeps that behavior for now. We'll consider overriding the default behavior (that is, making Babel not lookup .babelrc files) in the default configuration of Expo/RN projects. If this goes well and we empirically find that people are having a better time, we may want to consider flipping this option's default in Metro, so that Metro tells Babel not to look up .babelrc files by default.
Closes https://github.com/facebook/metro-bundler/pull/31
Differential Revision: D5469620
Pulled By: jeanlauliac
fbshipit-source-id: fe7a1042feafff843e1a6d8cc9487eb6ff8e8358
Summary:
The main goal of this is to be able to show bundle download progress in a follow up PR for react-native.
**Test plan**
Tested that it is possible to show bundle download progress in react-native using this header and added unit test.
Closes https://github.com/facebook/metro-bundler/pull/28
Reviewed By: davidaurelio
Differential Revision: D5443344
Pulled By: jeanlauliac
fbshipit-source-id: 63fd655c964d7df526125fbe55eb9c7cccd7dba9
Summary:
Adding a Babel plugin that will analyze the file looking for any potential candidate to use `regenerator-runtime`, and if so, will inject dynamically the module. The module is injected per file, so we avoid polluting the global environment. The plugin is also able to inject the `require` call beforehand, so that the inliner can pick them and inline them.
The Babel plugin is part of `react-native-babel-preset`, so as long as you are using this preset you are safe. If not, you should include the specific transformer into your list of plugins, as `react-native-babel-preset/transforms/transform-regenerator-runtime-insertion.js`.
Reviewed By: davidaurelio
Differential Revision: D5388655
fbshipit-source-id: dc403f3d5e2d807529eb8569a85c45fec36a6a3e