Gulp.js中allowEmpty:true不生效,useref误识别Thymeleaf属性报错
问题:Gulp-useref误处理Thymeleaf的th:src/th:href属性导致文件找不到错误
我的Gulp HTML处理任务代码
// HTML function html(callback) { return src([paths.src.html, '!./src/partials/**/*']) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(replace(/[^(th:src)]src="(.{0,10})node_modules/g, 'src="$1assets/libs')) .pipe(replace(/[^(th:href)]href="(.{0,10})node_modules/g, 'href="$1assets/libs')) .pipe(useref()) .pipe(replace(/[^(th:href)]href=".//g, 'href="')) .pipe(replace(/[^(th:href)]href="(.{0,14})assets/g, 'href="../$1static/assets')) .pipe(replace(/[^(th:src)]src=".//g, 'src="')) .pipe(replace(/[^(th:src)]src="(.{0,14})assets/g, 'src="../$1static/assets')) .pipe(cached()) .pipe(dest(paths.dist.html)) .pipe(browsersync.stream()); callback(); }
对应的HTML文件内容
<!-- Libs JS --> <script th:src="@{/assets/libs/jquery/dist/jquery.min.js}" src="@@webRoot/node_modules/jquery/dist/jquery.min.js"></script> <script th:src="@{/assets/libs/bootstrap/dist/js/bootstrap.bundle.min.js}" src="@@webRoot/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script> <script th:src="@{/assets/libs/simplebar/dist/simplebar.min.js}" src="@@webRoot/node_modules/simplebar/dist/simplebar.min.js"></script> <!-- Theme JS --> <!-- build:js @@webRoot/assets/js/theme.min.js --> <script th:src="@{/assets/js/main.js}" src="@@webRoot/assets/js/main.js"></script> <script th:src="@{/assets/js/darkMode.js}" src="@@webRoot/assets/js/darkMode.js"></script> <!-- endbuild -->
错误信息
Gulp-useref会误将Thymeleaf的th:src/th:href属性中的值当作资源路径解析,抛出文件找不到的错误:
[22:04:16] 'html' errored after 139 ms [22:04:16] Error: Error: File not found with singular glob: C:\project_folder\src\@{/assets/css/theme.css} (if this was purposeful, use `allowEmpty` option) at DestroyableTransform.<anonymous> (C:\project_folder\node_modules\gulp-useref\index.js:63:32) at DestroyableTransform.emit (node:events:513:28) at DestroyableTransform.emit (node:domain:489:12) at Pumpify.emit (node:events:513:28) at Pumpify.emit (node:domain:489:12) at Pumpify.Duplexify._destroy (C:\project_folder\node_modules\duplexify\index.js:191:15) at C:\project_folder\node_modules\duplexify\index.js:182:10 at processTicksAndRejections (node:internal/process/task_queues:78:11) [22:04:16] 'build' errored after 158 ms
已尝试的无效操作
在src()方法中添加allowEmpty:true参数,问题未解决:
src([paths.src.html, '!./src/partials/**/*'],{allowEmpty:true})...
解决方案
方案1:通过useref的transform临时替换Thymeleaf属性
利用useref提供的transform选项,先将Thymeleaf的th:src/th:href替换为临时标识,避免useref解析,处理完成后再恢复原属性:
function html(callback) { return src([paths.src.html, '!./src/partials/**/*']) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) // 修正原replace正则(原正则写法错误,改用负向前瞻匹配非Thymeleaf属性) .pipe(replace(/(?!th:)src="(.{0,10})node_modules/g, 'src="$1assets/libs')) .pipe(replace(/(?!th:)href="(.{0,10})node_modules/g, 'href="$1assets/libs')) // 配置useref的transform处理逻辑 .pipe(useref({ transform: function(content, target, options, alternate) { // 临时替换Thymeleaf属性,避免useref解析 content = content.replace(/th:src="([^&]+)"/g, 'temp-th-src="$1"'); content = content.replace(/th:href="([^&]+)"/g, 'temp-th-href="$1"'); // 调用useref默认处理逻辑 content = require('gulp-useref/lib/transform')(content, target, options, alternate); // 恢复Thymeleaf原属性 content = content.replace(/temp-th-src="([^&]+)"/g, 'th:src="$1"'); content = content.replace(/temp-th-href="([^&]+)"/g, 'th:href="$1"'); return content; } })) // 后续replace同样修正正则写法 .pipe(replace(/(?!th:)href=".//g, 'href="')) .pipe(replace(/(?!th:)href="(.{0,14})assets/g, 'href="../$1static/assets')) .pipe(replace(/(?!th:)src=".//g, 'src="')) .pipe(replace(/(?!th:)src="(.{0,14})assets/g, 'src="../$1static/assets')) .pipe(cached()) .pipe(dest(paths.dist.html)) .pipe(browsersync.stream()); callback(); }
方案2:提前隐藏Thymeleaf属性,处理后恢复
在useref处理前,将th:src/th:href注释掉,useref处理完成后再取消注释:
function html(callback) { return src([paths.src.html, '!./src/partials/**/*']) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(replace(/(?!th:)src="(.{0,10})node_modules/g, 'src="$1assets/libs')) .pipe(replace(/(?!th:)href="(.{0,10})node_modules/g, 'href="$1assets/libs')) // 注释Thymeleaf属性,避免useref识别 .pipe(replace(/(th:src|th:href)=/g, '<!--$1=')) .pipe(replace(/"([^&]+)"/g, '$1"-->')) // 执行useref处理 .pipe(useref()) // 恢复Thymeleaf原属性 .pipe(replace(/<!--(th:src|th:href)=([^"]+)"-->/g, '$1="$2"')) // 后续替换逻辑 .pipe(replace(/(?!th:)href=".//g, 'href="')) .pipe(replace(/(?!th:)href="(.{0,14})assets/g, 'href="../$1static/assets')) .pipe(replace(/(?!th:)src=".//g, 'src="')) .pipe(replace(/(?!th:)src="(.{0,14})assets/g, 'src="../$1static/assets')) .pipe(cached()) .pipe(dest(paths.dist.html)) .pipe(browsersync.stream()); callback(); }
额外修正:原replace正则的错误说明
原代码中的[^(th:src)]写法错误,它会匹配单个不是(、t、h、:、s、r、c的字符,而非“前面没有th:的src属性”。改用负向前瞻正则(?!th:),才能精准匹配普通的src/href属性,避免误触Thymeleaf属性。
内容的提问来源于stack exchange,提问作者OrkhanGG
相关产品推荐
相关产品推荐

