记node前后端代码共用的一次坑
项目背景
nodejs项目,webpack打包,用axios请求,Promise封装,nunjucks模板引擎;
之前已将nunjucks模板通过webpack打包策略,做成前后端共用;
目前需要将网络请求以及数据处理封装成service模块;
目录划分:

如上图所示:
将公共代码放到service中,整合两端共同的一些网络请求以及数据处理(node首屏,客户端再次请求数据更新等操作)
这里碰到的两个问题:
1. node模块使用module.exports,而webpack我们使用的是import/export,两者共用会报错;
2.我们使用了Promise做了两层封装(service封装、service中的fetch封装:抹平node和客户端的环境差异)
第一个问题,其实webpack也提供了module.exports的方法,所以两端的模块是可以共用的。
而第二个问题,我们使用了Promise,也在webpack全局引入了babel-polyfill,但是会报错:
Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
导致前面的排查思路一直以为是module.exports出了问题;
解决方法
我们刚开始是通过引入es6-promise来解决的:
service/fetch.js:
var axios = require('axios');
var Promise = require('es6-promise').Promise;
module.exports = function(opts, request) {
return new Promise(function(resolve, reject) {
axios(opts).then(function(res) {
res = res.data
if (res.success) {
resolve(res)
} else {
reject({ ___req: opts, ___res: res })
}
}).catch(function(err) {
reject({ ___req: opts, ___res: err.data || err.stack || err })
})
})
}
service/wawa.js
var fetch = require('./fetch');
var Promise = require('es6-promise').Promise;
var getGamelist = function(params, req) {
return new Promise(function(resolve, reject) {
fetch({
url: '/api/appeal/appealJoinOrderPage',
type: 'get',
params: params
}).then(function(res) {
resolve(res.data)
}).catch(function(err) {
reject(err)
})
})
}
module.exports = {
getGamelist
}
并且我们也尝试在全局引入es6-promise,仍然报错;
这样我们暂时得出结论,是原生Promise语法,直接与module.exports冲突报错。目前只能通过在当前js中引入es6-promise来规避。
所幸的是,每个js中重复引入的es6-promise,在最终webpack打包的时候会去重,也避免了打包体积变大的问题。
至此,node前后端代码共用的方案暂时通过。并且后面还可以写除了service以外的共用代码,提升了复用性和可维护性。
再次踩到坑
我们在迁移另一个公用service的时候,又碰到原来的问题,精简后的代码如下:
/**
* 获取红包列表
*/
var getRedList = function(params, req) {
return JSON.stringify({a:1})
} module.exports = {
getRedList
}
纳尼?又报错
Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
经过排查定位,发现是JSON.stringify不支持。。。但平时我们正常使用export/import从未碰到此问题。
所以猜测是module.exports出去的模块,在webpack中默认是不会给全局方法加上window的。
最终解决:兼容global和window(其实还不是最终)
那解决方法就容易了,给全局方法手动加上全局对象,兼容处理global和window就可以了:
(function(global) {
let isBrowser = global.toString() === '[object Window]';
/**
* 获取红包列表
*/
var getRedList = function(params, req) {
return JSON.stringify({a:1})
}
module.exports = {
getRedList
}
})(typeof exports === 'undefined' ? global = window : global);
以上,得出在node和浏览器webpack共用模块化代码的解决方案:
1. 使用 module.exports / require 做模块化
2. 兼容处理global和window
打死不改终极奥义最终版
上周末线上突然报错飙升,发现集中在安卓4.3以下,报错:Promise is not defined
经过不断试错排查,发现在module.exports出去后,里边的 'es6-promise'兼容包,在外面是不生效的。
最后决定在外边定义一个全局的Promise:
window.Promise = require('es6-promise').Promise;
此外,在低版本安卓中,判断window环境还有一个坑:
需要这么写
(function(global) {
module.exports = function(opts, request) {
var isBrowser = global.toString() === '[object Window]' || global.toString() === '[object DOMWindow]';
return new global.Promise(function(resolve, reject) {
if (isBrowser) {
axios(opts).then(function(res) {
}).catch(function(err) {
})
} else {
axios(opts).then(function(res) {
}).catch(function(err) {
})
}
})
}
})(typeof exports === 'undefined' ? global = window : global);
标红的那段是重点,划下来!!!
End
写到这里,已经做好了node项目代码复用的基础,那么整个接口的数据流程是怎么样的呢,又会碰到什么样的问题?
比如我们需要在两端调用service的时候必须获得同样的数据格式,而浏览器的请求实际是经过一次node接口转发,总共两次fetch流程产生的。
而且fetch模块,又需要支持浏览器和node的直接调用。所以我们整理出下面的接口请求流程图:

