requirejs似乎在内部做一些缓存需要JavaScript文件的事情。如果我更改所需的文件之一,则必须重命名该文件才能应用更改。

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

我正在寻找的是一种防止requirejs必需脚本的内部缓存的方法,而无需每次更新我的脚本文件。

跨平台解决方案:

我现在正在使用 urlArgs: "bust=" + (new Date()).getTime() 用于开发过程中自动缓存和 urlArgs: "bust=v2" 对于生产,在推出更新的必需脚本后,我会增加硬编码版本的数字。

笔记:

@Dustin Getz在最近的答案中提到,Chrome Developer工具将在JavaScript文件不断刷新时在调试期间放置断点。一个解决方法是写 debugger; 在大多数JavaScript调试者中触发断点的代码中。

服务器特定的解决方案:

有关可能对您的服务器环境(例如节点或Apache)更有效的特定解决方案,请参见下面的一些答案。

有帮助吗?

解决方案

可以配置requirejs,以将每个脚本URL的值附加到缓存破坏的脚本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>, ,这意味着该请求看起来就像加载的任何旧资产一样。)

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

使用requient的urlargs意味着您设置的任何断点都不会在刷新过程中保存;你最终需要放 debugger 您的代码中到处都是语句。坏的。我用 urlArgs 用于使用Git SHA生产升级期间的缓存资产;然后,我可以将自己的资产永久缓存,并保证永远不会拥有陈旧的资产。

在开发中,我用复杂的 无知 配置,然后我可以在仅JavaScript模式下使用我的应用 10行Python HTTP服务器都关闭了所有缓存. 。这为我扩展到了一个很大的“企业”应用程序,并具有数百个Restful Web服务端点。我们甚至有一个合同的设计师,他可以与我们的真实生产代码库一起工作,而无需让他访问我们的后端代码。

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

我终于放弃了 实施了我自己的修复 直接进入require.js。如果您愿意修改requirejs库的版本,则此解决方案可能对您有用。

您可以在这里看到补丁:

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

添加后,您可以在您的需求配置中执行类似的操作:

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

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

使用这样的需要:

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

将导致要求请求此文件:

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

在我们的服务器环境上,我们使用URL重写规则来剥离构建名称,并提供正确的JS文件。这样,我们实际上不必担心重命名所有JS文件。

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

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

更新:

在拉的请求讨论中,requirejs作者建议这可以作为解决方案的解决方案。

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

我没有尝试过,但是这意味着这会请求以下URL:

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

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

这是一些可能的重复问题:

requirejs和代理缓存

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

受到启发 在require.js data-main上过期缓存 我们通过以下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缓存URL。

造型地雷。

我遵循这个建议。

开发中

我更喜欢使用智能缓存可能经常更改的文件的服务器:发射的服务器 Last-Modified 并回应 If-Modified-Since 在适当的情况下使用304。甚至基于节点的服务器 表示 设置为静态文件提供的功能将其直接解决。它不需要对我的浏览器做任何事情,也不会弄乱断点。

我从 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 Dev工具中的缓存 (禁用网站开发的Chrome Cache)。缓存禁用仅在打开“开发工具对话框”时才发生,因此您不必担心每次定期浏览时都会切换此选项。

注意:使用'urlargs'是生产中适当的解决方案,因此用户获得了最新的代码。但这使调试变得困难,因为Chrome无效每个刷新(因为它每次都会提供一个“新”文件)。

我不建议使用'urlargs'对于用requirejs爆发的缓存。因为这不能完全解决问题。更新版本否将导致下载所有资源,即使您只需更改单个资源。

为了处理此问题,我建议使用诸如“ Filerev”之类的grunt模块来创建修订版。最重要的是,我已经在Gruntfile中编写了一个自定义任务,以更新任何需要的修订。

如果需要,我可以为此任务共享代码段。

这就是我在django /烧瓶中进行操作的方式(很容易适应其他语言 / 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.s.load功能,用自己的功能覆盖它,然后将修改后的URL解析为原始requirejs.s.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”包含在其中,您可以在其中覆盖requienjs.s.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"

enter image description here

T4模板:

enter image description here

生成的文件:enter image description here

加载config.js之前的变量存储:enter image description here

参考require.config.js:

enter image description here

就我而言,每次点击时,我都想加载相同的表格,我不希望我在文件停留上所做的更改。它可能与此帖子完全无关,但这可能是客户端的潜在解决方案,而无需设置Conforion。您可以制作所需文件的副本并保持实际文件完整,而不是直接发送内容。

LoadFile(filePath){
    const file = require(filePath);
    const result = angular.copy(file);
    return result;
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top