3.5.0 • Published 6 years ago

progressive-css v3.5.0

Weekly downloads
17
License
MIT
Repository
github
Last release
6 years ago

progressive-css

The future of loading CSS in React applications

Serve only the CSS you need, with no runtime overhead leveraging HTTP2. Because performance matters. More info: https://jakearchibald.com/2016/link-in-body/

Slow connection demo (thanks Jake Archibald) Notice how reloading is instant.

Install

  • Yarn: yarn add progressive-css; yarn add -D filehound
  • Npm: npm i -S progressive-css; npm i -D filehound

(filehound is a peer dependency)

Example usage:

Awesome.js
import React, { Component } from 'react';
import withCSS from 'progressive-css';

// Must be named __CSS__ and cannot import its value
const __CSS__ = ['/styles/normalize.css', '/styles/Awesome.*.*.css'];

class Awesome extends Component {
  render() {
    return <div className="hello">Hello World</div>;
  }
}

export default withCSS(__CSS__)(Awesome);

Add the babel plugin

.babelrc
"plugins": [
  // ... other plugins,
  ["progressive-css/babel-plugin", { root: "./", isProd: process.env.NODE_ENV === 'production' }]
]
Output (production):
<link rel="stylesheet" href="/styles/normalize.css" />
<link rel="stylesheet" href="/styles/Awesome.h4sh3d.min.css" />
<script> </script>
<div class="hello">Hello World</div>

During development it will point to /styles/Awesome.css instead.

API

React

const __CSS__ = string[] Paths to stylesheets, resolved as <link href="path" /> MUST be named __CSS__ if using the babel plugin, with a static value (not imported). A path can contain a glob but must be dot-delimited.

withCSS(__CSS__, scriptBlock: boolean = true, persist: boolean = false)(Component);

If scriptBlock is false, then it won't inject empty script tags to work around Firefox Flash Of Unstyled Content

persist will keep those stylesheets in CSS loaded in the document head even after the component unmounts

Server-side rendering

flushCSS()

If you perform server-side rendering you must let progressive-css know when to flush its CSS chunks. This is usually every time you call the reactDomServer methods (eg renderToString())

Example

// server-render.js

import React from 'react';
import { renderToString } from 'react-dom/server';
import { flushCSS } from 'progressive-css'

const getPage = (req, res) => {
   const toRender = renderToString(<App />);
   flushCSS();
   
   const result = `
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charSet="utf-8">
    <title>Example</title>
  </head>
  <body>
    <div id="root">${toRender}</div>
  </body>
</html>
`;

   res.status(200).send(result);
}

flushCSS() returns an array of the loaded CSS paths that were cleared, which can optionally be used for things like preloading.

getCSS() returns an array of the currently loaded CSS paths without clearing them

Example: preload the first 3 css chunks
const toRender = renderToString(<App />);
const cssChunks = flushCSS();

const result = `
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charSet="utf-8">
    <title>Example</title>
    ${
      cssChunks && cssChunks[0]
        ? cssChunks
            .slice(0, 3)
            .map((href) => `<link rel="preload" href="${href}" as="style">`)
            .join('\n')
        : ''
    }
  </head>
  <body>
    <div id="root">${toRender}</div>
  </body>
</html>
`;

Babel

const defaultOptions = {
  root: './', // All CSS paths are resolved relative to this
  isProd: false, // Enable to turn on file discovery and glob matching
  replaceDir: undefined // [regexp|substr, newSubstr|function] Applies string.replace() to the directories
}

Should be the last plugin. The css is resolved relative to ./ unless the root option specifies otherwise. In production you must specify isProd: true.
replaceDir is useful for separating your production CSS files. For example:

replaceDir: ['/styles/', '/dist/'] turns
['/styles/normalize.css', '/styles/Awesome.*.*.css'];
into
['/dist/normalize.css', '/dist/Awesome.*.*.css'];

SSR

Server-side rendering works out of the box using the provided babel plugin.

3.5.0

6 years ago

3.4.0

6 years ago

3.3.3

6 years ago

3.3.2

6 years ago

3.3.1

6 years ago

3.2.0

6 years ago

3.1.1

6 years ago

3.1.0

6 years ago

3.0.0

6 years ago

2.1.0

6 years ago

2.0.0

6 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago