Heim  >  Artikel  >  Web-Frontend  >  Eine kurze Diskussion über den direkten Stil des Reaktionsisomorphismus

Eine kurze Diskussion über den direkten Stil des Reaktionsisomorphismus

小云云
小云云Original
2017-12-26 13:47:512166Durchsuche

Wir haben zuvor über isomorphes serverseitiges Rendering gesprochen, mit dem die HTML-Struktur direkt extrahiert werden kann. Obwohl wir die Lösung für das Problem der Einführung statischer Ressourcen wie Stile und Bilder auf der Serverseite erklärt haben, haben wir das Relevante nicht tatsächlich durchgeführt In diesem Artikel wird erläutert, wie der Stil so geradlinig wie HTML angezeigt wird. In diesem Artikel wird hauptsächlich der Stil des direkten Ausdrucks des Reaktionsisomorphismus vorgestellt. Jetzt werde ich ihn mit Ihnen teilen und Ihnen eine Referenz geben. Folgen wir dem Herausgeber und schauen wir uns das an. Ich hoffe, es kann allen helfen.

PS: Ganz klar, ich verstehe, dass Sie die URL eingeben, um eine Get-Anfrage für den Zugriff auf den Server zu initiieren, und die vollständige Antwort direkt statt asynchron über Ajax erhalten.

Schlüsselelemente des React-Isomorphismus

Perfekte Komponenteneigenschaften sowie Lebenszyklus und clientseitiges Render-Timing sind die Schlüssel zum React-Isomorphismus.

DOM-Konsistenz

Das Rendern derselben Komponente am Front- und Backend führt zu einer konsistenten Dom-Struktur.

Unterschiedliche Lebenszyklen

Auf der Serverseite erreicht der Komponentenlebenszyklus nur ComponentWillMount, während auf der Clientseite der Lebenszyklus abgeschlossen ist.

Client-Rendering-Timing

Bei Isomorphie kombiniert der Server die Daten, um die Komponente in eine vollständige HTML-Zeichenfolge zu rendern, und gibt den Datenstatus an den Client zurück Es wird beurteilt, ob es direkt verwendet werden kann oder erneut montiert werden muss.

Das Obige sind die von React bereitgestellten Grundbedingungen für isomorphes/serverseitiges Rendering. In tatsächlichen Projektanwendungen müssen andere Eckprobleme berücksichtigt werden, z. B. dass auf der Serverseite kein Fensterobjekt vorhanden ist und eine andere Verarbeitung durchgeführt werden muss. Im Folgenden werden wir einige isomorphe Tipps und Optimierungsergebnisse durch spezifische Praktiken in der mobilen QQ-Heimschulgruppe teilen.

Stildateien hinzufügen

Derzeit gibt es in unserem Projekt keine Stildateien Um zunächst eine zu schreiben, schreiben wir eine Stildatei für die Komponenten-App.

Abhängigkeiten installieren

Die folgenden Abhängigkeiten werden später verwendet. Die Funktion jeder Abhängigkeit wird im Folgenden ausführlich erläutert.

Kopieren Sie den Code wie folgt:


npm install postcss-loader postcss-import postcss-cssnext postcss-nested postcss-functions css-loader style-loader isomorphic-style-loader - - save-dev

.pcss-Datei erstellen

Das Suffix der CSS-Datei ist .css und das Suffix der less-Datei ist .less. Hier wähle ich die Verwendung von PostCSS mit seinem Plug-in zum Schreiben des Stils, also habe ich einfach selbst ein Suffix .pcss definiert.

// ./src/client/component/app/style.pcss

.root {
 color: red;
}

Legen Sie eine Stammklasse fest und der Stil besteht darin, die Farbe einfach auf Rot zu setzen. Verweisen Sie dann in der App-Komponente darauf.

// ./src/client/component/app/index.tsx

...
import * as styles from './style.pcss';
...
 public render() {
  return (
   <p className={styles.root}>hello world</p>
  );
 }
...

Zu diesem Zeitpunkt finden Sie im Editor so etwas:

Dieses Problem tritt auf, weil ts die Typdefinition davon nicht kennt module , daher müssen wir manuell benutzerdefinierte Modultypdefinitionen hinzufügen. Erstellen Sie einen neuen @types-Ordner im Projektstammverzeichnis und erstellen Sie die Datei index.d.ts in diesem Verzeichnis:

// ./@types/index.d.ts

declare module '*.pcss' {
 const content: any;
 export = content;
}

