При создании новой темы у вас есть варианты выбора начиная с того, чтобы взять готовую тему (и начать её менять под ваши задачи) до создания новой темы с «нуля». Часто также берут легаси шаблон — т.е. тему с прошлого проекта, потому что «мы там всё уже знаем и сделали как нужно».
Все эти опции имеют свои плюсы и минусы, я же расскажу о варианте близком к «теме с нуля», но всё же позволяющей быстро начать писать полезный код/стили.
Основа темы
В Drupal есть так называемый startkit, который позволяет генерировать новые темы оформления. Он базируется на core/stable9. Содержит минимальные определения и шаблоны. Stable9 удобен тем, что он почти ничего не объявляет в стилях.
Перейдите в web-root сайта и запустите скрипт:
1 |
php ./core/scripts/drupal generate-theme THEMENAME. |
Скрипт создаст в папке ./themes/THEMENAME новую тему. Останется только активировать её через панель управления или drush командой:
1 |
drush theme:enable THEMENAME |
SCSS / JS + GULP
В только что собранной теме нет ничего, что помогало бы нам пользоваться сборщиками и препроцессорами. А вам вероятно потребуется обработка JS и SCSS. Т.е. в тему нужно добавить src папку, где мы будем хранить и разрабатывать исходники стилей и js, и из них получать уже рабочие библиотеки (которые будут регистрироваться в файле *.libraries.yml).
Я обычно раскладываю исходники по трем папкам

Начальные стили, которые есть в теме — размазаны по куче мелких файлов css/components/*.css, я копирую их в src/css, чтобы потом билдить из них один общий файл css/base/index.css. Нет особого смысла перекладывать работу по минификации и анализу этой мелочевки на drupal, т.к. это файл ~14кб, мы его билдим один раз, и возвращаемся к нему только тогда, когда нам требуется удалить какой то мешающийся там стиль.
В соответствии с этими изменениями нужно поменять в THEMENAME.libraries.yml ссылки css/сss/components/*.css на сss/base/index.css.
Для использования GULP потребуется сконфигурировать пакеты и написать gulpfile.js.
package.json
Конфигурация пакетов (package.json) прилагается ниже. Запускайте npm i для установки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
{ "name": "Drupal Blank Theme", "version": "1.0.0", "description": "", "main": "gulpfile.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "devDependencies": { "autoprefixer": "^10.2.5", "cssnano": "^5.0.2", "gulp": "^4.0.2", "gulp-clean-css": "^4.3.0", "gulp-notify": "^4.0.0", "gulp-postcss": "^9.0.0", "gulp-remove-empty-lines": "^0.1.0", "gulp-rename": "^2.0.0", "gulp-sass": "^6.0.1", "gulp-sass-unicode": "^1.0.5", "gulp-sourcemaps": "^3.0.0", "gulp-strip-css-comments": "^2.0.0", "gulp-terser": "^2.1.0", "sass": "^1.85.1" }, "dependencies": { "cucumber": "*", "gulp-concat": "^2.6.1", "path": "^0.12.7", "postcss": "^8.2.13" } } |
В корень темы также стоит добавить .gitignore со строкой:
1 |
node_modules |
Это избавит нас от попадания установленных модулей в репозиторий.
gulpfile.js
Основная функция сборщика — отслеживать изменения src файлов и билдить библиотеки.
Сборщик создаёт два css файла: уже упомянутый css/base/index.css и основной файл темы — css/styles.css (из исходных *.scss). А также он обрабатывает src/js файлы, минифицируя их в отдельные готовые *.js скрипты в папку темы /js.
Слежение запускается командой
1 |
gulp watch |
Исходный код gulpfile.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
// -------------------------------------------------- // Load Plugins // -------------------------------------------------- var gulp = require('gulp'), sass = require('gulp-sass')(require('sass')); postcss = require("gulp-postcss"), autoprefixer = require("autoprefixer"), cssnano = require("cssnano"), sourcemaps = require("gulp-sourcemaps"), notify = require('gulp-notify'), sassUnicode = require('gulp-sass-unicode'), rename = require('gulp-rename'), path = require('path'), stripCssComments = require('gulp-strip-css-comments'), concat = require('gulp-concat'), minifyCss = require('gulp-clean-css'), terser = require('gulp-terser'), removeEmptyLines = require('gulp-remove-empty-lines'); var config = { // all scss files in the scss directory mainScss: ['src/scss/index.scss'], baseCss: 'src/css/*.css', // the destination directory for our css cssDest: 'css/', // main js directory allJs: 'src/js/*.js', // the destination directory for our main JS jsDest: 'js', }; // Define tasks after requiring dependencies function plain_css_aggregation() { let files = gulp.src(config.baseCss) .pipe(sourcemaps.init()) .pipe(sass()) .pipe(sassUnicode()) .pipe(sass().on('error', swallowError)) .pipe(postcss([autoprefixer()])) .pipe(stripCssComments()) //.pipe(removeEmptyLines()) .pipe(minifyCss()); return files .pipe(concat('index.css')) .pipe(gulp.dest('css/base')) } function style() { let files = gulp.src(config.mainScss) // .pipe(sourcemaps.init()) .pipe(sass().on('error', swallowError)) .pipe(sassUnicode()) .pipe(postcss([autoprefixer()])) .pipe(stripCssComments()) .pipe(removeEmptyLines()) .pipe(minifyCss()) // .pipe(sourcemaps.write('../maps')) return files .pipe(concat('styles.css')) .pipe(gulp.dest(config.cssDest)); } function minifyMainJS() { return gulp.src(config.allJs) .pipe(terser()) // Minify JS with gulp-terser .pipe(rename({ suffix: '.min' })) // Rename to .min.js .pipe(gulp.dest(config.jsDest)); // Save to destination } // Expose the task by exporting it // This allows you to run it from the commandline using // $ gulp style exports.style = style; exports.minifyjs = gulp.parallel(minifyMainJS); function watch() { // gulp.watch takes in the location of the files to watch for changes // and the name of the function we want to run on change gulp.watch('src/**/*.scss', gulp.parallel(style)) gulp.watch(config.baseCss, plain_css_aggregation) // Watch all JavaScript files for changes and run minifyjs gulp.watch([config.allJs], exports.minifyjs); } // Don't forget to expose the task! exports.watch = watch function swallowError (error) { // If you want details of the error in the console console.log(error.toString()) this.emit('end') } |
Корнем сборки SCSS является файл src/scss/index.scss, который содержит в основном команды вроде @use и @forward.
В итоге мы имеем заготовку темы + настроенный препроцессор для scss и js. Дальнейшие изменения уже должны производиться согласно тому, что требует конкретная задача вашего проекта.