Upgrading Tailwind CSS to v2.0 in a Phoenix app

Hello! I have a Phoenix app that uses Tailwind CSS 1.9 and I’m upgrading it to Tailwind CSS 2.0.

I’m following this guide https://tailwindcss.com/docs/upgrading-to-v2 but after running:

npm install tailwindcss@latest postcss@latest autoprefixer@latest

webpack stops building my CSS.

Has anyone tried this upgrade already?

Hi,

Have you upgraded posts-loader ?

Hi! I’m using TailwindCSS 2 with Phoenix in a personal project and I did that just recently…

This is my package.json, see if it helps:

"dependencies": {
    "@tailwindcss/forms": "^0.2.1",
    "alpinejs": "^2.7.3",
    "animate.css": "^4.1.1",
    "autoprefixer": "^10.0.2",
    "phoenix": "file:../deps/phoenix",
    "phoenix_html": "file:../deps/phoenix_html",
    "popper.js": "^1.16.1",
    "postcss": "^8.1.7",
    "stickybits": "^3.7.7",
    "tailwindcss": "^2.0.1",
    "tippy.js": "^6.2.6",
    "trix": "^1.3.0",
    "unpoly": "^0.62.1"
  },
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "babel-loader": "^8.0.0",
    "copy-webpack-plugin": "^5.1.1",
    "css-loader": "^3.4.2",
    "hard-source-webpack-plugin": "^0.13.1",
    "mini-css-extract-plugin": "^0.9.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss-import": "^13.0.0",
    "postcss-loader": "^4.0.2",
    "terser-webpack-plugin": "^2.3.2",
    "webpack": "4.41.5",
    "webpack-cli": "^3.3.2"
  }

personally I haven’t - but see this tweet/guide and the reply from @andreaseriksson

edit: https://fullstackphoenix.com/boilerplates/new comes with tailwind2, so check out the boilerplate config

5 Likes

Thanks! I’ll review Mike Clark’s guide and see what’s changed.

1 Like

I’ve updated TailwindCSS to v2 on my side project recently and everything works fine so here are my package.json and webpack.config,js files. I’m using PostCSS 8 here. Hope this helps.

package.json

{
“repository”: {},
“description”: " ",
“license”: “MIT”,
“scripts”: {
“deploy”: “webpack --mode production”,
“watch”: “webpack --mode development --watch”
},
“dependencies”: {
“nprogress”: “^0.2.0”,
“phoenix”: “file:…/deps/phoenix”,
“phoenix_html”: “file:…/deps/phoenix_html”,
“phoenix_live_view”: “file:…/deps/phoenix_live_view”
},
“devDependencies”: {
@babel/core”: “^7.0.0”,
@babel/preset-env”: “^7.0.0”,
@tailwindcss/forms”: “^0.2.1”,
“autoprefixer”: “^10.0.2”,
“babel-loader”: “^8.0.0”,
“copy-webpack-plugin”: “^5.1.1”,
“css-loader”: “^3.4.2”,
“cssnano”: “^4.1.10”,
“file-loader”: “^6.2.0”,
“hard-source-webpack-plugin”: “^0.13.1”,
“mini-css-extract-plugin”: “^0.9.0”,
“node-sass”: “^4.13.1”,
“optimize-css-assets-webpack-plugin”: “^5.0.1”,
“postcss”: “^8.1.10”,
“postcss-import”: “^13.0.0”,
“postcss-loader”: “^4.0.4”,
“sass-loader”: “^8.0.2”,
“tailwindcss”: “^2.0.1”,
“terser-webpack-plugin”: “^2.3.2”,
“webpack”: “4.41.5”,
“webpack-cli”: “^3.3.2”
}
}

webpack.config.js

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

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

return {
optimization: {
minimizer: [
new TerserPlugin({ cache: true, parallel: true, sourceMap: devMode }),
new OptimizeCSSAssetsPlugin({})
]
},
entry: {
‘app’: glob.sync(’./vendor/**/*.js’).concat([’./js/app.js’])
},
output: {
filename: ‘[name].js’,
path: path.resolve(__dirname, ‘…/priv/static/js’),
publicPath: ‘/js/’
},
devtool: devMode ? ‘eval-cheap-module-source-map’ : undefined,
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: ‘babel-loader’
}
},
{
test: /.[s]?css$/,
use: [
MiniCssExtractPlugin.loader,
‘css-loader’,
‘postcss-loader’,
],
},
{
test: /.(woff(2)?|ttf|eot|svg)(?v=\d+.\d+.\d+)?$/,
include: path.resolve(__dirname, ‘./static/fonts’),
use: [
{
loader: ‘file-loader’,
options: {
name: ‘[name].[ext]’,
outputPath: ‘./fonts/’
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({ filename: ‘…/css/app.css’ }),
new CopyWebpackPlugin([{ from: ‘static/’, to: ‘…/’ }])
]
.concat(devMode ? [new HardSourceWebpackPlugin()] : [])
}
};

Thanks, the boilerplate generated by FullStackPhoenix works fine, so I’ll take that as my guide.

1 Like

I’m seeing two alternate approaches with regards to the ENV production variable in the various guides for Tailwind and Phoenix out there:

Approach 1:

In tailwind.config.js, in the purge section, set:
enabled: process.env.MIX_ENV === "prod",

Approach 2:

In package.json, in the deploy section:
"deploy": "NODE_ENV=production webpack --mode production"

Is one approach better than the other?

Thank you!