我应该如何配置grunt-usemin来处理相对路径

时间:2013-09-23 17:01:01

标签: gruntjs yeoman assemble grunt-usemin

我有一个由我根据generator-webapp构建的yeoman-generator支持的grunt项目,如果有任何帮助,你可以在GitHub上找到它

grunt项目让我们了解grunt-usemin任务。

我的项目涉及建立一个多语种网站,为了保持清洁,我决定将所有用一种语言写成的页面放在文件夹名称之后,用两个字母的短代码表示。

| project/
|--dist/
|----en/
|------index.html
|------404.html
|------...
|----fr/
|------index.html
|------404.html
|------...

文件由把手模板制作,并使用assemble进行处理。在布局中,我有usemin的构建块,例如

<!-- build:css(.tmp) styles/main.css -->
<link rel="stylesheet" href="../styles/main.css">
<!-- endbuild -->
<!-- build:js scripts/vendor/modernizr.js -->
<script src="../bower_components/modernizr/modernizr.js"></script>
<!-- endbuild -->

其中,在一个完美的世界中会转化为

<link rel="stylesheet" href="../styles/main.css">
<script src="../scripts/vendor/modernizr.js"></script>

,而是显示

<link rel="stylesheet" href="styles/main.css">
<script src="scripts/vendor/modernizr.js"></script>

在我的情况下不太理想。 Gruntfile.js的相关部分看起来像这样

    useminPrepare: {
        options: {
            dest: '<%= yeoman.dist %>'
        },
        html: [
            '<%= yeoman.app %>/fr/{,*/}*.html',
            '<%= yeoman.app %>/en/{,*/}*.html'
        ]
    },
    usemin: {
        options: {
            dirs: ['<%= yeoman.dist %>']
        },
        html: [
            '<%= yeoman.dist %>/fr/{,*/}*.html',
            '<%= yeoman.dist %>/en/{,*/}*.html'
        ],
        css: ['<%= yeoman.dist %>/styles/{,*/}*.css']
    }

我尝试使用basedir选项 通过将其设置为<%= yeoman.dist %>以及将构建块更改为

<!-- build:css(.tmp) ../styles/main.css -->
<link rel="stylesheet" href="../styles/main.css">
<!-- endbuild -->
<!-- build:js ../scripts/vendor/modernizr.js -->
<script src="../bower_components/modernizr/modernizr.js"></script>
<!-- endbuild -->

但遗憾的是无法获得正确的输出。

更具体地说,第一个没有更改任何内容,第二个文件夹scriptsstyles在层次结构中输出的级别太高

| project/
|--app/
|--dist/
|--styles/
|--scripts/

而不是

| project/
|--app/
|--dist/
|----styles/
|----scripts/

有人会碰巧知道该怎么办吗?它似乎是一个相当简单的用例,但我无法通过Google,GitHub或SO找到我需要的帮助......

9 个答案:

答案 0 :(得分:4)

我相信你可以通过这种方式实现你所需要的:

Html文件:

    <!-- build:css styles/main.css -->
    <link href='../styles/css/style.css' rel='stylesheet' type='text/css'>
    <link href='../styles/css/responsive.css' rel='stylesheet' type='text/css'>

    <link href="../styles/css/skins/welld.css" rel='stylesheet' type='text/css' id="skin-file">
    <!-- endbuild -->

Gruntfile.js

        useminPrepare: {
            options: {
                dest: '<%= yeoman.dist %>/'
            },
            html: ['<%= yeoman.app %>/snippets/head.html','<%= yeoman.app %>/snippets/tail.html']
        },
        usemin: {
            options: {
                dirs: ['<%= yeoman.dist %>/'],
                blockReplacements: {
                    css: function (block) {
                        return '<link rel="stylesheet" href="../' + block.dest + '"/>';
                    },
                    js: function (block) {
                        return '<script src="../' + block.dest + '"></script>';
                    }
                }
            },
            html: ['<%= yeoman.dist %>/{,*/}*.html'],
            css: ['<%= yeoman.dist %>/styles/{,*/}*.css']
        }

