Talking about the direct output of react homogeneous style and the react homogeneous Style
Preface
As mentioned above, through Homogeneous server rendering, you can directly export the html structure. Although we have explained the solutions for introducing problems to static resources such as styles and images on the server, we have not actually performed any relevant operations, this article explains how to make the style output as html.
PS: Direct output. In my understanding, the url is entered to initiate a get request to access the server and directly obtain the complete response result, instead of Asynchronously obtaining the result through ajax.
Key elements of React Homogeneity
The perfect Compponent attributes and the time to render the lifecycle with the client are the key to React homogeneous.
DOM consistency
Rendering the same Compponent on the front and back ends will output a consistent Dom structure.
Different lifecycles
On the server side, the Component life cycle only goes to componentWillMount, and the client is complete.
Client render time
When homogeneous, the server uses data to render the Component into a complete HTML string and return the data status to the client. The client determines whether the Component can be directly used or needs to be remounted.
The above are the basic conditions provided by React in homogeneous/Server rendering. In actual project applications, you also need to consider other corner issues. For example, if the server does not have a window object, you need to perform different processing. In the following, we will share some homogeneous Tips and optimization results through practices on the home school group in hand.
Add a Style File
Currently, no style file exists in our project, so you need to first write a style file for the component App.
Install dependency
The following dependencies will be used later. install them first. The following describes the functions of each dependency in detail.
Copy codeThe Code is as follows:
Npm install postcss-loader postcss-import postcss-cssnext postcss-nested postcss-functions css-loader style-loader isomorphic-style-loader -- save-dev
Create a. pcss File
The suffix of the CSS file is. CSS, And the suffix of the less file is. less. Here I choose to use PostCSS with its plug-in to write the style, so I will define a suffix. pcss by myself.
// ./src/client/component/app/style.pcss.root { color: red;}
Set a root class. The style is simply set to red. Then reference it in the App component.
// ./src/client/component/app/index.tsx...import * as styles from './style.pcss';... public render() { return ( <div className={styles.root}>hello world</div> ); }...
At this time, you will find the following in the Editor:
This problem occurs because ts does not know the type definition of this module, so we need to manually add custom module type definition. Create the @ types folder in the root directory of the project, and create the index. d. ts file in this directory:
// ./@types/index.d.tsdeclare module '*.pcss' { const content: any; export = content;}
After saving the file, you will not see an error in the editor. However, an error is prompted when packaging webpack in terminal, because the corresponding loader has not been added.
Configure resolution rules for. pcss files
Javascript is componentized, and css modularization is also necessary, so you don't have to worry about getting duplicate class names. In the base configuration, we export a new method to obtain the postcss rule.
// ./src/webpack/base.ts...export const getPostCssRule = (styleLoader) => ({ test: /\.pcss$/, use: [ styleLoader, { loader: 'css-loader', options: { camelCase: true, importLoaders: 1, localIdentName: '[path][name]---[local]---[hash:base64:5]', modules: true, }, }, { loader: 'postcss-loader', options: { plugins: () => [ require('postcss-import')({ path: path.join(baseDir, './src/client/style'), }), require('postcss-cssnext'), require('postcss-nested'), require('postcss-functions')({ functions: { x2(v, u) { return v * 2 + (u ? u : 'px'); }, }, }), ], }, }, ],});...
We can see from the above method that the processing is required. the pcss file requires three loaders, which are postcss-loader and css-loader from the bottom up in the processing order. There is also a variable styleLoader. What is this variable, we can see where this method is used:
// ./src/webpack/client.ts...(clientDevConfig.module as webpack.NewModule).rules.push( ... getPostCssRule({ loader: 'style-loader', }), ...);...
// ./src/webpack/server.ts...(clientDevConfig.module as webpack.NewModule).rules.push( ... getPostCssRule({ loader: 'isomorphic-style-loader', }), ...);...
StyleLoader must be used between the client and the server to process style files.
PostCSS Introduction
PostCSS is a tool that uses js to convert css. This is an official introduction. The loader used with webpack is postcss-loader, but only one postcss-loader is useless. It must be used with its plug-in to implement powerful functions.
1. postcss-import
This plug-in is used here to avoid complicated path writing during @ import in the style file. I have set the path value, in this case, I want to introduce the public variable style file in the corresponding path folder in the style file at any other level (for example, "variables. pcss ") is very convenient, you only need to write 'variables. pcss'; yes. Of course, if the corresponding file cannot be found, it will ignore the path and use the default relative path to find it.
2. postcss-cssnext
This plug-in can use the next generation css syntax.
3. postcss-nested
This plug-in can be nested to write styles.
4. postcss-functions
This plug-in can customize functions and call them in style files.
Let's talk a lot about it. Let's write the code to give you an example ~
We added the style folder under the client directory to store some style reset and variable files. Create two pcss files:
// ./src/client/style/variables.pcss:root { --fontSizeValue: 16;}
// ./src/client/style/index.pcss@import 'variables.pcss';body { margin: 0; font-size: x2(var(--fontSizeValue));}
Introduce the newly written index. pcss
// ./src/client/index.tsx...import './style/index.pcss';...
Introduction to CSS Modules
In short, css is modularized, so you don't have to worry about global class names. Based on the options of css-loader, we can see that:
- CamelCase is true. Run the camelCase to write the class name.
- The value of importLoaders is N because there are N loaders that have processed files before css-loader. Here, the value of N is 1 because there was a postcss-loader, this value must be set correctly. Otherwise, the @ import statement will be affected. This statement may not be correct. For details, see Clarify importLoaders documentation? This part has been explained in detail. I have translated it into a rough sense that the value N of this attribute indicates that the @ import file must be processed by N loaders after css-loader, the English is not very good. You can understand it yourself.
- LocalIdentName refers to the generated class name, which can be clearly viewed later.
- If modules is set to true, modularization is enabled.
Isomorphic-style-loader
When using style-loader on the client, it dynamically inserts the style element into the dom. The server needs isomorphic-style-loader because of the lack of client-related objects and APIs, currently, it is only used to avoid errors. Haha, it will play a major role in the future, and the style will depend on it directly.
Package and run
Note: Do not forget to give it to tsconfig before packaging and running. client. json and tsconfig. server. json introduces our custom module definition file index. d. ts. Otherwise, the module pcss cannot be found during webpack compilation.
// ./src/webpack/tsconfig.client(server).json..."include": [ ... "../../@types/**/*", ...]...
The running result is as follows:
Although the style element already exists, it is generated by style-loader and is not directly output by the server. You can see the page source.
In addition, when you refresh the page, you can see the flickering Effect of style changes.
Direct output style
We use isomorphic-style-loader to implement the server-side direct output style. The principle is to use the react context api according to the official introduction. During the server-side rendering process, use the insertCss injection method and the high-order component (hoc high-order component) component to obtain the style code.
Install dependency
npm install prop-types --save-dev
Rewrite App Components
According to its official introduction, we need to write a Provider to the App component without using its integrated isomorphic router:
// ./src/client/component/app/provider.tsximport * as React from 'react';import * as PropTypes from 'prop-types';class AppProvider extends React.PureComponent<any, any> { public static propTypes = { context: PropTypes.object, }; public static defaultProps = { context: { insertCss: () => '', }, }; public static childContextTypes = { insertCss: PropTypes.func.isRequired, }; public getChildContext() { return this.props.context; } public render() { return this.props.children || null; }}export default AppProvider;
Migrate the specific content of the original App component to the AppContent component:
// ./src/client/component/app/content.tsximport * as React from 'react';import * as styles from './style.pcss';/* tslint:disable-next-line no-submodule-imports */import withStyles from 'isomorphic-style-loader/lib/withStyles';@withStyles(styles)class AppContent extends React.PureComponent { public render() { return ( <div className={styles.root}>hello world</div> ); }}export default AppContent;
New App components:
// ./src/client/component/app/index.tsximport * as React from 'react';import AppProvider from './provider';import AppContent from './content';class App extends React.PureComponent { public render() { return ( <AppProvider> <AppContent /> </AppProvider> ); }}export default App;
Question 1: What is the AppProvider component?
A: Provider indicates the Provider. As the name suggests, AppProvider provides something for its child components. This is context, which has an insertCss method. According to its definition, this method has a default value. The function that returns an empty string does not work by default. However, you can use props to input context to customize the function. By setting childContextTypes and getChildContext, all components with contextTypes set by this component will have this. context object, and this object is the return value of getChildContext.
Question 2: Why should AppContent be independent?
A: In addition, The AppProvider component render has its child components. To make the context api take effect, its child components must define contextTypes, but we didn't see this definition in AppContent, this is because it is defined in withStyles, a high-order component (see its source code ).
Question 3: What is the syntax of @ withStyles?
A: This is a decoration device and belongs to es7. To use this syntax, You need to configure tsconfig:
// ./tsconfig.json// ./src/webpack/tsconfig.client(server).json{ ... "compilerOptions": { ... "experimentalDecorators": true, ... }, ...}
Rewrite the server bundle File
Because the App component is rewritten, the server cannot reuse the component, but AppProvider and AppContent can still be reused at present.
// ./src/server/bundle.tsximport * as React from 'react';/* tslint:disable-next-line no-submodule-imports */import { renderToString } from 'react-dom/server';import AppProvider from '../client/component/app/provider';import AppContent from '../client/component/app/content';export default { render() { const css = []; const context = { insertCss: (...styles) => styles.forEach((s) => css.push(s._getCss())) }; const html = renderToString( <AppProvider context={context}> <AppContent /> </AppProvider>, ); const style = css.join(''); return { html, style, }; },};
Here we passed in a custom context object and stored the style information through the css variable. Previously, the render function directly returned the html string of renderToString, but now there is a style, so we return the object with the html and style attributes.
Question 4: The official example css is a Set-type instance. How is an array-type instance?
A: Set is the new data structure in es6. It is similar to an array, but it can ensure that there are no repeated values. Only when the target in the tsconfig compilation option is es6, when es2017 lib is added, no error is reported. Because our target is es5, it is an array and there is no big problem in using arrays.
Process the server entry file
Because the bundle's render value is changed, we need to handle it.
//. /Src/server/index. tsx... router. get ('/*', (ctx: Koa. context, next) =>{// configure a simple get wildcard route const renderResult = bundle? Bundle. render (): {}; // get the rendered result object const {html = '', style =''} = renderResult ;... ctx. body = '...
Direct output result
Page source after the style is straight out:
Retrieve lost public style files
From the above direct output results, it is missing. /src/style/index. the pcss style code is obviously because it does not belong to any component and is public. We have introduced it in the client portal file. For public style files, the server must directly output this part of content. You can do this:
./src/server/bundle.tsx...import * as commonStyles from '../client/style/index.pcss';...const css = [commonStyles._getCss()];...
We can use the api provided by isomorphic-style-loader to obtain the style code strings. In this way, you can get a complete straight-out style.
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.