Organisierung der Eleventy config-Datei

Veröffentlicht:
Zuletzt bearbeitet:
Lesezeit:
9 Min.

Eleventy kommt mit grundlegenden Voreinstellungen. Das bedeutet, dass du nichts tun musst, um mit der Arbeit zu beginnen: der Ausgabeordner ist standardmäßig _site, und Eleventy sucht deine Quelldateien im Stammverzeichnis.

Das ist für sehr kleine Projekte auch vollkommen in Ordnung. Die meisten meiner Projekte werden jedoch ziemlich groß, und ich muss Dinge Anpassen und dependencies importieren. Ich habe auch persönliche Vorlieben, und Eleventy ist da ziemlich offen - du kannst alles so anlegen und nennen wie du möchtest. Um alle deine Wünsche zu erfüllen, gibt dir Eleventy die Möglichkeit eine Datei namens eleveny.js zu erstellen. In diesem Artikel geht es um die Organisation dieser Eleventy-Konfigurationsdatei.

Lass uns anfangen!

Inhaltsverzeichnis überspringen

Inhaltsverzeichnis

.eleventy.js Konfigurationsdatei erstellen

Füge eine neue Datei im Hauptverzeichnis mit dem Namen .eleventy.js hinzu (ab Eleventy 2.0 kann sie auch eleventy.config.js. heißen).

Zuerst passen wir die Ordnerstruktur etwas an.

module.exports = function (eleventyConfig) {
  return {
    dir: {
      input: 'src',
      output: 'dist',
      includes: '_includes',
      layouts: '_layouts'
    }
  };
};

Unser Ausgabeordner ist jetzt dist, und alle unsere Quelldateien kommen in den Ordner src.
Außerdem ziehe ich aufgrund meiner persönlichen Vorliebe den layouts-Ordner aus dem _includes-Ordner heraus, wo er normalerweise liegt, und stelle sicher, dass die Verzeichnisse nebeneinander liegen.

Das Root-Verzeichnis bleibt all den Dateien vorbehalten, die unbedingt dort liegen müssen - wie package.json und README.md, oder die Konfigurationsdateien anderer Module, die du in deinem Projekt verwendest.

Strukturierung des Eingabeordners

Erstelle einen Ordner namens src im Stammverzeichnis.

Obwohl wir die meisten Ordner nicht weiter besprechen, sieht ein Website-Projekt oftmals so aus:

│
├── src
│  │
│  ├── _data
│  ├── _includes
│  ├── _layouts
│  ├── assets
│  ├── pages
│  ├── posts
│  ├── projects
│

pages ist für deine statischen Seiten wie index.md, about.md, usw., posts enthält deine Blog-Artikel, und projects ist nur ein weiterer collections-Ordner, damit es sich überhaupt lohnt, diese Logik aus eleventy.js herauszuholen.

… Denn dort kannst du alle deine collections, shortcodes und filters direkt konfigurieren.

Auslagerung der helper methods von Eleventy

Ich möchte, dass meine Projekte frei wachsen können, ohne dass ich mir Sorgen machen muss, dass meine Konfigurationsdatei zu unübersichtlich wird. Deshalb kümmere ich mich an anderer Stelle um Anpassungen und importiere nur den return-Wert meiner Funktionen.

Üblicherweise lege ich einen neuen Ordner im Stammverzeichnis mit dem Namen config an.

Auch sehr gut ist die Lösung einen Ordner mit dem Namen _11ty in src zu legen. Ich habe das in Nicolas Hoizeys Starter pack11ty gesehen. Du kannst den Ordner nennen wie du willst und ihn an einem beliebigem Ort im Verzeichnis ablegen.
In diesem Fall gehe ich davon aus, dass du einen Ordner namens config in deinem Stammverzeichnis abgelegt hast.

Wir brauchen Eleventy nicht über die Existenz dieses Ordners zu informieren. Wir benutzen ihn einfach, um unsere return-Werte zu exportieren und sie in .eleventy.js zu importieren.

Ich stelle zwei Möglichkeiten vor, dies zu handhaben, am Beispiel von collections.

Methode 1: Datei importieren und über die collections “loopen”

Erstelle eine Datei namens collections.js in deinem config Ordner.
Definiere nun alle collections, die du verwenden möchtest:

module.exports = {
  posts: function (collectionApi) {
    return collectionApi.getFilteredByGlob('src/posts/**/*.md');
  },
  projects: function (collectionApi) {
    return collectionApi.getFilteredByGlob('src/projects/**/*.md');
  }
};

Deine eleventy.js sieht jetzt so aus:

const collections = require('./config/collections.js');

module.exports = eleventyConfig => {
  // Collections
  Object.keys(collections).forEach(collectionName => {
    eleventyConfig.addCollection(collectionName, collections[collectionName]);
  });

  return {
    dir: {
      input: 'src',
      output: 'dist',
      includes: '_includes',
      layouts: '_layouts'
    }
  };
};

