You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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=&quot;@{/assets/libs/jquery/dist/jquery.min.js}&quot; src=&quot;@@webRoot/node_modules/jquery/dist/jquery.min.js&quot;></script>
<script th:src=&quot;@{/assets/libs/bootstrap/dist/js/bootstrap.bundle.min.js}&quot; src=&quot;@@webRoot/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js&quot;></script>
<script th:src=&quot;@{/assets/libs/simplebar/dist/simplebar.min.js}&quot; src=&quot;@@webRoot/node_modules/simplebar/dist/simplebar.min.js&quot;></script>


<!-- Theme JS -->
<!-- build:js @@webRoot/assets/js/theme.min.js -->
<script th:src=&quot;@{/assets/js/main.js}&quot; src=&quot;@@webRoot/assets/js/main.js&quot;></script>
<script th:src=&quot;@{/assets/js/darkMode.js}&quot; src=&quot;@@webRoot/assets/js/darkMode.js&quot;></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=&quot;(.{0,10})node_modules/g, 'src=&quot;$1assets/libs'))
        .pipe(replace(/(?!th:)href=&quot;(.{0,10})node_modules/g, 'href=&quot;$1assets/libs'))
        // 配置useref的transform处理逻辑
        .pipe(useref({
            transform: function(content, target, options, alternate) {
                // 临时替换Thymeleaf属性,避免useref解析
                content = content.replace(/th:src=&quot;([^&]+)&quot;/g, 'temp-th-src="$1"');
                content = content.replace(/th:href=&quot;([^&]+)&quot;/g, 'temp-th-href="$1"');
                // 调用useref默认处理逻辑
                content = require('gulp-useref/lib/transform')(content, target, options, alternate);
                // 恢复Thymeleaf原属性
                content = content.replace(/temp-th-src=&quot;([^&]+)&quot;/g, 'th:src="$1"');
                content = content.replace(/temp-th-href=&quot;([^&]+)&quot;/g, 'th:href="$1"');
                return content;
            }
        }))
        // 后续replace同样修正正则写法
        .pipe(replace(/(?!th:)href=&quot;.//g, 'href=&quot;'))
        .pipe(replace(/(?!th:)href=&quot;(.{0,14})assets/g, 'href=&quot;../$1static/assets'))
        .pipe(replace(/(?!th:)src=&quot;.//g, 'src=&quot;'))
        .pipe(replace(/(?!th:)src=&quot;(.{0,14})assets/g, 'src=&quot;../$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=&quot;(.{0,10})node_modules/g, 'src=&quot;$1assets/libs'))
        .pipe(replace(/(?!th:)href=&quot;(.{0,10})node_modules/g, 'href=&quot;$1assets/libs'))
        // 注释Thymeleaf属性,避免useref识别
        .pipe(replace(/(th:src|th:href)=/g, '<!--$1='))
        .pipe(replace(/&quot;([^&]+)&quot;/g, '$1"-->'))
        // 执行useref处理
        .pipe(useref())
        // 恢复Thymeleaf原属性
        .pipe(replace(/<!--(th:src|th:href)=([^"]+)"-->/g, '$1="$2"'))
        // 后续替换逻辑
        .pipe(replace(/(?!th:)href=&quot;.//g, 'href=&quot;'))
        .pipe(replace(/(?!th:)href=&quot;(.{0,14})assets/g, 'href=&quot;../$1static/assets'))
        .pipe(replace(/(?!th:)src=&quot;.//g, 'src=&quot;'))
        .pipe(replace(/(?!th:)src=&quot;(.{0,14})assets/g, 'src=&quot;../$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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 18:50:24