Shift the offset during eval (using sourcemap)
Asked Answered
M

4

12

I'm loading a script from a file, and I'm using eval() to generate a Javascript code like this:

var code = fs.readFileSync('myfile');
var shiftedCode= 'function(param) {' + code + '}\n'+ '//# sourceURL=myfile';
eval(shiftedCode)

The problem is when I put a breakpoint or debugger inside the code, it stops two lines after the correct one because of the added chars at the beginning I suppose.

Is there a way to shift the sourceURL to the correct start point may be using sourcemaps?

Thank you in advance for your help.

Maloriemalory answered 5/7, 2017 at 13:21 Comment(5)
what if you use debugger removing the sourceUrl=myfile ? Does not open you file named like "VMXXX" with the code to debug ?Unrestrained
Add the script file as well.Aileneaileron
Couldnt you use vm.runThisContext("somechangedcode.js"); ?Ontine
check my answer @MaloriemaloryAiguille
I actually talk about it in my post: eloquentwebapp.com/webpack-missing-guide when I create the sourcemap. Basically, when you generate the source map you need to tell it which line is which.Smoothspoken
A
11

Defining the problem

I see that you're trying to import Javascript code from one page to another and you're facing some problems (You defined one and I will define another one):

  1. The sourcemaps/debugger problem:
    • First, I don't recommend building the sourcemap in the run time. Tools like Gulp, Grunt and Webpack are made to help you with those use cases and will let you focus on the business logic and keep you away from these kinds of problems.
    • Second Think about someone who will use this code in another page. Do you think that shifting the sourcemap would be fine? It would be the every time shift!
    • Possible solution: This lib also can help you with your use case. Generate new code first, then run it.

var offsetLines = require('offset-sourcemap-lines');
var conv = require('convert-source-map');
var fs = require('fs');
var code = fs.readFileSync('myfile');
var originalMap = conv.fromSource(code).toObject();
var codeBody = conv.removeComments(code);
var offsettedMap = offsetLines(originalMap, 1); // One line to be shifted
var newSourceMapComment = conv.fromObject(offsettedMap).toComment();
var shiftedCode= 'function(param) {\n' + codeBody + '}\n' + newSourceMapComment;
eval(shiftedCode)
  1. Be Careful! You're using the dangerous eval():
    • Using eval() can open a program up to several different injection attacks. The use of eval() in most contexts can be substituted for a better, alternative approach to a problem.
    • It results in slow code.
    • MDN: Don't use eval() needlessly!

      eval() is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval() with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage/extension. More importantly, third-party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways to which the similar Function is not susceptible.

      eval() is also generally slower than the alternatives, since it has to invoke the JS interpreter, while many other constructs are optimized by modern JS engines.

      There are safer (and faster!) alternatives to eval() for common use-cases.

Recommendations

As we agreed, you're trying to import some code. So, why don't you just use one of the modularity systems for Javascript like AMD, RequireJS, CommonJS, ES6 module feature,...

Assume you'll use ES6 modules, it would be very straight forward. You will need to export myfile script as a module and import it anywhere and that's it

//  myfile.js
export function sum (x, y) { return x + y }

//  someApp.js
import {sum} from "myfile"
console.log(sum(10, 20));
Aiguille answered 8/7, 2017 at 14:35 Comment(2)
if how its different from the other answer.. if you think answer is not explaining well enough, please edit it, rather than copy-pasting and modifying the answer as your own...Silkweed
Do u think it's not different? Really?! His answer cannot be considered an answer at all. It not working and not doesn't provide any quality. And who said that I should edit an answer with 10 lines to add 90 lines? You're indeed wrong, dudeAiguille
S
0

you can use below package offset-sourcemap-lines

var offsetLines = require('offset-sourcemap-lines');
var conv = require('convert-source-map');
var fs = require('fs');

var codeWithSourceMapComment = fs.readFileSync('/path/to/code-with-sourcemap-comment.js', 'utf-8');
var originalMap = conv.fromSource(codeWithSourceMapComment).toObject();

var header = 'function(param) {' + code + '}\n';
var offset = header.match(/\n/g).length + 2; //you might need to work on this

var offsettedMap = offsetLines(originalMap, offset);

var codeBody = conv.removeComments(codeWithSourceMapComment);
var newSourceMapComment = conv.fromObject(offsettedMap).toComment();
console.log(header + codeBody + '\n' + newSourceMapComment);
Silkweed answered 7/7, 2017 at 14:21 Comment(0)
A
0

What about that solution . instead of running the code with eval use Function constructor

myfile.js

var a = 123;
console.log(a, param1, param2);

loader.js

var code = fs.readFileSync('myfile.js');
var notShiftedCode = code + '\n//# sourceURL=myfile' 
var f = new Function('param1', 'param2', code2)

f(456,678)

I checked that on chrome devtool and it look very nit ( go into the function with F11)

Adrianeadrianna answered 14/7, 2017 at 12:8 Comment(2)
I really need to relay on another function inside eval or 'new Function'. Your solution works if you don't need to add any code before the dynamic code.Maloriemalory
i think it will be much more easy to help you if you bring good demo of myfile.jsAdrianeadrianna
M
0

I'm digging into source-map 'sections' property. From the specs, this could solve my problem by setting the starting offset: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt

But the main problem is that I can't find debug tools using this spec: seems widely implemented or not at all.

'offset-sourcemap-lines' is a valuable hack to solve the problem, but it can also offset dependent source-maps during merging for example.

Maloriemalory answered 14/7, 2017 at 12:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.