Wir “loopen” (wie sagt man das auf Deutsch?) über alle collections, die in collections.js definiert sind, und importieren sie in unsere Konfigurationsdatei. Genau dasselbe machen wir jetzt für filter, transforms, shortcodes usw.

Wenn du diese Methode in Aktion sehen willst, besuche das öffentliche Repo von Ryan Mulligans Website.

Sehr aufgeräumt!

Dieser Ansatz erzeugt eine sehr kompakte Konfigurationsdatei. Es gibt allerdings etwas, das mir an dieser Methode nicht gefällt.

Wir haben zwar Struktur reingebracht, aber ich möchte auch einen guten Überblick haben. Ich möchte direkt in meiner Konfigurationsdatei sehen können, welche collections ich verwende, welche filter, welche transforms und so weiter. Hier kommt also Methode zwei!

Wir haben zwar Struktur reingebracht, aber ich möchte sehen, was in mein Projekt importiert wird, und zwar genau dort, in meiner Konfigurationsdatei. Ich möchte wissen, welche collections ich verwende, welche filter, welche transforms und so weiter. Hier kommt also Methode zwei!

Methode 2: named exports

Anstelle von collections.js erstellen wir einen weiteren Ordner innerhalb von config mit dem Namen collections, und dort legen wir eine Datei namens index.js ab:

// blog posts
const getPosts = collection => {
  return collection.getFilteredByGlob('src/posts/**/*.md');
};

// projects
const getProjects = collection => {
  return collection.getFilteredByGlob('src/projects/**/*.md');
};

module.exports = {
  getPosts,
  getProjects
};

Named exports können einzeln oder unten gruppiert exportiert werden. Wenn man wie im Beispiel hier alles am Ende des Moduls exportiert, ist es viel übersichtlicher, daher bevorzuge ich natürlich diese Methode.

Und in der eleventy.js:

const {getPosts, getProjects} = require('./config/collections/index.js');

module.exports = eleventyConfig => {
  // Collections
  eleventyConfig.addCollection('posts', getPosts);
  eleventyConfig.addCollection('projects', getProjects);

  return {
    dir: {
      input: 'src',
      output: 'dist',
      includes: '_includes',
      layouts: '_layouts'
    }
  };
};

Erledigt!

Alles ist übersichtlich und ich kann auf einen Blick sehen, was ich für dieses Projekt importiere.

Wenn es zu viele filter, collections oder shortcodes werden, unterteile ich sie weiter in eigene Ordner, zum Beispiel nur die Filter für die Ausgabe des Datums an einem gemeinsamen Ort. Größere Blöcke wie die für die Eleventy Image shortcodes bekommen einen eigenen Ordner.
Die exportierten values werden dann erst in die übergeordnete index.js importiert und dann für die Dateieleventy.js wieder zusammen exportiert. 🤪

Methode 3: Weitere Konfigurationsdateien als Plugin

Nachdem ich diesen Artikel auf Mastodon geteilt hatte, wies mich Zach darauf hin, dass es noch eine weitere Möglichkeit gibt, meine Konfigurationskomponenten auszulagern:

eleventyConfig.addPlugin(require('other-config-file.js'));

Das ist nicht nur die kompakteste Schreibweise, da ich meine return values nicht erst importieren muss, sondern ich muss auch keinen Code umschreiben: Die ausgelagerten Konfigurationsdateien funktionieren genauso wie “elventy.js” selbst, indem sie eine callback function zurückgeben. Und ich kann sehen, was ich importiere!

Ich illustriere dies am Beispiel einer html-Minifizierung mit Eleventys eingebautem addTransform.

In deiner eleventy.js:

// nichts zu importieren! :)

module.exports = eleventyConfig => {
  // Transforms
  eleventyConfig.addPlugin(require('./config/transforms/html-config.js'));

  return {
    dir: {
      input: 'src',
      output: 'dist',
      includes: '_includes',
      layouts: '_layouts'
    }
  };
};

Deine html-config.js:

const htmlmin = require('html-minifier-terser');
const isProduction = process.env.ELEVENTY_ENV === 'production';

module.exports = eleventyConfig => {
  eleventyConfig.addTransform('html-minify', (content, path) => {
    if (path && path.endsWith('.html') && isProduction) {
      return htmlmin.minify(content, {
        collapseBooleanAttributes: true,
        collapseWhitespace: true,
        decodeEntities: true,
        includeAutoGeneratedTags: false,
        removeComments: true
      });
    }

    return content;
  });
};

Exzellent!

Als Nächstes: Passthrough File Copy.

Strukturierung der Passthrough File Copies

Manchmal möchten wir Dateien einfach in unseren Ausgabeordner kopieren, ohne sie weiteren Transformationsprozessen zu unterziehen. Und zwar genau so, wie sie sind. Hier kommen Passthrough File Copies ins Spiel.

