DEV Community

Masatoshi Nishiguchi
Masatoshi Nishiguchi

Posted on • Edited on

Adding Bootstrap 4 and PurgeCSS to Phoenix 1.5

I hear Tailwind is popular now, but I personally do not see any benefit. It just adds extra complexity. First I tried to get used to it but I feel a lot more productive using Bootstrap and I like simple Bootstrap styles better. So I decided to stick with Bootstrap. For setting up Tailwind, this Pragmatic Studio post was helpful, by the way.

日本語版

Here is how I set it up.

1. Install Bootstrap

cd path/to/my/phoenix/app
npm install --prefix assets --save-dev bootstrap@4 purgecss-webpack-plugin glob-all
Enter fullscreen mode Exit fullscreen mode

2. Import Bootstrap CSS

Next we need to import Bootstrap's CSS into our assets/css/app.scss file.

  /* This file is for your main application css. */
  @import "../node_modules/nprogress/nprogress.css";
+ @import "../node_modules/bootstrap/scss/bootstrap.scss";
Enter fullscreen mode Exit fullscreen mode

3. Configure Purge CSS

This is an optional step but we might as well get rid of unused CSS from Bootstrap since it is easy to set up. Open the assets/webpack.config.js file and modify a few locations:

  • Use glob-all instead of default glob because we need to specify multiple filenames to Purge CSS.
  • Require purgecss-webpack-plugin
  • Specify array of file paths that may reference any Bootstrap CSS class by name, which in Phoenix are all the view modules, template files, and JavaScript files.
  const path = require('path');
- const glob = require('glob');
+ const glob = require('glob-all');
  const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
  const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  const TerserPlugin = require('terser-webpack-plugin');
  const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
  const CopyWebpackPlugin = require('copy-webpack-plugin');
+ const PurgecssPlugin = require('purgecss-webpack-plugin');

  module.exports = (env, options) => {
    const devMode = options.mode !== 'production';

    return {

      # ...

      plugins: [
        new MiniCssExtractPlugin({ filename: '../css/app.css' }),
        new CopyWebpackPlugin([{ from: 'static/', to: '../' }]),
+       new PurgecssPlugin({
+         paths: glob.sync([
+           '../lib/**/*.ex',
+           '../lib/**/*.leex',
+           '../lib/**/*.eex',
+           './js/**/*.js',
+           './node_modules/some_library/**/*.js',
+         ]),
+       }),
      ]
      .concat(devMode ? [new HardSourceWebpackPlugin()] : [])
    }
  };
Enter fullscreen mode Exit fullscreen mode

Or if we want to use Purge CSS only in production mode

module.exports = (env, options) => {
  const devMode = options.mode !== 'production';

  return {

    # ...

    plugins: [
      new MiniCssExtractPlugin({ filename: '../css/app.css' }),
      new CopyWebpackPlugin([{ from: 'static/', to: '../' }]),
    ].concat(
      devMode
        ? [
            // development only
            new HardSourceWebpackPlugin(),
          ]
        : [
            // production only
            new PurgecssPlugin({
              paths: glob.sync([
                '../lib/**/*.ex',
                '../lib/**/*.leex',
                '../lib/**/*.eex',
                './js/**/*.js',
                './node_modules/some_library/**/*.js',
              ]),
            }),
          ]
    ),
  }
};
Enter fullscreen mode Exit fullscreen mode

I personally prefer to apply it to both development and production so that I can prevent surprise at deployment.

4. Remove unnecessay Phoenix default CSS

Now that we use Bootstrap CSS, we can remove Phoenix default CSS for the flash message, other than .alert:empty, which hides the flash message when there is nothing to show.

- .alert {
-   padding: 15px;
-   margin-bottom: 20px;
-   border: 1px solid transparent;
-   border-radius: 4px;
- }
- .alert-info {
-   color: #31708f;
-   background-color: #d9edf7;
-   border-color: #bce8f1;
- }
- .alert-warning {
-   color: #8a6d3b;
-   background-color: #fcf8e3;
-   border-color: #faebcc;
- }
- .alert-danger {
-   color: #a94442;
-   background-color: #f2dede;
-   border-color: #ebccd1;
- }
- .alert p {
-   margin-bottom: 0;
- }
  .alert:empty {
    display: none;
  }
Enter fullscreen mode Exit fullscreen mode

5. Override Bootstrap variables (optional)

Optionally, we can override Bootstrap variables so that we can customize the styling. You can find the full list of Bootstrap variables in the library's scss/_variables.scss file.

I personally make a file at assets/css/_variables.scss of my Phoenix project and copy some sections of Bootstrap variables that I intend to override. It may look like below.

@import "../node_modules/bootstrap/scss/functions";

// Custom Variables
// Override Bootstrap variables here.
// https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss

// Color system

$white:    #fff;
$gray-100: #eceff1;
$gray-200: #cfd8dc;
$gray-300: #b0bec5;
$gray-400: #90a4ae;
$gray-500: #78909c;
$gray-600: #607d8b;
$gray-700: #546e7a;
$gray-800: #455a64;
$gray-900: #37474f;
$black:    #263238;

$grays: ();
// stylelint-disable-next-line scss/dollar-variable-default
$grays: map-merge(
  (
    "100": $gray-100,
    "200": $gray-200,
    "300": $gray-300,
    "400": $gray-400,
    "500": $gray-500,
    "600": $gray-600,
    "700": $gray-700,
    "800": $gray-800,
    "900": $gray-900
  ),
  $grays
);

// https://material.io/resources/color
$blue:    #2962FF;
$indigo:  #304FFE;
$purple:  #AA00FF;
$pink:    #C51162;
$red:     #D50000;
$orange:  #FF6D00;
$yellow:  #FFD600;
$green:   #00C853;
$teal:    #00BFA5;
$cyan:    #00B8D4;
Enter fullscreen mode Exit fullscreen mode

One important thing is we should remove !default when we copy Bootstrap variable from the library's file because our custom values will be final, not default.

Then I import my custom variables in my assets/css/app.scss file.

  /* This file is for your main application css. */
+ @import 'variables';
  @import '../node_modules/nprogress/nprogress.css';
  @import '../node_modules/bootstrap/scss/bootstrap.scss';
Enter fullscreen mode Exit fullscreen mode

6. Add custom CSS (optional)

  /* This file is for your main application css. */
  @import 'variables';
  @import '../node_modules/nprogress/nprogress.css';
  @import '../node_modules/bootstrap/scss/bootstrap.scss';
+ @import 'my_custom_syles';
Enter fullscreen mode Exit fullscreen mode

That's it!

Top comments (0)