Nach dem Speichern wird der Editorfehler nicht angezeigt, sondern die Webpack-Verpackung darin Das Terminal wird angezeigt. Es tritt ein Fehler auf, da wir den entsprechenden Loader nicht hinzugefügt haben.

Konfigurieren Sie die Parsing-Regeln von .pcss-Dateien

JS ist komponentenorientiert und eine CSS-Modularisierung ist ebenfalls erforderlich. Sie müssen sich keine Gedanken mehr über die Vermeidung doppelter Klassennamen machen. Wir exportieren eine neue Methode in die Basiskonfiguration, um Postcss-Regeln zu erhalten.

// ./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');
       },
      },
     }),
    ],
   },
  },
 ],
});
...

Aus der obigen Methode können wir ersehen, dass zum Verarbeiten von .pcss-Dateien drei Loader erforderlich sind. Von unten nach oben in der Verarbeitungsreihenfolge: Postcss-Loader, CSS-Loader und ein weiterer Variable StyleLoader Was diese Variable ist, können wir sehen, wo diese Methode verwendet wird:

// ./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',
 }),
 ...
);
...

Der Client und der Server müssen unterschiedliche StyleLoader verwenden, um Stildateien zu verarbeiten.

Einführung in PostCSS

PostCSS ist ein Tool, das js zum Konvertieren von CSS verwendet. Dies ist die offizielle Einführung. Der mit Webpack verwendete Loader ist der PostCSS-Loader, aber nur ein einzelner PostCSS-Loader ist tatsächlich von geringem Nutzen. Er muss mit seinem Plug-In abgeglichen werden, um leistungsstarke Funktionen zu erreichen.

1. postcss-import

Der Grund, warum ich dieses Plug-in hier verwende, besteht darin, beim @importieren den Pfadwert zu vermeiden Für mich ist es sehr praktisch, die öffentliche Variablenstildatei (vorausgesetzt, sie heißt „variables.pcss“) in den Ordner einzuführen, der dem Pfad in der Stildatei auf jeder anderen Ebene entspricht. Ich muss nur „import“ „variables.pcss“ schreiben '; und das war's. Wenn die entsprechende Datei nicht gefunden werden kann, wird der Pfad ignoriert und der standardmäßige relative Pfad verwendet, um sie zu finden.

2. postcss-cssnext

Dieses Plug-in kann die nächste Generation der CSS-Syntax verwenden.

3. Postcss-nested

Dieses Plug-in kann Stile verschachteln.

4. Postcss-Funktionen

Dieses Plug-in kann Funktionen anpassen und in Stildateien aufrufen.

Nachdem wir so viel gesagt haben, geben wir ein Beispiel für das Schreiben von Code~

Wir fügen im Client-Verzeichnis einen neuen Style-Ordner hinzu, um einige Style-Resets, Variablendateien und dergleichen zu speichern. . Erstellen Sie dann zwei PCSS-Dateien:

// ./src/client/style/variables.pcss

:root {
 --fontSizeValue: 16;
}
// ./src/client/style/index.pcss

@import 'variables.pcss';

body {
 margin: 0;
 font-size: x2(var(--fontSizeValue));
}

Stellen Sie die index.pcss vor, die wir gerade geschrieben haben

// ./src/client/index.tsx
...
import './style/index.pcss';
...

Einführung in CSS-Module

Kurz gesagt, das ist es css Modular, Sie müssen sich keine Gedanken über globale Klassennamen machen. Schauen wir uns die Optionen des obigen CSS-Loaders an:

  1. camelCase为true运行使用驼峰写法来写类名

  2. importLoaders的值为N是因为在css-loader之前有N个loader已经处理过文件了,这里的N值是1,因为之前有一个postcss-loader,这个值一定要设置对,否则会影响@import语句,我的这个表述可能不是太正确,详细可参见 Clarify importLoaders documentation? 这个地方详细讲解了,我翻译一下大概意思是,这个属性的值N代表的是对于@import的文件要经过css-loader后面的N个loader的处理,英文不太好,大家可以自行理解。

  3. localIdentName这个就是指生成的类名啦,具体看后续结果截图就一目了然了。

  4. modules为true即启用模块化

isomorphic-style-loader

在客户端,使用style-loader,它会动态的往dom里插入style元素,而服务端由于缺少客户端的相关对象及API,所以需要isomorphic-style-loader,目前用到它只是为了避免报错哈哈,后续还有大作用,样式直出全靠它。

打包运行

注意:打包运行之前不要忘了给tsconfig.client.json和tsconfig.server.json引入我们的自定义模块定义文件index.d.ts,不然webpack编译就会报找不到pcss这种模块啦。

