How should I configure grunt-usemin to work with relative path

Jérémie Parker picture Jérémie Parker · Sep 23, 2013 · Viewed 18.1k times · Source

I have a grunt project backed by a yeoman-generator that I've built based on the generator-webapp, if it's of any help, you can find it on GitHub

The grunt project makes us of the grunt-usemin task.

My project involve building a multilingual website, and to keep things clean, I've decided to put all the pages written in a language in a folder name after the 2-letter shortcode of the said language.

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

The files are made from handlebars templates and processed with assemble. In the layout I have building blocks for usemin such as

<!-- 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 -->

Which, in a perfect world would translate to

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

but instead shows

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

which is less than ideal in my case. The relevant part of the Gruntfile.js looks like this

    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']
    }

I have tried to use the basedir option by setting it to <%= yeoman.dist %> as well as changing the build blocks to

<!-- 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 -->

But unfortunately wasn't able to get a proper output.

More specifically, the first one didn't change anything, the second one had the folders scripts and styles outputted one level too high in the hierarchy

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

instead of

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

Would anyone happen to know what to do ? It seems a rather simple usecase but I couldn't find the help I need via Google, GitHub or SO...

Answer

Luca Camerini picture Luca Camerini · Nov 25, 2014

I believe that you can achieve what you need in this way:

Html file:

    <!-- 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']
        }

The key solution is in the blockReplacements option of the usemin task. Basically, the task will put your files under <%= yeoman.dist %>/styles/main.css, while your html will be under <%= yeoman.dist %>/en/somefileinEnglish.html and every instance of 'styles/main.css' in this file will be replaced with '../styles/main.css', adding the correct relative path.

As an extra tip, if you are building a multilingual website, you may want to consider grunt-i18n to translate your file while building, so you won't need to maintain a different html file for every language.