Folgendes Gulp Setup wurde auf Basis des Setups von „tristanisfeld“ auf Github erstellt. Siehe https://gist.github.com/tristanisfeld/9deea503260324f5e9b0
ZIP herunterladen: DOWNLOAD
An dem folgenden Beispiel ist ein Gulp Setup zu sehen mit dem
- SCSS Dateien in CSS Dateien umgewandelt werden (inkl. Autoprefixer)
- JS Dateien in eine zusammengefasste JS Datei umgewandelt werden
- eine beliebige Live-Seite mit Browsersync gestyled werden kann
Ebenso kann über eine boolean Variable der „production“-Mode aktiviert bzw. deaktiviert werden um das „minifien“, „uglyfien“ bzw. generieren von Sourcemaps zu steuern.
package.json
{
"name": "my_custom_gulp_setup",
"author": "Kevin Pfeifer",
"license": "WTFPL",
"version": "2.0.0",
"description": "Generate minified CSS and JS from source files",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"browser-sync": "^2.26.7",
"gulp-autoprefixer": "^7.0.1",
"gulp-concat": "^2.6.1",
"gulp-if": "^3.0.0",
"gulp-load-plugins": "^2.0.1",
"gulp-minify-css": "^1.2.4",
"gulp-rename": "^1.4.0",
"gulp-sass": "^4.0.2",
"gulp-sourcemaps": "^2.6.5",
"gulp-uglify-es": "^2.0.0",
"gulp-watch": "^5.0.1",
"node-sass": "^4.13.0"
},
"dependencies": {
"gulp": "^4.0.2"
}
}
Hier befinden sich alle aktuell benötigten Node.js Modules (inkl. Version), die wir für das aktuelle Setup benötigen.
gulpfile.js
const gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins(),
config = require('./gulp/config');
// --------------------function to get tasks from gulp/tasks
function getTask(task) {
return require('./gulp/tasks/' + task)(gulp, plugins, config);
}
// ---------------------------------------------- Gulp Tasks
gulp.task('sass', getTask('sass'));
gulp.task('scripts', getTask('scripts'));
gulp.task('styles', getTask('styles'));
gulp.task('watch', getTask('watch'));
gulp.task('browsersync', getTask('browsersync'));
// --------------------------------------- Default Gulp Task
gulp.task('default', gulp.series('watch'));
Der Start jedes Gulp Setups beginnt in der „gulpfile.js„.
- gulp = require(‚gulp‘)
- Ladet die gulp standard Funktionalitäten in die Variable gulp
- gulpLoadPlugins = require(‚gulp-load-plugins‘)
- Ladet das Zusatz-Modul „gulp-load-plugins“
- plugins = gulpLoadPlugins()
- Ladet alle in der package.json definierten Module in die Variable plugins
- Siehe https://www.npmjs.com/package/gulp-load-plugins
- config = require(‚./gulp/config‘)
- Ladet die in der Datei „./gulp/config“ definierte Konfiguration in die Variable config
function getTask(task) {
return require('./gulp/tasks/' + task)(gulp, plugins, config);
}
Als nächstes wird eine generische Funktion definiert um die unterschiedlichen Tasks aus dem „./gulp/tasks/“ zu laden. Diese ist essentiell, damit wir pro Task 1 Datei erstellen können.
gulp.task('sass', getTask('sass'));
gulp.task('scripts', getTask('scripts'));
gulp.task('styles', getTask('styles'));
gulp.task('watch', getTask('watch'));
gulp.task('browsersync', getTask('browsersync'));
Nun werden alle Tasks geladen, die im Gulp zur Verfügung stehen sollen. D.h. wir haben für jeden Task eine Datei im Ordner „./gulp/tasks/„.
Gulp Plugin Loader
Nachdem wir nicht in jedem separaten Task-File die darin verwendeten Node.js-Modules requiren wollen gibt es die Möglichkeit über das Node.js-Module „gulp-load-plugin“ alle in der package.json vorhandenen Node.js-Modules in eine Variable zu laden.
Prinzipiell macht dieses Modul folgendes (ohne das wir es machen müssen):
plugins.sourcemaps = require('gulp-sourcemaps');
plugins.concat = require('gulp-concat');
plugins.uglifyEs = require('gulp-uglify-es');
Dies passiert ganz am Anfang in unserer gulpfile.js in den folgenden 2 Zeilen:
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins()
Wichtig ist anzumerken, dass dieses Modul den Namen des eingebundenen Moduls abändert, damit man es per Funktionsaufruf durchführen kann.
Node Module Name | Funktionsname |
---|---|
gulp-sourcemaps | sourcemaps |
gulp-concat | concat |
gulp-uglify-es | uglifyEs |
Und damit haben wir über die Variable „plugins“ auf alle in der package.json definierten Module Zugriff und können es somit über unsere generische Funktion „getTask“ an jedes Task-File übergeben.
Aufbau eines Tasks
// =========================================================
// Gulp Task: sass
// Description: transpiles sass, adds sourcemaps, prefixes
// npm install --save-dev node-sass gulp-sass gulp-sourcemaps gulp-autoprefixer gulp-load-plugins
// =========================================================
module.exports = function(gulp, plugins, config) {
return function() {
return gulp.src(config.sass.src)
.pipe(plugins.if(!config.production, plugins.sourcemaps.init()))
.pipe(plugins.sass(config.sass.opts).on('error', plugins.sass.logError))
.pipe(plugins.autoprefixer())
.pipe(plugins.if(!config.production, plugins.sourcemaps.write('.')))
.pipe(gulp.dest(config.sass.dest));
}
};
Gehen wir Zeile pro Zeile durch.
module.exports = function(gulp, plugins, config) {
Mit dem „module.exports“ wird definiert, dass diese Funktion von anderen JS Files inkludiert werden kann. Die in der function() definierten Parameter gulp, plugins und config sind die gleichen, die wir oben in der generischen Funktion mit übergeben.
return function() {
Die wirkliche Funktionalität des Tasks muss innerhalb einer function() gewrappt sein damit Gulp im Hintergrund die „Callbacks“ richtig ausführen kann.
return gulp.src(config.sass.src)
...
Danach folgt der „übliche“ Gulp Code, mit dem die diversen Funktionalitäten durchgeführt werden. Wichtig ist nur, dass der „Gulp-Stream“ returned wird.
Unterschiedliche Konfiguration für dev und production build
In dem oben beschriebenen Tasks is schon ein Beispiel zu sehen.
.pipe(plugins.if(!config.production, plugins.sourcemaps.init()))
Als Basis wird das Node-Module „gulp-if“ verwendet. Siehe https://www.npmjs.com/package/gulp-if
D.h. wenn in unserem Config-JSON „production“ false ist werden noch zusätzlich die Sourcemaps für das SASS generiert.
In einem anderen Task „scripts“ haben wir ebenso folgendes Beispiel:
.pipe(plugins.if(config.production, plugins.uglifyEs.default(), plugins.sourcemaps.init()))
D.h. wenn in unserem Config-JSON „production“ true ist wird der JS-Code „uglified“, andernfalls werden die Sourcemaps dafür generiert.
Autoprefixer Einstellungen
Mit der aktuellsten Version vom Autoprefixer wird es nicht mehr empfohlen die Einstellungen im JS-File durchzuführen sondern eine extra Datei Namens „.browserslistrc“ zu erstellen.
In dieser befindet sich aber die gleiche Config. Siehe https://github.com/postcss/autoprefixer#options
# Browsers that we support
last 2 version
> 1%
maintained node versions
not dead
config.js
Folgendes JSON beschreibt die diversen Einstellungen, die für die jeweiligen Tasks durchgeführt werden können.
Beschreibung der abgekürzten Variablen:
- opts => Optionen für den jeweiligen Gulp-Task
- src => Pfad zu Ordner mit den Source-Dateien
- dest => Pfad zu Ordner für die generierten Dateien
Andernfalls ist Inline-Dokumentation vorhanden.
module.exports = {
production: false,
rename: {
min: { suffix: '.min' }
},
// --------------------------------------------- browsersync
browsersync: {
opts: {
proxy: "http://localhost", // The URL of the website you want to browsersync
port: 4000, // The port, from which the browsersync tab will be opened
serveStatic: [{
route: '/', // The route, from which the "live" website serves CSS and JS files
dir: './dist' // Your local path coming from the gulpfile.js where the newly local generated files are laying
}],
},
watch: [
'./dist/assets/css',
'./dist/assets/js'
]
},
// ---------------------------------------------------- sass
sass: {
src: [
"./source/sass/**/*.scss",
],
opts: { }, // add sass options here
dest: "./dist/assets/css"
},
// ------------------------------------------------- scripts
scripts: {
src: [
'source/js/main.js'
],
base: 'source/js', // common base folder of all concatenated JS files so sourcempas are working correctly
filename: 'main.js', // filename of outputted, concatenated JS file
dest: "./dist/assets/js" // folder where the JS files should be populated
},
// -------------------------------------------------- styles
styles: {
src: [
"./source/css/**/*.css",
],
dest: './dist/assets/css'
},
};