密钥解决方案位于usemin任务的blockReplacements选项中。基本上,任务将把你的文件放在&lt;%= yeoman.dist%&gt; /styles/main.css下,而你的html将在&lt;%= yeoman.dist%&gt; /en/somefileinEnglish.html下&style; main.css&#39;的实例在此文件中将替换为&#39; ../ styles / main.css&#39;,添加正确的相对路径。

作为额外提示,如果您要构建多语言网站,可能需要考虑grunt-i18n在构建时翻译文件,因此您不需要为每种语言维护不同的html文件。

答案 1 :(得分:3)

我正在建造自己的Grunt脚手架,我对此问题感到沮丧。我设法制作了一个我想与你分享的作品。

我想用我自己的一个例子来说明他的问题背后的原因以及我是如何设法解决的。假设我的目录结构如下:

| in/
+---- pages/
|    +---- login.html
+---- js/
|    +---- s1.js
|    +---- s2.js
+---- index.html
| out/
| Gruntfile.js

in/是我所有源文件所在的位置,out/dest目录,其中将存储所有输出文件。假设我要将s1.js导入login.html,我会写下这样的内容:

<!-- build:js ../js/login.js -->
<script src="../js/s1.js"></script>
<!-- endbuild -->

在这里,usemin块执行一个简单的字符串替换,因此输出路径应该是我想要链接输出文件的位置。当问题login.js落在out/js/login.js时,问题就会发生,而useminPrepare最终会将其降落在js/login.js。这背后的原因是useminPrepare只是在dest(即out)和输出路径(../js/login.js)之间执行路径连接,而它应该执行路径连接关于找到HTML文件的位置。

要解决此问题,请注意,如果我将dest设置为out/pages哪个方面尊重login.html,那么它就可以正常运行。但是请注意,如果index.html以类似的方式导入js/s2.js,那么这将被搞砸。因此,为了解决这个问题,我们需要为index.html dest: "out"创建一个useminPrepare目标,为login.html创建另一个dest: "out/pages"目标。因此我的useminPrepare配置现在看起来像这样:

