似乎是突然之间,我为这个网站设置的 Gulp 处理开始出现竞争条件。我运行我的 watch
命令,更改一些 CSS,处理有时会留下一些应该在处理过程中清理的额外文件。就像清理任务在文件进入文件系统之前就发生了(或者其他事情...我从来没有真正弄明白)。
不用管那个错误的细节。我认为我会通过升级到使用 Gulp 4.x 而不是 3.x 来解决它,并在内置的 gulp.series
命令中运行它们,我认为这会有所帮助(确实如此)。
让我使用 Gulp 4.x 真是个不小的挑战,我放弃了一整年,然后重新燃起斗争,最终修复了它。我的问题是 Gulp 4 需要 2.x 版本的 CLI,而 Gulp 3 由于某种原因使用了 3.x 版本。实际上,我需要将版本 *降级*,但是尝试了无数方法,却似乎什么也行不通,就好像我的机器上有一个 CLI 3.x 的幽灵版本。
我相信那些更熟悉命令行的人会比我更快地找到答案,但事实证明,运行 command -v gulp
会显示 Gulp 安装位置的文件路径,对我来说,它显示的是 /usr/local/share/npm/bin/gulp
,手动删除它,然后重新安装最新版本,就可以让我降级到 2.x。
现在我可以用 Gulp 4.x 了,我将我的 gulpfile.js 重写为更小的函数,每个函数的职责都比较独立。其中很多 *非常适合我的设置*,所以它并不意味着要成为通用使用的样板代码。我只是发布它,因为在创建它的时候,如果我能参考它,肯定会很有帮助。
我的 Gulpfile 做了什么
- 运行一个 Web 服务器(Browsersync)用于样式注入和自动刷新
- 运行一个文件监视器(Gulp 的原生功能)用于对正确文件运行正确任务并执行上述操作
- CSS 处理
- Sass > Autoprefixer > 压缩
- 从模板中中断样式表缓存(例如
<link href="style.css?BREAK_CACHE">
) - 将 style.css 放在 WordPress 主题的正确位置,并清理仅在处理期间需要的文件
- JavaScript 处理
- Babel > 合并 > 压缩
- 中断
<script>
的浏览器缓存 - 清理处理中创建的未使用的文件
- SVG 处理
- 创建一个 SVG 精灵(
<symbol>
块) - 将其命名为 sprite.php 文件(以便它可以被 PHP 包含在模板中)并将其放在特定位置
- 创建一个 SVG 精灵(
- PHP 处理
- 更新 JavaScript 中的 Ajax 调用,以便在广告更改时清除缓存
代码转储!
const gulp = require("gulp"),
browserSync = require("browser-sync").create(),
sass = require("gulp-sass"),
postcss = require("gulp-postcss"),
autoprefixer = require("autoprefixer"),
cssnano = require("cssnano"),
del = require("del"),
babel = require("gulp-babel"),
minify = require("gulp-minify"),
concat = require("gulp-concat"),
rename = require("gulp-rename"),
replace = require("gulp-replace"),
svgSymbols = require("gulp-svg-symbols"),
svgmin = require("gulp-svgmin");
const paths = {
styles: {
src: ["./scss/*.scss", "./art-direction/*.scss"],
dest: "./css/"
},
scripts: {
src: ["./js/*.js", "./js/libs/*.js", "!./js/min/*.js"],
dest: "./js/min"
},
svg: {
src: "./icons/*.svg"
},
php: {
src: ["./*.php", "./ads/*.php", "./art-direction/*.php", "./parts/**/*.php"]
},
ads: {
src: "./ads/*.php"
}
};
/* STYLES */
function doStyles(done) {
return gulp.series(style, moveMainStyle, deleteOldMainStyle, done => {
cacheBust("./header.php", "./");
done();
})(done);
}
function style() {
return gulp
.src(paths.styles.src)
.pipe(sass())
.on("error", sass.logError)
.pipe(postcss([autoprefixer(), cssnano()]))
.pipe(gulp.dest(paths.styles.dest))
.pipe(browserSync.stream());
}
function moveMainStyle() {
return gulp.src("./css/style.css").pipe(gulp.dest("./"));
}
function deleteOldMainStyle() {
return del("./css/style.css");
}
/* END STYLES */
/* SCRIPTS */
function doScripts(done) {
return gulp.series(
preprocessJs,
concatJs,
minifyJs,
deleteArtifactJs,
reload,
done => {
cacheBust("./parts/footer-scripts.php", "./parts/");
done();
}
)(done);
}
function preprocessJs() {
return gulp
.src(paths.scripts.src)
.pipe(
babel({
presets: ["@babel/env"],
plugins: ["@babel/plugin-proposal-class-properties"]
})
)
.pipe(gulp.dest("./js/babel/"));
}
function concatJs() {
return gulp
.src([
"js/libs/jquery.lazy.js",
"js/libs/jquery.fitvids.js",
"js/libs/jquery.resizable.js",
"js/libs/prism.js",
"js/babel/highlighting-fixes.js",
"js/babel/global.js"
])
.pipe(concat("global-concat.js"))
.pipe(gulp.dest("./js/concat/"));
}
function minifyJs() {
return gulp
.src(["./js/babel/*.js", "./js/concat/*.js"])
.pipe(
minify({
ext: {
src: ".js",
min: ".min.js"
}
})
)
.pipe(gulp.dest(paths.scripts.dest));
}
function deleteArtifactJs() {
return del([
"./js/babel",
"./js/concat",
"./js/min/*.js",
"!./js/min/*.min.js"
]);
}
/* END SCRIPTS */
/* SVG */
function doSvg() {
return gulp
.src(paths.svg.src)
.pipe(svgmin())
.pipe(
svgSymbols({
templates: ["default-svg"],
svgAttrs: {
width: 0,
height: 0,
display: "none"
}
})
)
.pipe(rename("icons/sprite/icons.php"))
.pipe(gulp.dest("./"));
}
/* END SVG */
/* GENERIC THINGS */
function cacheBust(src, dest) {
var cbString = new Date().getTime();
return gulp
.src(src)
.pipe(
replace(/cache_bust=\d+/g, function() {
return "cache_bust=" + cbString;
})
)
.pipe(gulp.dest(dest));
}
function reload(done) {
browserSync.reload();
done();
}
function watch() {
browserSync.init({
proxy: "csstricks.local"
});
gulp.watch(paths.styles.src, doStyles);
gulp.watch(paths.scripts.src, doScripts);
gulp.watch(paths.svg.src, doSvg);
gulp.watch(paths.php.src, reload);
gulp.watch(paths.ads.src, done => {
cacheBust("./js/global.js", "./js/");
done();
});
}
gulp.task("default", watch);
问题 / 疑问
- 最糟糕的是它没有非常智能地中断缓存。当 CSS 更改时,它会中断所有样式表的缓存,而不仅仅是相关的样式表。
- 将来我可能会使用 PHP
include()
将 SVG 图标内联,而不是处理精灵图。 - 如果原始 SVG 具有
width
和height
属性,则 SVG 处理程序会中断,这似乎是错误的。 - gulp-changed 会加快速度吗?也就是说,只查看已更改的文件而不是所有文件?还是现在不再需要了?
- 我应该在 gulpfile.js 更改时 重新启动 gulp 吗?
- 如果我使用所有库都与 ES6 兼容,这样我就可以
import
内容,而不是手动合并,那就太好了。
总是还有很多事情可以做。理想情况下,我会开源整个网站,但我还没有做到。
我们的 gulp 文件实际上非常相似,除了缓存清除。由于我们在 php(wordpress)中排队加载脚本和样式,因此我们只需将文件修改时间戳作为缓存清除器添加。效果很好,缓存只会在文件实际更改时才会清除。
wp 排队加载函数以 $ver 作为第四个参数,如下所示
wp_enqueue_style( 'handle', './pathtofile/style.css', 'dep', filetime('./pathtofile/style.css') );
啊,应该说明一下,第二个排队加载参数是文件的 URL,filetime 函数是文件的系统路径。
我想,假设对于服务器来说,每次请求都计算
filetime()
很简单?我还不够了解服务器方面的知识。兄弟,我不得不告诉你,gulp-cli 还没有发布 3.0 版本(虽然它已经发布了 0.3.0 版本)。
但是,cli 甚至不是必需的。
它所做的就是允许您通过全局调用来运行本地(节点模块或其他)版本的 gulp(在正确的项目中),从而允许不同的项目使用不同的 gulp 版本,但只有一个全局 gulp。
filetime()
非常巧妙,Jakob。它似乎非常高效,对于少量文件来说可能可以忽略不计。对于在生产环境中不太常更改的网站,更细粒度的方法是追加主题版本:
wp_get_theme()->get('Version')
。这样做的额外好处是,它迫使我们始终更新数字 :)。我想出了更通用、更终极的解决方案
https://gist.github.com/marsjaninzmarsa/038ce27f1e76b90edd5773532e48520b
针对您的 gulp 缓存清除,可以采用类似的方法。它会在每次构建中计算过滤器中的所有内容,但只有在文件更改时才会更新哈希。
// 安装 gulp-rev、gulp-rev-replace
var revisionFilter = gulp.filter([‘/*’, ‘!/index.html’], { restore: true });
gulp.src(…)
.pipe(revisionFilter)
.pipe(gulp.rev()) // 计算文件的哈希值
.pipe(revisionFilter.restore)
我使用 ‘gulp-rev’ 来进行基于内容哈希的版本控制,这样可以确保在文件实际更改之前,版本保持不变。由于我们项目的结构(输出许多针对不同主题的 css 文件,这些主题可以在我们的 CMS 中选择),然后我们使用它来生成一个清单,以获取后端代码的所有文件名。也就是说,我还没有在 Gulp 4 中尝试过。由于 Gulp 3 在最新版本的 Node 中无法正常工作,因此我们需要尽快克服这个障碍。
我只想补充一下关于
gulp-rev
的两分钱 - 我已经使用它很多年了,并取得了巨大的成功,它与gulp-rev-rewrite
和gulp-rev-delete-original
搭配使用。Zach - 我在 Gulp 4 中没有遇到任何问题 :)
我同样也制作了一个 Gulp 4 文件,它已公开发布 https://github.com/jenstornell/gulpfile-style-script。我的仓库的一个好处是,您可以通过在 cmd 中复制粘贴一行代码来安装它。
我非常喜欢 gulp-load-plugins。它基本上可以让您跳过顶部的大部分必需内容。
let $ = require('gulp-load-plugins')();
然后,在您需要任何东西时,例如 autoprefixer
.pipe($.autoprefixer())
它会自动从您的 package.json 中获取它。
啊,之前没有注意到
不幸的是,我在 gulp + wordpress + browser-sync 中遇到了问题。
Gulp 经常崩溃。
我将所有内容重写为 webpack,现在工作正常了。
为了实现这一点,整个环境都在 Docker 容器中运行,并带有用于 wordpress 的 xdebug。
js / css 文件中的每次更改都会创建单独的哈希文件。
这些文件会动态加载到 php 中。
CSS 以内联形式提供,因为每个子页面都有自己的 css 和 js,所以不存在大小问题。
如果有人感兴趣,那么我推荐 https://github.com/tomik23/docker-wordpress-xdebug
当然,模板本身很简陋,这是一个精简版本,仅供参考。
哇,我最近的 gulp 工作流程与你的非常相似
我的工作流程中只缺少与 php 相关的任务
为了防止缓存失效,我使用了当前日期和时间,并使用正则表达式在 html 文件中替换它
为了避免因文件更改而必须重启 gulp,我实现了以下两件事
– 在 BrowserSync 配置中添加
watchEvents: [ 'change', 'add', 'unlink', 'addDir', 'unlinkDir' ]
。– gulp-include,这样我就不必在 gulp 文件中定义 JS 的源文件,并根据其在
./src/
目录中的位置来连接和构建不同的文件。如果您有兴趣,这里有一个带有完整 gulp 设置的 gist。
我正在从 sass-lint 转向stylelint,因为 sass-lint 已经不再维护了。
迷你 Gulp 相关链接集...
2019 年 11 月 - Kieran Barker 的如何使用 gulp 压缩 JavaScript 和 CSS 文件
2019 年 12 月 - Ethan Marcottes 的设置
2019 年 12 月 - Jason Pamental 的设置