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学习笔记(五)正则表达式
Apr 08 Javascript
jquery动画2.元素坐标动画效果(创建一个图片走廊)
Aug 24 Javascript
localResizeIMG先压缩后使用ajax无刷新上传(移动端)
Aug 11 Javascript
js 获取站点应用名的简单实例
Aug 18 Javascript
微信小程序 WXDropDownMenu组件详解及实例代码
Oct 24 Javascript
jQuery实现简易的输入框字数计数功能示例
Jan 16 Javascript
js 博客内容进度插件详解
Feb 19 Javascript
史上最全JavaScript数组去重的十种方法(推荐)
Aug 17 Javascript
在Create React App中启用Sass和Less的方法示例
Jan 16 Javascript
Vue实现点击按钮复制文本内容的例子
Nov 09 Javascript
Element Collapse 折叠面板的使用方法
Jul 26 Javascript
JQuery Ajax如何实现注册检测用户名
Sep 25 jQuery
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
PHP mail 通过Windows的SMTP发送邮件失败的解决方案
2009/05/27 PHP
php中批量修改文件后缀名的函数代码
2011/10/23 PHP
详解php命令注入攻击
2019/04/06 PHP
php如何实现数据库的备份和恢复
2020/11/30 PHP
jquery用get实现ajax在ie里面刷新不进入后台解决方法
2013/08/12 Javascript
javascript根据像素点取位置示例
2014/01/27 Javascript
纯css+js写的一个简单的tab标签页带样式
2014/01/28 Javascript
jQuery图片特效插件Revealing实现拉伸放大
2015/04/22 Javascript
再谈JavaScript线程
2015/07/10 Javascript
jQuery实现可高亮显示的二级CSS菜单效果
2015/09/01 Javascript
走进AngularJs之过滤器(filter)详解
2017/02/17 Javascript
微信小程序图片自适应支持多图实例详解
2017/06/21 Javascript
运用jQuery写的验证表单(实例讲解)
2017/07/06 jQuery
详述 Sublime Text 打开 GBK 格式中文乱码的解决方法
2017/10/26 Javascript
使用 Vue 绑定单个或多个 Class 名的实例代码
2018/01/08 Javascript
node.js通过Sequelize 连接MySQL的方法
2020/12/28 Javascript
Python自动化测试工具Splinter简介和使用实例
2014/05/13 Python
Python中的rjust()方法使用详解
2015/05/19 Python
Python实现TCP协议下的端口映射功能的脚本程序示例
2016/06/14 Python
python3实现暴力穷举博客园密码
2016/06/19 Python
python开发环境PyScripter中文乱码问题解决方案
2016/09/11 Python
Python实现的简单读写csv文件操作示例
2018/07/12 Python
Sanic框架安装与简单入门示例
2018/07/16 Python
Django框架教程之中间件MiddleWare浅析
2019/12/29 Python
python使用yaml 管理selenium元素的示例
2020/12/01 Python
使用python实现学生信息管理系统
2021/02/25 Python
英国定做窗帘和纺织品面料一站式商店:Dekoria
2018/08/29 全球购物
Ajax和javascript的区别
2013/07/20 面试题
教育实习生的自我评价分享
2013/11/21 职场文书
十八届三中全会宣传方案
2014/02/21 职场文书
学习决心书范文
2014/03/11 职场文书
上课玩手机的检讨书
2014/10/01 职场文书
抗洪救灾标语
2014/10/08 职场文书
2016年元旦寄语
2015/08/17 职场文书
党务工作者主要事迹材料
2015/11/03 职场文书
CSS3实现指纹特效代码
2022/03/17 HTML / CSS