Pregunta

RequestJS parece hacer algo internamente que los cachés requerían archivos JavaScript. Si hago un cambio en uno de los archivos requeridos, tengo que cambiar el nombre del archivo para que se apliquen los cambios.

El truco común de agregar un número de versión como un parámetro de consulta hasta el final del nombre de archivo no funciona con requestjs <script src="jsfile.js?v2"></script>

Lo que estoy buscando es una forma de evitar esta caché interna de los scripts requeridos por los requisitos sin tener que cambiar el nombre de mis archivos de script cada vez que se actualizan.

Solución multiplataforma:

Ahora estoy usando urlArgs: "bust=" + (new Date()).getTime() para la caza de caché automático durante el desarrollo y urlArgs: "bust=v2" Para la producción, donde incremento el número de versión codificada después de lanzar un script requerido actualizado.

Nota:

@Dustin Getz mencionó en una respuesta reciente que las herramientas de desarrollador de Chrome eliminarán los puntos de interrupción durante la depuración cuando los archivos JavaScript se actualicen continuamente así. Una solución es escribir debugger; en código para activar un punto de interrupción en la mayoría de los depuradores de JavaScript.

Soluciones específicas del servidor:

Para soluciones específicas que puedan funcionar mejor para el entorno de su servidor, como Node o Apache, consulte algunas de las respuestas a continuación.

¿Fue útil?

Solución

Se pueden configurar las necesidades para agregar un valor a cada una de las URL de script para la quiebra de caché.

