Phoenix 1.4, Webpack 4 and Bulma, Bootstrap 4 SASS

I am trying to get Phoenix 1.4-dev (soon 1.4) working with Webpack 4 and Sass.

Has anyone else managed this?

I have an older stack which I am trying to upgrade, my target is this

Ubuntu 18.04 Bionic Beaver
Erlang 20
Elixir 1.6
Webpack 4
SASS
Bulma or Bootstrap 4 (Bootswatch)
jQuery
custom local fonts
custom local icons svg


I tried the master package.json, babelrc, webpack.config.js and its broken and only css, I assume the generator will not include sass config by default

I’ll post more as I progress

4 Likes

Bulma

{
“repository”: {},
“license”: “MIT”,
“scripts”: {
“deploy”: “webpack --mode production --progress”,
“watch”: “webpack --watch-stdin --progress --color”
},
“dependencies”: {
“animate.css”: “^3.5.2”,
“bulma”: “^0.6.2”,
“bulma-extensions”: “^1.0.0”,
“jquery”: “^3.3.1”,
“phoenix”: “file:…/…/…/deps/phoenix”,
“phoenix_html”: “file:…/…/…/deps/phoenix_html”
},
“devDependencies”: {
“babel-core”: “^6.26.0”,
“babel-loader”: “^7.1.3”,
“babel-preset-env”: “^1.6.1”,
“copy-webpack-plugin”: “^4.5.0”,
“css-loader”: “^0.28.10”,
“exports-loader”: “^0.7.0”,
“file-loader”: “^1.1.11”,
“mini-css-extract-plugin”: “^0.4.0”,
“node-sass”: “^4.9.0”,
“optimize-css-assets-webpack-plugin”: “^4.0.0”,
“postcss-loader”: “^2.1.5”,
“sass-loader”: “^7.0.1”,
“style-loader”: “^0.21.0”,
“uglifyjs-webpack-plugin”: “^1.2.4”,
“webpack”: “4.4.0”,
“webpack-cli”: “^2.0.10”
}
}

const path = require(‘path’);
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”);

const staticDir = path.join(__dirname, ‘.’);
const destDir = path.join(__dirname, ‘…/priv/static’);
const publicPath = ‘/’;

module.exports = (env, options) => ({
entry: {
app: [
staticDir + “/css/app.scss”,
staticDir + “/js/app.js”
]
},
output: {
path: destDir,
filename: “js/[name].js”,
publicPath
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: ‘babel-loader’
}
},
// Adds font implications
{
test: /.(css|scss|sass)/,
use: [ ‘style-loader’, MiniCssExtractPlugin.loader, ‘css-loader’, ‘sass-loader’]
},
{
test: /.(eot|svg|ttf|woff|woff2)(?\S*)?$/,
loader: “file-loader”
},
{
test: /.(png|jpe?g|gif|svg)(?\S*)?$/,
loader: “file-loader”,
query: {
name: “[name].[ext]?[hash]”
}
}
]
},
plugins: [
new MiniCssExtractPlugin({ filename: ‘./css/app.css’ }),
new CopyWebpackPlugin([{ from: “./static” }]),
new webpack.ProvidePlugin({
$: “jquery”,
jQuery: “jquery”,
“window.jQuery”: “jquery”
}),

]
});

if (process.env.NODE_ENV === “production”) {
module.exports.devtool = “#cheap-module-eval-source-map”;

module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
“process.env”: {
NODE_ENV: “‘production’”
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new OptimizeCssAssetsPlugin()
]);
}

Bootstrap 4

