How to setup Zurb Foundation 6 with a Phoenix app

I can’t figure out how to set up Zurb Foundation 6 with a Phoenix app using webpack, no docs at all :frowning: . It was much easier to do that for Bootstrap 4 by just following this simple and useful tutorial.
Foundation docs say to add these 3 JS scripts at the end of a body:

<body>
    <h1>Hello, world!</h1>

    <script src="js/vendor/jquery.js"></script>
    <script src="js/vendor/what-input.js"></script>
    <script src="js/vendor/foundation.min.js"></script>
    <script>
      $(document).foundation();
    </script>

  </body>

But Phoenix builds everything in a single app.js if I’m not mistaken :thinking:
Here is what I added to app.js file:

import 'foundation-sites'
import css from "../css/app.scss"
import "phoenix_html"

I also renamed app.css -> to app.scss and here is its content:

@import "./node_modules/foundation-sites/scss/foundation";

I also installed:

what-input.js
jquery.js
node-sass
sass-loader

Tneh I modified webpack.config.js as follows to use sass-loader and load app.scss:

module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.s?css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
      }
    ]
  },

When starting the server, it compiles without errors but:

  • there are no Foundation styles at all
  • there is Uncaught ReferenceError: $ is not defined error.

Any idea how to make it work? Thank you

1 Like

Maybe You can add in webpack.config.js something like this…

const webpack = require('webpack');
  ...
  plugins: [
    ....
    new webpack.ProvidePlugin({ // inject modules as global vars
      $: 'jquery',
      jQuery: 'jquery', 'window.jQuery': 'jquery',
    })
  ]

You might add what-input, but this I don’t know because I have never used zurb foundation :slight_smile:

Here is the modifcation I added to webpack.config.js:

plugins: [
    new MiniCssExtractPlugin({ filename: '../css/app.css' }),
    new CopyWebpackPlugin([{ from: 'static/', to: '../' }]),
    new webpack.ProvidePlugin({ // inject modules as global vars
      $: 'jquery',
      jQuery: 'jquery', 'window.jQuery': 'jquery',
    })
  ]

it still fails with the same error:

(index):62 Uncaught ReferenceError: $ is not defined
    at (index): 62:

pointing to the line required to be added by Foundation to the template:

<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
    <script>
      $(document).foundation();
    </script>

I made MVP and had the same error, but I could see $ was defined in chrome console. You need to wait document is loaded before using $.

Try like this… it worked for me.

    <script>
      document.onload = () => $(document).foundation()
    </script>

Yes, using

<script>
      document.onload = () => $(document).foundation()
    </script>

fixed jQuery error, but still no Foundation CSS, app.css in the console Sources tab is just empty:

/* This file is for your main application css. */
/**
 * Foundation for Sites by ZURB
 * Version 6.5.3
 * foundation.zurb.com
 * Licensed under MIT Open Source
 */

I am not sure this is the good path…

I guess it should be

@import "../node_modules/foundation-sites/scss/foundation";

# or

@import "~foundation-sites/scss/foundation";

I tried both of them, none worked :frowning:

Yo! I figured out how to make it work :slight_smile:.
Here is what I put in app.js file:

import $ from 'jquery'

require   ('what-input');
window.$ = $;


import Foundation from 'foundation-sites';
$(document).foundation();

import css from "../css/app.scss"
import "phoenix_html"

Then I modified app.scss as follows:

@import "~foundation-sites/scss/foundation";
@include foundation-everything();

I totally removed from app.html.eex template the JS line you suggested:

<script>
  document.onload = () => $(document).foundation()
</script>

and it has the only one generated by Phoenix:

<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>

Finally, webpack.config.js contains this:

...
plugins: [
    require('autoprefixer'),
    new MiniCssExtractPlugin({ filename: '../css/app.css' }),
    new CopyWebpackPlugin([{ from: 'static/', to: '../' }]),
    new webpack.ProvidePlugin({ // inject modules as global vars
      $: 'jquery',
      jQuery: 'jquery', 'window.jQuery': 'jquery',
    })

Hope this helps.

1 Like

Hi @belgoros,

Thanks for your great post.

Just wondering - how and where did you put the foundation-sites project?
did you put it into

  • your assets, or
  • allow npm install to put it into nod_modules?

regards,

PK

@pkbyron, thank you. You can find the project code source here, hope this helps :slight_smile:

1 Like

@belgoros - your notes were essential for me working this out. Thanks so much for doing some hard yards in there!

Have it up and running!

phoenix “1.4.1”
foundation “6.6.1”
mac_osx: 10.15.3
node: 13.12.0

Getting Foundation working within Phoenix

Step 1. Getting Foundation in the right spot

I couldn’t get the foundation-cli working: it has a problem with node versions > 10.x; and as I am running node version 13.12.x, it was easier just to get the git version 6.6.1 from github.

  1. Download foundation 6.6.1 from github
  2. Unzip the download file into project_folder/assets/node_modules
  3. Make sure the directory name is foundation-sites (mine was called foundation-sites-develop)
  4. cd project_folder/assets/node_modules/foundation-site and view the README.md file. Within here there should be instructions on how to get foundation-site running…
    - npm install
    - npm start
    - after it starts, you can stop this running
  5. go back to your assets folder cd ../..

Step 2. Update your phoenix files

Change the extension of your app.css file

% mv assets/css/app.css -> assets/css/app.scss
// file: app.scss
@import "~foundation-sites/scss/foundation";
@include foundation-everything();
@import "./phoenix.css";

Edit your assets/js/app.js

// We need to import jquery for the webpack build of foundation
// And attach the foundation build to the document
import $ from 'jquery'
require('what-input');
window.$ = $;

import Foundation from 'foundation-sites';
$(document).foundation();

// We need to import the CSS so that webpack will load it.
// The MiniCssExtractPlugin is used to separate it out into
// its own CSS file.
import css from "../css/app.scss";

// webpack automatically bundles all modules in your
// entry points. Those entry points can be configured
// in "webpack.config.js".
//
// Import dependencies
//
import "phoenix_html"

// Import local files
//
// Local files can be imported directly using relative paths, for example:
// import socket from "./socket"

Step 3. Change the Phoenix setup

Here is my webpack.config.js file

!Important! - this includes a couple of packages you need to install first, cause if you don’t you will get errors on build.

% npm install jquery
% npm install sass-loader
% npm install node-sass
% npm install autoprefixer
% npm install webpack
const path = require('path');
const glob = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');

module.exports = (env, options) => ({
  optimization: {
    minimizer: [
      new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: false }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  entry: {
    './js/app.js': ['./js/app.js'].concat(glob.sync('./vendor/**/*.js'))
  },
  output: {
    filename: 'app.js',
    path: path.resolve(__dirname, '../priv/static/js')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.s?css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
      }
    ]
  },
  plugins: [
    require('autoprefixer'),
    new MiniCssExtractPlugin({ filename: '../css/app.css' }),
    new CopyWebpackPlugin([{ from: 'static/', to: '../' }]),
    new webpack.ProvidePlugin({ // inject modules as global vars
      $: 'jquery',
      jQuery: 'jquery', 'window.jQuery': 'jquery',
    })
  ]
});

Hope this helps.

3 Likes

Thanks - that was super-helpful - but one question. In these steps:

is there a reason why it’s installed manually vs

npm install --save-dev foundation-sites

Thanks!