When it comes to executing code,
eval() is a terrible idea. However, somewhere in your coding career, you will need to evaluate code.
And unfortunately, if there’s an error in the code, any line numbers are going to point to the invocation of
eval() and not the erroring line within the body itself. Lucky for us,
<script> tags correctly report erroring lines with line numbers.
Before we go any further, this is an obligatory don’t use eval. It should be an option of last resort. Your Content Security Policy is hopefully already preventing you from doing this.
The first attempt was to set
appendChild. If you are only concerned with modern non-microsoft browsers, you’d be done at this point.
innerHTML property is set. However, it uniquely supports the “text” property, which no other browsers seem to support. When set, scripts in IE will execute once appended to the DOM. A few changes to our above script, and we have a “safe” method. Borrowing from the idea of feature testing for things only IE supports, we’ll actually feature test against this text property, falling back to alternate versions as needed.
Further optimizations can be used to pre-select the best insertion method. In inject, we wrap the code we want to execute within a function declaration and assignment. This enables us to store the results of the
eval so that modules can then be executed on demand. The below example is just a simple JSON evaluator as a proof of concept. Like all things
eval, you should always be cautious with invoking it on items that are not 100% in your control.
While this code definitely makes it possible to do more harm than good (we’re stepping around JSLint/Hint eval checks), the upside is huge when you’re evaluating code and need to understand at what line something is failing on. In the case of a module loading system, having both the upsides of a lazy eval and the embedded script tag is a huge win.