2008-10-16 9 views
16

¿Hay alguna herramienta que le permita "intercambiar en caliente" los contenidos de JavaScript mientras se ejecuta una página web?¿Hay alguna manera de "cambiar en caliente" el código JavaScript dentro del navegador?

Estoy buscando algo similar a lo que hace HotSpot para Java, una forma de "implementar en caliente" el nuevo código JS sin tener que volver a cargar toda la página.

¿Hay algo así por ahí?

Aclarar en caso de que la gente no entiende "intercambio en caliente", según lo indicado por bloqueo:

Por "intercambio en caliente" me refiero a lo que me permite cambiar partes del código contenidas en la propia página y sus archivos .js.

Entonces este marco detectaría el cambio, ya sea automágicamente o por alguna indicación de mi parte, y volvería a cargar el código de forma dinámica, evitando la nueva publicación del lado del servidor (recargar).

Ese tipo de enfoque simplificaría la eliminación de errores y la corrección de errores, ya que no necesita volver a cargar la página y comenzar la interacción desde el principio.

+0

la forma más sencilla de hacerlo es utilizar un sistema de módulos como RequireJS - https://medium.com/@the1mills/hot-reloading-with-react- requirejs-7b2aa6cb06e1 –

Respuesta

4

Una idea interesante :)

me escribió lo siguiente bookmarklet:

function reload(){var scripts=document.getElementsByTagName("script");var head=document.getElementsByTagName("head")[0];var newScripts=[];var removeScripts=[];for(var i=0;i<scripts.length;i++){var parent=scripts[i].parentNode;if(parent==head&&scripts[i].src){var newScript={};newScript.src=scripts[i].src;newScript.innerHTML=scripts[i].innerHTML;newScripts.push(newScript);removeScripts.push(scripts[i]);}}for(var i=0;i<removeScripts.length;i++){head.removeChild(removeScripts[i]);}for(var i=0;i<newScripts.length;i++){var script=document.createElement("script");script.src=newScripts[i].src;script.type="text/javascript";script.innerHTML=newScripts[i].innerHTML;head.appendChild(script);}} 

añadir que a la ubicación de un nuevo marcador, y se volverá a cargar todos los archivos JavaScript que se hace referencia en la cabeza < >. No estoy seguro de qué tan bien funcionará en la práctica, pero valió la pena intentarlo :) Supongo que tendrías que tener mucho cuidado en la forma en que escribes tus guiones, para no tener que agregar cosas al cuerpo de la página varias veces, etc. Tal vez el soporte para un atributo 'reload = "true' 'podría ser útil, de esa manera podría etiquetar solo sus bibliotecas como recargables.

fuente completo:

function reload() { 
    var scripts = document.getElementsByTagName("script"); 
    var head = document.getElementsByTagName("head")[0]; 
    var newScripts = []; 
    var removeScripts = []; 
    for(var i=0; i < scripts.length; i++) { 
     var parent = scripts[i].parentNode; 
     if(parent == head && scripts[i].src) { 
      var newScript = {}; 
      newScript.src = scripts[i].src; 
      newScript.innerHTML = scripts[i].innerHTML; 
      newScripts.push(newScript); 
      removeScripts.push(scripts[i]); 
     } 
    } 

    for(var i=0; i < removeScripts.length; i++) { 
     head.removeChild(removeScripts[i]); 
    } 

    for(var i=0; i < newScripts.length; i++) { 
     var script = document.createElement("script"); 
     script.src = newScripts[i].src; 
     script.type = "text/javascript"; 
     script.innerHTML = newScripts[i].innerHTML; 
     head.appendChild(script); 
    } 
} 
0

Si desea hacer esto con enteros archivos de JavaScript, vea this question para algo similar que le permita obtener los conceptos básicos de la idea.

1

No estoy familiarizado con HotSport, pero si habla de cargar dinámicamente JavaScript, sí, puede hacerlo. MooTools le permite hacer eso, al igual que , Prototype, Dojo y YUI, y estoy seguro de que la mayoría de los otros marcos también lo hacen. También puede hacerlo con native JavaScript.

1

Estoy seguro de que no hay demasiada gente aquí sabe lo que quiere decir con intercambio en caliente sino como virtuosiMedia dijeron mootools permite que, si no confiar en mootools que mucho entonces hay una misma plug-in para jQuery y aún si no quieres marcos siempre se puede añadir esos guiones a través de dom

pero estoy seguro de que no se le permite alterar las secuencias de comandos de nivel de la cabeza que ya ha definido como las secuencias de comandos añadidos dinámicamente a través de DOM es único nivel corporal

+0

He agregado una aclaración, avíseme si es mejor. – kolrie

3

Ya que tenía un problema similar para resolver escribí un pequeño lib js a HOTSWAP archivos JavaScript, CSS y de imagen.Es, por supuesto, de código abierto en github: hotswap.js

Espero que ayude.

actualización: He adjuntado la fuente lib completo aquí. Para usarlo, simplemente copiar el contenido en un archivo (por ejemplo: hotswap.js) e insertar la etiqueta de secuencia de comandos en su sitio web como este:

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

API:.

// refresh .js files 
hotswap.refreshAllJs(arrExcludedFiles); 
hotswap.refreshJs(arrIncludedFiles); 

// refresh .css files 
hotswap.refreshAllCss(arrExcludedFiles); 
hotswap.refreshCss(arrIncludedFiles); 

// refresh images 
hotswap.refreshAllImg(arrExcludedFiles); 
hotswap.refreshImg(arrIncludedFiles); 

// show a gui (this is optional and not required for hotswap to work) (Click on the "H"). 
hotswap.createGui(); 

// Examples: 
// refresh all .js files 
hotswap.refreshAllJs(); 

// refresh main.css only 
hotswap.refreshCss(["main.js"]); 

// refresh all images (img tags) except "dont-refreh-me.png". 
hotswap.refreshAllImg(["dont-refreh-me.png"]); 

fuente completo (v 0.2 .0):

Tuve que eliminar todos los comentarios para que quedaran por debajo del límite de respuesta de 30000 caracteres. El html + css en línea es feo, lo sé, pero quería mantenerlo dentro de un solo archivo .js.

