Maison > Article > interface Web > Une brève discussion sur le style direct de l'isomorphisme de réaction
Nous avons déjà parlé du rendu isomorphe côté serveur, qui peut extraire directement la structure HTML. Bien que nous ayons expliqué la solution au problème de l'introduction de ressources statiques telles que des styles et des images côté serveur, nous n'avons pas réellement effectué les tâches correspondantes. opérations. Cet article explique comment rendre le style aussi simple que du HTML. Cet article présente principalement le style d'expression directe de l'isomorphisme de réaction. L'éditeur pense que c'est assez bon. Maintenant, je vais le partager avec vous et vous donner une référence. Suivons l'éditeur pour y jeter un œil, j'espère que cela pourra aider tout le monde.
PS : d'emblée, je crois comprendre que vous entrez l'URL pour lancer une demande d'obtention d'accès au serveur et obtenez la réponse complète directement au lieu de manière asynchrone via ajax.
Éléments clés de l'isomorphisme React
Les propriétés, le cycle de vie et le timing de rendu côté client des composants parfaits sont les clés de l'isomorphisme React.
Cohérence DOM
Le rendu du même composant sur les fronts avant et arrière produira une structure Dom cohérente.
Différents cycles de vie
Côté serveur, le cycle de vie du composant n'atteindra que composantWillMount, tandis que le côté client est terminé.
Temps de rendu du client
Lorsqu'il est isomorphe, le serveur combine les données pour restituer le composant dans une chaîne HTML complète et renvoie l'état des données au client. Il sera jugé s'il peut être utilisé directement ou s'il doit être remonté.
Ce qui précède sont les conditions de base fournies par React pour le rendu isomorphe/côté serveur. Dans les applications de projet réelles, d'autres problèmes doivent être pris en compte. Par exemple, il n'y a pas d'objet fenêtre côté serveur et un traitement différent doit être effectué. Ci-dessous, nous partagerons quelques conseils isomorphes et résultats d'optimisation grâce à des pratiques spécifiques sur le groupe mobile QQ home-school
Ajouter des fichiers de style
Actuellement, il n'y a pas de fichier de style dans notre projet, vous en avez donc besoin. pour en écrire un d'abord, écrivons un fichier de style pour le composant App.
Installation des dépendances
Les dépendances suivantes seront utilisées plus tard. Installez-les en premier. La fonction de chaque dépendance sera expliquée en détail ci-dessous.
Copiez le code comme suit :
npm install postcss-loader postcss-import postcss-cssnext postcss-nested postcss-functions css-loader style-loader isomorphic-style-loader - - save-dev
Créer un fichier .pcss
Le suffixe du fichier css est .css, et le suffixe du fichier less est .less Ici, je choisis d'utiliser PostCSS. avec son plug-in pour écrire le style. Je viens donc de définir moi-même un suffixe .pcss.
// ./src/client/component/app/style.pcss .root { color: red; }
Définissez une classe racine, et le style consiste simplement à définir la couleur sur rouge. Ensuite, référencez-le dans le composant App.
// ./src/client/component/app/index.tsx ... import * as styles from './style.pcss'; ... public render() { return ( <p className={styles.root}>hello world</p> ); } ...
À ce moment, vous trouverez quelque chose comme ceci dans l'éditeur :
Ce problème se produit car ts ne connaît pas la définition de type de ceci module , nous devons donc ajouter manuellement des définitions de type de module personnalisées. Créez un nouveau dossier @types dans le répertoire racine du projet et créez le fichier index.d.ts dans ce répertoire :
// ./@types/index.d.ts declare module '*.pcss' { const content: any; export = content; }
Après l'enregistrement, vous ne verrez pas l'erreur de l'éditeur, mais l'empaquetage du webpack dans le terminal Une erreur se produit car nous n'avons pas ajouté le chargeur correspondant.
Configurez les règles d'analyse des fichiers .pcss
JS est composé de composants et la modularisation CSS est également nécessaire. Vous n'avez plus à vous soucier d'éviter les noms de classe en double. Nous exportons une nouvelle méthode dans la configuration de base pour obtenir les règles postcss.
// ./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'); }, }, }), ], }, }, ], }); ...
Nous pouvons voir à partir de la méthode ci-dessus que trois chargeurs sont nécessaires pour traiter les fichiers .pcss. De bas en haut dans l'ordre de traitement, il y a postcss-loader, css-loader et un autre styleLoader variable, comme pour. quelle est cette variable, nous pouvons voir où cette méthode est utilisée :
// ./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', }), ... ); ...
Le client et le serveur doivent utiliser des styleLoaders différents pour traiter les fichiers de style.
Introduction à PostCSS
PostCSS est un outil qui utilise js pour convertir les CSS Ceci est l'introduction officielle. Le chargeur utilisé avec webpack est postcss-loader, mais un seul postcss-loader est en réalité de peu d'utilité. Il doit être associé à son plug-in pour obtenir des fonctions puissantes.
1. postcss-import
La raison pour laquelle j'utilise ce plug-in ici est d'éviter l'écriture de chemin complexe lors de l'@import dans le fichier de style, puis je définis la valeur du chemin. Il est très pratique pour moi d'introduire le fichier de style de variable publique (en supposant qu'il s'appelle "variables.pcss") dans le dossier correspondant au chemin d'accès au fichier de style à n'importe quel autre niveau. Il me suffit d'écrire import 'variables.pcss. '; et c'est tout. Bien sûr, si le fichier correspondant ne peut pas être trouvé, il ignorera le chemin et utilisera le chemin relatif par défaut pour le trouver.
2. postcss-cssnext
Ce plug-in peut utiliser la nouvelle génération de syntaxe CSS.
3. imbriqués postcss
Ce plug-in peut imbriquer des styles d'écriture.
4. fonctions postcss
Ce plug-in peut personnaliser les fonctions et les appeler dans des fichiers de style.
Cela dit, donnons un exemple d'écriture de code~
Nous ajoutons un nouveau dossier de style dans le répertoire client pour stocker certaines réinitialisations de style, fichiers variables, etc. . Créez ensuite deux fichiers pcss :
// ./src/client/style/variables.pcss :root { --fontSizeValue: 16; }
// ./src/client/style/index.pcss @import 'variables.pcss'; body { margin: 0; font-size: x2(var(--fontSizeValue)); }
Introduisez le index.pcss que nous venons d'écrire
// ./src/client/index.tsx ... import './style/index.pcss'; ...
Introduction aux modules CSS
En bref, c'est css Modulaire, pas besoin de s'inquiéter des noms de classes globaux. Regardons les options du chargeur CSS ci-dessus :
camelCase为true运行使用驼峰写法来写类名
importLoaders的值为N是因为在css-loader之前有N个loader已经处理过文件了,这里的N值是1,因为之前有一个postcss-loader,这个值一定要设置对,否则会影响@import语句,我的这个表述可能不是太正确,详细可参见 Clarify importLoaders documentation? 这个地方详细讲解了,我翻译一下大概意思是,这个属性的值N代表的是对于@import的文件要经过css-loader后面的N个loader的处理,英文不太好,大家可以自行理解。
localIdentName这个就是指生成的类名啦,具体看后续结果截图就一目了然了。
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
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!