内容简介:最近将以前的一个毕业设计的网站的文章详情页做了服务端渲染的重构,看SSR的实现文档看似很简单,但是实现起来确实坑不少。可以让node识别es6的语法。 然后在根目录重新创建
最近将以前的一个毕业设计的网站的文章详情页做了服务端渲染的重构,看SSR的实现文档看似很简单,但是实现起来确实坑不少。
无法使用import引入
-
错误信息:
unexpected token import
-
场景:第一次在node中直接使用
import Story from '../js/containers/story'
;就会报这个错误。 -
错误说明:node本身使用的是
commonjs
的语法,支持的模块引入和导出方式为require
以及module.export
,然而es6定义的js模块方式为import
和export[default]
,因此node虽然支持了大部分的es6语法,但是由于es6的模块与node本身的cjs的模块产生了冲突,因此node不会支持esm的模块,因此造成了无法识别import
的情况。 -
解决办法:以前整个项目中node和react使用同一个
.babelrc
文件,为了解决这个问题,同时也由于react
和node
的差异越来越大,最后决定拆分.babelrc
文件,在/node
(后端)目录以及/public
(前端)目录下分别创建.babelrc
文件,作为前端和后端各自的babel配置。 其中node的.babelrc
文件配置中的:
// .babelrc "presets": [ [ "env", { "targets": { "node": "current" } } ], "react", "es2015", "stage-0" ] 复制代码
可以让node识别es6的语法。 然后在根目录重新创建 nodemon.json
文件用来处理 import
问题。 上网查资料, babel-node
插件可以解决不识别 import
的问题。
$npm i babel-cli --save
然后改写 nodemon.json
文件:
// nodemon.json { "verbose": false, "env": { "NODE_ENV": "development", "BABEL_ENV": "node" }, "watch": ["node", "config"], "ignore": ["public"], "execMap":{ "js": "babel-node" } } 复制代码
然后再次启动node服务器就可以发现node正常识别import了。
无法访问window对象
-
错误信息:
window is not defined
- 场景:js文件中一开始使用了很多window.xxx的属性,import到node环境中之后就会报这个错误。
- 说明:服务端缺乏BOM和DOM环境,服务端下无法访问window,navigator等对象。
-
解决办法:针对此种错误,有三种解决办法:
- 通过fake window等对象(如window等库)的使用,给node环境创建全局window对象。
- 前端组件中延迟这些对象的调用,在didMount中才进行调用。
- 将组件中的所有用window的属性,都通过props的方式获取,然后将所有应该传入组件的props属性在node中传进组件。
// storyController.js const props = { userInfo: ctx.session, articleInfo: { author: author[0].nickname, avatar: author[0].avatar, author_fans_count: fans_count[0].count, ...info[0] }, isSelf: info[0].uid === ctx.session.uid }; const html = renderToString(<Story {...props} />); ctx.render('story', { __PROPS__: JSON.stringify(props), title: info[0].title, html }); 复制代码
// pages/story.js render( <Story {...window.__PROPS__} />, document.getElementById('root') ); 复制代码
这样在组件中就可以通过props的方式获取数据,从而解决这个问题。
无法访问alias路径
-
错误信息:
cannot find module 'components/xxx'
-
场景:在组件中使用了
webpack
配置的alias
路径,做ssr时node就会报这个错误。 -
错误说明:当在webpack中配置
alias
时,我们可以在组件中简写路径,但是在node中无法识别webpack的alias
,所以这种路径node会从node_modules
中寻找这个组件,找不到就会报错。 -
解决办法:解决办法自然是node也找一个alias的库:
module-resolver
库可以完美解决这个问题。$ npm install --save-dev babel-plugin-module-resolver
安装完成之后,改造一下node下面的.babelrc
文件即可:
// .babelrc "plugins": [ ["module-resolver", { "cwd": "babelrc", "root": ["../public/js"], "alias": { "scss": "../public/scss", "components": "../public/js/components", "containers": "../public/js/containers", "constants": "../public/js/constants", "lib": "../public/js/lib", "router": "../public/js/router", "stirngs": "../public/js/string.js", "store": "../public/js/store" } }] ] 复制代码
其中的alias和webpack中的alias一样。
无法引入静态资源
-
错误信息:
/Users/xxx/xxx/node_modules/antd/lib/style/index.css:6
-
场景:组件中使用了
antd
组件,或者引入了我们自己的scss
文件时,会报这个错误。 -
错误说明:客户端通常使用webpack进行编译,资源的加载通过各种
loader
进行处理,但这写loader
只是针对于客户端环境的,编译生成的代码,无法应用于服务端,因此node无法解析scss
、less
等文件。 - 解决办法:我们只要让node不解析这些样式文件即可。 在node入口文件app.js中最上方加入以下代码:
// app.js require.extensions['.scss'] = function() { return null; }; require.extensions['.css'] = function() { return null; }; require.extensions['.less'] = function() { return null; }; require.extensions['.png'] = function(module, file) { return module._compile('module.exports = ""', file); }; require.extensions['.svg'] = function() { return null; }; 复制代码
这样node就可以正常运行了,但是同时又暴露出了一个问题,当node进行首屏渲染的时候,是没有样式的,这就导致当客户端开始加载样式之后,会造成页面样式抖动的问题。
为此我们通过编写webpack插件,将 ExtractTextPlugin
生成的css文件,内联插入页面的pug模板中,这样服务端首屏渲染就可以支持样式了。
require方式引入组件报错
-
错误信息:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object
- 场景:node中使用require引入组件,然后传入renderToString会报错。
- 错误说明:这个错误涉及到esm和cjs交互的问题,我们通过require引入的东西和我们通过import引入的并不一样,具体原因可以参考另一篇文章深入解析ES Module。
-
解决办法:
-
我们在组件中通过
export default class xxx extends Component
的方式导出组件,在node中必须要通过const Component = require('....').default
的方式才能够正确获取到组件,大家可以自己console.log
一下,直接require
进来的是一个object
,里面的default
属性才是我们的组件。 -
安装
babel-plugin-add-module-exports
插件。$ npm install babel-plugin-add-module-exports@next --save-dev
然后改写react中的.babelrc
文件:
-
我们在组件中通过
// .babelrc "plugins": [ ... "babel-plugin-add-module-exports" ] 复制代码
这是个比较hack的方法,强行将esm和cjs的表现置为相同,但是可能会出现问题,所以尽量不要将esm和cjs混用,在node中直接使用import引入组件最好,不要用require引入。
(待续)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- WGCLOUD 监控系统更新,重构告警信息开关组,提升性能
- 高性能监控系统 WGCLOUD 更新,重构告警消息推送机制
- Linux 监控工具 WGCLOUD 更新,重构数据源监控,提升性能
- Librem 5 发布 8 月更新,GNOME Contacts 重构
- 运维监控软件 wgcloud 更新,v3.2.7 重构告警模块
- NG-ZORRO 0.7.0 发布,底层大量重构与改动更新
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Perl高效编程
霍尔 / 胜春、王晖、张东亮、蒋永清 / 人民邮电出版社 / 2011-5 / 65.00元
《Perl高效编程(第2版)》,本书是Perl编程领域的“圣经级”著作。它提供了一百多个详实的应用案例,足以涵盖编程过程中经常遇到的方方面面,由此详细阐释出各种高效且简洁的写法。一起来看看 《Perl高效编程》 这本书的介绍吧!