防止RequireJS缓存所需的脚本

2020/10/04 16:01 · javascript ·  · 0评论

RequireJS似乎在内部做了一些缓存所需的javascript文件的操作。如果我更改了所需的文件之一,则必须重命名文件才能应用更改。

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

我正在寻找的是一种防止RequireJS必需脚本在内部进行缓存的方法,而不必在每次更新脚本文件时都对其重命名。

跨平台解决方案:

现在,我用于urlArgs: "bust=" + (new Date()).getTime()开发和urlArgs: "bust=v2"生产期间的自动缓存清除,在部署更新的必需脚本后,我增加了硬编码的版本号。

注意:

@Dustin Getz在最近的回答中提到,当像这样不断刷新Javascript文件时,Chrome开发者工具会在调试过程中删除断点。一种解决方法是debugger;在大多数Javascript调试器中编写代码以触发断点。

服务器特定的解决方案:

有关可能更适合您的服务器环境(例如Node或Apache)的特定解决方案,请参阅以下一些答案。

可以将RequireJS配置为向每个脚本URL附加一个值以进行缓存清除。

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

urlArgs:附加到RequireJS用于获取资源的URL的额外查询字符串参数。当浏览器或服务器配置不正确时,最有用的方法是缓存崩溃。

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

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

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

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

不要为此使用urlArgs!

要求脚本加载遵守http缓存标头。(脚本加载时带有动态插入的<script>,这意味着请求看起来就像正在加载的任何旧资产一样。)

使用适当的HTTP标头为您的JavaScript资产提供服务,以在开发过程中禁用缓存。

使用require的urlArgs意味着您设置的任何断点将不会在刷新之间保留;您最终需要将debugger语句放在代码的任何地方。坏。我在使用urlArgsgit sha进行生产升级时用于破坏缓存的资产;然后我可以将资产设置为永久缓存,并保证永远不会过时的资产。

在开发中,我使用复杂的mockjax配置模拟所有ajax请求,然后可以使用JavaScript模式在10行python http服务器(关闭所有缓存)的情况下为我的应用提供服务对于我来说,这已经扩展到具有数百个宁静的Web服务端点的相当大的“ enterprisey”应用程序。我们甚至有一个签约设计师,他可以使用我们的实际生产代码库,而无需授予他访问我们的后端代码的权限。

urlArgs解决方案有问题。不幸的是,您无法控制您和用户的Web浏览器之间的所有代理服务器。不幸的是,其中一些代理服务器可以配置为在缓存文件时忽略URL参数。如果发生这种情况,则会将错误版本的JS文件发送给您的用户。

我最终放弃了,并将自己的修复程序直接实现到require.js中。如果您愿意修改requirejs库的版本,则此解决方案可能适用。

您可以在此处查看补丁:

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

添加后,您可以在require config中执行以下操作:

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

使用您的构建系统或服务器环境,buildNumber用版本ID /软件版本/喜欢的颜色替换

这样使用require:

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

将导致要求请求此文件:

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

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

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

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

更新:

在请求请求讨论中,requirejs作者建议这可以作为为修订版本号加上前缀的解决方案:

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

我没有尝试过,但这意味着这将要求以下URL:

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

对于许多可以使用前缀的人来说,这可能会非常有效。

以下是一些可能重复的问题:

RequireJS和代理缓存

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

require.js数据主体上Expire缓存的启发,我们使用以下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

对于已部署的资产,我更喜欢将整个构建的版本或哈希作为构建目录,然后只需修改baseUrl用于项目配置以将该版本目录用作即可baseUrl然后,其他文件没有更改,这有助于避免某些代理问题,因为它们可能不会缓存带有查询字符串的URL。

[造型我的]

我遵循这个建议。

开发中

我更喜欢使用智能缓存可能经常更改的文件的服务器:在适当时发出Last-Modified并响应If-Modified-Since304的服务器即使是基于Node的快速服务器来提供静态文件的服务器,也可以做到这一点。它不需要对我的浏览器做任何事情,也不会弄乱断点。

我从AskApache提取了此代码片段,并将其放入本地Apache Web服务器的单独.conf文件中(在我的情况下为/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>

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

快速修复开发

为了发展,你可以只禁用Chrome开发工具中的缓存禁用浏览器缓存网站开发)。仅当打开“开发工具”对话框时才会禁用缓存,因此您不必担心每次进行常规浏览时都会切换此选项。

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

我不建议对RequireJS使用“ urlArgs ”进行缓存爆发。因为这不能完全解决问题。更新版本no将导致下载所有资源,即使您仅更改单个资源也是如此。

为了解决这个问题,我建议使用Grunt模块(例如“ filerev”)来创建版本号。在此之上,我在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 %}
  • 不需要手动构建过程
  • git rev-parse HEAD应用启动时仅运行一次,并将其存储在config对象中

动态解决方案(无urlArgs)

有一个针对此问题的简单解决方案,因此您可以为每个模块加载唯一的修订号。

您可以保存原始的requirejs.load函数,用自己的函数覆盖它,然后将修改后的url再次解析为原始的requirejs.load:

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

在我们的构建过程中,我使用“ gulp-rev”构建了清单文件,其中包含了所使用的所有模块的所有修订版。我的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('./'));
});

这将生成一个带有模块名修订号的AMD模块,该模块在main.js中包含为“ oRevision”,您可以在其中覆盖如前所示的requirejs.load函数。

除了@phil mccull接受的答案之外。

我使用他的方法,但是我还通过创建要在构建前运行的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加载之前存储在变量中:
在此处输入图片说明

在require.config.js中的参考:

在此处输入图片说明

就我而言,我希望每次单击时都加载相同的表单,但我不希望保留对文件所做的更改。这可能与本帖子不完全相关,但是如果没有为require设置配置,这可能是客户端上的潜在解决方案。您可以直接复制所需文件,而无需保留直接发送内容的方式,而是保留实际文件的完整性。

LoadFile(filePath){
    const file = require(filePath);
    const result = angular.copy(file);
    return result;
}
本文地址:http://javascript.askforanswer.com/fangzhirequirejshuancunsuoxudejiaoben.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!