Erste Schritte mit CSS Modules

Avatar of Robin Rendle
Robin Rendle am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Es gibt nicht *einen einzigen* Ansatz bei CSS Modules, um die JavaScript-Vorlagen, die CSS-Dateien oder die Build-Schritte zu erstellen, die für deren Funktion notwendig sind. In diesem Beitrag, der Teil einer Serie über CSS Modules ist, werden wir einen Ansatz beleuchten. Das Ziel dieses Beitrags ist es, ein CSS Modules-Projekt zum Laufen zu bringen.

Artikelserie

  1. Was sind CSS Modules und warum brauchen wir sie?
  2. Erste Schritte mit CSS Modules (Sie sind hier!)
  3. React + CSS Modules = 😍

In den Projekten, an denen ich arbeite, gibt es die Anforderung, dass CSS niemals auf clientseitigem JavaScript basieren darf, um zu funktionieren. Daher muss der Build-Schritt alles in funktionierendes HTML und CSS verarbeiten, bevor es bereitgestellt wird. Wir werden webpack verwenden, ein Build-System und Modul-Bundler. Im nächsten Beitrag konzentrieren wir uns darauf, den unten stehenden Code für ein reales Projekt geeignet zu machen, das statisches HTML an den Browser rendert.

Legen wir los!

Webpack installieren

Nachdem wir NPM und Node installiert haben, müssen wir ein leeres Verzeichnis einrichten und Folgendes ausführen:

npm init --y

Dies erstellt eine Datei package.json und füllt sie mit vielen Standardwerten. Dies ist unser Abhängigkeitsmanifest – die Anweisungen, was heruntergeladen und installiert wird, wenn andere Personen dieses Projekt mit npm install installieren.

webpack wird unseren Build-Prozess handhaben. Es wird unsere CSS-, JavaScript- und HTML-Dateien beobachten und alle Magie dazwischen durchführen. Aber was ist webpack? Maxime Fabre fragte sich, ob webpack ein Build-System oder ein Modul-Bundler ist

Nun, es ist beides – und damit meine ich nicht, dass es beides tut, sondern dass es beides kombiniert. webpack baut Ihre Assets nicht auf und bündelt dann separat Ihre Module, es betrachtet Ihre Assets selbst als Module… die importiert, modifiziert, manipuliert und letztendlich in Ihr finales Bundle gepackt werden können.

Wenn das seltsam klingt, machen Sie sich keine Sorgen. Erinnern Sie sich, als Sass und Gulp und npm alle unbekannt und beängstigend waren? Wir werden das schon hinkriegen.

Lassen Sie uns sicherstellen, dass webpack Module korrekt „bündelt“, indem wir eine JavaScript-Datei erstellen, die eine Abhängigkeit definiert, damit wir diesen Code-Teil importieren können. Zuerst müssen wir webpack global installieren, was uns Zugriff auf den Befehl webpack in unseren Terminals gibt.

npm install webpack -g

Sobald dies abgeschlossen ist, müssen wir webpack lokal in unserem Projekt installieren, so:

npm i -D webpack

Nun müssen wir eine Datei index.js in einem Verzeichnis /src erstellen. Typischerweise erstelle ich gerne ein Verzeichnis, in dem alle statischen Assets (wie Bilder, Schriftarten, CSS-Dateien und Markup) liegen. Jeder Code, den ich schreibe, wird typischerweise in einem Verzeichnis /src liegen, während jeder Code, der von einer Maschine geschrieben oder in einem bestimmten Prozess interpretiert wird, in einem Verzeichnis /build liegen sollte. Meine Überlegung ist, dass es völlig in Ordnung sein sollte, ein Verzeichnis /build zu löschen, ohne irgendwelche Probleme zu erleiden, da wir einfach einen Befehl ausführen und es die Dinge aus dem Verzeichnis /src verarbeitet und das Verzeichnis /build vollständig neu erstellt. In diesem Fall möchten wir, dass webpack alles im Verzeichnis /src betrachtet, einen bestimmten Prozess durchführt und dann diesen Code in das Verzeichnis /build verschiebt.

Im Verzeichnis /src können wir auch eine leere Datei alert.js hinzufügen (wir werden in einer Minute darauf zurückkommen). Wir benötigen auch eine Datei webpack.config.js, die sich am Stammverzeichnis unseres Projekts befindet, außerhalb des Verzeichnisses /src, sodass unsere Projektstruktur nun so aussehen sollte:

package.json
webpack.config.js
/node_modules
/src
  index.js
  alert.js

Innerhalb von webpack.config.js (einer Datei zur Konfiguration von webpack) können wir Folgendes hinzufügen:

module.exports = {
  entry: './src',
  output: {
    path: 'build',
    filename: 'bundle.js',
  },
};

Immer wenn wir von nun an den Befehl webpack ausführen, wird webpack alle Assets in /src betrachten, um einen Abhängigkeitsbaum zu erstellen.

Zurück zu unserer Datei src/index.js können wir Folgendes hinzufügen:

require("./alert.js");

Und in unserer Datei alert.js können wir Folgendes schreiben:

alert("LOUD NOISES");

Erstellen wir nun eine Datei index.html in unserem Stammverzeichnis und fügen Sie unseren Bundle in einem Skript-Tag kurz vor dem schließenden hinzu:



    
    

CSS Modules Demo


    <script src="build/bundle.js"></script>

Diese Datei bundle.js wird von webpack generiert. Um sie zu generieren, müssen wir lediglich den Befehl webpack ausführen. Um es uns einfacher zu machen, können wir unsere Datei package.json mit einem Build-Skript aktualisieren. So sollte diese Datei aussehen:

"scripts": {
  "test": "echo 'Error: no test specified' &amp;&amp; exit 1"
},

Das sind die Standardwerte, die npm uns gegeben hat, aber wir können das obige durch den folgenden Code ersetzen, um unser eigenes Kommandozeilen-Skript zu erstellen, das webpack für uns ausführt und ein Browserfenster öffnet:

"scripts": {
  "start": "webpack &amp;&amp; open index.html"
},

Immer wenn wir also npm start ausführen, werden wir automatisch den Befehl webpack ausführen und unsere Indexdatei im Browser öffnen. Tun wir das jetzt und sehen wir, was passiert.

Hurra, etwas funktioniert! Dies beweist, dass unsere Datei index.js unseren Code aus alert.js importiert und dass webpack alles richtig bündelt. Wenn wir nun die Datei alert.js löschen, erhalten wir bei erneutem Ausführen von npm start einen Fehler:

Das ist der Fehler, den webpack anzeigt, wenn es ein importiertes Modul nicht finden kann. Aber jetzt, da wir bestätigt haben, dass all dies funktioniert, können wir die require-Anweisung in unserer Datei index.js verwerfen und mit dem nächsten Schritt beim Erlernen von Webpack fortfahren.

Unseren ersten Loader hinzufügen

Ein Loader in webpack ist sehr wichtig. Maxime Fabre sagt dazu auf diesem Thema:

Loader sind kleine Plugins, die im Grunde sagen: „Wenn du auf diese Art von Datei stößt, mache dies damit.“

In Maximes Tutorial fügt er den Babel-Loader hinzu, was ein wirklich guter Ausgangspunkt ist, denn Babel ermöglicht uns die Verwendung von ES2015 und den neuesten Verbesserungen der JavaScript-Sprache. Anstatt der Common.js-Funktion, die wir zuvor zum require eines anderen Moduls verwendet haben, können wir stattdessen import verwenden. Mit Babel können wir auch Klassen, Pfeilfunktionen und eine Vielzahl anderer cooler Features verwenden.

Tools wie Babel ermöglichen es uns, heute neuen ES2015-Code zu schreiben und eine Aufgabe namens Transpilieren (ähnlich wie Präprozessieren) durchzuführen, um den Code in eine frühere Version von JavaScript umzuwandeln, die eine bessere Browserunterstützung hat. Dies ist ähnlich wie Sass funktioniert; Sie schreiben Ihren Code zunächst in Sass-Syntax, und dann kompiliert ein Präprozessor ihn zu Standard-CSS.

Das Folgende installiert den webpack Babel-Loader und die Abhängigkeiten, die wir benötigen, um Babel auszuführen:

npm i -D babel-loader babel-core babel-preset-env

In einer Datei .babelrc im Stammverzeichnis unseres Projekts können wir das Preset konfigurieren, um anderen mitzuteilen, welche JavaScript-Syntax wir verwenden werden:

{
  "presets": ["babel-preset-env"]
}

