Styling
=======
With the basic component and tooling in place, we will now expand that to have a bit more content and then also include some styling. First, copy the contents of the ``
`` of the ``login.html`` file from week 1, paste it into the ``athena.jsx`` and adjust the classes to bootstrap, so that it looks like this:
.. code-block:: jsx
import React from "react";
import ReactDom from "react-dom";
function Athena() {
return (
);
}
ReactDom.render(, document.getElementById("app-entry-point"));
There are a few rules in JSX that mean that attributes are spelled slightly differently to standard HTML. The first is that instead of ``class`` you must always use ``className``. The second is that all attributes need to be camel-cased, so for example ``tabindex`` becomes ``tabIndex``. Make those two changes and the code will compile without warnings in the browser and you will see an unstyled login page.
To add styling, we basically take the same approach as for the JSX support. We need to install additional packages for Webpack, so that it knows how to deal with style files:
.. code-block:: console
$ yarn add sass-loader node-sass style-loader css-loader bootstrap
Next, update the ``webpack.conf.js``, adding a module rule to deal with the scss files we use to create our styling:
.. code-block:: js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: path.resolve(__dirname, "src/js/athena.jsx"),
output: {
filename: "[name]-bundle.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: "var",
library: "Athena",
},
mode: "development",
plugins: [
new HtmlWebpackPlugin({
title: "Athena",
template: path.resolve(__dirname, "src/index.html"),
inject: false,
xhtml: true,
}),
],
module: {
rules: [
{
test: /\.m?jsx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
plugins: ["babel-plugin-transform-class-properties"],
},
},
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
},
{
loader: "sass-loader",
options: {
sassOptions: {
includePaths: [path.resolve(__dirname, "node_modules")],
},
},
},
],
},
],
},
resolve: {
extensions: ["*", ".js", ".jsx"],
},
devServer: {
static: {
directory: path.resolve(__dirname, "dist"),
},
open: false,
historyApiFallback: true,
},
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
commons: {
test: /node_modules/,
name: "athena-vendor",
chunks: "initial",
minSize: 1,
},
},
},
},
};
Next, create a new directory ``src/styles`` and copy the ``app.scss``from ``week09/app/styles`` into that directory. The most important part of the addition is the ``includePaths`` which tells the SASS/SCSS compiler where to look for files included from our style files.
At this point, if you re-start the build server, you will see that the styling is still not being applied. This is because we haven't told Webpack where to find it and include it. To include styling we use the standard JavaScript ``import`` function in the ``athena.jsx``:
.. code-block:: js
import React from 'react';
import ReactDOM from 'react-dom';
import '../styles/app.scss';
function Athena() {
...
}
Because we have configured a module to handle \*.scss files, it knows what to do, when a SCSS file is imported and you will see that at this point the application is styled correctly.