How can I configure jQuery to ensure external scripts (src="...") remain external when injecting markup using .html()?

150 Views Asked by At

I've observed that when I utilize jQuery's .html('...') method to insert markup containing an external <script src="..."></script> tag, jQuery doesn't insert the script tag directly into the DOM as is. Instead, it retrieves the contents of the script first and then generates a new inline <script> tag containing the original contents.

In other words, if the inserted HTML contains:

<script src="xyz.js"></script>

jQuery transforms it into:

<script> ... contents of xyz.js ... </script>

However, because my content security policy (CSP) prohibits inline script tags, the browser now refuses to execute this script. I understand that jQuery has to parse the script tags since setting HTML via .innerHTML won't execute scripts contained in the markup. But why is an external script transformed into an inline script? Is there a way to configure jQuery's behaviour here or do I have to override .html() myself?

2

There are 2 best solutions below

3
On

Had the same trouble some days ago

Here's what i did;

Variable data is containing the html as plain string..
Variable container is my body where i want to append (jQuery El)

success : data => {
    // dump data to container
    container.css({opacity: '0.0'});
    /* do not use jQuery -> it will always trigger the CSP, and the worst part about this is the CSP is right */
    /* TL;DR jQuery fails to load script with src by setting src, instead it converts the script to inline, and the CSP says no! */
    container[0].innerHTML = data;
    /* instead we do this! */
    container.find(`script[src]`).toArray().map(Script => {
     let test = document.createElement(`script`)
     test.src = Script.src;
     $(`head`)[0].appendChild(test);
    });
    container.delay(50).animate({opacity: '1.0'}, 300);
    setTimeout(() => { $(`head script`).remove(); }, 250);
    // clear data var
    data = null;
    container = null;
    $(`body`).removeClass(`hidden-menu`);
},
0
On

Something like this ought to work. We can just .appendTo() it, instead of using .html().

https://codepen.io/Terrafire123/pen/mdaKpJG?editors=1010

var myString = `
<h1>My First Heading</h1>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
<p>My first paragraph.</p> 
`;

var html = jQuery(myString);
html.appendTo(jQuery("#myTarget"));