vue、react等单页面项目应该这样子部署到服务器


Posted in Javascript onJanuary 03, 2018

最近好多伙伴说,我用vue做的项目本地是可以的,但部署到服务器遇到好多问题:资源找不到,直接访问index.html页面空白,刷新当前路由404。。。现在我们一起讨论下单页面如何部署到服务器?

由于前端路由缘故,单页面应用应该放到nginx或者apache、tomcat等web代理服务器中,千万不要直接访问index.html,同时要根据自己服务器的项目路径更改react或vue的路由地址。

如果说项目是直接跟在域名后面的,比如:http://www.sosout.com ,根路由就是 '/'。

如果说项目是直接跟在域名后面的一个子目录中的,比如:http://www.sosout.com/children ,根路由就是 '/children ',不能直接访问index.html。

以配置Nginx为例,配置过程大致如下:(假设:

1、项目文件目录: /mnt/html/spa(spa目录下的文件就是执行了npm run dist 后生成的dist目录下的文件)

2、访问域名:spa.sosout.com)

进入nginx.conf新增如下配置:

server {
  listen 80;
  server_name spa.sosout.com;
  root /mnt/html/spa;
  index index.html;
  location ~ ^/favicon\.ico$ {
    root /mnt/html/spa;
  }

  location / {
    try_files $uri $uri/ /index.html;
    proxy_set_header  Host       $host;
    proxy_set_header  X-Real-IP    $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
  }
  access_log /mnt/logs/nginx/access.log main;
}

注意事项:

1、配置域名的话,需要80端口,成功后,只要访问域名即可访问的项目

2、如果你使用了react-router的 browserHistory 模式或 vue-router的 history 模式,在nginx配置还需要重写路由:

server {
  listen 80;
  server_name spa.sosout.com;
  root /mnt/html/spa;
  index index.html;
  location ~ ^/favicon\.ico$ {
    root /mnt/html/spa;
  }

  location / {
    try_files $uri $uri/ @fallback;
    index index.html;
    proxy_set_header  Host       $host;
    proxy_set_header  X-Real-IP    $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
  }
  location @fallback {
    rewrite ^.*$ /index.html break;
  }
  access_log /mnt/logs/nginx/access.log main;
}

为什么要重写路由?因为我们的项目只有一个根入口,当输入类似/home的url时,如果找不到对应的页面,nginx会尝试加载index.html,这是通过react-router就能正确的匹配我们输入的/home路由,从而显示正确的home页面,如果browserHistory模式或history模式的项目没有配置上述内容,会出现404的情况。

简单举两个例子,一个vue项目一个react项目:

vue项目:

域名:http://tb.sosout.com

vue、react等单页面项目应该这样子部署到服务器

import App from '../App'
// 首页
const home = r => require.ensure([], () => r(require('../page/home/index')), 'home')
// 物流
const logistics = r => require.ensure([], () => r(require('../page/logistics/index')), 'logistics')
// 购物车
const cart = r => require.ensure([], () => r(require('../page/cart/index')), 'cart')
// 我的
const profile = r => require.ensure([], () => r(require('../page/profile/index')), 'profile')
// 登录界面
const login = r => require.ensure([], () => r(require('../page/user/login')), 'login')
export default [{
 path: '/',
 component: App, // 顶层路由,对应index.html
 children: [{
  path: '/home', // 首页
  component: home
 }, {
  path: '/logistics', // 物流
  component: logistics,
  meta: {
   login: true
  }
 }, {
  path: '/cart', // 购物车
  component: cart,
  meta: {
   login: true
  }
 }, {
  path: '/profile', // 我的
  component: profile
 }, {
  path: '/login', // 登录界面
  component: login
 }, {
  path: '*',
  redirect: '/home'
 }]
}]

vue、react等单页面项目应该这样子部署到服务器

############
# 其他配置
############

http {
  ############
  # 其他配置
  ############
  server {
    listen 80;
    server_name tb.sosout.com;
    root /mnt/html/tb;
    index index.html;
    location ~ ^/favicon\.ico$ {
      root /mnt/html/tb;
    }
  
    location / {
      try_files $uri $uri/ @fallback;
      index index.html;
      proxy_set_header  Host       $host;
      proxy_set_header  X-Real-IP    $remote_addr;
      proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header  X-Forwarded-Proto $scheme;
    }
    location @fallback {
      rewrite ^.*$ /index.html break;
    }
    access_log /mnt/logs/nginx/access.log main;
  }
  ############
  # 其他配置
  ############  
}

