若谷学院
互联网公司技术架构分享

9.WordPress:如何正确管理静态资源文件的版本号

WordPress的静态资源版本号: 我应该删除版本号吗?

WordPress默认情况下,会在CSS/JS静态资源的URL后面加上版本号,比如 domain.com/style.css?ver=4.6. 一些服务和代理服务器无法缓存带有查询字符串的请求。使用Google PageSpeedPingdomGTMetrix之类的工具评测页面性能时,会提示“Remove query strings from static resources.”
删除静态资源文件中的查询字符串
在升级插件的版本时,静态资源版本号自动升级。比如 style.css 从 ?ver=4.6 升级到 ?ver=4.7。
 

删除静态资源文件名中Query String的错误做法

如果按照PageSpeed评测工具的建议,直接删除文件名后的Query String,会带来新的问题:在版本升级时,或者静态资源文件的内容发生变化时,客户端可能会由于浏览器上的页面缓存而没有更新静态资源文件,也可能由于CDN上的静态资源文件,客户端看到的文件是旧的。 实际上很多为了提高PageSpeed评分的插件,都使用了错误的方法,这些插件直接删除了 URL后面带有的版本号,比如 ?ver=4.7。
 

正确处理WordPress的静态资源版本号:整体思路

为了确保服务器/CDN能够正确缓存静态资源文件,文件名后面不应该带有查询字符串的版本号;
同时为了确保静态资源文件能够正确更新,我们又需要做静态资源的版本管理,正确的做法是使用文件内容的Hash值作为文件名,比如使用postratings-js-830dae7fb9.js替换掉postratings-js.js作为静态资源文件名。
那么如何做到这一点呢?
 
我们可以通过两个步骤来实现:
1.使用Gulp来做静态资源文件的处理,为CSS/JS文件生成对应的带有Hash摘要的目标文件名,同时把文件内容复制到目标文件中。
2.然后在页面内容渲染时,使用生成的文件名(这一步骤可以在插件中实现)
 
正确处理WordPress的静态资源版本号:操作步骤

1.安装node

curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash –
sudo apt-get install -y nodejs
 
 

2.安装gulp-rev

npm init .
npm install –save-dev gulp
npm install –save-dev gulp-rev
npm install –save-dev merge-stream
 

3.配置Gulpfile

参考:https://github.com/sindresorhus/gulp-rev
# 切换到WordPress根目录,创建文件gulpfile.js
$ cd /data/www  
$ vim gulpfile.js
const gulp = require(‘gulp’);
const rev = require(‘gulp-rev’);
 
gulp.task(‘default’, () =>
        // by default, gulp would pick `assets/css` as the base,
        // so we need to set it explicitly:
        gulp.src([‘wp-includes/**/*.css’, ‘wp-includes/**/*.js’, ‘wp-content/**/*.css’, ‘wp-content/**/*.js’], {base: ‘.’})
                .pipe(gulp.dest(‘assets’))  // copy original assets to assets dir
                .pipe(rev())
                .pipe(gulp.dest(‘assets’))  // write rev’d assets to assets dir
                .pipe(rev.manifest())
                .pipe(gulp.dest(‘assets’))  // write manifest to assets dir
);
 
assets/rev-manifest.json文件的内容是JSON的hash map。
生成的js, css文件拷贝到WordPress根目录的assets目录下。
 

4.运行gulp生成文件

node ../node_modules/gulp/bin/gulp.js
运行gulp命令来读取gulpfile.js,扫描处理静态资源文件,生成带有hash摘要的文件名,并复制文件。
 
步骤5,6,7做完后,发现页面少了字体。
有css文件中用相对路径引用了ttf, woff字体文件,因此需要在gulpfile.js中把字体文件也复制到assets目录,以下是gulpfile.js的升级版本:
const gulp = require(‘gulp’);
const rev = require(‘gulp-rev’);
var merge = require(‘merge-stream’);
 
gulp.task(‘default’, function() {
        // by default, gulp would pick `assets/css` as the base,
        // so we need to set it explicitly:
        var js_cs = gulp.src([‘wp-includes/**/*.css’, ‘wp-includes/**/*.js’, ‘wp-content/**/*.css’, ‘wp-content/**/*.js’], {base: ‘.’})
                .pipe(gulp.dest(‘assets’))  // copy original assets to assets dir
                .pipe(rev())
                .pipe(gulp.dest(‘assets’))  // write rev’d assets to assets dir
                .pipe(rev.manifest())
                .pipe(gulp.dest(‘assets’));  // write manifest to assets dir
        var fonts = gulp.src([‘wp-includes/**/*.ttf’, ‘wp-content/**/*.png’, ‘wp-content/**/*.ttf’, ‘wp-content/**/*.woff’], {base: ‘.’})
                .pipe(gulp.dest(‘assets’));  // write rev’d assets to assets dir
        return merge(js_cs,fonts);
        }
);
 
未来每次有插件升级,或者新插件时,运行这个步骤的node命令来重新生成文件。
 

5.替换WP中的静态资源文件路径

在插件  remove-query-string-correctly 的 php文件中加上代码。
plugins# vim remove-query-string-correctly/remove-query-string-correctly.php
/**
* Get cache-busting hashed filename from rev-manifest.json.
*
* @param  string $filename Original name of the file.
* @return string Current cache-busting hashed name of the file.
*/
function get_asset_path( $filename ) {
 
    // Cache the decoded manifest so that we only read it in once.
    static $manifest = null;
    if ( null === $manifest ) {
        $dir_name = dirname(dirname(dirname(get_template_directory())));
        $manifest_path =  $dir_name. ‘/assets/rev-manifest.json’;
        $manifest = file_exists( $manifest_path )
            ? json_decode( file_get_contents( $manifest_path ), true )
            : [];
    }
 
    // If the manifest contains the requested file, return the hashed name.
    if ( array_key_exists( $filename, $manifest ) ) {
        return ‘assets/’ . $manifest[ $filename ];
    }
 
    return $filename;
}
 
//删除文件名后面的查询字符串,并使用文件名中带有Content Hash的文件。
function rm_query_string_correctly( $src ){
        $parts = explode( ‘?ver’, $src );
 
        //write_log(“src=”.$parts[0].” size of exploded array:”.sizeof($parts));
        $url = $parts[0];
        $pos_content = strpos($url,’wp-content’);
        $pos_includes = strpos($url,’wp-includes’);
        if( $pos_content || $pos_includes ){
                $pos = $pos_content ? $pos_content : $pos_includes;
                $relative_path = substr($url, $pos);
                $path = substr($url,0,$pos).get_asset_path($relative_path);
                //write_log(“relative path:”.$relative_path.” path:”.$path);
                return $path;
        }
        return $parts[0];
}
 
// Don’t touch admin scripts
if ( !is_admin() ) {
            add_filter( ‘script_loader_src’, ‘rm_query_string_correctly’, 15, 1 );
            add_filter( ‘style_loader_src’, ‘rm_query_string_correctly’, 15, 1 );
}
 

6.CDN的配置更新,把assets目录配置成走CDN (可选,看站点是否启用CDN)

由于包含Hash值版本号的文件在assets目录。
记得在CDN配置的包含路径中加上assets目录,这样会自动使用CDN。

7.页面访问,查看页面源码看到的效果

如下图,JS文件名中有了Hash摘要的版本号。
 

 

全球互联网技术架构,前沿架构参考

联系我们博客/网站内容提交