{
“repository”: {},
“license”: “MIT”,
“scripts”: {
“deploy”: “webpack --mode production --progress”,
“watch”: “webpack --watch-stdin --progress --color”
},
“dependencies”: {
“animate.css”: “^3.5.2”,
“bootstrap”: “4.0.0-alpha.6”,
“bootswatch”: “https://github.com:/thomaspark/bootswatch.git#v4.0.0-beta.2”,
“phoenix”: “file:…/…/…/deps/phoenix”,
“phoenix_html”: “file:…/…/…/deps/phoenix_html”
},
“devDependencies”: {
“babel-core”: “^6.26.0”,
“babel-loader”: “^7.1.3”,
“babel-preset-env”: “^1.6.1”,
“copy-webpack-plugin”: “^4.5.0”,
“css-loader”: “^0.28.10”,
“exports-loader”: “^0.7.0”,
“file-loader”: “^1.1.11”,
“mini-css-extract-plugin”: “^0.4.0”,
“node-sass”: “^4.9.0”,
“optimize-css-assets-webpack-plugin”: “^4.0.0”,
“postcss-loader”: “^2.1.5”,
“sass-loader”: “^7.0.1”,
“style-loader”: “^0.21.0”,
“uglifyjs-webpack-plugin”: “^1.2.4”,
“webpack”: “4.4.0”,
“webpack-cli”: “^2.0.10”
}
}

const path = require(‘path’);
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”);

const staticDir = path.join(__dirname, ‘.’);
const destDir = path.join(__dirname, ‘…/priv/static’);
const publicPath = ‘/’;

module.exports = (env, options) => ({
entry: {
app: [
staticDir + “/css/animate.css”,
staticDir + “/js/app.js”,
staticDir + “/js/bootstrap/alert.js”,
staticDir + “/js/bootstrap/button.js”,
staticDir + “/js/bootstrap/carousel.js”,
staticDir + “/js/bootstrap/collapse.js”,
staticDir + “/js/bootstrap/dropdown.js”,
staticDir + “/js/bootstrap/modal.js”,
staticDir + “/js/bootstrap/popover.js”,
staticDir + “/js/bootstrap/scrollspy.js”,
staticDir + “/js/bootstrap/tab.js”,
staticDir + “/js/bootstrap/tooltip.js”,
staticDir + “/js/bootstrap/util.js”]
},
output: {
path: destDir,
filename: “js/[name].js”,
publicPath
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: ‘babel-loader’
}
},
// Adds font implications
{
test: /.(css|scss|sass)/,
use: [ ‘style-loader’, MiniCssExtractPlugin.loader, ‘css-loader’, ‘sass-loader’]
},
{
test: /.(eot|svg|ttf|woff|woff2)(?\S*)?$/,
loader: “file-loader”
},
{
test: /.(png|jpe?g|gif|svg)(?\S*)?$/,
loader: “file-loader”,
query: {
name: “[name].[ext]?[hash]”
}
}
]
},
plugins: [
new MiniCssExtractPlugin({ filename: ‘./css/app.css’ }),
new CopyWebpackPlugin([{ from: “./static” }]),
new webpack.ProvidePlugin({
$: “jquery”,
jQuery: “jquery”,
“window.jQuery”: “jquery”,
Tether: “tether”,
“window.Tether”: “tether”,
Alert: “exports-loader?Alert!bootstrap/js/dist/alert”,
Button: “exports-loader?Button!bootstrap/js/dist/button”,
Carousel: “exports-loader?Carousel!bootstrap/js/dist/carousel”,
Collapse: “exports-loader?Collapse!bootstrap/js/dist/collapse”,
Dropdown: “exports-loader?Dropdown!bootstrap/js/dist/dropdown”,
Modal: “exports-loader?Modal!bootstrap/js/dist/modal”,
Popover: “exports-loader?Popover!bootstrap/js/dist/popover”,
Scrollspy: “exports-loader?Scrollspy!bootstrap/js/dist/scrollspy”,
Tab: “exports-loader?Tab!bootstrap/js/dist/tab”,
Tooltip: “exports-loader?Tooltip!bootstrap/js/dist/tooltip”,
Util: “exports-loader?Util!bootstrap/js/dist/util”,
}),

]
});

if (process.env.NODE_ENV === “production”) {
module.exports.devtool = “#cheap-module-eval-source-map”;

module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
“process.env”: {
NODE_ENV: “‘production’”
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new OptimizeCssAssetsPlugin()
]);
}

2 Likes

Were you able to get live reloading working for the css/scss? I’ve hit a wall and just reverted back to my webpack3 setup that works flawlessly.

I dont think its working actually

I see the 1.4 book is out in beta and the paper edition is due for September, so I guess things are going to be settling down next few months

I actually think a few things are broken actually, not suprising

