Tailwindcss JIT integration with Sage 10

Upgrading to tailwind 2.1.1 on the latest Sage 10 build worked for me. Here are the changes I made:

  • In tailwind.config.js added mode: 'jit', to the top of module.exports
  • In package.json I modified the scripts to "build": "TAILWIND_MODE=build mix",, "build:production": "TAILWIND_MODE=build mix --production", and "start": "TAILWIND_MODE=watch mix watch",

That was it. The purge rules were already configured with the latest build of Sage 10 so I didn’t need to add anything else. I had a lot of variants enabled and quite a few other assets and build time went from 18 seconds to about 2. It’s a great tool for the Tailwind workflow.

4 Likes

Thanks so much, this works well for me!

Thanks so much, these instructions work perfectly for me. Amazingly fast!

I tried this, but get still an error, when running yarn build:

● Mix █████████████████████████ done (99%)  
 plugins

ERROR in ./resources/styles/app.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
TypeError: node.clone is not a function
    at /home/markus/code/blog/web/app/themes/dev-theme/node_modules/tailwindcss/jit/lib/utils.js:94:35
    at Array.map (<anonymous>)
    at cloneNodes (/home/markus/code/blog/web/app/themes/dev-theme/node_modules/tailwindcss/jit/lib/utils.js:94:16)
    at /home/markus/code/blog/web/app/themes/dev-theme/node_modules/tailwindcss/jit/lib/expandTailwindAtRules.js:257:35
    at LazyResult.runOnRoot (/home/markus/code/blog/web/app/themes/dev-theme/node_modules/postcss/lib/lazy-result.js:303:16)
    at LazyResult.runAsync (/home/markus/code/blog/web/app/themes/dev-theme/node_modules/postcss/lib/lazy-result.js:355:26)
    at LazyResult.async (/home/markus/code/blog/web/app/themes/dev-theme/node_modules/postcss/lib/lazy-result.js:205:30)
    at LazyResult.then (/home/markus/code/blog/web/app/themes/dev-theme/node_modules/postcss/lib/lazy-result.js:190:17)
    at processResult (/home/markus/code/blog/web/app/themes/dev-theme/node_modules/webpack/lib/NormalModule.js:675:19)
    at /home/markus/code/blog/web/app/themes/dev-theme/node_modules/webpack/lib/NormalModule.js:777:5
    at /home/markus/code/blog/web/app/themes/dev-theme/node_modules/loader-runner/lib/LoaderRunner.js:399:11
    at /home/markus/code/blog/web/app/themes/dev-theme/node_modules/loader-runner/lib/LoaderRunner.js:251:18
    at context.callback (/home/markus/code/blog/web/app/themes/dev-theme/node_modules/loader-runner/lib/LoaderRunner.js:124:13)
    at Object.loader (/home/markus/code/blog/web/app/themes/dev-theme/node_modules/postcss-loader/dist/index.js:96:7)

The package.json:

 {
  "private": true,
  "browserslist": [
"extends @wordpress/browserslist-config"
  ],
  "engines": {
"node": ">=12.14.0"
  },
  "scripts": {
"build": "TAILWIND_MODE=build mix",
"build:production": "TAILWIND_MODE=build mix --production",
"start": "TAILWIND_MODE=watch mix watch",
"hot": "mix watch --hot",
"clear": "wp acorn optimize:clear",
"test": "npm run lint",
"lint": "npm run lint:js && npm run lint:css",
"lint:js": "eslint resources/scripts",
"lint:css": "stylelint \"resources/**/*.{css,scss,vue}\"",
"translate": "npm run translate:pot && npm run translate:js",
"translate:pot": "wp i18n make-pot . ./resources/lang/sage.pot --ignore-domain --include=\"app,resources\"",
"translate:js": "wp i18n make-json ./resources/lang --pretty-print"
  },
  "devDependencies": {
"@tailwindcss/typography": "^0.4.0",
"@tinypixelco/laravel-mix-wp-blocks": "^1.1.0",
"@wordpress/babel-preset-default": "^5.0.1",
"@wordpress/browserslist-config": "^3.0.1",
"@wordpress/dependency-extraction-webpack-plugin": "^3.0.1",
"babel-eslint": "^10.1.0",
"browser-sync": "^2.26.14",
"browser-sync-webpack-plugin": "^2.3.0",
"eslint": "^7.20.0",
"eslint-plugin-import": "^2.22.1",
"laravel-mix": "^6.0.11",
"postcss": "^8.2.6",
"sass": "^1.32.7",
"sass-loader": "11.0.1",
"stylelint": "^13.10.0",
"stylelint-config-standard": "^20.0.0",
"tailwindcss": "^2.1"
  },
  "dependencies": {
"@tailwindcss/forms": "^0.2.1",
"@tailwindcss/line-clamp": "^0.2.0",
"alpinejs": "^2.8.0",
"tailwindcss-fl": "^0.3.0"
  }
}

and the webpack.mix.js:

const mix = require('laravel-mix');
require('@tinypixelco/laravel-mix-wp-blocks');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Sage application. By default, we are compiling the Sass file
 | for your application, as well as bundling up your JS files.
 |
 */

mix
  .setPublicPath('./public')
  .browserSync('dev-blog.ddev.site');

mix
  .sass('resources/styles/app.scss', 'styles')
  .sass('resources/styles/editor.scss', 'styles')
  .options({
    processCssUrls: false,
    postCss: [require('tailwindcss')],
  });

