最近和朋友聊天,发现我朋友调试前端页面的时候,都是上传svn或者git到测试服务器上调试,这样一来效率非常差,并且在多人的时候会频繁更新测试环境,然后我问我朋友,为什么不本地开发?然后我朋友说因为后端是java,所以本地要搭建java环境那些,很麻烦,也不会。
其实前端搭建本地开发环境非常简单,而且半小时就搞掂,下面来给大家分享一下一套半小时就能搭建的本地环境的方式,以及思路。
作为一名前端,在开发中经常需要将写好的代码在浏览器中展现才能知道我们编写的组件、样式等是否如我们所期望的样子展示。所以我们需要经常去刷新页面进行查看。
在现在2019,React和Vue使用率持续上升,但是React和Vue都有一个很重要的点,就是需要依赖数据进行渲染。当然我们可以mock数据,来模拟请求获取的数据。但是随着页面的复杂度,就不能简单的去mock数据那么简单了。
举个例子:
一个测试环境可以大致分为上图中的几步
那么我们分解出来的几个步骤后就可以开始我们的本地服务的搭建了。
一般我们构建页面都是需要使用webpack的,那么我们就可以利用webpack提供给我们的devServer这个参数进行配置了,如果不懂可以直接看webpack的文档就可以了,非常简单。
// 使用ip这个node的第三方库
const ip = require( 'ip' );
devServer = {
host: ip.address().toString(),
allowedHosts: [
'localhost',
ip.address(),
'0.0.0.0',
'127.0.0.1',
],
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
},
disableHostCheck: true,
port: 9527,
setup: router // 新版可以用before
};
关键是setup/before这部分了,这里将是如何获取模板和接口的关键了。
之前有说,如果我们的后端是php、java、python等等的后端语言,我们往往不一定在电脑中具备那么的语言运行环境。就算你都会搭建,你也要浪费很多时间,当然可以使用docker来一键部署,另外数据库的权限不一定提供给你,哪怕的测试环境的。就算提供给你,你确定你的电脑在跑着webpack的情况下,还能有很充足的内存支持你开启一些后端服务?
既然这样何苦难为你的电脑呢,我们采取一个更加简单的方式。首先我们需要和后端做一些约定,来实现我在本地能使用测试环境的服务器来实现模板引擎的渲染。
路由配置示例:
const bodyParser = require( 'body-parser' );
function router( app, Server ) {
app.use( bodyParser.urlencoded( { extended: false } ) );
// 首页模板
app.get( /\/index\.php/, function ( request, response ) {
const fileContent = readFile( 'home' );
// 获取服务器渲染后的html文件字符串
getHomeHtml( request, response, fileContent, userLog.cookie, ( html ) => {
response.send( html );
} );
} );
}
如何获取本地模板?
获取webpack内存中的模板
async function readHtml(name, Server, pageType) {
console.log(`http://localhost:9527/html/${name}.html`)
const res = await axios({
url: `http://localhost:9527/html/${name}.html`,
method: 'get',
responseType: 'text'
});
return res.data;
}
每个人的配置或许会有点差异,实际情况根据自己配置的路径来获取
静态资源其实交给webpack处理就可以了,通过配置publicPath来确认输出出来的路径,又webpack启动的服务来获取就可以,不懂的可以去看webpack的文档。
因为我们启动webpack的构建,在不借用任何修改host或者自己启动dns服务等操作的情况下,一般我们通过前3步搭建出来的页面,在加载完js之后,请求接口都会出现跨域的问题。因为如果我们不配置host,那么我们一般是用ip加上端口来访问我们webpack启动的服务的,这个时候就形成了一个跨域问题,如果你修改host,那么也会有端口跨域问题,所以我们就可以利用webpack提供给我们的devServer功能,做一个简单的反向代理的功能。
利用setup/before中配置路由的方式配置一个你的ajax路径的反向代理规则
app.post(/\/home\/getData\.php/, function (request, response) {
let reqData = request.body;
ajaxRequest(reqData, request, response, (result) => {
response.json(result);
});
});
ajaxRequest
const querystring = require( 'querystring' );
function getOptions( postData, request, hostname ) {
return {
hostname: '你的测试域名',
port: 80,
path: request.originalUrl,
method: request.method,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength( postData ),
'Cookie': ''
}
};
}
function ajaxRequest( data, request, response, callback, hostname ) {
const postData = querystring.stringify( data );
let req = http.request( getOptions( postData, request, hostname ), ( res ) => {
let data = '';
res.setEncoding( 'utf8' );
res.on( 'data', ( chunk ) => {
data += chunk;
} );
res.on( 'end', () => {
let parsedBody = data;
if ( res.headers['content-type'] ) {
let contentType = res.headers['content-type']
if ( ~contentType.search(/^|\/json/i) ) {
try {
parsedBody = JSON.parse(data)
} catch (err) {
parsedBody = data
}
}
}
callback instanceof Function && callback(parsedBody);
} )
} );
req.on( 'error', ( e ) => {
if (/\((.*)\)$/.test(data)) {
data = data.match(/\((.*)\)$/)[1];
}
console.error( '出错了,' + e.message );
} );
req.write( postData );
req.end();
}
简单来说就是匹配你页面中请求的路径,因为host和端口不一样导致跨域,所以用node这层来做一个反向代理,设定好host和端口,来帮你从node这一层去模拟浏览器发出的请求,欺骗服务以为你是浏览器发送过来的(其实就像爬虫一样)。从而实现跨域的请求方式,来解决我本地开发中的ajax跨域问题。
到这里其实基本的本地服务环境就已经搭建起来了,当然其实还可以扩展出欺骗浏览器登录的方式,既然我们都可以实现了反向代理了,那么我们就可以这么做来完成登录模式下的本地开发了。
login
function createCookieStr( cookies ) {
let str = '';
for ( let i = 0; i < cookies.length; i++ ) {
str += `${cookies[i].split( ' ' )[0]} `;
}
return str;
}
function login( user, pwd ) {
return new Promise( ( resolve, reject ) => {
let req = http.request( {
hostname: 'xxx.xxx.com',
port: 80,
path: `http://xxx.xxx.com/login.php?user=${user}&pwd=${pwd}`,
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}, ( res ) => {
res.on( 'end', () => {
let cookies = res.headers['set-cookie'];
cookie = createCookieStr( cookies );
if ( cookie != '' ) {
console.log( '登录成功' );
} else {
console.log( '登录失败' );
}
resolve( cookie );
} )
} );
req.on( 'error', ( e ) => {
console.error( '出错了,' + e.message );
} );
req.write( '' );
req.end();
} );
}
//创建登录记录log
function creatUserLog(data) {
let dirPath = path.join( root, '/.user_log' );
if ( !fs.existsSync( dirPath ) ) {
fs.mkdirSync( dirPath );
}
fs.writeFileSync(
path.join( root, '/.user_log/userLog.json' ),
JSON.stringify( data, null, 4 )
);
}
login( user, pwd )
.then( cookie => {
creatUserLog( {
cookie: cookie,
id: user
});
})
在请求中我们可以在代码上这样添加
let userJson = {};
// 通过判断环境变量或者判断文件是否存在
if ( NODE_LOGIN == 'true' ) {
userJson =require( '../.user_log/userLog.json' );
}
function getOptions( postData, request, hostname ) {
const cookie = userJson.cookie || request.headers.cookie;
return {
hostname: '你的测试域名',
port: 80,
path: request.originalUrl,
method: request.method,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength( postData ),
'Cookie': ''
}
};
}
这样就可以实现欺骗服务的你已经登录了。
以上就是我本篇文章的分享,如果你也有很方便的本地开发方案,欢迎留言或者链接贴一下给我互相学习一下。