Skip to content

Instantly share code, notes, and snippets.

@muratgozel
Last active May 28, 2017 18:51
Show Gist options
  • Save muratgozel/e3ca2c08f74c9cb6eb7314e3088edb77 to your computer and use it in GitHub Desktop.
Save muratgozel/e3ca2c08f74c9cb6eb7314e3088edb77 to your computer and use it in GitHub Desktop.
Use jss and postcss together in your project.
// If you are planning to use postcss plugins like autoprefixer,
//you probably should precompile your jss style objects with postcss-js before running your app.
// Because autoprefixer makes a network request and loads caniusedb json file into your bundle
//and this will dramaticly increase the size of your bundle.
// So lets create a precompile script
// Following 2 library needed for writing compiled jss style objects to files
var fs = require("fs");
var stringifyObject = require("stringify-object");
// Create postcss parser object
var postcssJs = require("postcss-js");
var autoprefixer = require("autoprefixer");
var postcss = postcssJs.sync([ autoprefixer ]);
// A sample jss style objects that will be compiled by postcss
const homeStyles = {
header: {
'display': 'flex',
'flex-direction': 'column',
'align-items': 'center',
'margin-top': '8rem'
},
headerDark: {
extend: 'header',
'color': '#000'
},
headerLight: {
extend: 'header',
'color': '#fff'
},
title: {
'text-align': 'center',
'padding': '0 4rem',
'margin-bottom': '2rem'
}
}
const formStyles = {
form: {
'width': '80%',
'display': 'flex',
'flex-direction': 'column',
'align-items': 'center'
},
label: {
'display': 'block',
'width': '100%',
'font-size': '2rem',
'margin-bottom': '3rem',
'text-align': 'center'
},
input: {
'font-size': '2rem',
'padding': '1rem 2rem',
'width': '100%',
'margin-bottom': '3rem'
}
}
// Create a jss container style object
// We want output our compiled jss style objects to files as "home.js" and "form.js"
// So we can use "import styles from '../styles/home.js'" in our components
const jssContainer = {
home: homeStyles,
form: formStyles
}
// This function compiles each class definition in every style object and
//creates files according to the jss container
function saveJssChunksToFile( jssContainer ) {
if(typeof jssContainer !== 'object') {
return
}
for(var chunk in jssContainer) {
// postcssJss is a custom function that compiles each jss class with postcss
var data = 'export default '+stringifyObject( postcssJss( jssContainer[chunk] ) );
// Write chunk to a file
fs.writeFile('styles/'+chunk+'.js', data, function(err) {
if(err) throw err;
})
}
return
}
// This function compiles single jss style object with postcss
function postcssJss( jssStyleObject ) {
var result = {};
if(typeof jssStyleObject !== 'object') {
return result;
}
// process every css class in the object
for (var jssClass in jssStyleObject) {
result[jssClass] = postcss(jssStyleObject[jssClass]);
}
return result;
}
// run
saveJssChunksToFile( jssContainer );
// adding npm script to the package.json recommended
// "scripts": {
// ...
// "styler": "node ./scripts/dev/createStyles.js"
// ...
// },
// use postcss-js package to parse css-in-js styles before jss compiles it
import postcssJs from 'postcss-js'
// import postcss plugins you want to use in your project
import autoprefixer from 'autoprefixer'
// import jss and jss camelcase plugin. We must use camelcase plugin to let jss properly process postcss style objects
import { create } from 'jss'
import camelCase from 'jss-camel-case'
// create jss object
let jss = create()
jss.use(camelCase())
// create postcss parser with plugins we want to use
const postcss = postcssJs.sync([ autoprefixer ])
// a sample style object that gives jss the power of postcss
const testStyle = {
testClass: postcss({
transform: 'translateX(-50%) translateY(-50%)',
filter: 'brightness(0)',
display: 'flex',
animation: 'explode 0.3s cubic-bezier(.12,.61,.26,.93) 0s 1 normal forwards'
}),
'@keyframes explode': {
from: postcss({
'filter': 'brightness(0)'
}),
to: postcss({
'filter': 'brightness(1)'
})
},
}
@giuseppeg
Copy link

giuseppeg commented Jun 15, 2016

Neat! Could something like this work?

// create postcss parser with plugins we want to use
const postcss = postcssJs.sync([ autoprefixer ])

// $tyle lets you declare styles using es6 templates strings
const $tyle = css => postcssJs.objectify(postcss.parse(css));

const testStyle = {
  testClass: $tyle(`
    transform: translateX(-50%) translateY(-50%);
    filter: brightness(0);
    display: flex;
    animation: explode 0.3s cubic-bezier(.12,.61,.26,.93) 0s 1 normal forwards;
    background-color: hotpink;
  `)
}

@muratgozel
Copy link
Author

Yes. It should work. But there is an important thing that we should consider before using autoprefixer in our apps.

I realized that a serius performance problem happens if i import autoprefixer the way above. Because autoprefixer loads caniusedb json file into the app bundle file. In order to prevent this i wrote a small script that process all jss files with postcss before app bundling starts. This way, app bundle takes already autoprefixed jss files.

I will share the code in a short time.

@giuseppeg
Copy link

In order to prevent this i wrote a small script that process all jss files with postcss before app bundling starts.

Agreed! I am doing the same, I build the files with a custom preprocessor based on postcss and then feed them to the $tyle function :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment