Skip to content

TheSpicyMeatball/js-to-css-generator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

15 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Build Status Coverage Status

js-to-css-generator

Generate CSS style sheets from your css-in-js JSON objects

Hello friend.

CSS-in-JS is awesome and powerful, but what do you do if you also have legacy apps to support which can only consume regular CSS?

[pause for effect...]

Well, that's where js-to-css-generator comes in to save the day!

With js-to-css-generator, you can auto-MAGICALLY deliver classic CSS alongside your CSS-in-JS so your legacy apps can hang around even longer! (just what you've always wanted)

Version: 1.5.3

Utils

Examples

Supporting Types


getFile

Optional utility to help you easily create a {File} object to use with {jsToCss}

Since v0.0.2

Param Type

srcFile

The string contents of the original source file
string

module

Object that contains all of your styled objects
Record<string, Record<string, string | number>>

settings (optional)

Optional object containing settings for how to parse the file
GetFileSettings

Returns: {File} The generated CSS file content

Import

import { getFile, File, GetFileSettings, Tag } from 'js-to-css-generator';

jsToCss

Convert JavaScript style objects to CSS files

Since v0.0.1

Param Type

files

The configurations for the CSS files
File | File[]

Returns: {CSSFile | CSSFile[]} The generated CSS file content

Import

import { jsToCss, CSSFile, File } from 'js-to-css-generator';

Examples

Basic

Let's say we have a file called styles.js which looks like this:

// styles.js

export const something = {
  backgroundColor: '#fff',
  fontSize: 12,
  padding: 16,
};

export const somethingElse = {
  backgroundColor: '#ccc',
  fontSize: 10,
  padding: 8,
};

You can create a CSS style sheet like so:

// Get the style objects as a module via require:
const styles = require('./styles.js');

// ...or assemble all style objects into a single object:
const styles = {
  something: {
    backgroundColor: '#fff',
    fontSize: 12,
    padding: 16,
  },
  somethingElse: {
    backgroundColor: '#ccc',
    fontSize: 10,
    padding: 8,
  },
};

// Generate CSS file
const { writeFileSync } = require('fs');
const { join } = require('path');
const { jsToCss } = require('js-to-css-generator');

const file = {
  name: 'styles.css',
  module: styles,
};

const cssFile = jsToCss(file);

writeFileSync(join(__dirname, cssFile.name), cssFile.css, 'utf8');

The above script will create a file styles.css which contains:

.something {
  background-color: #fff;
  font-size: 12px;
  padding: 16px;
}

.something-else {
  background-color: #ccc;
  font-size: 10px;
  padding: 8px;
}

Nested Styles & Combinators

jsToCss can also handle nested styles and combinators:

// styles.js

export const something = {
  backgroundColor: '#fff',
  fontSize: 12,
  padding: 16,
  ':hover': {
    backgroundColor: '#ccc',
  },
  '& + &': {
    marginLeft: 8,
  },
};
// Bring in the style objects
const styles = require('./styles.js');

// Generate CSS file
const { writeFileSync } = require('fs');
const { join } = require('path');
const { jsToCss } = require('js-to-css-generator');

const file = {
  name: 'styles.css',
  module: styles,
};

const cssFile = jsToCss(file);

writeFileSync(join(__dirname, cssFile.name), cssFile.css, 'utf8');

The above script will create a file styles.css which contains:

.something {
  background-color: #fff;
  font-size: 12px;
  padding: 16px;
}

.something:hover {
  background-color: #ccc;
}

.something + .something {
  margin-left: 8px;
}

What if my combinators are in separate objects?

In this example, we have a separate object called spacing which holds the combinators for something. We can still generate the correct styles with the combinators override:

// styles.js

export const something = {
  backgroundColor: '#fff',
  fontSize: 12,
  padding: 16,
  ':hover': {
    backgroundColor: '#ccc',
  }
};

export const spacing = {
  '& + &': {
    marginLeft: 8,
  },
};
// Bring in the style objects
const styles = require('./styles.js');

// Generate CSS file
const { writeFileSync } = require('fs');
const { join } = require('path');
const { jsToCss } = require('js-to-css-generator');

const file = {
  name: 'styles.css',
  combinators: {
    spacing: '.something',
  },
  module: styles,
};

const cssFile = jsToCss(file);

writeFileSync(join(__dirname, cssFile.name), cssFile.css, 'utf8');

The above script will create a file styles.css which contains:

.something {
  background-color: #fff;
  font-size: 12px;
  padding: 16px;
}

.something:hover {
  background-color: #ccc;
}

.something + .something {
  margin-left: 8px;
}

Notice how we added a combinators key to our file object which contains a spacing key that matches the name of the object with a combinator in our styles.js file. The value for spacing indicates the class name that should be used for the combinator in place of the &.

Other Advanced Features

There are more advanced features to give us more control over the output such as prepending, versioning, overrides, ignoring, etc.

Let's say we have a file called styles.js which looks like this:

// styles.js

export const something = {
  backgroundColor: '#fff',
  fontSize: 12,
  padding: 16,
};

export const somethingElse = {
  backgroundColor: '#ccc',
  fontSize: 10,
  padding: 8,
};

export const anotherSomething = {
  backgroundColor: 'green',
  display: 'flex',
  margin: 8,
};

export const oneMore = {
  border: '1px solid #ccc',
  padding: 16,
};
// Bring in the style objects
const styles = require('./styles.js');

// Generate CSS file
const { writeFileSync } = require('fs');
const { join } = require('path');
const { jsToCss } = require('js-to-css-generator');

const file = {
  name: 'styles.css',
  prepend: '.test',
  version: '1',
  overrides: {
    somethingElse: '.my-override',
  },
  ignore: ['anotherSomething'],
  map: true,
  module: styles,
};

const cssFile = jsToCss(file);

writeFileSync(join(__dirname, cssFile.name), cssFile.css, 'utf8');

The above script will create a file styles.css which contains:

/* something */
.test-v1-something {
  background-color: #fff;
  font-size: 12px;
  padding: 16px;
}

/* somethingElse */
.my-override {
  background-color: #ccc;
  font-size: 10px;
  padding: 8px;
}

/* oneMore */
.test-v1-one-more {
  border: 1px solid #ccc;
  padding: 16px;
}

We have prepended all of our class names with a base class and version .test-v1 except for somethingElse which has an override value of .my-override. We've also decided that we don't want to output anotherSomething so it's been added to the ignore list. Lastly, by setting map: true, we've mapped the original object name to each class name as a code comment above each class.

Multiple Files

jsToCss can also handle multiple files at a time. Simply pass in an array of your File objects and you'll get an array of CSSFile objects in return:

const files = [file1, file2, file3];
const cssFiles = jsToCss(files);

OK, but is there an easy way to build my File objects by marking up my original source files?

Yes there is! We can use getFile for that.

Let's say we have a file called styles.js which looks like this:

/** 
 * @config
 * @prepend .test
 * @map
 */


export const something = {
  backgroundColor: '#fff',
  fontSize: 12,
  padding: 16,
};

/** @class .my-override */
export const somethingElse = {
  backgroundColor: '#ccc',
  fontSize: 10,
  padding: 8,
};

/** @ignore */
export const anotherSomething = {
  backgroundColor: 'green',
  display: 'flex',
  margin: 8,
};

export const oneMore = {
  border: '1px solid #ccc',
  padding: 16,
};

Notice how we've marked up the file with some jsdoc tags. Especially notice the config:

/** 
 * @config
 * @prepend .test
 * @map
 */

The presence of a @config in the file indicates that these are settings that we want to apply to the whole file. In this case, we want to prepend all of our classes with .test and we want to map the original object names to each class by including a code comment above each.

We can now parse those out with the getFile util:

const { readFileSync } = require('fs');

// Bring in the style objects
const styles = require('./styles.js');

const srcFile = readFileSync('./styles.js', 'utf8');
const file = getFile(srcFile, styles, { name: 'styles.css', version: '1' });

const cssFile = jsToCss(file);

writeFileSync(join(__dirname, cssFile.name), cssFile.css, 'utf8');

The above script will create a file styles.css which contains:

/* something */
.test-v1-something {
  background-color: #fff;
  font-size: 12px;
  padding: 16px;
}

/* somethingElse */
.my-override {
  background-color: #ccc;
  font-size: 10px;
  padding: 8px;
}

/* oneMore */
.test-v1-one-more {
  border: 1px solid #ccc;
  padding: 16px;
}

Just for Fun

I know what you're thinking. "That's cool, but can it do emojis?"

You betcha!

// Get the style objects as a module via require:
const styles = require('./styles.js');

// Generate CSS file
const { writeFileSync } = require('fs');
const { join } = require('path');
const { jsToCss } = require('js-to-css-generator');

const file = {
  name: 'styles.css',
  prepend: '.πŸ’©',
  module: styles,
};

const cssFile = jsToCss(file);

writeFileSync(join(__dirname, cssFile.name), cssFile.css, 'utf8');

The above script will create a file styles.css which contains:

.πŸ’©-something {
  background-color: #fff;
  font-size: 12px;
  padding: 16px;
}

.πŸ’©-something-else {
  background-color: #ccc;
  font-size: 10px;
  padding: 8px;
}

Why might you do this? I don't know, but I'm sure you have your reasons and who am I to stand in your way?

Supporting Types

These are optional type definitions you can import for TypeScript. If you're not using TypeScript, you can use them as reference for the object shapes that you will be passing in as arguments or getting back as a return type.

File

export type File = {
  // any name that you would like to use as an identifier for the File
  name?: string,

  // optional string to use to prepend all of your classes for scope
  prepend?: string, 

  // optional object with key/value pairs where the keys match the
  // style object names you want to override and values that are the
  // class names to use as the overrides
  overrides?: Record<string, string>, 

  // optional object with key/value pairs where the keys match the
  // style object names you want to affect and values that are the
  // class names to use for the combinators. The value will replace
  // any '&' in your style names.
  combinators?: Record<string, string>,

  // optional array of names of style objects you don't want to
  // include as part of the output CSS file
  ignore?: string[],

  // optional string representation of the file version to add as
  // part of the class name
  version?: string,
  
  // optionally map the original object name to the outputted class
  // name via including a code comment above the class name with the
  // original object name
  map?: boolean,

  // object that contains all of your styled objects
  module: Record<string, Record<string, string | number>>,
};

CSSFile

export type CSSFile = {
  // any name that you gave your {File}
  name?: string,
  
  // The CSS file string content
  css: string,
  
  // JavaScript Map object of key/value pairs that maps the JS object name to a class name.
  objectToStyleMap: Map<string, string>,

  // JavaScript Map object of key/value pairs that maps the class name name to a JS object.
  styleToObjectMap: Map<string, string>,
};

Tags

Object used to define what the jsdoc tags are for parsing with getFile.

export type Tags = {
  class?: string,
  combinator?: string,
  config?: string,
  ignore?: string,
  map?: string,
  prepend?: string,
};

If not specified, the default values are:

{
  class: '@class',
  combinator: '@combinator',
  config: '@config',
  ignore: '@ignore',
  map: '@map',
  prepend: '@prepend',
};

GetFileSettings

export type GetFileSettings = {
  // any name that you gave your {File}
  name?: string, 

  // optional string to use to prepend all of your classes for scope
  prepend?: string, 

  // optional string representation of the file version to add as
  // part of the class name
  version?: string, 

  // RegEx string used to find specific objects and jsdoc inside the
  // source file. This string should include 'XXXXXX' in it which
  // will be a placeholder for the object name to search for.
  styleRegEx?: string, 

  // Object used to define what the jsdoc tags are for parsing
  tags?: Tags, 
};

Package Contents

Within the module you'll find the following directories and files:

package.json
CHANGELOG.md -- history of changes to the module
LICENSE
README.md -- this file
/lib
  └───/es5
    └───/getFile
      └───index.d.ts - 872 Bytes
      └───index.js - 4.1 KB
      └───index.d.ts - 141 Bytes
      └───index.js - 430 Bytes
    └───/jsToCss
      └───index.d.ts - 519 Bytes
      └───index.js - 11.25 KB
      └───types.d.ts - 795 Bytes
      └───types.js - 79 Bytes
  └───/es6
    └───/getFile
      └───index.d.ts - 872 Bytes
      └───index.js - 3.81 KB
      └───index.d.ts - 141 Bytes
      └───index.js - 76 Bytes
    └───/jsToCss
      └───index.d.ts - 519 Bytes
      └───index.js - 11.05 KB
      └───types.d.ts - 795 Bytes
      └───types.js - 12 Bytes

License

MIT

About

Generate CSS style sheets from your css-in-js JSON objects

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published