具体项目架构会在下一期文章给出。
记node前后端代码共用的一次坑的更多相关文章
- 基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.0.0版)
TableGo v6.0.0 版震撼发布,此次版本更新如下: 1.UI界面大改版,组件大调整,提升界面功能的可扩展性. 2.新增BeautyEye主题,界面更加清新美观,也可以通过配置切换到原生Jav ...
- 实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了
实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了 前言 在日常的软件开发中,程序员往往需要花费大量的时间写CRUD,不仅枯燥效率低,而且每个人的代码风格不统一.MyBatis-P ...
- [Java 开源项目]一款无需写任何代码,即可一键生成前后端代码的工具
作者:HelloGitHub-小鱼干 JeecgBoot 是一款基于代码生成器的低代码开发平台,零代码开发.JeecgBoot 采用开发模式:Online Coding 模式-> 代码生成器模式 ...
- Node前后端分离基本概括
首先从一个重要的概念“模板”说起. 广义上来说,web中的模板就是填充数据后可以生成文件的页面. 严格意义上来说,应该是模板引擎利用特定格式的文件和所提供的数据编译生成页面.模板大致分为前端模板(如e ...
- layui上传文件组件(前后端代码实现)
我个人博客系统上传特色图片功能就是用layui上传文件组件做的.另外采用某个生态框架,尽量都统一用该生态框架对应的解决方案,因为这样一来,有这么几个好处?1.统一而不杂糅,有利于制定相应的编码规范,方 ...
- SpringCloud微服务实战——搭建企业级开发框架(三十一):自定义MybatisPlus代码生成器实现前后端代码自动生成
理想的情况下,代码生成可以节省很多重复且没有技术含量的工作量,并且代码生成可以按照统一的代码规范和格式来生成代码,给日常的代码开发提供很大的帮助.但是,代码生成也有其局限性,当牵涉到复杂的业务逻辑 ...
- easyui中权限分配和添加 前后端代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- ajax请求, 前后端, 代码示例
[博客园cnblogs笔者m-yb原创,转载请加本文博客链接,笔者github: https://github.com/mayangbo666,公众号aandb7,QQ群927113708] http ...
- vue.js异步上传文件前后端代码
上传文件前端代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type&q ...
随机推荐
- nginx+apache前后台搭配使用
nginx apache都是web服务器 但是nginx更轻型对静态处理强大,而且nginx也是反向代理服务器,可以作转发 apache比较重型,非常稳定,处理动态WEB程序非常好,但是对静态处理就比 ...
- Python初体验
今天开始所有的工作脚本全都从perl转变到python,开发速度明显降低了不少,相信以后随着熟练度提升会好起来.贴一下今天一个工作代码,由于之前去一家小公司测序时,序列长度竟然都没有达到要求,为了之后 ...
- C程序设计语言(第二版)--- 习题选
1. 解: 2. 解: 3. (分析的好有条理啊!) 4. 解:
- 每天学一点Docker(5)——了解Docker架构
Docker的核心组件: 1.Docker客户端 - Client 2.Docker服务器 - Docker deamon 3.Docker镜像 - Image 4.仓库 - Registry 5.D ...
- CSS3 黑白图片
每当有自然灾害的时候,很多网站都是灰白的,想知道是怎么实现的嘛? 1.IE私有滤镜的方式 自IE4开始,IE引入了私有滤镜,可以实现透明度.模糊.阴影.发光等效果,当然也可以实现灰度图像效果.代码如下 ...
- TS Eslint规则说明
,//禁止使用alert confirm prompt ,//禁止使用数组构造器 ,//禁止使用按位运算符 ,//禁止使用arguments.caller或arguments.callee ,//禁止 ...
- 浅谈MVC MVP MVVM
复杂的软件必须有清晰合理的架构,否则无法开发和维护. MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用. 它本身很容易理解,但是要讲清楚,它与衍生的 MVP ...
- web前端经典面试题大全及答案
阅读目录 JavaScript部分 JQurey部分 HTML/CSS部分 正则表达式 开发及性能优化部分 本篇收录了一些面试中经常会遇到的经典面试题以及自己面试过程中遇到的一些问题,并且都给出了我在 ...
- Zabbix实战-简易教程--低层次发现(LLD)
一.概述 自动发现(LLD)提供了一种在为不同实体自动创建监控项,触发器和图形的方法.例如,Zabbix可以在你的机器上自动监控磁盘或网卡,而无需为每个磁盘或网卡手动创建监控项.(LLD) 此外,可以 ...
- Zabbix实战-简易教程(8)--添加item
一.术语 1.1 Item概念 Item是从主机里面获取的所有数据.通常情况下 item称为监控项,例如我们host加入了 zabbix 监控,我们需要监控它的内存.CPU信息,那么获取的CPU或内存 ...