Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs EJS partials with scripts in the head

I'm working with EJS to render and server HTML pages from a Nodejs server. Some of the partials I include have scripts and stylesheets referenced in the head, but this causes the client to make multiple requests for the same file (for example if the parent view also includes that file)

For example:

<!-- file: parent.ejs -->
<html>
    <head>
        <link rel="stylesheet" href="public/mystylesheet.css">
        <script src="public/myscript.js">
    </head>
    <body>
        <%- partial("partial.ejs") %>
    </body>
</html>

And in the partial:

<!-- file: partial.ejs -->
<html>
    <head>
        <link rel="stylesheet" href="public/mystylesheet.css">
        <script src="public/myscript.js">
    </head>
    <body>
        This is an EJS partial!
    </body>
</html>

In this case, "mystylesheet.css" is loaded by the client twice (unnecessarily), and so is "myscript.js"

Is there an easy way (preferably using EJS) to make sure that a stylesheet or script is included when a partial requires it, but not if the parent view already has included the resource?

like image 638
bigpopakap Avatar asked Nov 05 '22 08:11

bigpopakap


1 Answers

I found a fairly good solution to this problem, which basically boils down to using an EJS variable to keep track of resources included as the EJS document is rendered. Here's a shortened example below, that only works for script tags (but can easily be extended to stylesheets or anything else)

A partial that helps with the inclusion of resources:

//file: "include.ejs"
<% for (var i in scripts) { %> //scripts an arr of js files to (maybe) include
    <% if (!resources[scripts[i]]) { %>
        <script src="<%= scripts[i] %>"></script>
        <% resources[scripts[i]] = true %>
    <% } %>
<% } %> <!-- end for -->

And a file that uses this partial to include scripts

//file: "somepartial.ejs"
<html>
    <head>
        <%- partial("include.ejs", {
                scripts: ["lib/jquery.js", "lib/bootstrap-tabs.js"]
            }) %>
    </head>
    <body>
        <!-- MY EJS PARTIAL! -->
    </body>
</html>

And when rendering the partial:

response.render('somepartial.ejs', {
    resources: {},
    /* some other variables */
});

This way, you can be sure that a script is included by a partial, but not unless it was already included somewhere in the rendered HTML page

A limitation

There is one limitation that I came across: If you load part of your page with an AJAX request like

$("#someDiv").load("/another/part/of/the/page.html");

Then the resources included with the AJAX-loaded portion of the page won't be aware of the scripts already loaded (unless you pass that information in a REST argument, like I'm doing):

$("#someDiv").load("/another/part/of/the/page.html?resources={...}");

Of course, with this little fix, any two parts of the page that are loaded with an AJAX call may request the same resource, and there's no way for them to know that since they are only aware of what the parent document has had loaded (hope that makes sense)

like image 177
bigpopakap Avatar answered Nov 09 '22 15:11

bigpopakap