Как настроить 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...
Ответы
Ответ 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 для использования относительного пути