// ./src/webpack/tsconfig.client(server).json
...
"include": [
  ...
  "../../@types/**/*",
  ...
]
...

运行结果如下:

虽然style元素已经存在,但是这个是由style-loader生成的,并不是服务端直出的,看page source就知道了。

而且在刷新页面的时候能很明显的看到样式变化闪烁的效果。

直出样式

我们利用isomorphic-style-loader来实现服务端直出样式,原理的话根据官方介绍就是利用了react的context api来实现,在服务端渲染的过程中,利用注入的insertCss方法和高阶组件(hoc high-order component)来获取样式代码。

安装依赖

npm install prop-types --save-dev

改写App组件

根据其官方介绍,我们在不使用其整合完毕的isomorphic router的情况下,需要写一个Provider给App组件:

// ./src/client/component/app/provider.tsx

import * 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;

将原App组件里的具体内容迁移到AppContent组件里去:

// ./src/client/component/app/content.tsx

import * 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 (
   <p className={styles.root}>hello world</p>
  );
 }
}

export default AppContent;

新的App组件:

// ./src/client/component/app/index.tsx

import * 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;

疑问一:AppProvider组件是做什么的?

答:Provider的意思是 供应者,提供者 。顾名思义,AppProvider为其后代组件提供了一些东西,这个东西就是context,它有一个insertCss方法。根据其定义,该方法拥有默认值,返回空字符串的函数,即默认没什么作用,但是可以通过props传入context来达到自定义的目的。通过设定childContextTypes和getChildContext,该组件后代凡是设定了contextTypes的组件都会拥有this.context对象,而这个对象正是getChildContext的返回值。

疑问二:AppContent为何要独立出去?

答:接上一疑问,AppProvider组件render其子组件,而要使得context这个api生效,其子组件必须是定义了contextTypes的,但是我们并没有看见AppContent有这个定义,这个是因为这个定义在高阶组件withStyles里面(参见其 源码 )。

疑问三:@withStyles是什么语法?

答:这个是装饰器,属于es7。使用该语法,需要配置tsconfig:

// ./tsconfig.json
// ./src/webpack/tsconfig.client(server).json

{
 ...
 "compilerOptions": {
  ...
  "experimentalDecorators": true,
  ...
 },
 ...
}

改写服务端bundle文件

由于App组件的改写,服务端不能再复用该组件,但是AppProvider和AppContent目前还是可以复用的。

// ./src/server/bundle.tsx

import * 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,
  };
 },
};

这里我们传入了自定义的context对象,通过css这个变量来存储style信息。我们原先render函数直接返回renderToString的html字符串,而现在多了一个style,所以我们返回拥有html和style属性的对象。

疑问四:官方示例css是一个Set类型实例,这里怎么是一个数组类型实例?

答:Set是es6中新的数据结构,类似数组,但可以保证无重复值,只有tsconfig的编译选项中的target为es6时,且加入es2017的lib时才不会报错,由于我们的target是es5,所以是数组,且使用数组并没有太大问题。

处理服务端入口文件

由于bundle的render值变更,所以我们也要处理一下。

// ./src/server/index.tsx

...
router.get('/*', (ctx: Koa.Context, next) => { // 配置一个简单的get通配路由
 const renderResult = bundle ? bundle.render() : {}; // 获得渲染出的结果对象
 const { html = '', style = '' } = renderResult;
 ...
 ctx.body = `
  ...
  <head>
   ...
   ${style ? `<style>${style}</style>` : ''}
   ...
  </head>
  ...
 `;
 ...
});
...

直出结果

样式直出后的page source:

找回丢失的公共样式文件

从上面的直出结果来看,缺少./src/style/index.pcss这个样式代码,原因显而易见,它不属于任何一个组件,它是公共的,我们在客户端入口文件里引入了它。对于公共样式文件,服务端要直出这部分内容,可以这么做:

./src/server/bundle.tsx

...
import * as commonStyles from '../client/style/index.pcss';
...
const css = [commonStyles._getCss()];
...

我们利用isomorphic-style-loader提供的api可以得到这部分样式代码字符串。这样就可以得到完整的直出样式了。

相关推荐:

Node直出理论与实践总结_html/css_WEB-ITnose

详解React、ajax、java实现上传图片并预览功能

详解在React 组件中使用Echarts的正确姿势

Das obige ist der detaillierte Inhalt vonEine kurze Diskussion über den direkten Stil des Reaktionsisomorphismus. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn