The React community has been exploring various JSS solutions, such as the now famous Styled – Components, but they have more or less problems, but the community has been exploring JSS solutions, and the one that looks like the best solution is the Linaria library. There is almost no Relevant Chinese information in this library, so I wrote this article to share and introduce the relevant content with you

introduce

Linaria is a zero-runtime JSS framework with the following features:

  • Incorporate CSS into YOUR JS architecture, and this support costs nothing! Css-related code is extracted into a CSS file at compile time
  • Syntax for CSS of class Sass
  • Linaria supports rapid creation of React style components with dynamic properties by using CSS variables
  • Using CSS Sourcemaps makes it easy to locate style positions
  • Support stylint
  • You don’t need a preprocessor, you can use JavaScript to control the logic of your CSS
  • However, the use of preprocessors, such as Sass or PostCSS, is supported

Advantages over traditional CSS solutions

1. Style isolation

const title = css`
  font-size: 18px;
`;
Copy the code

Similar code will eventually be compiled into

.k4yi6fg {
  font-size: 18px;
}
Copy the code

Its class name is determined by calculating the hash value of the file path

2. The styles and components belong to the same file

No more writing components that need to switch contexts between JS files and CSS files. However, if you want to separate, it is also supported

3. Reliable and safe refactoring support

Because JSS styles are really just JS variables, you can easily find component-specific style logic through the code logic without fear of unexpected refactoring effects

4. No more preprocessors

One of the most fascinating aspects of JSS is that when you attribute CSS to JS, you automatically gain the ability to write CSS logic using JS, the most basic conditional calculations, wrapped in complex logic for simple function calls. This means that the upper limit of CSS expressive power is no longer limited to itself, but is determined by JS

For example, you could write code like this


const DEFAULT_COLOR = '#fffff'
const PRIMARY_COLOR = '#de2d68';

const getColor = Math.random() > 0.5 ? PRIMARY_COLOR : DEFAULT_COLOR;

const button = css`
  background-color: ${getColor()};

  &:hover {
    background-color: The ${Math.random() > 0.5 ? PRIMARY_COLOR : DEFAULT_COLOR}; } `;
Copy the code

5. Tree shaking

As we said earlier, JSS is just a JS variable, so naturally JS is Tree shaking, Linaria. This is actually attractive to UI library developers, who no longer need to import additional Babel plug-ins, but automatically import styles on demand through Tree Shaking

6. Automatically add the browser prefix

Linaria automatically supports compatibility with specific properties by adding browser prefixes, but you can still use PostCSS for further optimization

The ability to control the React component style declaratively and dynamically

Using the Styled API, it is easy to declare the React dynamic style component. The principle is the ability to automatically update component styles via CSS variables, whereas normal CSS solutions require you to manually maintain the associated logic

const Box = styled.div`
  background-color: orange;
  height: ${props => props.size}px;
  width: ${props => props.size}px;
`;

<Box size={48}>
Copy the code

Advantages over CSS preprocessors

1. No new learning costs

Linaria’s syntax can be thought of as simply supporting nested CSS syntax. No variables, no mixins, no functions, that can be replaced by JS logic, right

2. The advantages over traditional CSS solutions are the same for CSS preprocessors

Advantages over direct inline styles

1. Full CSS capability support

Inline styles have limitations, whereas Linaria supports all the features of CSS:

  • Media queries
  • CSS 3 animation
  • Pseudo class, pseudo element

2. Performance advantages

Applying styles through class naming is faster than applying inline styles

Advantages over other JSS solutions

1. CSS is downloaded and parsed separately from JS

Because CSS is pulled out of the CSS file by the compiler, the browser can download CSS and JS files in parallel, speeding up the first screen time

2. No additional parsing costs

Many JSS frameworks parse CSS strings through a third-party JS library, and the need to include a parser increases the size of the library. And the CSS parsing execution is deferred to the JS runtime, which on some low-end devices can easily cause appreciable delays

Linaria is special because it doesn’t have a runtime. Its styles are parsed out at compile time, generating CSS files, without having to be parsed at run time.

3. There is no performance loss of repeated rendering in SSR

For component-based JSS frameworks, rendering the same component with different props will cause the same style to be copied multiple times, which increases the size of the product in SSR. Although in most cases the performance cost of this problem is negligible, rendering multiple large lists with only slight differences can easily add up to a rapid increase in volume

In addition, when doing SSR you need to extract the CSS style from the JS file and then transfer it to the browser, which also increases the size of the product

Linaria generates unique style rules, using CSS variables to apply different differences, so there is no problem with duplicate styles, reducing the size of the product

4. Check syntax errors during compilation

Illegal JS values and bad CSS syntax are detected at compile time, rather than at run time. This means you won’t encounter these low-level errors in production mode, and Linaria supports stylelint, so you’ll still have the same lint experience.

5. Familiar with CSS syntax

Unlike some other JSS frameworks, Linaria syntax simply supports nested CSS native syntax with no initial cost. Perfect support for copy-paste programming

6. Support running without JavaScript

If your site needs to run with JavaScript disabled, or if you want to compile a static web page, Linaria will also work well in those situations because of its lack of runtime features

Install the configuration

Linaria supports Webpack, Rollup, and Sevlte. This article will only describe how it works with Webpack. For additional requirements, you can check out the documentation for other build tools on the web site

First of all,

If you are using Babel for translation or polyfill in your project, make sure to create a Babel configuration file under the root project with the presets and plugins you need, otherwise Linaria will not be able to parse your code

And Webpack cooperate

Working with Webpack is easy, just add Linaria /loader to babel-loader, make sure linaria/loader is next to and after babel-loader

{
  test: /\.js$/,
  use: [
    { loader: 'babel-loader' },
    {
      loader: 'linaria/loader'.options: {
        sourceMap: process.env.NODE_ENV ! = ='production',},}],}Copy the code

In addition, in order to extract the collected styles, you need another Webpack plugin, mini-CSs-extract-plugin. Execute NPM I-d CSS-loader mini-CSs-extract-plugin to install it

Then import the mini-CSs-extract-plugin

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
Copy the code

Then set up the corresponding parsing rules and plug-ins

{
  test: /\.css$/,
  use: [
    {
      loader: MiniCssExtractPlugin.loader,
      options: {
        hmr: process.env.NODE_ENV ! = ='production',}}, {loader: 'css-loader'.options: {
        sourceMap: process.env.NODE_ENV ! = ='production',},},],},Copy the code

Add the mini-CSs-extract-plugin to the plugins property of the Webpack configuration

new MiniCssExtractPlugin({
  filename: 'styles.css'});Copy the code

You can use the HTMLWebpackPlugin to link the extracted CSS file to the HTML file generated by the build. For production mode, you may need to set the hash value to the CSS file name:

new MiniCssExtractPlugin({
  filename: 'styles-[contenthash].css'});Copy the code

Because Linaria pulls out the style files to go through the Loader line of Webpack. CSS rules, you can easily use postCSS or clean-CSS to do some customization

A complete example of Webpack configuration

const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

constdev = process.env.NODE_ENV ! = ='production';

module.exports = {
  mode: dev ? 'development' : 'production'.devtool: 'source-map'.entry: {
    app: './src/index',},output: {
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist/'.filename: '[name].bundle.js',},optimization: {
    noEmitOnErrors: true,},plugins: [
    new webpack.DefinePlugin({
      'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV) },
    }),
    new MiniCssExtractPlugin({ filename: 'styles.css'}),].module: {
    rules: [{test: /\.js$/,
        exclude: /node_modules/,
        use: [
          { loader: 'babel-loader' },
          {
            loader: 'linaria/loader'.options: { sourceMap: dev },
          },
        ],
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV ! = ='production',}}, {loader: 'css-loader'.options: { sourceMap: dev },
          },
        ],
      },
      {
        test: /\.(jpg|png|gif|woff|woff2|eot|ttf|svg)$/,
        use: [{ loader: 'file-loader'}],},]},devServer: {
    contentBase: [path.join(__dirname, 'public')].historyApiFallback: true,}};Copy the code

You can install all the necessary NPM libraries using the following command

npm i -D webpack webpack-cli webpack-dev-server mini-css-extract-plugin css-loader file-loader babel-loader
Copy the code

Customize linaria/ Loader options properties

You can pass the options property like this