Nun möchten wir Babel auf alle unsere .js-Dateien anwenden, aber nur auf die Dateien, die *wir* schreiben. Alle anderen Abhängigkeiten, die wir später installieren, haben möglicherweise ihre eigene Syntax, und wir möchten diesen Code nicht verändern. Hier kommt der webpack-Loader ins Spiel. Wir können die Datei webpack.config.js öffnen und diesen Code damit ersetzen:

module.exports = {
  entry:  './src',
  output: {
  path: 'build',
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /\.js/,
        loader: 'babel-loader',
        include: __dirname + '/src',
       }
    ],
  }
};

Das Schlüssel-Wert-Paar test innerhalb des Arrays loaders teilt webpack mit, auf welche Art von Datei eine Aktion angewendet werden soll, während include ihm genau mitteilt, wo in unserem Projekt diese Aktion ausgeführt werden soll.

Testen wir, ob Babel in Verbindung mit webpack funktioniert. In einer neuen Datei (src/robot.js) schreiben wir Folgendes:

const greetings = (text, person) =&gt; {
  return `${text}, ${person}. I read you but I’m sorry, I’m afraid I can’t do that.`;
}

export default greetings;

Diese JavaScript-Datei verwendet eine Reihe von ES2015-spezifischen Features, wie export, const und let, Pfeilfunktionen und Template-Literale.

Jetzt können wir dieses Modul in unsere Datei src/index.js importieren, so:

import greetings from './robot.js'
document.write(greetings("Affirmative", "Dave"));

Schließlich müssen wir nur noch npm start erneut ausführen, und unser Browser sollte mit dem Text erscheinen: „Affirmative, Dave. I read you but I’m sorry, I’m afraid I can’t do that.“ Dies bestätigt einfach, dass Babel wie erwartet funktioniert.

Hurra! Das ist noch kein CSS Module, obwohl wir definitiv einen Schritt näher gekommen sind. Aber bevor wir weitermachen, löschen wir src/robot.js und den gesamten Code aus src/index.js.

Styles laden

Nun, da unsere Vorlagen fast funktionieren, müssen wir zwei weitere Loader hinzufügen: css-loader und style-loader, die wir installieren werden:

npm i -D css-loader style-loader

Der css-loader nimmt eine CSS-Datei und liest alle ihre Abhängigkeiten aus, während der style-loader diese Stile direkt in das Markup einbettet. Testen wir dies, indem wir etwas CSS in src/app.css schreiben:

.element {
  background-color: blue;
  color: white;
  font-size: 20px;
  padding: 20px;
}

Dann können wir dieses Stylesheet in unsere Datei src/index.js importieren:

import styles from './app.css'

let element = `

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur laudantium recusandae itaque libero velit minus ex reiciendis veniam. Eligendi modi sint delectus beatae nemo provident ratione maiores, voluptatibus a tempore!

`

document.write(element);

Whoa, Moment mal! Haben wir gerade ein Stylesheet zu einer Abhängigkeit einer JavaScript-Datei gemacht? Ja, das haben wir. Aber bevor es richtig funktioniert und bevor wir sehen, warum das nützlich ist, müssen wir unsere Datei webpack.config.js erneut konfigurieren:

module.exports = {
  entry:  './src',
  output: {
    path: 'build',
      filename: 'bundle.js',
    },
  module: {
    loaders: [
      {
        test: /\.js/,
        loader: 'babel',
        include: __dirname + '/src',
      },
      {
        test: /\.css/,
        loaders: ['style', 'css'],
        include: __dirname + '/src'
      }
    ],
  }
};

Wenn wir npm start ausführen, erhalten wir etwas wie das hier:

Folglich, wenn wir „Element untersuchen“ auf unserem Dokument ausführen, werden wir feststellen, dass der style-loader diese Datei in ein platziert hat:

<style>-Tag im <head> des Dokuments:

Werfen wir einen Blick darauf, was gerade passiert ist. Wir haben eine JavaScript-Datei erstellt, die eine andere CSS-Datei angefordert hat, und dieser Code wurde dann in eine Webseite eingebettet. In einem realistischeren Beispiel könnten wir also eine Datei buttons.js erstellen und buttons.css zu einer Abhängigkeit davon machen und dann diese JavaScript in eine andere Datei importieren, die unsere Vorlagen organisiert und etwas HTML ausgibt. Dies sollte unseren Code absurd modular und leicht lesbar machen!

