阻止RequireJScaching所需的脚本

RequireJS似乎在内部做一些caching所需的JavaScript文件。 如果我对所需文件中的一个进行了更改,则必须重命名该文件才能应用更改。

追加版本号作为查询string参数到文件名末尾的常见技巧不能用于requirejs <script src="jsfile.js?v2"></script>

我正在寻找的是防止这个RequireJS所需脚本的内部caching,而不必在每次更新时重命名我的脚本文件的方法。

跨平台解决scheme:

我现在在开发过程中使用urlArgs: "bust=" + (new Date()).getTime()用于自动caching清除, urlArgs: "bust=v2"用于生产的urlArgs: "bust=v2" ,其中我在推出后递增硬编码版本num一个更新的必需脚本。

注意:

@Dustin Getz最近在回答中提到Chrome开发者工具将在debugging过程中抛弃断点,当Javascript文件不断刷新。 一种解决方法是编写debugger; 在代码中触发大多数JavaScriptdebugging器中的断点。

服务器特定解决scheme:

对于适合您的服务器环境(如Node或Apache)的特定解决scheme,请参阅下面的一些答案。

可以将RequireJSconfiguration为将值附加到每个脚本URL以caching清除。

从RequireJS文档( http://requirejs.org/docs/api.html#config ):

urlArgs :额外的查询string参数追加到RequireJS用来获取资源的URL。 当浏览器或服务器configuration不正确时,最有用的方法是caching。

例如,将“v2”附加到所有脚本中:

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

出于开发目的,您可以强制RequireJS通过附加时间戳来绕过caching:

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

不要为此使用urlArgs!

要求脚本加载尊重HTTPcaching头。 (脚本加载了一个dynamic插入的<script> ,这意味着请求看起来就像任何旧的资产被加载。

在正确的HTTP标头中为您的JavaScript资源提供服务,以在开发期间禁用caching。

使用require的urlArgs意味着您设置的任何断点在刷新时不会被保留; 您最终需要在代码中的任何位置放置debugger语句。 坏。 在生产升级过程中,我使用urlArgs作为caching清除资产, 那么我可以设置我的资产永久caching,并保证永远不会有陈旧的资产。

在开发中,我用一个复杂的mockjaxconfiguration来模拟所有的ajax请求,然后我可以用一个10行的python http服务器来closures所有的caching,以javascript-only模式提供我的应用程序。 这已经扩展到一个相当大的“企业”应用程序与数百个宁静的web服务端点。 我们甚至有一个签约的devise师,可以使用我们真实的生产代码库,而不必让他访问我们的后端代码。

urlArgs解决scheme有问题。 不幸的是,你不能控制可能在你和用户的networking浏览器之间的所有代理服务器。 其中一些代理服务器可能会被configuration为在caching文件时忽略URL参数。 如果发生这种情况,您的JS文件的错误版本将被传递给您的用户。

我终于放弃了,并直接将我自己的修复程序实施到require.js中。 如果你愿意修改你的requirejs库的版本,这个解决scheme可能适合你。

你可以在这里看到补丁:

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

一旦添加,你可以在你需要的configuration中做这样的事情:

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

使用您的构build系统或服务器环境来使用修订版本ID /软件版本/最喜欢的颜色replacebuildNumber

使用这样的要求:

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

将导致需要请求此文件:

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

在我们的服务器环境中,我们使用url重写规则去除buildNumber,并提供正确的JS文件。 这样我们实际上不必担心重命名我们所有的JS文件。

该补丁将忽略任何指定协议的脚本,并且不会影响任何非JS文件。

这适用于我的环境,但是我意识到有些用户更喜欢前缀而不是后缀,应该很容易修改我的提交以适合您的需要。

更新:

在拉请求的讨论中,requirejs作者build议这可以作为一个解决scheme来修改数字的前缀:

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

我没有试过这个,但其含义是,这将要求以下url:

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

对于许多可以使用前缀的人来说,这可能效果很好。

这里有一些可能的重复问题:

RequireJS和代理caching

require.js – 如何在需要的模块上设置一个版本作为URL的一部分?

受到require.js data-main上Expirecaching的启发,我们使用以下ant任务更新了部署脚本:

 <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> 

main.js的开头看起来像:

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

在生产中

urlArgs可能会导致问题!

requirejs的主要作者不喜欢使用urlArgs

对于已部署的资产,我倾向于将整个构build的版本或散列作为构build目录,然后修改用于该项目的baseUrlconfiguration,以使用该版本化的目录作为baseUrl 。 然后没有其他文件改变,它有助于避免一些代理问题,他们可能不caching一个URL上的查询string。

[造型我的。]

我遵循这个build议。

开发中

我更喜欢使用智能caching可能经常更改的文件的服务器:发出Last-Modified并响应If-Modified-Since的服务器,并在适当的时候使用304。 即使是一个基于Node的Express服务器来提供静态文件的服务器也是如此。 它不需要对我的浏览器做任何事情,也不会弄乱断点。

我把这个片段从AskApache中拿出来放到我的本地Apache web服务器(在我的例子中是/etc/apache2/others/preventcaching.conf)的一个单独的.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> 

对于开发,这工作正常,不需要更改代码。 至于制作,我可能会使用@ dvtoever的方法。

快速修复开发

对于开发,您可以在Chrome开发工具 ( 禁用Chromecaching进行网站开发 )中禁用caching 。 caching禁用只有在开发工具对话框打开的情况下才会发生,所以您不必担心在每次定期浏览时切换此选项。

注意:使用' urlArgs '是生产中的正确解决scheme,以便用户获得最新的代码。 但是它使debugging变得困难,因为chrome每次刷新都会使断点无效(因为每次都有一个“新”文件被提供)。

我不build议使用' urlArgs '作为RequireJS的caching突发。 因为这不能完全解决问题。 更新版本号将导致下载所有资源,即使您只是更改了单个资源。

为了处理这个问题,我build议使用像“filerev”这样的Grunt模块来创build版本号。 在此之上,我已经写了一个自定义任务Gruntfile来更新修订号码任何地方需要。

如果需要,我可以分享这个任务的代码片段。

这是我在Django / Flask中做的(可以很容易地适应其他语言/ VCS系统):

在你的config.py (我在python3中使用这个,所以你可能需要调整python2中的编码)

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

然后在您的模板中:

 {% if config.DEBUG %} require.config({urlArgs: "bust=" + (new Date().getTime())}); {% else %} require.config({urlArgs: "bust=" + {{ config.GIT_HASH|tojson }}}); {% endif %} 
  • 不需要手动构build过程
  • 只有在应用程序启动时才运行git rev-parse HEAD ,并将其存储在config对象中

这个问题有一个简单的解决scheme,所以你可以为每个模块加载唯一的版本号。

你可以保存原始的requirejs.load函数,用你自己的函数覆盖它,并再次将你的修改后的urlparsing为原始的requirejs.load:

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

在我们的构build过程中,我使用“gulp-rev”来构build一个清单文件,其中包含所有正在使用的模块的所有修订版本。 我的大嘴巴任务的简化版本:

 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('./')); }); 

