Deploy Wagtail CMS to PythonAnywhere (part 2)

Set up Webpack and client side code compilation

This is a minimal setup for compiling client side code with Webpack.

It will compile all files in client/styles css, client/scripts javascript and output them to webapp/static as bundle.css and bundle.js.

Setup node and NPM

First lets make sure the node version used will always be the intended version 18.

In the root of your project run:

echo 18 > .nvmrc
bash
note code Copy code

Install NVM (node version manager)

Instructions can be viewed at https://github.com/nvm-sh/nvm where you can choose your preferred installation method. I used brew on MacOS.

brew install nvm
bash
note code Copy code

Use node version 18

nvm use
bash
note code Copy code

If you don't have the correct version of node installed a message will tell you that and you can install it with:

nvm install 18
bash
note code Copy code

Initialize NPM

npm init
bash
note code Copy code

This will create a package.json file in the root of your project.

Then install the required packages by running:

npm install --save-dev \
    @babel/preset-env \
    babel-loader \
    browser-sync-webpack-plugin \
    css-loader \
    mini-css-extract-plugin \
    sass \
    sass-loader \
    webpack \
    webpack-cli \
    webpack-dev-server
bash
note code Copy code

This will have created a node_modules directory in the root of your project. It's not a folder we need to commit to the repository so add it to the .gitignore file.

echo "node_modules" >> .gitignore
bash
note code Copy code

Add Webpack configuration

You can read more about Webpack at https://webpack.js.org/.

Create a file webpack.config.js in the root of your project with the following content:

const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const BrowserSyncPlugin = require("browser-sync-webpack-plugin");

module.exports = {
  mode: "production", // or "development"
  entry: path.resolve(__dirname, "./client/scripts/index.js"),
  output: {
    path: path.resolve(__dirname, "./webapp/static/webapp"),
    filename: "bundle.js",
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"],
          },
        },
      },
      {
        test: /\.scss$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "bundle.css",
    }),
    new BrowserSyncPlugin({
      host: "localhost",
      port: 3000,
      proxy: "http://127.0.0.1:8000/", // the port your django app will be running on in development
      files: ["./**/*.html"],
    }),
  ],
};
javascript
note code Copy code

Add client side code

Create a directory called client in the root of your project with the following folders:

mkdir -p client/{scripts,styles}
bash
note code Copy code

Add styles

Create a file client/styles/index.scss with the following content:

body {
  background-color: grey;
}
css
note code Copy code

Add javascript

Create a file client/scripts/index.js with the following content:

console.log("Awesome Wagtail !");
javascript
note code Copy code

Update the scripts section in the package.json file to:

"scripts": {
  "build": "webpack --mode production",
  "start": "webpack --mode development --watch"
},
json
note code Copy code

Run Webpack

To compile the client side code during development run:

npm start # which will compile and watch for changes
bash
note code Copy code

To compile the client side code for production run:

npm run build # which will compile and minify the code
bash
note code Copy code

Running either of these commands will create a webapp/static/webapp directory containing bundle.css and bundle.js.

Update the base template to use the compiled files

Open the webapp/templates/base.html file and update the head section to include the compiled css and javascript files:

<!-- change -->
<link rel="stylesheet" type="text/css" href="{% static 'css/webapp.css' %}">
<!-- to -->
<link rel="stylesheet" type="text/css" href="{% static 'webapp/bundle.css' %}">
<!-- change -->
<script src="{% static 'js/webapp.js' %}"></script>
<!-- to -->
<script src="{% static 'webapp/bundle.js' %}"></script>
html
note code Copy code

You can delete the webapp/static/css and webapp/static/js directories and files as they are no longer needed.

Run the development server

In a new console run the development server (after activating the virtualenv):

python manage.py runserver
bash
note code Copy code

As long as you are running the npm start command in the other console...

Open your browser at http://localhost:3000 and you should see the home page with a grey background and a message in the console.

Try changing the background color in client/styles/index.scss and you should see the changes in the browser without having to refresh the page.

Just for fun :-)

Create a file client/scripts/logo.js with the following content:

class Logo {
  constructor() {
        this.logo = document.getElementsByClassName('logo')[0];
        this.header = document.getElementsByClassName('header')[0];
    }

    init() {
      setTimeout(() => {
        this.logo.classList.add('logo--fade-in');
            this.header.classList.add('header--slope');
        }, 1000);
    }
}

module.exports = Logo;
javascript
note code Copy code

Update client/scripts/index.js to the following:

import "../styles/index.scss";
import Logo from "./logo.js";

const logo = new Logo();
logo.init();
javascript
note code Copy code

Create a file client/styles/_vars.scss with the following content:

$background-color: #43b1b0;
$foreground-color: #fff;
css
note code Copy code

Alter the client/styles/index.scss file to the following:

@import "./vars";

body {
  background-color: $background-color;
}

h2, a {
  color: $foreground-color !important;
}

svg .egg {
  fill: $foreground-color;
}

.logo--fade-in {
  animation: fade-in 1s ease-out;
  animation-fill-mode: forwards;
  svg g {
    fill: white;
  }
}

@keyframes fade-in {
  0% {
    opacity: 0.2;
    transform: scale(1);
  }
  75% {
    opacity: 0.8;
    transform: scale(1.8) translateX(10%);
  }
  100% {
    opacity: 1;
    transform: scale(1.4) translateX(0) translateY(20px) rotate(0deg);
  }
}

.header--slope {
  animation: slope 1s ease-in-out;
  animation-fill-mode: forwards;  
}

@keyframes slope {
  0% {
    transform: rotate(0deg);
  }
  90% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(-2deg);
  }
}
css
note code Copy code

With npm start still running: If you view the Wagtail start page (home) it's going to look a little different.