{
  loader: 'linaria/loader'.options: {
    sourceMap: false.// Whether to generate CSS source map. The default is false
    cacheDirectory: '.linaria-cache'.// See the file where the cache resides, default.linaria-cache
		extension: '.linaria.css'.// CSS file name in intermediate state, default.linaria.css
		preprocessor: 'stylis'.// Define the preprocessor for CSS. The default is stylis}},Copy the code

use

Linaria is very simple to use. There is only one core method, CSS, that can cover almost any scenario, and there are some syntactic sugar helper functions for ease of development

Browser side API

css` ` `

CSS is a label function, which means you can call it from the template string ““ instead of (). The label function evaluation is converted to a unique class name by the Babel plugin

import { css } from 'linaria';

const flower = css`
  display: inline;
  color: violet;
`;

// flower === flower__9o5awv -- > with Babel plugin
Copy the code

Any CSS styles written in template strings are limited to the appropriate class name, including media queries and animations. We can declare animation like this:

import { css } from 'linaria';

const box = css`
  animation: rotate 1s linear infinite;

  @keyframes rotate {
    { from: 0deg; }
    { to: 360deg; }} `;
Copy the code

cx(... classNames: Array<string | false | void | null | 0>) => string

Cx () concatenates the string passed in, but ignores Falsy values such as ”, null, and undefined

import { css, cx } from 'linaria';

const cat = css`
  font-weight: bold;
`;

const yarn = css`
  color: violet;
`;

const fun = css`
  display: flex;
`;

function App({ isPlaying }) {
  return <Playground className={cx(cat, yarn.isPlaying && fun)} / >;
}
Copy the code

The cx() function looks a lot like a popular library classnames, but it’s a little different in that cx() doesn’t handle objects

styled

Styled Components an auxiliary object for quickly creating the React component, which is used much like gravitation-Components:

Styled is used in much the same way as CSS. In addition, you can insert functions in the template string to get props for the component and set the style dynamically

import { styled } from 'linaria/react';
import colors from './colors.json';

const Container = styled.div`
  background-color: ${colors.background};
  color: ${props => props.color};
  width: The ${100 / 3}%;
  border: 1px solid red;

  &:hover {
    border-color: blue;
  }
`; 
Copy the code

Similarly, all style rules are localized. To avoid repeating CSS style code, we can refer to other styles in this way

const Title = styled.h1` font-size: 36px; `;

const Article = styled.article` font-size: 16px; /* this will evaluate to the selector that refers to `Title` * /${Title} {
    margin-bottom: 24px;
  }
`;
Copy the code

Also, we can use the AS attribute to specify what the actual rendering HTML tag will be

// Here `Button` is defined as a `button` tag
const Button = styled.button` background-color: rebeccapurple; `;

// You can switch it to use an `a` tag with the `as` prop
<Button as="a" href="/get-started">
  Click me
</Button>;
Copy the code

Styled also supports style nesting similar to higher-order component form

const Button = styled.button` background-color: rebeccapurple; `;

// The background-color in FancyButton will take precedence
const FancyButton = styled(Button)` background-color: black; `;
Copy the code

Server API (linaria/server)

collect(html: string, css: string) => string

When doing SSR, we not only need to return the corresponding HTML code, but also need to return the required style code, which is the key CSS code, we can use the collect() function to extract the key CSS code

import { collect } from 'linaria/server';

const css = fs.readFileSync('./dist/styles.css'.'utf8');
const html = ReactDOMServer.renderToString(<App />);
const { critical, other } = collect(html, css);

// Critical - returns critical CSS for given HTML
// other -- returns the rest of styles
Copy the code

Collect () extracts the CSS code used by the element based on its class attribute so that it can be returned along with the HTML

Note that the order of the selectors in the extracted CSS code can be out of order, which makes it possible to get unexpected errors if your style depends on the weight of the selectors order, but since Linaria generates class names that are unique, this usually doesn’t happen. But be aware of this when working with other libraries

warning

Linaria is based on CSS variables. Most modern browsers support this feature, but not for IE 11 and below, so if you need to support IE 11, Linaria may not be your best choice

subsequent

Linaria /lader has been renamed @Linaria/webpack4-Loader