"useminPrepare": {
    t1: {
        dest: "out",
        files: [{src: ["in/*.html"]}],
        ...
    },
    t2: {
        dest: "out/pages",
        files: [{src: ["in/pages/*.html"]],
        ....
    }
}

所有目标都必须运行。现在你可能会说;如果我在其他子目录下有更多HTML文件怎么办?这是否意味着我必须为找到HTML文件的每个目录创建一个目标?这是屁股和愚蠢的痛苦。它是!我同意。所以我写了一个非常特别的咕噜声任务来帮忙。我称之为useminPreparePrepare我故意将它命名为愚蠢,因为它是愚蠢的。我非常希望有一天当usemin人员解决这个问题时摆脱这项工作。顾名思义,useminPreparePrepare为useminPrepare准备配置。它自己的配置镜像useminPrepare(事实上,大多数配置只是被复制)有一个例外;您必须添加一个src属性,该属性指向所有源文件所在的源根目录,以便它可以找出源根目录和HTML文件之间的相对路径。它将基本上执行我上面提到的。另外,它对于暂存目录也是如此,因此暂存文件不会&#39;突破登台目录。您甚至可以在useminPreparePrepare中拥有多个目标,它将复制您运行的目标的选项。

要使用此工作,您首先必须导入useminPreparePrepare。我没有把它放在npm上,所以你必须复制并粘贴它。我不介意。然后只需将useminPrepare配置重命名为useminPreparePrepare,并添加src属性。对于上面的示例,src: "in"。然后你需要运行useminPreparePrepare和你通常喜欢的目标,然后立即运行useminPrepare而不指定目标,以便所有目标都能运行。鉴于以上示例,Grunt配置可能如下所示:

"useminPreparePrepare": {
    html: "in/**/*.html",   // All HTML files under in/ and its subdirectories.
    options: {
        src: "in",
        dest: "out",
        ....
    }
},
"copy": {
    html: { // Copies all HTML files from in/ to out/ preserving their relative paths.
        files: [{
                expand: true,
                cwd: "in",
                src: ["**/*.html"],
                dest: "out"
            }
        ]
    }
},
"usemin": {
    html: "out/**/*.html",  // Process all HTML files under out/ and its subdirectories.
    ...
}

您可以看到上面的配置非常简单,可以在源目录下递归包含所有HTML文件。 useminPreparePrepare负责处理所有愚蠢的工作,同时看起来就像useminPrepare。

我希望这有帮助!

答案 2 :(得分:1)

我的解决方案是手动修改grunt-usemin插件。

在您喜欢的文本编辑器中打开node_modules/grunt-usemin/fileprocessor.js。第152行附近找到:

if (assetSearchPath && assetSearchPath.length !== 0) {
  this.file.searchPath = assetSearchPath;
}

并将其替换为:

if (assetSearchPath && assetSearchPath.length !== 0) {
  this.file.searchPath.splice(0, 0, assetSearchPath);
}

默认情况下,this.file.searchPath是一个包含当前文件的绝对路径的数组。使用['dist']覆盖它没有意义,最好在数组前加上&#39; dist&#39;。这样,如果在&#39; dist&#39;中找不到商品。目录可以断定路径是相对的还是错误的。因此,我们使用searchPath数组中的第二个值来查找文件,如果它是相对路径 - 我们得到了我们想要的结果。

答案 3 :(得分:1)

我使用了多个目标,如下所示:

 useminPrepare: {
        target1 : {
                src : ['target1/*.html'],
                options : {
                    dest: 'out'
                }
            },

            target2 : {
                src : ['target2/folder/*.html'],
                options : {
                    dest: 'out/subfolder'
                }
            }
    },

然后在HTML块中你可以这样:

<!-- build:js ../subfolder/script.js -->
<script src="../subfolder/scripts/main.js></script>
<!-- endbuild -->

答案 4 :(得分:0)

我见过很多关于这方面的问题而且没有真正的答案。在我的项目中,我已将“dist”文件夹映射到“/ static”服务器端。所以我不需要在index.html中计算相对路径。

但是,问题仍然存在于usemin

<!-- build:css(.tmp) static/css/main.css -->
<link rel="stylesheet" href="css/main.css">
<!-- endbuild -->

usemin文件将写在dist/static/css/main.css

并且HTML将显示错误的(但预期的)路径

<link rel="stylesheet" href="static/css/main.css">

我发现的唯一解决方法是不要触摸usemin块,运行grunt并手动更新路径。

答案 5 :(得分:0)

如果我正确理解你的问题,我认为你需要'root'选项:

{
  useminPrepare: {
    html: 'html/index.html',
    options: {
    root: 'app'
    dest: 'dist'
    }
  }
}

虽然index.html位于html /文件夹中,但文件查找将来自app / not html /

答案 6 :(得分:0)

我使用相对于模板的usemin块。

我有这样的结构:

app/ - webroot source (devmode)
app/views/layouts - layouts for server-generated pages (also has usermin tags init)
app/js - source javascript

dist/ - production build dir

我在app / layouts / main.html中使我的html看起来像这样:

    <!-- build:js js/static.min.js -->
      <script src="../../js/controllers/StaticCtrl.js"></script>
      <script src="../../js/directives/backImg.js"></script>
      <script src="../../js/smooth-scroll.js"></script>
    <!-- endbuild -->

on dev(没有usemin,只提供文件)“../../”巧妙地解析为“/”,所以它仍然有效。这样您就不需要在开发过程中进行预处理(使用监视任务或其他任何方式。)

答案 7 :(得分:0)

useminPrepare: {
        loyalty: {
            src: '<%= loyalty.app %>/Views/index.tpl',
            options: {
                dest: '.',
                flow: {
                    html: {
                        steps: {
                            js: ['concat', 'uglifyjs'],
                            css: ['cssmin']
                        },
                        post: {}
                    }
                }
            }
        }
    },
<!-- build:css /resources/v4/css/loyalty/index.css -->
<link rel="stylesheet" href="../Resources/css/main.css">
<link rel="stylesheet" href="../Resources/css/product.css">
<link rel="stylesheet" href="../Resources/css/use_code.css">
<!-- endbuild -->

使用&#39;。&#39;作为gruntfile中的目的地。

答案 8 :(得分:0)

我为相对路径修复了错误。 https://www.npmjs.com/package/grunt-usemin-fix

您可以将更改复制并通过use-min来使用相对路径