mix
  .js('resources/scripts/app.js', 'scripts')
  .js('resources/scripts/customizer.js', 'scripts')
  .blocks('resources/scripts/editor.js', 'scripts')
  .autoload({ jquery: ['$', 'window.jQuery'] })
  .extract();

mix
  .copyDirectory('resources/images', 'public/images')
  .copyDirectory('resources/fonts', 'public/fonts');

mix
  .sourceMaps()
  .version();

and finally the tailwind config:

const colors = require('tailwindcss/colors')
const defaultTheme = require('tailwindcss/defaultTheme')

module.exports = {
  mode: 'jit',
  purge: {
    content: [
      './app/**/*.php',
      './resources/**/*.php',
      './resources/**/*.vue',
      './resources/**/*.js',
    ],
  },
  darkMode: 'media', // or 'media' or 'class'
  theme: {
    colors: {
      transparent: 'transparent',
      current: 'currentColor',
      black: colors.black,
      white: colors.white,
      gray: colors.trueGray,
      blue: colors.lightBlue,
      red: colors.red,
      yellow: colors.amber,
    },
    fontFamily: {
      'sans': ['Inter', ...defaultTheme.fontFamily.sans],
      'serif': [...defaultTheme.fontFamily.serif],
      'mono': [...defaultTheme.fontFamily.mono],
    },
    extend: {
      colors: {
        primary: '#911616',
      },
    },
    container: {
      center: true,
      padding: '1rem',
    },
  },
  variants: {
    extend: {},
  },
  plugins: [
    require('tailwindcss-fl')({
      screenMin: 'screens.sm',
      screenMax: 'screens.xl',
      defaultRatio: 1.618,
    }),
    require('@tailwindcss/forms'),
    require('@tailwindcss/line-clamp'),
    require('@tailwindcss/typography'),
  ],
};

Does anybody know where the issue is?

Regards,
Markus

Could it be that you’re not requiring jit in your webpack?

Tried it, but still doesn’t work. But with tailwind 2.1 jit was added to the core, and afaik you don’t need to reference it either. In a plain test, just tailwind 2.1, mix, etc. it works fine, but in the sage-setup I’m getting that error.

And the error is only in the “jit”-mode, when mode: 'jit is set in the tailwind config.

I am glad others got this working! :movie_camera: This video was before I changed the start script†, but the same thing happens that you can see in this video. yarn start goes up, changing anything outside of a .scss file works great, but updating a .scss file does not work.

† After this video I updated the start script and it looks like this: "start": "TAILWIND_MODE=watch mix watch",

Could it be the Tailwind plugin, tailwind-fl? I’ve never used it but it’s in your config file. It looks like it hasn’t been updated in a while. Could be tripping up the build?

1 Like

Thats it! That was the issues. When I remove it, it works!

Interesting, so I am the only one who can’t get the watch task to work now?

The scss file changing doesn’t do anything for me neither. I can even write some garbage in the scss files and they don’t complain until I run yarn start again.

:frowning:

1 Like

I am sure it is related to the scss processing as I have another project (not sage) with css instead of scss and it works flawlessly. So at least we know what to focus in.

P.S. Just to narrow it a little bit more, if you edit directly in app.scss and not inside an imported scss it works. Why would that happen??

1 Like

FWIW I setup a dummy Gatsby site via gatsby new <project name> and converted that to work with Tailwind, the JIT compiler and Emotion for gatsby’s build and watch tasks in less than 30 minutes. The process is dead simple. Why we’re having an issue here with SCSS and Laravel Mix is beyond me.

Ok, I was trying some options and there is some dirty workaround. For some unknown reason, saving a scss file doesn’t trigger the rebuild of the css for jit. But app.scss always do. So while we know how to fix the problem, saving the app.scss file after saving the imported one will update the styles. :tada:

1 Like

The only thing i recognised is, that the watch task get slowier with the time. But don’t know if it’s an sage issue, or tailwind in generally. But will have an eye on it on other (non sage/wordpress) projects

What version of node are you running?

15.8.0 Why? Can it be a problem with node you think?

I had issues with a create react app, app and Node 12 with the JIT compiler not compiling the media query TW classes. 14.x.x fixed that issue. I haven’t had a chance to try ~14 on this sage project yet but wanted to see what you were using to see if it was also an older version. I’ll report back if anything changes but I would imagine 15 would be fine. I have nvm for older projects I work on that need 12.

Is anyone else having issues with all the color options not rendering?

For example, sometimes bg-gray-100, 200, 300, etc will render correctly and sometimes not. Same with blues, etc.

This div should have a gray-600 background but its white:

If I change it to gray-900 and the back to 600, it will render sometimes but then disappear again.
Other times I have to run yarn cache clean and then run yarn build in order to get the correct colors to show up.

Some sort of cache issue? I am not seeing this as a problem with anything else except bg colors. Text colors render fine everytime.

This is my entire tailwind config:

module.exports = {
  mode: 'jit',
  purge: {
    content: [
      './app/**/*.php',
      './resources/**/*.php',
      './resources/**/*.js',
    ],
  },
}

If you dynamically generate those class names (eg <div class="text-' . $alignment"> PurgeCSS can’t pick them up. Use a lookup table in your component classes/view composer so the full string class names can be picked up by Purge