Die Verzeichnisstruktur intakt halten

Nehmen wir an, du hast deine lokalen Schriftarten in src/assets/fonts gespeichert.

Wenn du diese Struktur beibehalten willst, fügst du folgendes zu eleventy.js hinzu:

module.exports = eleventyConfig => {
  // Passthrough Copy
  eleventyConfig.addPassthroughCopy('src/assets/fonts/');

  return {
    dir: {
      input: 'src',
      output: 'dist',
      includes: '_includes',
      layouts: '_layouts'
    }
  };
};

Nun werden deine Schriftarten mit der gleichen Verzeichnisstruktur kopiert, in dist/assets/fonts/.

Normalerweise habe ich mehr als nur einen Ordner in assets, mit denen ich gleichermaßen verfahren möchte.
Auch dafür gibt es eine kompakte Lösung!

['src/assets/fonts/', 'src/assets/images/', 'src/assets/pdf/'].forEach(path =>
  eleventyConfig.addPassthroughCopy(path)
);

Wir packen alle Verzeichnisse in ein Array und wenden die Methode “forEach()” an, um den passthrough-Befehl für jedes Arrayelement einmal auszuführen.

Dateien in ein anderes Verzeichnis kopieren

Manchmal möchtest du deine Dateien in ein anderes Verzeichnis kopieren. Für mich macht das vor allem bei meinen Favicon-Varianten Sinn. Man kann dem Browser sagen, dass er sie in einem Ordner suchen soll, aber meine Erfahrung ist, dass sie am besten in das Stammverzeichnis der Webseite gelegt werden. Ich möchte sie jedoch nicht im root meinees Projekts sehen (zu viel Lärm!), also lege ich sie normalerweise alle in src/assets/images/favicon/ ab.

Um eine einzelne Datei in das Stammverzeichnis von dist zu kopieren, verwende ich diesen Befehl:

eleventyConfig.addPassthroughCopy({
  'src/assets/images/favicon/apple-touch-icon.png': 'apple-touch-icon.png'
});

Jetzt könntest du das für jede Favicon-Datei tun, aber das wäre eine Menge unnötiger Wiederholungen. Stattdessen kannst du alle Dateien im Favicon-Verzeichnis mit dem Platzhalter * (asterisk) selektieren:

eleventyConfig.addPassthroughCopy({
  'src/assets/images/favicon/*': '/'
});

Was Art und Anzahl von Favicons angeht, empfehle ich Andrey Sitniks Artikel.

Weitere Passthrough File Copy Tricks

Hier könnt ihr wirklich kreativ werden.

Man kann alle JPG-Bilder in allen Ordnern ansprechen und sie alle zusammen in einen gemeinsamen Ausgabeordner schicken:

eleventyConfig.addPassthroughCopy({
  '**/*.jpg': 'img'
});

Du kannst deine Assets in einem Array kombinieren und dabei die Verzeichnisstruktur beibehalten:

['src/assets/images/', 'src/assets/fonts/', 'src/assets/pdf/'].forEach(path =>
  eleventyConfig.addPassthroughCopy(path)
);

Oder du kannst diese interessante Filterung anwenden, die ich im Quellcode von Robb Knights persönlicher Website entdeckt habe, wo alles innerhalb von src/assets und src/files in das Ausgabeverzeichnis kopiert wird, außer allen CSS-Dateien und Dateien, die mit einem Unterstrich beginnen.

['src/assets', 'src/files'].forEach(path => {
  eleventyConfig.addPassthroughCopy(path, {
    filter: path => !path.endsWith('.css') && !path.startsWith('_')
  });
});

Wrap up

So strukturiere ich derzeit meine Projekte. Du kannst die Methoden angewandt in meinem Starter eleventy-excellent sehen. Ein wunderbares Beispiel für eine aufgeräumte Eleventy Konfigurationsdatei findet ihr im Repository von Miriam Suzannes Website.

Ein Blick in den offiziellen Eleventy-Starter lohnt sich immer, denn dort sind Sicherheit cutting edge Ideen zu finden.

Generell ist es immer eine gute Idee, tief in die Repos von Starterprojekten oder Webseiten anderer EntwicklerInnen einzutauchen.

Es gibt so viele großartige Ideen!

Eleventy Meetup

Ich wurde als Rednerin zum Eleventy Meetup Ep. 12 am 16. März 2023 eingeladen und hielt einen kurzen Vortrag, der auf diesem Artikel basierte.


Ich versuche meine Artikel aktuell zu halten, und natürlich kann ich mich auch irren, oder es gibt eine bessere Lösung. Wenn du etwas siehst was so nicht (mehr) stimmt, oder etwas das noch erwähnt werden sollte, kannst du den Artikel gerne bearbeiten: GitHub.

Webmentions

Hast du eine Antwort veröffentlicht? Lass mich wissen, wo: