@maman/css-literal-loader
Extract and process inline CSS literals in JavaScript files
Last updated a year ago by maman .
MIT · Repository · Bugs · Original npm · Tarball · package.json
$ cnpm install @maman/css-literal-loader 
SYNC missed versions from official npm registry.

@maman/css-literal-loader

A webpack loader and babel plugin for extracting and processing css defined in other files.

"Inline css" that just works with CSS, PostCSS, Less, Sass, or any other css preprocessor, and plays nicely with existing style tooling like extract-text-webpack-plugin.

import React from 'react';
import { css } from '@maman/css-literal-loader/styled';

const styles = css`
  .button {
    color: black;
    border: 1px solid black;
    background-color: white;
  }
`;

export default function Button({ children }) {
  return <button className={styles.button}>{children}</button>;
}

When processed, the css block will be extracted and treated as a .css file, taking advantage of any and all of the other loaders configured to handle css.

It even handles statically analyzable interpolations!

import { css } from '@maman/css-literal-loader/styled';

const margin = 10;
const height = 50;
const bottom = height + margin;

const styles = css`
  .box {
    height: ${height}px;
    margin-bottom: ${margin}px;
  }

  .footer {
    position: absolute;
    top: ${bottom}px;
  }
`;

Experimental component API

For those that want something a bit more like styled-components, there is an experimental component API!

import { styled, css } from '@maman/css-literal-loader/styled'; // import needed!

const Button = styled('button')`
  color: black;
  border: 1px solid black;
  background-color: white;

  &.primary {
    color: blue;
    border: 1px solid blue;
  }

  &.color-green {
    color: green;
  }
`;

You can render this with:

render(
  <Button primary color="green">
    A styled button
  </Button>,
  mountNode,
);

The above transpiles to something like:

const styles = css`
  .button {
    color: black;
    border: 1px solid black;
    background-color: white;

    &.primary {
      color: blue;
      border: 1px solid blue;
    }

    &.color-green {
      color: green;
    }
  }
`;

function Button({ primary, color, className, ...props }) {
  return (
    <div
      {...props}
      className={classNames(
        className,
        styles.button,
        primary && styles.primary,
        color === 'green' && styles.colorGreen,
      )}
    />
  );
}

Styles are still extracted to a separate file, any props matching other defined classes are passed to the classNames() library. At runtime styled() returns a React component with the static CSS classes applied. You can check out the "runtime" it just creates a component.

There are a whole bucket of caveats of course, to keep the above statically extractable, and limit runtime code.

  • We assume you are using css-modules in your css pipeline to return classes from the style files, we don't do any of that ourselves.
  • Prop value handling requires the nesting transform
  • All "top level" styles have any @import statements hoisted up (via a regex)

WHY?!

The goal of this API is not to mimic or reimplement the features of other css-in-js libraries, but to provide a more ergonomic way to write normal css/less/sass next to your javascript.

What does that mean? css-in-js libraries are often a replacement for css preprocessors, in that they provide ways of doing variables, composition, mixins, imports etc. Usually they accomplish this by leaning on JS language features where appropriate, and adding there own domain-specific language bits when needed.

@maman/css-literal-loader doesn't try to do any of that because it's not trying to replace preprocessors but rather, make component-centric javascript work better with existing styling tooling. This means at a minimum it needs to scope styles to the component (handled by css-modules) and map those styles to your component's API (props), which is what the above API strives for.

Composition, variables, etc?

How you accomplish that is mostly up to your preprocessor. Leverage Sass variables, or Less mixins, orpostcss nesting polyfills, or whatever. The css you'r writing is treated just like a normal style file so all the tooling your used to works here. For composition specifically around classes you can also use css-modules composes to compose styles, since @maman/css-literal-loader extracts styles to consistent names;

// Button.js

const helpers = css`
  .heavy {
    font-weight: 900;
  }
`;

const Title = styled('h3')`
  composes: heavy from './Button-helpers.css';

  font-size: 12%;
`;

You can also don't have to define everything in a .js file. Where it makes sense just use normal css (or which tfile type) is appropriate.

// mixins.scss
@mixin heavy() {
  font-weight: 900;
}

and then:

// Button.js
const Title = styled('h3')`
  @import './mixins.scss';

  @include heavy();
  font-size: 12%;
`;

With props

It can also be useful to create components with props already applied, like the example below. We recommend using recompose's withProps higher-order component to do this.

withProps documentation

import { styled } from '@maman/css-literal-loader/styled';
import withProps from 'recompose/withProps';

const PasswordInput = withProps({ type: 'password' })(styled('input')`
  background-color: #ccc;
`);

Setup

Add the @maman/css-literal-loader to JavaScript loader configuration, and whatever you want to handle .css files:

{
 module: {
   rules: {
     {
       test: /\.css$/,
       use: [
         'style-loader',
        { loader: 'css-loader', options: { modules: true } }
      ],
     },
     {
       test: /\.js$/,
       use: ['babel-loader','@maman/css-literal-loader'],
     },
     // @maman/css-literal-loader works out of the box with typescript (.ts or .tsx files).
     {
       test: /\.tsx?$/,
       use: ['ts-loader','@maman/css-literal-loader'],
     },
   }
 }
}

Options

@maman/css-literal-loader accepts a few query options.

  • tagName: (default: 'css') The tag identifier used to locate inline css literals and extract them.
  • extension: (default: '.css') the extension used for extracted "virtual" files. Change to whatever file type you want webpack to process extracted literals as.

Note: @maman/css-literal-loader expects uncompiled JavaScript code, If you are using babel or Typescript to transform tagged template literals, ensure the loader runs before babel or typescript loaders.

Use without webpack

If you aren't using webpack and still want to define styles inline, there is a babel plugin for that.

Config shown below with the default options.

// babelrc.js
module.exports = {
  plugins: [
    [
      '@maman/css-literal-loader/babel',
      {
        tagName: 'css',
        extension: '.css',
        writeFiles: true, // Writes css files to disk using the result of `getFileName`
        getFileName(hostFilePath, pluginsOptions) {
          const basepath = join(
            dirname(hostFilePath),
            basename(hostFilePath, extname(hostFilePath)),
          );
          return `${basepath}__extracted_style${opts.extension}`;
        },
      },
    ],
  ],
};

The extracted styles are also available on the metadata object returned from babel.transform.

const { metadata } = babel.transformFile(myJsfile);

metadata['@maman/css-literal-loader'].styles; // [{ path, value }]

Current Tags

  • 0.5.1-p2                                ...           latest (a year ago)

2 Versions

  • 0.5.1-p2                                ...           a year ago
  • 0.5.1-p1                                ...           a year ago
Maintainers (1)
Downloads
Today 0
This Week 2
This Month 2
Last Day 2
Last Week 0
Last Month 1
Dependencies (9)
Dependents (0)
None

Copyright 2014 - 2016 © taobao.org |