4

I have the following javascript which works fine in debug, but is failing in production due to improper minification:

function buildNotification(config) {

    var notificationWrapper = $('<div>', {
        'id': _.uniqueId('notification_'),
        'class': 'notificationWrapper'
    });

    var notification = $('<div>', {
        'class': 'notification ui-widget ui-state-default'
    });
    notification.addClass(config.notificationClass);
    notification.appendTo(notificationWrapper);

    var notificationList = $('<ul/>', {
        'class': 'notificationList'
    }).appendTo(notification);

    //  THIS CODE IS IMPROPERLY MINIFIED: 
    $.each(config.messages, function() {
        $('<li/>', {
            html: this
        }).appendTo(notificationList);
    });

    return notificationWrapper;
}

The cuplrit being where I set the list item's HTML markup based on config.

The minified mark-up looks like:

function g(a) {
    var b = $("<div>", { id: _.uniqueId("notification_"), "class": "notificationWrapper" }), c = $("<div>", { "class": "notification ui-widget ui-state-default" });
    c.addClass(a.notificationClass);
    c.appendTo(b);
    var d = $("<ul/>", { "class": "notificationList" }).appendTo(c);
    $.each(a.messages, function() { $("<li/>", { html: this }).appendTo(d); });
    return b;
}

And here's the error message I receive:

enter image description here

Could someone drop some knowledge on me? Am I doing something that's bad practice? I ran the code through JSHint, no complaints, and I also have 'use strict' at the top of the file.

UPDATE: I experience the same issue when minifying using Google Closure. The code generated by it is:

function g(a) {
    var b = $("<div>", { id: _.uniqueId("notification_"), "class": "notificationWrapper" }), c = $("<div>", { "class": "notification ui-widget ui-state-default" });
    c.addClass(a.notificationClass);
    c.appendTo(b);
    var d = $("<ul/>", { "class": "notificationList" }).appendTo(c);
    $.each(a.messages, function() { $("<li/>", { html: this }).appendTo(d); });
    return b;
}

This is identical to YUI Compressor.

UPDATE 2: http://jscompress.com/ If I compress my file using this software, it works.

The generated code:

function r(e) {
    var t = $("<div>", { id: _.uniqueId("notification_"), "class": "notificationWrapper" });
    var n = $("<div>", { "class": "notification ui-widget ui-state-default" });
    n.addClass(e.notificationClass);
    n.appendTo(t);
    var i = $("<ul/>", { "class": "notificationList" }).appendTo(n);
    $.each(e.messages, function() { $("<li/>", { html: this }).appendTo(i); });
    return t;
}
8
  • 1
    Try to minify with a different tool first, like Google Closure: closure-compiler.appspot.com/home Commented Sep 26, 2013 at 17:38
  • It's part of an existing project with thousands of files. I'm not really comfortable changing minification tools currently. I will compare the minification results though and see if there are differences. Commented Sep 26, 2013 at 17:39
  • @EugeneXa I experience the same error with Google Closure. Commented Sep 26, 2013 at 17:42
  • Did you try in other web browsers? I think this is a chrome's bug. Commented Sep 26, 2013 at 17:45
  • @RicardoGonzales It does not work in the latest FF, either, but other minification tools seem to produce working code... I'm wondering if there is something ambiguous about what I've written. Hmm. Commented Sep 26, 2013 at 17:50

2 Answers 2

4

The problem is that when looping through $.each() -- this is expecting / pointing to a jQuery wrapped element. If you have HTML within a string it sees <i>Test</i> as:

String {0: "<", 1: "i", 2: ">", 3: "T", 4: "e", 5: "s", 6: "t", 7: "<", 8: "/", 9: "i", 10: ">"}

Hence giving the error:

Uncaught NotFoundError: An attempt was made to reference a Node in a context where it does not exist. 

If you were pointing to a jQuery wrapped element like: $('#test'), then this would work as intended. But since you are passing a string or array of strings (with HTML in them) you have to use the 2nd parameter of your function element to get what you need.

Here is a jsFiddle example: http://jsfiddle.net/BJBV5/

var messages = $('#test');

$.each(messages, function(index, element) {
    console.log(element);
    console.log(this); // <-- notice this works as intended
    $("<li/>", { 
        html: this
    }).appendTo('div');
});

var messages = ['<i>Test</i>'];

$.each(messages, function(index, element) {
    console.log(element);
    console.log(this); // <-- notice this will show an array of each letter in the string
    $("<li/>", { 
        html: element
    }).appendTo('div');
});
Sign up to request clarification or add additional context in comments.

Comments

0

If I change the offending code snippet from:

$.each(config.messages, function () {
    $('<li/>', {
        html: this
    }).appendTo(notificationList);
});

to

$.each(config.messages, function (index, message) {
    $('<li/>', {
        html: message
    }).appendTo(notificationList);
});

The minified code works.

I would be interested in understanding why, but this resolves my issue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.