react项目:

域名:http://antd.sosout.com

vue、react等单页面项目应该这样子部署到服务器

/**
* 疑惑一:
* React createClass 和 extends React.Component 有什么区别?
* 之前写法:
* let app = React.createClass({
*   getInitialState: function(){
*    // some thing
*   }
* })
* ES6写法(通过es6类的继承实现时state的初始化要在constructor中声明):
* class exampleComponent extends React.Component {
*  constructor(props) {
*    super(props);
*    this.state = {example: 'example'}
*  }
* }
*/

import React, {Component, PropTypes} from 'react'; // react核心
import { Router, Route, Redirect, IndexRoute, browserHistory, hashHistory } from 'react-router'; // 创建route所需
import Config from '../config/index';
import layout from '../component/layout/layout'; // 布局界面

import login from '../containers/login/login'; // 登录界面

/**
 * (路由根目录组件,显示当前符合条件的组件)
 * 
 * @class Roots
 * @extends {Component}
 */
class Roots extends Component {
  render() {
    // 这个组件是一个包裹组件,所有的路由跳转的页面都会以this.props.children的形式加载到本组件下
    return (
      <div>{this.props.children}</div>
    );
  }
}

// const history = process.env.NODE_ENV !== 'production' ? browserHistory : hashHistory;

// 快速入门
const home = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/home/homeIndex').default)
  }, 'home');
}

// 百度图表-折线图
const chartLine = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/charts/lines').default)
  }, 'chartLine');
}

// 基础组件-按钮
const button = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/general/buttonIndex').default)
  }, 'button');
}

// 基础组件-图标
const icon = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/general/iconIndex').default)
  }, 'icon');
}

// 用户管理
const user = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/user/userIndex').default)
  }, 'user');
}

// 系统设置
const setting = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/setting/settingIndex').default)
  }, 'setting');
}

// 广告管理
const adver = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/adver/adverIndex').default)
  }, 'adver');
}

// 组件一
const oneui = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/ui/oneIndex').default)
  }, 'oneui');
}

// 组件二
const twoui = (location, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/ui/twoIndex').default)
  }, 'twoui');
}

// 登录验证
const requireAuth = (nextState, replace) => {
  let token = (new Date()).getTime() - Config.localItem('USER_AUTHORIZATION');
  if(token > 7200000) { // 模拟Token保存2个小时
    replace({
      pathname: '/login',
      state: { nextPathname: nextState.location.pathname }
    });
  }
}

const RouteConfig = (
  <Router history={browserHistory}>
    <Route path="/home" component={layout} onEnter={requireAuth}>
      <IndexRoute getComponent={home} onEnter={requireAuth} /> // 默认加载的组件,比如访问www.test.com,会自动跳转到www.test.com/home
      <Route path="/home" getComponent={home} onEnter={requireAuth} />
      <Route path="/chart/line" getComponent={chartLine} onEnter={requireAuth} />
      <Route path="/general/button" getComponent={button} onEnter={requireAuth} />
      <Route path="/general/icon" getComponent={icon} onEnter={requireAuth} />
      <Route path="/user" getComponent={user} onEnter={requireAuth} />
      <Route path="/setting" getComponent={setting} onEnter={requireAuth} />
      <Route path="/adver" getComponent={adver} onEnter={requireAuth} />
      <Route path="/ui/oneui" getComponent={oneui} onEnter={requireAuth} />
      <Route path="/ui/twoui" getComponent={twoui} onEnter={requireAuth} />
    </Route>
    <Route path="/login" component={Roots}> // 所有的访问,都跳转到Roots
      <IndexRoute component={login} /> // 默认加载的组件,比如访问www.test.com,会自动跳转到www.test.com/home
    </Route>
    <Redirect from="*" to="/home" />
  </Router>
);

export default RouteConfig;

vue、react等单页面项目应该这样子部署到服务器

############
# 其他配置
############