to be clear, I am having problems with live reloading and I think sockets, bit hard to unpack my bugs, core code changes, and core code bugs

I will probably pull myself away from this for a few weeks and see what happens with 1.4 etc

Adding sass/scss to a Phoenix 1.4 project involves the following:

  1. Adding node-sass and sass-loader to assets/package.json
  2. Renaming assets/css/app.css to assets/css/app.scss
  3. Adding the sass-loader to the css file section in webpack.config.js and changing the extension to .scss
  4. changing import css from "../css/app.css" to import css from "../css/app.scss" in assets/js/app.js

Here’s a diff of the altered files:

package.json:

     "copy-webpack-plugin": "^4.5.0",
     "css-loader": "^0.28.10",
     "mini-css-extract-plugin": "^0.4.0",
+    "node-sass": "^4.9.0",
     "optimize-css-assets-webpack-plugin": "^4.0.0",
+    "sass-loader": "^7.0.1",
     "uglifyjs-webpack-plugin": "^1.2.4",
     "webpack": "4.4.0",
     "webpack-cli": "^2.0.10"

webpack.config.js:

       {
-        test: /\.css$/,
-        use: [MiniCssExtractPlugin.loader, 'css-loader']
+        test: /\.scss$/,
+        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
       }
     ]
   },

assets/js/app.js

 // 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.css"
+import css from "../css/app.scss"

Live reloading works for this setup.

28 Likes

Thanks, I will give this a try - but what are you using in the package.json scripts to start the dev watcher? I was able to have webpack extract the CSS, but then the changes in files weren’t triggering the reload (I was using phoenix 1.3 though no sure it would matter?)

Thanks i upgraded webpack3 to webpack4 without any problem.

When using Phoenix 1.4 (currently with the master branch) generating a new application will use:

  watchers: [node: ["node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch-stdin",
                    cd: Path.expand("../assets", __DIR__)]]
4 Likes

Thank you @gazler, I will give this a try

thanks very much. works for me on Brunch SASS etc

:grin:

it works! the problem was I was using yarn to launch the script here it seems - although it looks like it should work (I probably misconfigured something somewhere else…) thx

correction, webpack works with Bulma AND webpack (mistyped Brunch)

Don’t use yarn: https://mixmax.com/blog/to-yarn-and-back-again-npm

1 Like

There should be a js.flavour-of-the-month.com website were we would check what was the right tool in a certain month to use - I won’t probably run into the issues mentioned there and I was quite happy now that I found out I could create offline mirrors for the yarn.lock (which means able to do fully reproducible build without downloading packages, nor having to commit the whole node_modules to the repo).

Perhaps I need to take yours and perry’s advice and just build my own pipeline but it’s such a grunt…

1 Like

I’ve never used yarn publish, but in 2 years of using yarn, I’ve never encountered any of the problems the author mentioned, but I’ve been burned by npm several times.

1 Like

Do you know how to configure the app to export multiple css files? For example, if I wanted a vendor.css and app.css?

Just add a reference to your CSS file.

module.exports = {
  entry: {
    app: ['./assets/App.js', './assets/App.scss'],
    vendor: ['react', 'react-dom', './assets/Vendor.scss']
  },
  // ...
}

However, I don’t see any reason to split your CSS.

2 Likes

Hi everyone, I am also trying to install Bulma for a 1.4-dev project.

Here are the steps I followed (thanks to @niccolox ox and @Gazler) :

I added to my dependencies in package.json (left Jquery in devDependencies):

  • “animate.css”: “^3.5.2”,
  • “bulma”: “^0.6.2”,
  • “bulma-extensions”: “^1.0.0”,

I added to my devDependencies in packages.json:

  • “node-sass”: “^4.9.0”,

  • “sass-loader”: “^7.0.1”,

  • Added node-sass and sass-loader to assets/package.json

  • Renamed assets/css/app.css to assets/css/app.scss

  • Added the sass-loader to the css file section in webpack.config.js and changing the extension to .scss

  • changed import css from "../css/app.css" to import css from "../css/app.scss" in assets/js/app.js

  • ran npm i in /myproject/assets (got no error)

but I Bulma isn’t working.

Did I forget something ?