(function() { 
    var root = this; 
    var previousHotswap = root.hotswap; 
    var hotswap = function() 
    { 
     if (!(this instanceof hotswap)) 
     { 
      return new hotswap(); 
     } 
     else 
     { 
      return this; 
     } 
    }; 
    root.hotswap = hotswap(); 
    hotswap.prototype.VERSION = '0.2.0'; 
    hotswap.prototype.RND_PARAM_NAME = 'hs982345jkasg89zqnsl'; 
    hotswap.prototype.FILE_REMOVAL_DELAY = 400; 
    hotswap.prototype.CSS_HTML_PREFIX = 'hs982345jkasg89zqnsl'; 
    hotswap.prototype._prefix = false; 
    hotswap.prototype._prefixCache = []; 
    hotswap.prototype._guiCache = {}; 
    hotswap.prototype._guiGuiRefreshInterval = null; 
    hotswap.prototype._guiHtml = '' + 
     '<style type="text/css">'+ 
     ' #PREFIX'+ 
     ' {'+ 
     '  display: block;'+ 
     '  position: fixed;'+ 
     '  top: 20%;/*distance from top*/'+ 
     '  right: 0;'+ 
     '  z-index: 99999;'+ 
     '  width: 20em;'+ 
     '  height: auto;'+ 
     '  color: black;'+ 
     '  background-color: #666666;'+ 
     '  font-family: Verdana, sans-serif;'+ 
     '  font-size: 0.8em;'+ 
     '  -webkit-box-shadow: 0 0px 0.3em 0.1em #999999;'+ 
     '  -moz-box-shadow: 0 0px 0.3em 0.1em #999999;'+ 
     '  box-shadow: 0 0px 0.3em 0.1em #999999;'+ 
     ' }'+ 
     ' #PREFIX.mini'+ 
     ' {'+ 
     '  width: 2.9em;'+ 
     '  height: 2.9em;'+ 
     '  overflow:hidden;'+ 
     ' }'+ 
     ' #PREFIX.mini .PREFIX-header input, #PREFIX.mini .PREFIX-list, #PREFIX.mini .PREFIX-footer'+ 
     ' {'+ 
     '  display:none;'+ 
     ' }'+ 
     '  #PREFIX.mini .PREFIX-header div'+ 
     ' {'+ 
     '  display: block;'+ 
     '  width: 100%;'+ 
     '  height: 100%;'+ 
     ' }'+ 
     ' #PREFIX input'+ 
     ' {'+ 
     '  font-size: 1.0em;'+ 
     '  border: 0.1em solid #999999;'+ 
     '  border-radius: 0.2em;'+ 
     '  padding: 0.2em 0.1em;'+ 
     '  }'+ 
     ' #PREFIX .PREFIX-header'+ 
     ' {'+ 
     '  height: 2.4em;'+ 
     '  overflow:hidden;'+ 
     '  padding: 0.4em;'+ 
     '  color: white;'+ 
     '  background-color: black;'+ 
     '  }'+ 
     ' #PREFIX .PREFIX-header input'+ 
     ' {'+ 
     '  width: 83.5%;'+ 
     '  height: 1.6em;'+ 
     ' }'+ 
     ' #PREFIX .PREFIX-header div'+ 
     ' {'+ 
     '  position: absolute;'+ 
     '  top:0;'+ 
     '  right:0;'+ 
     '  width: 14.5%;'+ 
     '  height: 1.6em;'+ 
     '  line-height: 1.4em;'+ 
     '  text-align: center;'+ 
     '  font-size: 2em;'+ 
     '  font-weight: bold;'+ 
     '  cursor: pointer;'+ 
     ' }'+ 
     ' #PREFIX .PREFIX-header div:hover'+ 
     ' {'+ 
     '  background-color: #444444;'+ 
     ' }'+ 
     ' #PREFIX .PREFIX-list'+ 
     ' {'+ 
     '  width: 100%;'+ 
     '  height: 22em;'+ 
     '  overflow: auto;'+ 
     ' }'+ 
     ' #PREFIX ul'+ 
     ' {'+ 
     '  list-style-type: none;'+ 
     '  list-style-position: inside;'+ 
     '  padding: 0;'+ 
     '  margin: 0.5em 0.5em 1.2em 0.5em;'+ 
     ' }'+ 
     ' #PREFIX ul li'+ 
     ' {'+ 
     '  margin: 0.3em;'+ 
     '  padding: 0.5em 0.5em;'+ 
     '  color: white;'+ 
     '  background-color: #717171;'+ 
     '  font-size: 0.9em;'+ 
     '  line-height: 1.5em;'+ 
     '  cursor: pointer;'+ 
     ' }'+ 
     ' #PREFIX ul li:hover'+ 
     ' {'+ 
     '  background-color: #797979;'+ 
     ' }'+ 
     ' #PREFIX ul li.template'+ 
     ' {'+ 
     '  display: none;'+ 
     ' }'+ 
     ' #PREFIX ul li.active'+ 
     ' {'+ 
     '  background-color: black;'+ 
     ' }'+ 
     ' #PREFIX ul li.PREFIX-headline'+ 
     ' {'+ 
     '  color: white;'+ 
     '  background-color: transparent;'+ 
     '  text-align: center;'+ 
     '  font-weight: bold;'+ 
     '  cursor: default;'+ 
     ' }'+ 
     ' #PREFIX .PREFIX-footer'+ 
     ' {'+ 
     '  padding: 0;'+ 
     '  margin:0;'+ 
     '  background-color: #444444;'+ 
     ' }'+ 
     ' #PREFIX .PREFIX-footer ul'+ 
     ' {'+ 
     '  margin: 0;'+ 
     '  padding: 0.5em;'+ 
     ' }'+ 
     ' #PREFIX .PREFIX-footer ul li'+ 
     ' {'+ 
     '  color: white;'+ 
     '  background-color: black;'+ 
     '  font-size: 1.0em;'+ 
     '  border-radius: 0.5em;'+ 
     '  text-align: center;'+ 
     '  height: 2.2em;'+ 
     '  line-height: 2.2em;'+ 
     ' }'+ 
     ' #PREFIX .PREFIX-footer ul li input.PREFIX-seconds'+ 
     ' {'+ 
     '  text-align: center;'+ 
     '  width: 2em;'+ 
     ' }'+ 
     ' #PREFIX .PREFIX-footer ul li:hover'+ 
     ' {'+ 
     '  background-color: #222222;'+ 
     '  }'+ 
     ' #PREFIX .PREFIX-footer ul li.inactive'+ 
     ' {'+ 
     '  background-color: #666666;'+ 
     '  cursor: default;'+ 
     ' }'+ 
     ' </style>'+ 
     ' <div id="PREFIX" class="mini">'+ 
     '  <div class="PREFIX-header">'+ 
     '   <input id="PREFIX-prefix" placeholder="prefix" type="text" name="" />'+ 
     '   <div id="PREFIX-toggle">H</div>'+ 
     '  </div>'+ 
     '  <div class="PREFIX-list">'+ 
     '   <ul id="PREFIX-css">'+ 
     '    <li class="PREFIX-headline">CSS</li>'+ 
     '    <li class="template"></li>'+ 
     '   </ul>'+ 
     '   <ul id="PREFIX-js">'+ 
     '    <li class="PREFIX-headline">JS</li>'+ 
     '    <li class="template"></li>'+ 
     '   </ul>'+ 
     '   <ul id="PREFIX-img">'+ 
     '    <li class="PREFIX-headline">IMG</li>'+ 
     '    <li class="template"></li>'+ 
     '   </ul>'+ 
     '  </div>'+ 
     '  <div class="PREFIX-footer">'+ 
     '   <ul>'+ 
     '    <li id="PREFIX-submit-selected">refresh selected</li>'+ 
     '    <li id="PREFIX-submit-start">refresh every <input class="PREFIX-seconds" type="text" value="1" /> sec.</li>'+ 
     '    <li id="PREFIX-submit-stop" class="inactive">stop refreshing</li>'+ 
     '    <li id="PREFIX-submit-refresh-list">refresh list</li>'+ 
     '   </ul>'+ 
     '  </div>'+ 
     ' </div>'; 
    var 
     xGetElementById  = function(sId){ return document.getElementById(sId) }, 
     xGetElementsByTagName = function(sTags){ return document.getElementsByTagName(sTags) }, 
     xAppendChild   = function(parent, child){ return parent.appendChild(child) }, 
     xCloneNode   = function(node){ return document.cloneNode(node) }, 
     xCreateElement  = function(sTag){ return document.createElement(sTag) }, 
     xCloneNode   = function(ele, deep){ return ele.cloneNode(deep) }, 
     xRemove = function(ele) 
     { 
      if(typeof ele.parentNode != "undefined" && ele.parentNode) 
      { 
       ele.parentNode.removeChild(ele); 
      } 
     }, 
     xAddEventListener = function(ele, sEvent, fn, bCaptureOrBubble) 
     { 
      if(xIsEmpty(bCaptureOrBubble)) 
      { 
       bCaptureOrBubble = false; 
      } 
      if (ele.addEventListener) 
      { 
       ele.addEventListener(sEvent, fn, bCaptureOrBubble); 
       return true; 
      } 
      else if (ele.attachEvent) 
      { 
       return ele.attachEvent('on' + sEvent, fn); 
      } 
      else 
      { 
       ele['on' + sEvent] = fn; 
      } 
     }, 
     xStopPropagation = function(evt) 
     { 
      if (evt && evt.stopPropogation) 
      { 
       evt.stopPropogation(); 
      } 
      else if (window.event && window.event.cancelBubble) 
      { 
       window.event.cancelBubble = true; 
      } 
     }, 
     xPreventDefault = function(evt) 
     { 
      if (evt && evt.preventDefault) 
      { 
       evt.preventDefault(); 
      } 
      else if (window.event && window.event.returnValue) 
      { 
       window.eventReturnValue = false; 
      } 
     }, 
     xContains = function(sHaystack, sNeedle) 
     { 
      return sHaystack.indexOf(sNeedle) >= 0 
     }, 
     xStartsWith = function(sHaystack, sNeedle) 
     { 
      return sHaystack.indexOf(sNeedle) === 0 
     }, 
     xReplace = function(sHaystack, sNeedle, sReplacement) 
     { 
      if(xIsEmpty(sReplacement)) 
      { 
       sReplacement = ""; 
      } 
      return sHaystack.split(sNeedle).join(sReplacement); 
     }, 
     xGetAttribute = function(ele, sAttr) 
     { 
      var result = (ele.getAttribute && ele.getAttribute(sAttr)) || null; 
      if(!result) { 
       result = ele[sAttr]; 
      } 
      if(!result) { 
       var attrs = ele.attributes; 
       var length = attrs.length; 
       for(var i = 0; i < length; i++) 
        if(attrs[i].nodeName === sAttr) 
         result = attrs[i].nodeValue; 
      } 
      return result; 
     }, 
     xSetAttribute = function(ele, sAttr, value) 
     { 
      if(ele.setAttribute) 
      { 
       ele.setAttribute(sAttr, value) 
      } 
      else 
      { 
       ele[sAttr] = value; 
      } 
     }, 
     xGetParent = function(ele) 
     { 
      return ele.parentNode || ele.parentElement; 
     }, 
     xInsertAfter = function(refEle, newEle) 
     { 
      return xGetParent(refEle).insertBefore(newEle, refEle.nextSibling); 
     }, 
     xBind = function(func, context) 
     { 
      if (Function.prototype.bind && func.bind === Function.prototype.bind) 
      { 
       return func.bind(context); 
      } 
      else 
      { 
       return function() { 
        if(arguments.length > 2) 
        { 
         return func.apply(context, arguments.slice(2)); 
        } 
        else 
        { 
         return func.apply(context); 
        } 
       }; 
      } 
     }, 
     xIsEmpty = function(value) 
     { 
      var ret = true; 
      if(value instanceof Object) 
      { 
       for(var i in value){ if(value.hasOwnProperty(i)){return false}} 
       return true; 
      } 
      ret = typeof value === "undefined" || value === undefined || value === null || value === ""; 
      return ret; 
     }, 
     xAddClass = function(ele, sClass) 
     { 
      var clazz = xGetAttribute(ele, "class"); 
      if(!xHasClass(ele, sClass)) 
      { 
       xSetAttribute(ele, "class", clazz + " " + sClass); 
      } 
     }, 
     xRemoveClass = function(ele, sClass) 
     { 
      var clazz = xGetAttribute(ele, "class"); 
      if(xHasClass(ele, sClass)) 
      { 
       xSetAttribute(ele, "class", xReplace(clazz, sClass, "")); 
      } 
     }, 
     xHasClass = function(ele, sClass) 
     { 
      var clazz = xGetAttribute(ele, "class"); 
      return !xIsEmpty(clazz) && xContains(clazz, sClass); 
     }; 
    hotswap.prototype._recreate = function(type, xcludedFiles, xcludeComparator, nDeleteDelay, bForceRecreation) 
    { 
     if(typeof nDeleteDelay == "undefined") 
     { 
      nDeleteDelay = 0; 
     } 

     if(typeof bForceRecreation == "undefined") 
     { 
      bForceRecreation = false; 
     } 

     var tags = this._getFilesByType(type, xcludedFiles, xcludeComparator); 
     var newTags = []; 
     var removeTags = []; 
     var i, src, detected, node, srcAttributeName; 
     for(i=0; i<tags.length; i++) 
     { 
      node = tags[i].node; 
      srcAttributeName = tags[i].srcAttributeName; 
      var newNode = { 
       node: null, 
       oldNode: node, 
       parent: xGetParent(node) 
      }; 
      if(bForceRecreation) 
      { 
       newNode.node = xCreateElement("script"); 
      } 
      else 
      { 
       newNode.node = xCloneNode(node, false); 
      } 
      for (var p in node) { 
       if (node.hasOwnProperty(p)) { 
        newNode.node.p = node.p; 
       } 
      } 
      src = xGetAttribute(node, srcAttributeName); 
      xSetAttribute(newNode.node, srcAttributeName, this._updatedUrl(src)); 
      newTags.push(newNode); 
      removeTags.push(node); 
     } 
     for(var i=0; i < newTags.length; i++) { 
      xInsertAfter(newTags[i].oldNode, newTags[i].node); 
     } 
     if(nDeleteDelay > 0) 
     { 
      for(var i=0; i < removeTags.length; i++) { 
       xSetAttribute(removeTags[i], "data-hotswap-deleted", "1"); 
      } 

      setTimeout(function() { 
       for(var i=0; i < removeTags.length; i++) { 
        xRemove(removeTags[i]); 
       } 
      }, nDeleteDelay); 
     } 
     else 
     { 
      for(var i=0; i < removeTags.length; i++) { 
       xRemove(removeTags[i]); 
      } 
     } 
    }; 
    hotswap.prototype._reload = function(type, xcludedFiles, xcludeComparator) 
    { 
     var tags = this._getFilesByType(type, xcludedFiles, xcludeComparator); 
     var i, src, node, srcAttributeName; 
     for(i=0; i<tags.length; i++) 
     { 
      node = tags[i].node; 
      srcAttributeName = tags[i].srcAttributeName; 
      // update the src property 
      src = xGetAttribute(node, srcAttributeName); 
      xSetAttribute(node, srcAttributeName, this._updatedUrl(src)); 
     } 
    }; 
    hotswap.prototype._getFilesByType = function(type, xcludedFiles, xcludeComparator) 
    { 
     var files; 
     switch(type) 
     { 
      case "css": 
       files = this._getFiles(
        "css", 
        "link", 
        function(ele) 
        { 
         return (xGetAttribute(ele, "rel") == "stylesheet" || xGetAttribute(ele, "type") == "text/css"); 
        }, 
        "href", 
        xcludedFiles, 
        xcludeComparator 
       ) 
       break; 

      case "js": 
       files = this._getFiles(
        "js", 
        "script", 
        function(ele) 
        { 
         return (xGetAttribute(ele, "type") == "" || xGetAttribute(ele, "type") == "text/javascript"); 
        }, 
        "src", 
        xcludedFiles, 
        xcludeComparator 
       ) 
       break; 

      case "img": 
       files = this._getFiles(
        "img", 
        "img", 
        function(ele) 
        { 
         return (xGetAttribute(ele, "src") != ""); 
        }, 
        "src", 
        xcludedFiles, 
        xcludeComparator 
       ) 
       break; 
     } 

     return files; 
    } 
    hotswap.prototype._getFiles = function(type, tagName, tagFilterFunc, srcAttributeName, xcludedFiles, xcludeComparator) 
    { 
     if(typeof xcludedFiles == "undefined" || !xcludedFiles) 
     { 
      xcludedFiles = []; 
     } 

     if(typeof xcludeComparator == "undefined" || !xcludeComparator) 
     { 
      xcludeComparator = false; 
     } 

     var fileNodes = []; 
     var tags = xGetElementsByTagName(tagName); 
     var src, detected, node; 
     for(var i=0; i<tags.length; i++) { 
      node = tags[i]; 
      src = xGetAttribute(node,[srcAttributeName]); 
      if(xIsEmpty(xGetAttribute(node, "data-hotswap-deleted"))) 
      { 
       if(src && tagFilterFunc(node)) 
       { 
        detected = false; 
        for(var j=0; j<xcludedFiles.length; j++) { 
         if(xContains(src,xcludedFiles[j])) 
         { 
          detected = true; 
          break; 
         } 
        } 
        if(detected == xcludeComparator) 
        { 
         fileNodes.push({ 
          type: type, 
          node : node, 
          tagName : tagName, 
          srcAttributeName : srcAttributeName 
         }); 
        } 
       } 
      } 
     } 

     return fileNodes; 
    }; 
    hotswap.prototype._updatedUrl = function(url, getCleanUrl) 
    { 
     var cleanUrl; 
     if(typeof getCleanUrl == "undefined") 
     { 
      getCleanUrl = false; 
     } 
     url = cleanUrl = url.replace(new RegExp("(\\?|&)"+this.RND_PARAM_NAME+"=[0-9.]*","g"), ""); 
     var queryString = "", randomizedQueryString = ""; 
     if(xContains(url, "?")) 
     { 
      if(xContains(url, "&" + this.RND_PARAM_NAME)) 
      { 
       queryString = url.split("&" + this.RND_PARAM_NAME).slice(1,-1).join(""); 
      } 
      randomizedQueryString = queryString + "&" + this.RND_PARAM_NAME + "=" + Math.random() * 99999999; 
     } 
     else 
     { 
      if(xContains(url, "?" + this.RND_PARAM_NAME)) 
      { 
       queryString = url.split("?" + this.RND_PARAM_NAME).slice(1,-1).join(""); 
      } 
      randomizedQueryString = queryString + "?" + this.RND_PARAM_NAME + "=" + Math.random() * 99999999; 
     } 
     var foundAt = -1; 
     if(!xIsEmpty(this._prefixCache)) 
     { 
      for(var i=0; i<this._prefixCache.length; ++i) 
      { 
       if(!xIsEmpty(this._prefixCache[i]) && foundAt < 0) 
       { 
        for(var h=0; h<this._prefixCache[i].length; ++h) 
        { 
         if(this._prefixCache[i][h] == cleanUrl + queryString) 
         { 
          cleanUrl = this._prefixCache[i][0]; 
          foundAt = i; 
          break; 
         } 
        } 
       } 
      } 
     } 

     var prefixHistory = [cleanUrl + queryString]; 
     var applyPrefix = true; 
     if(prefixHistory[0].match(new RegExp('^[A-Za-z0-9-_]+://'))) 
     { 
      applyPrefix = false; 
     } 
     var prefix = this._prefix; 
     if(!xIsEmpty(this._prefix) && this._prefix) 
     { 
      prefixHistory.push(this._prefix + cleanUrl + queryString); 
      if(foundAt >= 0) 
      { 
       this._prefixCache[foundAt] = prefixHistory; 
      } 
      else 
      { 
       this._prefixCache.push(prefixHistory); 
      } 
     } 
     else 
     { 
      prefix = ""; 
     } 
     if(!applyPrefix) 
     { 
      prefix = ""; 
     } 
     url = prefix + cleanUrl + randomizedQueryString; 

     return (getCleanUrl) ? (cleanUrl + queryString) : url; 
    } 
    hotswap.prototype.refreshAllJs = function(excludedFiles) 
    { 
     if(typeof excludedFiles == "undefined" || !excludedFiles) 
     { 
      excludedFiles = [] 
     } 
     excludedFiles.push("hotswap.js"); 

     this._recreate("js", excludedFiles, false, 0, true); 
    }; 
    hotswap.prototype.refreshJs = function(includedFiles) 
    { 
     this._recreate("js", includedFiles, true, 0, true); 
    }; 
    hotswap.prototype.refreshAllCss = function(excludedFiles) 
    { 
     this._recreate("css", excludedFiles, false, this.FILE_REMOVAL_DELAY); 
    }; 
    hotswap.prototype.refreshCss = function(includedFiles) 
    { 
     this._recreate("css", includedFiles, true, this.FILE_REMOVAL_DELAY); 
    }; 
    hotswap.prototype.refreshAllImg = function(excludedFiles) 
    { 
     this._reload("img", excludedFiles, false); 
    }; 
    hotswap.prototype.refreshImg = function(includedFiles) 
    { 
     this._reload("img", includedFiles, true); 
    }; 
    hotswap.prototype.setPrefix = function(prefix) 
    { 
     this._prefix = prefix; 
     var gui = xGetElementById(this.CSS_HTML_PREFIX + "_wrapper"); 
     if(gui) 
     { 
      if(!xIsEmpty(this._prefix) && this._prefix) 
      { 
       xGetElementById(this.CSS_HTML_PREFIX+"-prefix").value = this._prefix; 
      } 
      else 
      { 
       xGetElementById(this.CSS_HTML_PREFIX+"-prefix").value = ""; 
      } 
     } 
    } 
    hotswap.prototype.getPrefix = function() 
    { 
     return this._prefix; 
    } 
    hotswap.prototype.createGui = function(nDistanceFromTopInPercent) 
    { 
     if(xIsEmpty(nDistanceFromTopInPercent)) 
     { 
      nDistanceFromTopInPercent = 20; 
     } 
     var gui = xGetElementById(this.CSS_HTML_PREFIX + "_wrapper"); 
     if(gui) 
     { 
      xRemove(xGetElementById(this.CSS_HTML_PREFIX + "_wrapper")); 
     } 
     gui = xCreateElement("div"); 
     xSetAttribute(gui, "id", this.CSS_HTML_PREFIX + "_wrapper"); 
     var guiHtml = xReplace(this._guiHtml, "PREFIX", this.CSS_HTML_PREFIX); 
     guiHtml = xReplace(guiHtml, '20%;/*distance from top*/', nDistanceFromTopInPercent+'%;/*distance from top*/'); 
     gui.innerHTML = guiHtml; 
     xAppendChild(xGetElementsByTagName("body")[0], gui); 
     if(!xIsEmpty(this._guiCache)) 
     { 
      this._guiCache = {}; 
     } 
     this._guiCreateFilesList(); 
     if(!xIsEmpty(this._prefix) && this._prefix) 
     { 
      xGetElementById(this.CSS_HTML_PREFIX+"-prefix").value = this._prefix; 
     } 
     var self = this; 
     xAddEventListener(xGetElementById(this.CSS_HTML_PREFIX+"-toggle"), "click", function(evt) 
     { 
      var gui = xGetElementById(self.CSS_HTML_PREFIX); 
      if(xHasClass(gui, "mini")) 
      { 
       xRemoveClass(gui, "mini"); 
      } 
      else 
      { 
       xAddClass(gui, "mini"); 
      } 
     }); 
     xAddEventListener(xGetElementById(this.CSS_HTML_PREFIX+"-prefix"), "blur", function(evt) 
     { 
      self._guiPrefixChanged(evt.target); 
     }); 
     xAddEventListener(xGetElementById(this.CSS_HTML_PREFIX+"-submit-selected"), "click", function(evt) 
     { 
      self._guiRefreshSelected() 
     }); 
     xAddEventListener(xGetElementById(this.CSS_HTML_PREFIX+"-submit-start"), "click", function(evt) 
     { 
      if(xGetAttribute(evt.target, "class") != this.CSS_HTML_PREFIX+"-seconds") 
      { 
       var input, nSeconds = 1; 
       var children = evt.target.children; 
       for(var i=0; i<children.length; ++i) 
       { 
        if(xGetAttribute(children[i], "class") == this.CSS_HTML_PREFIX+"-seconds") 
        { 
         nSeconds = children[i].value; 
        } 
       } 

       self._guiRefreshSelected(); 
       self._guiRefreshStart(nSeconds); 
      } 
     }); 
     xAddEventListener(xGetElementById(this.CSS_HTML_PREFIX+"-submit-stop"), "click", function(evt) 
     { 
      self._guiRefreshStop(); 
     }); 
     xAddEventListener(xGetElementById(this.CSS_HTML_PREFIX+"-submit-refresh-list"), "click", xBind(self.guiRefreshFilesList,self)); 
    } 

    hotswap.prototype._guiCreateFilesList = function() 
    { 
     this._guiCache.files = []; 
     this._guiCache.activeFiles = { 
      "css" : [], 
      "js" : [], 
      "img" : [] 
     }; 

     var self = this; 
     var createFilesList = function(list, files) 
     { 
      var i, j, r, clone, template, file, fileName, nodesToRemove = []; 
      for(j=0; j<list.children.length; ++j) 
      { 
       if(xHasClass(list.children[j], "template")) 
       { 
        template = list.children[j]; 
       } 
       else 
       { 
        if(!xHasClass(list.children[j], self.CSS_HTML_PREFIX + "-headline")) 
        { 
         nodesToRemove.push(list.children[j]); 
        } 
       } 
      } 
      for(r=0; r<nodesToRemove.length; ++r) 
      { 
       xRemove(nodesToRemove[r]); 
      } 
      for(i=0; i<files.length; ++i) 
      { 
       file = files[i]; 
       clone = xCloneNode(template); 
       xRemoveClass(clone, "template"); 
       fileName = self._updatedUrl(xGetAttribute(file.node, file.srcAttributeName), true); 
       if(!xContains(self._guiCache.files,fileName)) 
       { 
        self._guiCache.files.push(fileName); 
        clone.innerHTML = fileName; 
        xAppendChild(list, clone); 
        xAddEventListener(clone, "click", (function(type, fileName){ 
         return function(evt){ 
          xStopPropagation(evt); 
          xPreventDefault(evt); 
          self._guiClickedFile(evt.target, type, fileName); 
         }; 
        })(file.type, fileName) 
        ); 
       } 
      } 
     } 

     createFilesList(xGetElementById(this.CSS_HTML_PREFIX+"-css"), this._getFilesByType("css")); 
     createFilesList(xGetElementById(this.CSS_HTML_PREFIX+"-js"), this._getFilesByType("js", ["hotswap.js"])); 
     createFilesList(xGetElementById(this.CSS_HTML_PREFIX+"-img"), this._getFilesByType("img")); 
    } 
    hotswap.prototype.deleteGui = function() 
    { 
     var gui = xGetElementById(this.CSS_HTML_PREFIX + "_wrapper"); 
     if(gui) 
     { 
      xRemove(xGetElementById(this.CSS_HTML_PREFIX + "_wrapper")); 
     } 
    } 
    hotswap.prototype._guiPrefixChanged = function(ele) 
    { 
     if(ele) 
     { 
      this.setPrefix(ele.value); 
     } 
    }, 

    hotswap.prototype._guiClickedFile = function(ele, sType, sFileName) 
    { 
     var activeFiles = this._guiCache.activeFiles[sType]; 
     if(xContains(activeFiles, sFileName)) 
     { 
      xRemoveClass(ele, "active"); 
      activeFiles.splice(activeFiles.indexOf(sFileName), 1) 
     } 
     else 
     { 
      xAddClass(ele, "active"); 
      activeFiles.push(sFileName); 
     } 
    }, 

    hotswap.prototype._guiRefreshSelected = function() 
    { 
     var activeFiles = this._guiCache.activeFiles; 
     if(activeFiles['css'].length > 0) 
     { 
      this.refreshCss(activeFiles['css']); 
     } 
     if(activeFiles['js'].length > 0) 
     { 
      this.refreshJs(activeFiles['js']); 
     } 
     if(activeFiles['img'].length > 0) 
     { 
      this.refreshImg(activeFiles['img']); 
     } 
    }, 

    hotswap.prototype._guiRefreshStart = function(nSeconds) 
    { 
     if(this._guiGuiRefreshInterval !== null) 
     { 
      this._guiRefreshStop(); 
     } 
     var self = this; 
     this._guiGuiRefreshInterval = setInterval(xBind(this._guiRefreshSelected, this), nSeconds * 1000); 
     xAddClass(xGetElementById(this.CSS_HTML_PREFIX+"-submit-start"), "inactive"); 
     xRemoveClass(xGetElementById(this.CSS_HTML_PREFIX+"-submit-stop"), "inactive"); 
    }, 

    hotswap.prototype._guiRefreshStop = function() 
    { 
     if(this._guiGuiRefreshInterval !== null) 
     { 
      clearInterval(this._guiGuiRefreshInterval); 
     } 
     this._guiGuiRefreshInterval = null; 
     xRemoveClass(xGetElementById(this.CSS_HTML_PREFIX+"-submit-start"), "inactive"); 
     xAddClass(xGetElementById(this.CSS_HTML_PREFIX+"-submit-stop"), "inactive"); 
    } 

    hotswap.prototype.guiRefreshFilesList = function() 
    { 
     this._guiCreateFilesList(); 
    } 

}).call(this); 
+0

Lo siento, esa no era mi intención. He actualizado la respuesta para contener el código fuente completo y algunos ejemplos. – geoathome

+0

gracias ...... :-) – kleopatra

1

Puede fácilmente en caliente recargar código JavaScript con el sistema de módulo frontal RequireJS, escribí un artículo sobre el tema recientemente (septiembre de 2015)

https://medium.com/@the1mills/hot-reloading-with-react-requirejs-7b2aa6cb06e1

que, básicamente, eliminar la caché de un módulo AMD y RequireJS irán a buscar el nuevo desde el sistema de archivos.

el truco es usar websockets (socket.io funciona bien) para decirle al navegador que el archivo ha cambiado, y para eliminar el caché y volver a requerir el archivo.

el resto de la información se encuentra en el artículo

Cuestiones relacionadas