Comments (3)
This is not really about inlining source maps, which are orthogonal to the issue here. Hermes can consume a source map, if it is given one, but this is almost never done by the existing tools, and even if it was, it does not affect the size of the generated bytecode file, it just affects the source locations.
This is something else entirely. Hermes bytecode by default always contains line number information, because that is required to generate proper stack traces.
If we take this source, for example:
function foo() {
throw Error("Noo!");
}
function bar() {
foo();
}
bar();
We can compile it to bytecode:
$ hermesc -emit-binary prog.js -out prog.hbc
$ ls -l prog.hbc
-rw-r--r-- 1 tmikov staff 520 Jun 3 11:50 prog.hbc
And then run it:
$ hermes prog.hbc
Uncaught Error: Noo!
at foo (prog.js:2:16)
at bar (prog.js:5:8)
at global (prog.js:7:4)
As you can see, we get a nice stack trace. This is not debug information, this is just expected functionality provided by all JS engines.
Optionally, it is possible to strip this line number information in order to get an even smaller binary. The --output-source-map
CLI flag forces Hermes to save the line numbers information in a separate source map file:
$ hermesc -emit-binary prog.js -out prog.hbc --output-source-map
$ ls -l prog.*
-rw-r--r-- 1 tmikov staff 376 Jun 3 11:49 prog.hbc
-rw-r--r-- 1 tmikov staff 173 Jun 3 11:49 prog.hbc.map
-rw-r--r-- 1 tmikov staff 81 Jun 3 11:42 prog.js
Note that prog.hbc
decreased from 520 bytes to 376 bytes. However if we run it now, we don't get a nice stack trace:
$ hermes prog.hbc
Uncaught Error: Noo!
at foo (address at prog.hbc:1:63)
at bar (address at prog.hbc:1:79)
at global (address at prog.hbc:1:43)
The "columns" in the above stack trace are actually bytecode offsets. The engine no longer has access to the line numbers, so all it can do is dump numbers.
You can still get to the original lines, but you need to use the generated source map. For example:
$ npm install sourcemap-lookup
$ node ./node_modules/sourcemap-lookup/index.js prog.hbc:1:79
Original Position:
prog.js, Line 5:7
Code Section:
1 | function foo() {
2 | throw Error("Noo!");
3 | }
4 | function bar() {
5>| foo();
^
6 | }
7 | bar();
8 |
So, it is up to the integrator whether to remove the line numbers and use the generated source map for symbolication of stack traces.
from expo.
@iway1 I opened a PR so if you can see how I approached this. Feel free to try in your own project and report back if error handling was still reasonable in production.
from expo.
Can confirm this behavior. Will add my findings here.
- The terminal logging is not an error, the output is larger.
- With
--no-bytecode
enabled, both JS files are the same size. This means the issue is either with the pipeline or the HBC command. I suspect that the hbc command automatically inlines source maps when source maps aren't explicitly enabled. Skipping source maps is an optimization we added to Expo CLI to reduce unused work, but it might not be worth it. - I checked the HBC command help output to see if it indicated this behavior:
EXPO_DEBUG=1 npx expo export
prints the hbc command we use./Users/path/to/expo/node_modules/react-native/sdks/hermesc/osx-bin/hermesc -help
doesn't show anything about inlining source maps. Leading me to believe it may still be a hidden default.
- When I decompile the hbc for both larger and smaller bundles, they both come out to be the same size! This could be the result of comments (inline source maps) getting removed on decompilation.
- There's no plain-text comment at the end of the bin file so it's hard to confirm my theory, perhaps executing in an engine and throwing an error could show more results.
- When I disassemble the HBC it appears that the bundles are different. I see a number of lines like
[Debug offsets: source_locs=0xb46d5, scope_desc_data=0x0]
. - The maps don't appear to be added as an inline comment when source maps are disabled, so it's unclear to me where the extra data is coming from tbh.
- Tagging @tmikov since he would likely know exactly what's happening here.
It doesn't appear to be related to inline source maps. When source maps aren't enabled, we skip all the extra work and don't pass any source map-related info to the HBC command. If the bundle is larger, it's seemingly coming from the hermesc
command and not from Expo CLI.
I'm considering just always enabling source maps and throwing away the results as a hack to work around the size increase. Here's my findings:
- Is it much slower to always enable source maps? Let's profile just the hermes command with source maps provided:
- Source maps enabled: ~1.2s
- Source maps disabled: ~815ms
- Baseline bundle (
--no-bytecode
, no source maps, full cache) is about 1.9s, so this 1.2s is a notable increase overall. We should avoid needlessly generating code and not using it. I'd lean toward figuring out what's going on in the HBC command.
- Will wait to hear from the Hermes team before continuing. It's likely meaningful data that's being added to the bundle and I'm not super interested in solving bugs related to HBC being broken without the upstream-intended debug data.
Was pondering the [Debug offsets...
lines, and figured I'd check the HBC output again. I was a little confused by this part:
Choose optimization level:
-O0 - No optimizations
-Og - Optimizations suitable for debugging
-O - Expensive optimizations
Because we use -O
, and not -Og
, I figured debugging wasn't enabled. This was not the case. Adding -g0
made the bundles just as small as when source maps are enabled!
So it seems like when source maps are skipped, debug info is injected by Hermes to compensate. I'd still like to understand how these debug traces are used before choosing to enable/disable them in Expo CLI (I'd like to avoid adding extra options to the CLI).
from expo.
Related Issues (20)
- Undocumented behavioral difference with flex HOT 2
- preview failing HOT 1
- How to use TaskManager with File-base routing. HOT 1
- TaskManager not working on iOS HOT 2
- TaskManager not compatible with expo-router HOT 3
- @expo/fingerprint fails to source Expo Config that uses ts-node/register HOT 2
- [docs] Expo AV - Audio PlaybackStatusUpdate error HOT 1
- autolinking exclude is not working properly and addin unnecessary permissions in android manifest HOT 1
- "Cannot read property 'blobId' of undefined" - Dev vs Production builds HOT 1
- Modal presentation not working? HOT 1
- How to handle maven repositories HOT 1
- Local Expo CLI: Can't set webpack port anymore (webOnly setting) HOT 1
- TaskManager does not work on iOS HOT 4
- shared element transitions dont seem to work on dev builds after expo 49
- Cannot customize the web port
- WebBrowser.dismissAuthSession is not available on android [docs]
- Expo Camera barcode scanner not working on WEB (Chrome)
- Environment Variables Not Loading During Production Build HOT 1
- Could not resolve com.facebook.react:react-native-gradle-plugin
- Inconsistent RefreshControl between Expo Go and dev build
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from expo.