这将生成一个带修订号的AMD模块到moduleNames,它被包含在main.js中的“oRevision”中,在这里覆盖了前面所示的requirejs.load函数。

嗯,那requirejs.undef呢?

https://groups.google.com/forum/#!topic/requirejs/gq4bX8u6lPU

来自James Burke本人,RequireJS的作者:

确保使用requirejs 2.0,然后在重新定义mod2之前使用requirejs.undef()函数取消定义mod2:

http://requirejs.org/docs/api.html#undef

詹姆士

这是@ phil mccull接受的答案。

我使用他的方法,但我也通过创build一个T4模板来运行预生成自动化的过程。

预生成命令:

 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" 

在这里输入图像说明

T4模板:

在这里输入图像说明

生成的文件: 在这里输入图像说明

在require.config.js加载之前存储在variables中: 在这里输入图像说明

在require.config.js中引用:

在这里输入图像说明

在我的情况下,我想每次点击时加载相同的表单,我不希望我对文件所做的更改保持不变。 这可能与这篇文章无关,但是这可能是客户端的一个潜在的解决scheme,而不需要设置configuration。 不要直接发送内容,您可以制作所需文件的副本,并保持实际文件不变。

 LoadFile(filePath){ const file = require(filePath); const result = angular.copy(file); return result; }