Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Metro source maps #1

Closed
wants to merge 11 commits into from
4 changes: 0 additions & 4 deletions expo/.expo-shared/assets.json

This file was deleted.

9 changes: 9 additions & 0 deletions expo/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
module.exports = function(api) {

// Log a stack trace so we can see where and how Babel is being called:
//
// * Called inside `metro-react-native-babel-transformer` when running `expo start`
// * Called inside `metro-babel-transformer` when running `node build-metro.js`
//
console.trace('resolving config')

api.cache(true);
return {
inputSourceMap: true, // NOTE: removing this line has no effect on the sourcemap file produced by Metro in `build-metro.js`
presets: ['babel-preset-expo'],
};
};
32 changes: 32 additions & 0 deletions expo/build-babel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// taken from: metro-babel-transformer
// https://github.com/facebook/metro/blob/main/packages/metro-babel-transformer/src/index.js

const { transformSync, parseSync, transformFromAstSync } = require("@babel/core");

// const HermesParser = require("hermes-parser");

// const { generateFunctionMap } = require("metro-source-map");


const fs = require('fs')

const INFILE = "target/index.js"
const OUTFILE = "target/babel-index.js"

const src = fs.readFileSync(INFILE, 'utf8')

const babelConfig = {
ast: true,
// code: false, // <-- set by metro-babel-transformer
filename: INFILE,
sourceType: "module",
inputSourceMap: true,
sourceMaps: true,
};

const sourceAst = parseSync(src, babelConfig);
const result = transformFromAstSync(sourceAst, src, babelConfig);

console.log(`writing ${OUTFILE}…`)
fs.writeFileSync(`${OUTFILE}`, result.code)
fs.writeFileSync(`${OUTFILE}.map`, JSON.stringify(result.map, null, 2))
26 changes: 26 additions & 0 deletions expo/build-metro.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Build an metro bundle file so we can debug sourcemaps.

const Metro = require('metro');
const fs = require('fs');

const BUILD_DIR = 'build'
const PLATFORM = 'ios'

fs.mkdirSync(BUILD_DIR, {recursive: true});

async function build() {
const config = await Metro.loadConfig();
config.resetCache = true

await Metro.runBuild(config, {
entry: 'target/index.js',
sourceMap: true,
platform: PLATFORM,
minify: true,
out: `${BUILD_DIR}/metro-${PLATFORM}.js`,
});

// TODO: see if Babel is generating source maps correctly inside metro-babel-transformer
}

build()
1 change: 1 addition & 0 deletions expo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"start-clear": "expo start --clear",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
Expand Down
40 changes: 40 additions & 0 deletions expo/remap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const fs = require('fs')
const remapping = require('@ampproject/remapping')
const {AnyMap} = require('@jridgewell/trace-mapping')
const {SourceMapConsumer} = require('source-map')

const read = f => fs.readFileSync(f,'utf8')
const write = (f,v) => fs.writeFileSync(f,v)
const writeJson = (f,v) => write(f,JSON.stringify(v))

// TARGET source map is:
// -> merged into METRO source map
// -> to produce the FIXED source map

// filenames
const targetFile = 'target/index.js.map'
const metroFile = 'build/metro-ios.map'
const fixedFile = 'build/metro-ios-fixed.map'

// source maps
const metroMap = read(metroFile)
const targetMap = AnyMap(read(targetFile)) // required: shadow-cljs "sections" need to be flattened

// determines how target file is identified in metro source map
const isTarget = file => file.endsWith('target/index.js')

// source map loader that returns the target map we wish to merge in
const loader = (file,ctx) => isTarget(file) ? targetMap : null

// produce a merged source map
const fixedMap = remapping(metroMap, loader)
writeJson(fixedFile, fixedMap)

// test source map
const consumer = new SourceMapConsumer(fixedMap)
const testPos = consumer.generatedPositionFor({
source: 'my_app/main.cljs',
line: 14,
column: 6,
})
console.log(testPos)
1 change: 1 addition & 0 deletions src/my_app/main.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
($ rn/View {:style #js {:flex 1
:alignItems "center"
:justifyContent "center"}}
(throw (js/Error. "my error thrown from my-app.main/root"))
($ rn/Text {:style #js {:fontSize 24 :color "blue"}}
"Hello from ClojureScript")))

Expand Down