http {
  ############
  # 其他配置
  ############
  server {
    listen 80;
    server_name antd.sosout.com;
    root /mnt/html/reactAntd;
    index index.html;
    location ~ ^/favicon\.ico$ {
      root /mnt/html/reactAntd;
    }

    location / {
      try_files $uri $uri/ @router;
      index index.html;
      proxy_set_header  Host       $host;
      proxy_set_header  X-Real-IP    $remote_addr;
      proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header  X-Forwarded-Proto $scheme;
    }
    location @router {
      rewrite ^.*$ /index.html break;
    }
    access_log /mnt/logs/nginx/access.log main;
  }

  ############
  # 其他配置
  ############  
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
理解JavaScript的caller,callee,call,apply
Apr 28 Javascript
jquery last-child 列表最后一项的样式
Jan 22 Javascript
基于jquery+thickbox仿校内登录注册框
Jun 07 Javascript
利用jquery的获取JS文件中的字符串内容
Feb 14 Javascript
jQuery动态添加删除select项(实现代码)
Sep 03 Javascript
js获得网页背景色和字体色的方法
Mar 21 Javascript
js 实现的可折叠留言板(附源码下载)
Jul 01 Javascript
node.js中的console.assert方法使用说明
Dec 10 Javascript
jQuery自定义图片缩放拖拽插件imageQ实现方法(附demo源码下载)
May 27 Javascript
jQuery Easyui Treegrid实现显示checkbox功能
Aug 08 jQuery
jQuery属性选择器用法实例分析
Jun 28 jQuery
Node在Controller层进行数据校验的过程详解
Aug 28 Javascript
AngularJS实现的2048小游戏功能【附源码下载】
Jan 03 #Javascript
浅谈node模块与npm包管理工具
Jan 03 #Javascript
JavaScript基于面向对象实现的猜拳游戏
Jan 03 #Javascript
JS实现的简单拖拽购物车功能示例【附源码下载】
Jan 03 #Javascript
基于js 各种排序方法和sort方法的区别(详解)
Jan 03 #Javascript
vue项目中用cdn优化的方法
Jan 03 #Javascript
不到200行 JavaScript 代码实现富文本编辑器的方法
Jan 03 #Javascript
You might like
THINKPHP2.0到3.0有哪些改进之处
2015/01/04 PHP
浅析Yii2中GridView常见操作
2016/04/22 PHP
Symfony查询方法实例小结
2017/06/28 PHP
PHP设计模式之适配器模式定义与用法详解
2018/04/03 PHP
ThinkPHP框架整合微信支付之刷卡模式图文详解
2019/04/10 PHP
详解laravel passport OAuth2.0的4种模式
2019/11/04 PHP
Laravel5.1 框架表单验证操作实例详解
2020/01/07 PHP
JavaScript中的私有成员
2006/09/18 Javascript
javascript suggest效果 自动完成实现代码分享
2012/02/17 Javascript
JavaScript设置首页和收藏页面的小例子
2013/11/11 Javascript
js使用html()或text()方法获取设置p标签的显示的值
2014/08/01 Javascript
jquery背景跟随鼠标滑动导航
2015/11/20 Javascript
探讨JavaScript标签位置的存放与功能有无关系
2016/01/15 Javascript
JQuery异步提交表单与文件上传功能示例
2017/01/12 Javascript
ES6中的Promise代码详解
2017/10/09 Javascript
Vue中之nextTick函数源码分析详解
2017/10/17 Javascript
JavaScript实现图片的放大缩小及拖拽功能示例
2019/05/14 Javascript
layui 富文本赋值,取值,取纯文本值的实例
2019/09/18 Javascript
使用layui的layer组件做弹出层的例子
2019/09/27 Javascript
一文秒懂JavaScript构造函数、实例、原型对象以及原型链
2020/08/25 Javascript
[05:10]2014DOTA2国际邀请赛 通往胜利之匙赛场探秘之旅
2014/07/18 DOTA
python爬虫headers设置后无效的解决方法
2017/10/21 Python
Python3基础教程之递归函数简单示例
2019/06/07 Python
Python标准库itertools的使用方法
2020/01/17 Python
联想澳大利亚官网:Lenovo Australia
2018/01/18 全球购物
美国最流行的男士时尚网站:Touch of Modern
2018/02/05 全球购物
C语言笔试题
2014/09/04 面试题
房地产广告词大全
2014/03/19 职场文书
管理岗位竞聘演讲稿
2014/08/18 职场文书
村党支部书记个人对照材料汇报
2014/10/26 职场文书
《爱的教育》读书心得
2014/11/08 职场文书
机动车交通事故协议书
2015/01/29 职场文书
2016年小学教师师德承诺书
2016/03/25 职场文书
使用logback实现按自己的需求打印日志到自定义的文件里
2021/08/30 Java/Android
如何基于python实现单目三维重建详解
2022/06/25 Python
Python使用pandas导入csv文件内容的示例代码
2022/12/24 Python