De la documentación requiradora (http://requirejs.org/docs/api.html#config):

urlargs: Argumentos de cadena de consulta adicional adjuntas a URL que requieren USJS para obtener recursos. Más útil para almacenar en caché cuando el navegador o el servidor no está configurado correctamente.

Ejemplo, agregar "V2" a todos los scripts:

require.config({
    urlArgs: "bust=v2"
});

Para fines de desarrollo, puede obligar a los requisitos a evitar el caché agregando una marca de tiempo:

require.config({
    urlArgs: "bust=" + (new Date()).getTime()
});

Otros consejos

¡No use Urlargs para esto!

Requerir cargas de script respetando los encabezados de almacenamiento en caché HTTP. (Los scripts se cargan con un insertado dinámicamente <script>, lo que significa que la solicitud se parece a cualquier activo antiguo que se cargue).

Sirva sus activos de JavaScript con los encabezados HTTP adecuados para deshabilitar el almacenamiento en caché durante el desarrollo.

Usar Urlargs de Requerir significa que los puntos de interrupción que establezcan no se conservarán en las actualizaciones; terminas necesitando poner debugger declaraciones en todas partes en su código. Malo. yo suelo urlArgs para activos que destruyen caché durante las actualizaciones de producción con el GIT SHA; Entonces puedo establecer mis activos para que se almacenen en caché para siempre y se garantice que nunca tenga activos obsoletos.

En el desarrollo, me burlo de todas las solicitudes de Ajax con un complejo mockjax Configuración, luego puedo servir mi aplicación en modo solo JavaScript con un Servidor HTTP Python de 10 líneas con todo el almacenamiento en caché apagado. Esto me ha ampliado a una aplicación de "empresa" bastante grande con cientos de puntos finales de servicio web relajante. Incluso tenemos un diseñador contratado que puede trabajar con nuestra base de código de producción real sin darle acceso a nuestro código de back -end.

La solución Urlargs tiene problemas. Desafortunadamente, no puede controlar todos los servidores proxy que podrían ser entre usted y el navegador web de su usuario. Desafortunadamente, algunos de estos servidores proxy se pueden configurar para ignorar los parámetros de URL al almacenar archivos. Si esto sucede, la versión incorrecta de su archivo JS se entregará a su usuario.

Finalmente me di por vencido y Implementé mi propia solución directamente en requerir.js. Si está dispuesto a modificar su versión de la biblioteca RequestJS, esta solución podría funcionar para usted.

Puedes ver el parche aquí:

https://github.com/jbcpollak/requirejs/commit/589ee0cdfe6f719cd761eee631ce68ee09a5a67

Una vez agregado, puede hacer algo como esto en su configuración de requerimiento:

var require = {
    baseUrl: "/scripts/",
    cacheSuffix: ".buildNumber"
}

Use su sistema de compilación o entorno de servidor para reemplazar buildNumber con una ID de revisión / versión de software / color favorito.

Usando requerir así:

require(["myModule"], function() {
    // no-op;
});

Hará que requiera solicitar este archivo:

http://yourserver.com/scripts/myModule.buildNumber.js

En el entorno de nuestro servidor, utilizamos reglas de reescritura de URL para eliminar el Number Build y servir el archivo JS correcto. De esta manera, en realidad no tenemos que preocuparnos por cambiar el nombre de todos nuestros archivos JS.

El parche ignorará cualquier script que especifique un protocolo, y no afectará ningún archivo que no sea JS.

Esto funciona bien para mi entorno, pero me doy cuenta de que algunos usuarios preferirían un prefijo en lugar de un sufijo, debería ser fácil modificar mi compromiso para satisfacer sus necesidades.

Actualizar:

En la discusión de solicitud de extracción, el autor de requisitos sugiere que esto podría funcionar como una solución para prefijo el número de revisión:

var require = {
    baseUrl: "/scripts/buildNumber."
};

No he intentado esto, pero la implicación es que esto solicitaría la siguiente URL:

http://yourserver.com/scripts/buildNumber.myModule.js

Lo que podría funcionar muy bien para muchas personas que pueden usar un prefijo.

Aquí hay algunas preguntas duplicadas posibles:

Requerir JS y caché de caché

Request.js - ¿Cómo puedo establecer una versión en los módulos requeridos como parte de la URL?

Inspirado por Expirar caché en requerir.js data-main Actualizamos nuestro script de implementación con la siguiente tarea de hormiga:

<target name="deployWebsite">
    <untar src="${temp.dir}/website.tar.gz" dest="${website.dir}" compression="gzip" />       
    <!-- fetch latest buildNumber from build agent -->
    <replace file="${website.dir}/js/main.js" token="@Revision@" value="${buildNumber}" />
</target>

Donde se ve el comienzo de Main.js:

require.config({
    baseUrl: '/js',
    urlArgs: 'bust=@Revision@',
    ...
});

En producción

urlArgs ¡Puede causar problemas!

El autor principal de requirirjs prefiere no usar urlArgs:

Para los activos implementados, prefiero poner la versión o el hash para toda la compilación como directorio de compilación, solo modificar el baseUrl configuración utilizada para el proyecto para usar ese directorio versionado como el baseUrl. Entonces ningún otro archivo cambia y ayuda a evitar Algunos problemas proxy en los que no pueden almacenar una URL con una cadena de consulta.

Mía de estilo.

Sigo este consejo.

En desarrollo

Prefiero usar un servidor que almacena de manera inteligente archivos que puedan cambiar con frecuencia: un servidor que emite Last-Modified y responde a If-Modified-Since con 304 cuando sea apropiado. Incluso un servidor basado en el nodo Rápido Establecer para servir archivos estáticos hace esto directamente en el cuadro. No requiere hacer nada a mi navegador, y no arruina los puntos de descanso.

Tomé este fragmento de Askapache y póngalo en un archivo .conf separado de mi servidor web de Apache local (en mi caso /etc/apache2/others/preventcaching.conf):

<FilesMatch "\.(html|htm|js|css)$">
FileETag None
<ifModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</ifModule>
</FilesMatch>

Para el desarrollo, esto funciona bien sin necesidad de cambiar el código. En cuanto a la producción, podría usar el enfoque de @dvtoever.

Dría rápida para el desarrollo

Para el desarrollo, solo podrías Deshabilite el caché en las herramientas de desarrollo cromado (Deshabilitar el caché de Chrome para el desarrollo del sitio web). La desactivación de caché ocurre solo si el diálogo de herramientas de desarrollo está abierto, por lo que no debe preocuparse por alternar esta opción cada vez que navega regularmente.

Nota: Usando 'urlargs'es la solución adecuada en la producción para que los usuarios obtengan el último código. Pero dificulta la depuración porque Chrome invalida los puntos de interrupción con cada actualización (porque es un archivo 'nuevo' que se sirve cada vez).

No recomiendo usar 'urlargs'Para la explosión de caché con requisitos. Como esto no resuelve el problema por completo. La actualización de una versión NO dará como resultado descargar todos los recursos, a pesar de que solo tiene un solo recurso.

Para manejar este problema, recomiendo usar módulos Grunt como 'FileRev' para crear la revisión no. Además de esto, he escrito una tarea personalizada en Gruntfile para actualizar la revisión que no se requiere.

Si es necesario, puedo compartir el fragmento de código para esta tarea.

Así es como lo hago en Django / Flask (se puede adaptar fácilmente a otros idiomas / sistemas VCS):

En tus config.py (Uso esto en Python3, por lo que es posible que deba ajustar la codificación en Python2)

import subprocess
GIT_HASH = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8')

Luego en tu plantilla:

{% if config.DEBUG %}
     require.config({urlArgs: "bust=" + (new Date().getTime())});
{% else %}
    require.config({urlArgs: "bust=" + {{ config.GIT_HASH|tojson }}});
{% endif %}
  • No requiere un proceso de construcción manual
  • Solo corre git rev-parse HEAD Una vez, cuando la aplicación comienza y la almacena en el config objeto

Solución dinámica (sin Urlargs)

Hay una solución simple para este problema, para que pueda cargar un número de revisión único para cada módulo.

Puede guardar la función de requisito de necesidad original, sobrescribirla con su propia función y analizar su URL modificada con el INSEXITOR original.LOAD nuevamente:

var load = requirejs.load;
requirejs.load = function (context, moduleId, url) {
    url += "?v=" + oRevision[moduleId];
    load(context, moduleId, url);
};

En nuestro proceso de construcción, utilicé "Gulp-Rev" para construir un archivo manifiesto con toda la revisión de todos los módulos que se usan. Versión simplificada de mi tarea Gulp:

gulp.task('gulp-revision', function() {
    var sManifestFileName = 'revision.js';

    return gulp.src(aGulpPaths)
        .pipe(rev())
        .pipe(rev.manifest(sManifestFileName, {
        transformer: {
            stringify: function(a) {
                var oAssetHashes = {};

                for(var k in a) {
                    var key = (k.substr(0, k.length - 3));

                    var sHash = a[k].substr(a[k].indexOf(".") - 10, 10);
                    oAssetHashes[key] = sHash;
                }

                return "define([], function() { return " + JSON.stringify(oAssetHashes) + "; });"
            }
        }
    }))
    .pipe(gulp.dest('./'));
});

Esto generará un módulo AMD con números de revisión a los nombres de modulenos, que se incluye como 'orevisión' en Main.js, donde sobrescribe la función Requestjs.Load como se muestra antes.

Esto se suma a la respuesta aceptada de @Phil McCull.

Utilizo su método, pero también automatizo el proceso creando una plantilla T4 para ejecutar antes de la construcción.

Comandos previos a la construcción:

set textTemplatingPath="%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe"
if %textTemplatingPath%=="\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe" set textTemplatingPath="%CommonProgramFiles%\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe"
%textTemplatingPath% "$(ProjectDir)CacheBuster.tt"

enter image description here

Plantilla T4:

enter image description here

Archivo generado:enter image description here

Almacene en variable antes que require.config.js está cargado:enter image description here

Referencia en request.config.js:

enter image description here

En mi caso, quería cargar el mismo formulario cada vez que hago clic, no quería los cambios que he realizado en el archivo. Puede que no sea relevante para esta publicación exactamente, pero esta podría ser una solución potencial en el lado del cliente sin configurar la configuración para requerir. En lugar de enviar el contenido directamente, puede hacer una copia del archivo requerido y mantener intacto el archivo real.

LoadFile(filePath){
    const file = require(filePath);
    const result = angular.copy(file);
    return result;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top