Persönlich, um die Dinge sauber zu halten, hätte ich lieber eine separate CSS-Datei, anstatt allen Code inline hinzuzufügen. Dazu benötigen wir ein webpack Plugin namens extract text, welches

bewegt jedes require(‚style.css‘) in Entry Chunks in eine separate CSS-Ausgabedatei. So werden Ihre Stile nicht mehr in JavaScript eingebettet, sondern separat in einer CSS-Bundle-Datei (styles.css). Wenn Ihr gesamtes Stylesheet-Volumen groß ist, wird es schneller, da das Stylesheet-Bundle parallel zum JavaScript-Bundle geladen wird.

Wir müssen das mit npm installieren:

npm i -D extract-text-webpack-plugin

Jetzt können wir unsere Datei webpack.config.js erneut aktualisieren, indem wir sie anfordern und unseren CSS-Loader darin platzieren:

var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry:  './src',
  output: {
    path: 'build',
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /\.js/,
        loader: 'babel',
        include: __dirname + '/src',
      },
      {
        test: /\.css/,
        loader: ExtractTextPlugin.extract("css")
      }
    ],
  },
  plugins: [
    new ExtractTextPlugin("styles.css")
  ]
};

ExtractTextPlugin wird nun eine Datei styles.css für uns erstellen!

Sie haben vielleicht bemerkt, dass wir den style-loader komplett entfernt haben. Das liegt daran, dass wir diese Stile nicht mehr in unser Markup einbetten wollen. Wenn wir also jetzt das Verzeichnis /build öffnen, sollten wir feststellen, dass eine Datei styles.css mit unserem gesamten Code darin erstellt wurde. Und in unserer Datei index.html können wir nun unser Stylesheet im <head> hinzufügen:

<link rel="stylesheet" href="build/styles.css">

Führen Sie npm start erneut aus und *blammo!* – unsere Stile erscheinen magisch wieder auf der Seite, wo sie hingehören.

Nachdem wir nun unsere CSS und HTML auf der Seite funktionsfähig haben, wie manipulieren wir die Klassennamen, um alle Vorteile eines lokalen Geltungsbereichs zu nutzen? Alles, was wir tun müssen, ist, unsere Datei webpack.config.js wie folgt zu aktualisieren:

{
  test: /\.css/,
  loader: ExtractTextPlugin.extract('css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'),
}

Dies fügt den verrückt generierten Text am Ende des Klassennamens hinzu. Das ist alles, was CSS Modules wirklich ist: ein Hash, der die Klassen ändert, die in webpack über einen CSS-Loader hinzugefügt werden können.

Als Nächstes müssen wir unsere Datei index.js mit der Klasse styles.element aktualisieren:

import styles from './app.css'

let element = `
  <div class="${styles.element}">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur laudantium recusandae itaque libero velit minus ex reiciendis veniam. Eligendi modi sint delectus beatae nemo provident ratione maiores, voluptatibus a tempore!
  </div>
`

document.write(element);

Schauen Sie, was passiert! Ein weiteres npm start und unser Code wurde von webpack verarbeitet, sodass der lokale Geltungsbereich kein Problem mehr darstellt, da die Klasse, die in die Webseite injiziert wird, nun so aussieht:

<div class="app__element___1MmQg">
  ...
</div>

Wir sind immer noch nicht wirklich fertig, da viele Fragen offen bleiben. Wie könnten wir solchen Code in der Entwicklung schreiben? Wie umgehen wir die unschöne Regel document.write, mit der wir das Markup in die Seite einfügen? Wie sollten wir unsere Module und Dateien strukturieren? CSS Modules zum Laufen zu bringen ist nur die halbe Arbeit, als Nächstes müssen wir darüber nachdenken, wie wir eine Codebasis von einem anderen System darauf portieren könnten.

Im nächsten Tutorial werden wir uns ansehen, wie React uns helfen kann, übersichtliche kleine Module zu generieren, außerdem werden wir sehen, wie wir statisches Markup aus einer Reihe von Vorlagen generieren und wie wir andere Funktionen wie Sass und PostCSS zu unserem Projekt hinzufügen können.

Artikelserie

  1. Was sind CSS Modules und warum brauchen wir sie?
  2. Erste Schritte mit CSS Modules (Sie sind hier!)
  3. React + CSS Modules = 😍