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