Подтвердить что ты не робот

Как настроить grunt-usemin для работы с относительным путем

У меня есть проект grunt, поддерживаемый генератором-йоменом, который я построил на основе generator-webapp, если это поможет, вы можете найти его на GitHub

Проект grunt дает нам задачу grunt-usemin.

Мой проект включает в себя создание многоязычного веб-сайта и сохранение чистоты, я решил поместить все страницы, написанные на языке в имени папки, после 2-буквенного короткого кода указанного языка.

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

Но, к сожалению, он не смог получить правильный результат.

Более конкретно, первая ничего не изменила, вторая имела папки scripts и styles, выведенные на один уровень слишком высоко в иерархии

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

вместо

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

Кто-нибудь может знать, что делать? Это довольно простая утилита, но я не мог найти нужную мне помощь через Google, GitHub или SO...

4b9b3361

Ответ 1

Я считаю, что вы можете добиться того, что вам нужно таким образом:

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

Ключевое решение находится в опции blockReplacements задачи usemin. В основном задача будет помещать ваши файлы под <% = yeoman.dist% > /styles/main.css, тогда как ваш html будет находиться под <% = yeoman.dist% > /en/somefileinEnglish.html и каждый экземпляр "styles/main.css" в этом файле будет заменен на "../styles/main.css", добавив правильный относительный путь.

В качестве дополнительного совета, если вы строите многоязычный веб-сайт, вы можете рассмотреть grunt-i18n, чтобы перевести ваш файл при построении, поэтому вам не нужно поддерживать другой html файл для каждого языка.

Ответ 2

Я строил свои собственные леса 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 аналогичным образом, то это будет прикручено. Поэтому для того, чтобы обойти THAT, нам нужно создать одну цель useminPrepare для index.html с помощью dest: "out" и другую цель для 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. Он будет выполнять, по сути, то, что я упомянул выше. Кроме того, он делает то же самое и для промежуточной директории, поэтому файлы промежуточного уровня не выходят из промежуточного каталога. Вы можете даже иметь несколько целей в useminPreparePrepare, он скопирует параметры для вашей цели.

Чтобы использовать эту работу, вам сначала нужно будет импортировать useminPreparePrepare. Я не поместил его на npm, поэтому вам придется просто скопировать и вставить его. Я не против. Затем просто переименуйте конфигурацию useminPrepare в useminPreparePrepare и добавьте свойство src. В приведенном выше примере src: "in". Затем вам нужно запустить useminPreparePrepare с той целью, которой вы обычно хотели бы, а затем сразу запустить useminPrepare без указания цели, чтобы все цели были запущены. Учитывая приведенный выше пример, Grunt config может выглядеть примерно так:

"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.

Надеюсь, это поможет!

Ответ 3

Мое решение состояло в том, чтобы вручную модифицировать плагин 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'], лучше добавить массив с "dist". Таким образом, если элемент не найден в каталоге "dist", можно сделать вывод, что либо путь относительный, либо неправильный. Таким образом, мы используем второе значение из массива searchPath для поиска файла, и если это относительный путь - мы получаем то, что хотели.

Ответ 4

Я использовал несколько целей, как показано ниже:

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

Ответ 5

Я видел много вопросов об этом и реальных ответов. В моем проекте я сопоставил папку "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 и обновлять путь вручную.

Ответ 6

Если я правильно понимаю ваш вопрос, я думаю, вам нужен вариант "root":

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

Хотя index.html находится в html/папке, поиск файлов будет из app/not html/

Ответ 7

Я делаю блоки 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

Я делаю свой html похожим на это в app/layouts/main.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 -->

на dev (no usemin, только обслуживающие файлы) "../../" ловко просто решает "/", поэтому он все еще работает. Таким образом, вы не нуждаетесь в предварительной обработке во время разработки (с задачами с часами или что-то еще.)

Ответ 8

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

используйте '.' как назначение в файле grunt.

Ответ 9

Я делаю исправление ошибки для относительного пути. https://www.npmjs.com/package/grunt-usemin-fix

Вы можете скопировать и пройти изменение к источнику использования-min для использования относительного пути