使用Vue.js 2.0搭建单页应用:从构建到部署

入门请参考这篇文章:Vue构建单页应用最佳实战

在此记录下在我使用Vue.js 2.0开发较大型的单页应用时遇到的困难。

写文章不容易,如果这篇文章对你有帮助,请给我的github仓库加个star~ 
github项目地址

项目结构

.
├── build/                      # webpack config files
│   └── ...
├── config/                     
│   ├── index.js                # main project config
│   └── ...
├── src/
│   ├── main.js                 # app entry file
│   ├── App.vue                 # main app component
│   ├── components/             # ui components
│   │   └── ...
│   └── assets/                 # module assets (processed by webpack)
│       └── ...
├── static/                     # pure static assets (directly copied)
├── test/
│   └── unit/                   # unit tests
│   │   ├── specs/              # test spec files
│   │   ├── index.js            # test build entry file
│   │   └── karma.conf.js       # test runner config file
│   └── e2e/                    # e2e tests
│   │   ├── specs/              # test spec files
│   │   ├── custom-assertions/  # custom assertions for e2e tests
│   │   ├── runner.js           # test runner script
│   │   └── nightwatch.conf.js  # test runner config file
├── .babelrc                    # babel config
├── .editorconfig.js            # editor config
├── .eslintrc.js                # eslint config
├── index.html                  # index.html template
└── package.json                # build scripts and dependencies
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

Vue相关


Vue.js 2.0

载入静态资源

参考链接: 
Handing Static Assets

static/目录下的文件不会被webpack处理,可以在index.html中直接引用其中的资源

Transition Effects

参考链接: 
Transition Effects

Vue提供多种在items被插入,更新或者从DOM中移除时应用过渡效果的方式。它包括以下的方式:

  • 自动应用CSS transitions 和 animations
  • 集成第三方CSS animation 库,例如Animate.css
  • 使用JavaScript 直接在transition 钩子期间操纵DOM
  • 集成第三方JavaScript animation 库,例如Velocity.js

在此处,我主要讲讲使用transition为mdl-spinner添加CSS动画的经验。

Vue提供4种应用在 enter/leave 过渡上的class:

  1. v-enter: 进入的初始状态。在元素被插入前应用,一帧后被移除。
  2. v-enter-active: 进入的激活和结束状态。在元素被插入前应用,在过渡/动画结束后移除。
  3. v-leave: 离开的初始状态。在离开过渡效果触发的时候应用,一帧后被移除。
  4. v-leave-active: 离开的激活和结束状态。在离开过渡效果触发的时候应用,在过渡/动画结束后移除。

这里写图片描述

上代码:

<transition name="spinner-move">
  <div v-show="$store.state.common.loading">
    <div class="mdl-spinner mdl-js-spinner is-active loading"></div>
  </div>
</transition>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
.spinner-move-enter-active {
  position: relative;
  animation: move-in .5s;
}
.spinner-move-leave-active {
  position: relative;
  animation: move-out .5s;
}
@keyframes move-in {
  0% {
    top: -50px;
  }
  50% {
    top: 10px;
  }
  100% {
    top: 0px;
  }
}
@keyframes move-out {
  0% {
    top: 0px;
  }
  50% {
    top: 10px;
  }
  100% {
    top: -50px;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

Watchers

参考文章: 
vm.$watch( expOrFn, callback, [options] ) 
vuejs怎么watch对象里某个属性的变化呢?

观察Vue实例上的一个表达式或者computed function的改变。

我的需求是,设置Tip组件出现的条件。

1.在vuex中的state中设置一个属性及其mutation:

const state = {
  tip: {
    message: '',
    actionHandler: function (event) {},
    timeout: 2000,
    actionText: ''
  }
  //
}

const mutations = {
  [SET_TIP] (state, tip) {
    state.tip = tip
  }
  //
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2.新建Tip.vue:

<template>
  <div id="snackbar" class="mdl-js-snackbar mdl-snackbar">
    <div class="mdl-snackbar__text"></div>
    <button class="mdl-snackbar__action" type="button"></button>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        //将Store.state绑定在data上
        data: this.$store.state
      }
    },
    watch: {
      // 但state中的tip改变时调用showTip方法
      'data.doc.tip': 'showTip'
    },
    methods: {
      showTip () {
        let snackbarContainer = document.querySelector('#snackbar')
        snackbarContainer.MaterialSnackbar.showSnackbar(this.data.doc.tip)
      }
    }
  }
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

3.在需要时commit:

commit(types.SET_TIP, {
  message: err.statusText,
  actionHandler: function (event) {},
  timeout: 2000,
  actionText: 'Undo'
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Computed Properties

参考链接: 
Computed Properties

我想使loading组件根据当前路由清空展示不同的样式,由于判断表达式比较复杂且不止在一个地方调用了该判断表达式,我使用了computed属性:

computed: {
  forLogin: function () {
    return this.$route.path === '/login'
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  <div>
    <transition name="spinner-move">
      <div v-show="$store.state.doc.loading && forLogin" class="loading-wrapper loading-login-wrapper">
        <div class="mdl-spinner mdl-js-spinner is-active loading"></div>
      </div>
    </transition>
    <transition name="spinner-move">
      <div v-show="$store.state.doc.loading && !forLogin" class="loading-wrapper">
        <div class="mdl-spinner mdl-js-spinner is-active loading loading-common"></div>
      </div>
    </transition>
  </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

通过Props与<router-view>子组件通信

参考链接: 
Props

通过阅读官方文档可知,Vue.js可以通过Pros将数据从父组件中传递到子组件,但官网给的例子一般是这样的:

Vue.component('child', {
  // camelCase in JavaScript
  props: ['myMessage'],
  template: '<span>{{ myMessage }}</span>'
})
  • 1
  • 2
  • 3
  • 4
  • 5

props传递的数据直接在模板中使用,但是,开发中还会经常遇到另外一种情况,在<script>中引用props的数据,事实上,官方文档也给了例子:

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}
  • 1
  • 2
  • 3
  • 4

然而,非常遗憾的是,这段代码在我这里跑不通,于是,我就去研究Vue实例的生命周期图:

hook

注意右下角的圆环处,当数据改变时,virtual DOM 会重新渲染更新,结合上面提到的props传递的数据直接在模板中使用可以正常引用,所以我想到了下面这种方式:

<template>
  <div>
    <span style="display:none;">
      {{initialCounter}}
    </span>
  </div>
</template>

<script>
  export default {
    props: ['initialCounter'],
    updated () {
      // props中的值只有在updated钩子中才能正常访问
      // next(this.initialCounter)
    }
  }
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

模板中引用props的值,会触发updated钩子,此时this.initialCounter已经被初始化可以被引用了,至于为什么要多次一举,也许就要问尤大大了。


vue-router

<router-view>正确渲染

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

<router-view> 组件是一个 functional 组件,渲染路径匹配到的视图组件。<router-view> 渲染的组件还可以内嵌自己的 <router-view>,根据嵌套路径,渲染嵌套组件。

踩到的坑:

  1. 如果在某个组件中需要嵌套组件,记得加上<router-view>
  2. 不要试图跳过父组件,直接访问更上层的组件或是该类组件的子组件。惨痛教训,chrome会报这个神奇的bug: 
    bug detail
    Vue.js的作者尤雨溪说: 
    vue-router组件渲染和virtual DOM更新构成了竞争情况

使用懒加载异步加载组件

参考链接: 
懒加载 · GitBook

当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

导航钩子

参考链接: 
导航钩子 · GitBook

今天在试图在使用百度地图api的时候,动态加载远程script遇到了大麻烦的回调,最后用组件内的钩子的钩子解决。 代码:
beforeRouteEnter (to, from, next) {
  // 在渲染该组件的对应路由被 confirm 前调用
  // 不!能!获取组件实例 `this`
  // 因为当钩子执行前,组件实例还没被创建
  next(() => {
    loadScript()
    initialize()
  })
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

动态路由匹配

参考链接: 
动态路由匹配 · GitBook

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用『动态路径参数』(dynamic segment)来达到这个效果:
<div id="app">
  <p>
    <router-link to="/user/foo">/user/foo</router-link>
    <router-link to="/user/bar">/user/bar</router-link>
  </p>
  <router-view></router-view>
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
const User = {
  template: `<div>User {{ $route.params.id }}</div>`
}

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
})

const app = new Vue({ router }).$mount('#app')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
上面是官方文档中的例子,可以发现在传递路径参数的时候,使用的是固定的值,那么,当需要传递动态的路径参数时该如何做呢? 答案是使用v-bind 的 JS 表达式,直接上例子:
<table>
  <tbody>
    <tr v-for="(item, index) in items">
      <th >{{ index }}</th>
      <td>
        <router-link v-bind:to="{ name: 'example', params: { id: index }}">{{ item }}</router-link>
      </td>
    </tr>
  </tbody>
</table>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
解释一下,`:to`属性中的值会被解析成js表达式,所以例子中的`index`可以被识别成当前循环元素的索引,进而体现路径匹配中的动态性。

嵌套路由

实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,例如:
/user/foo/profile                     /user/foo/posts
+------------------+                  +-----------------+
| User             |                  | User            |
| +--------------+ |                  | +-------------+ |
| | Profile      | |  +------------>  | | Posts       | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
借助 `vue-router`,使用嵌套路由配置,就可以很简单地表达这种关系。 在由`vue-cli`创建的项目中, `` 是最顶层的出口,渲染最高级路由匹配到的组件。同样地,一个被渲染组件同样可以包含自己的嵌套 ``。例如,在 User 组件的模板添加一个 ``:
const User = {
  template: `
    <div class="user">
      <h2>User {{ $route.params.id }}</h2>
      <router-view></router-view>
    </div>
  `
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
要在嵌套的出口中渲染组件,需要在 VueRouter 的参数中使用 children 配置:
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User,
      children: [
        {
          // 当 /user/:id/profile 匹配成功,
          // UserProfile 会被渲染在 User 的 <router-view> 中
          path: 'profile',
          component: UserProfile
        },
        {
          // 当 /user/:id/posts 匹配成功
          // UserPosts 会被渲染在 User 的 <router-view> 中
          path: 'posts',
          component: UserPosts
        }
      ]
    }
  ]
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
上面的例子可以符合简单的业务逻辑,但是一旦业务逻辑变得复杂起来,就需要自己摸索一定的技巧了。这就是这篇文章下一个探讨的话题

嵌套路由与动态路由匹配结合使用

前面探讨了动态路由匹配和嵌套路由的基本使用方式,但是在现实的开发过程中,难免会遇到二者相结合的情况,接着上面的例子:
/user/:id/posts/:id/comments                
+------------------+ 
| User             | 
| +--------------+ |
| | Posts        | | 
| | ------------ |
| |   Comments   | |
| | ------------ | | 
| +--------------+ | 
+------------------+  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
上面的例子嵌套了2层路由,且包含了2层的动态路由匹配,一般的方法无法解决这个问题,需要一些特殊的方法。 其实上述提到过,:to中包含的是js表达式,所以可以以此为切入点,将:to的值与`computed`中的变量绑定:
<router-link :to="link">
  test
</router-link>
  • 1
  • 2
  • 3
computed: {
  link () {
    return '/user/' + this.$route.params.id + '/chart/' + this.id
  }
},
  • 1
  • 2
  • 3
  • 4
  • 5

使用重定向模拟嵌套二级菜单效果

前面已经提到过,APP.vue中包含的<router-view>作为顶层路由渲染出口,其子组件中可以包含嵌套的<router-view>路由渲染出口。按照上面的思路,我们可以轻松的实现二级菜单甚至多级菜单。

现在考虑一下这种情况,在我们的应用中,侧边一个Drawer作为一级菜单,页面顶部一个TapBar作为二级菜单,类似这样:

这里写图片描述

我们可以把二级菜单的内容放置在顶层路由渲染出口中渲染,这么做有几个好处:

  1. <router-view>层级减少,提高渲染性能;
  2. 在特定的需求下,二级菜单内容在APP.vue中渲染更合适;
  3. 可以利用vue-router的.router-link-active属性添加链接被点击后效果的CSS样式;

那么,该如何实现呢?

可以使用重定向进行模拟

  • 将二级菜单的路由设置成2层路由,但该组件依旧在顶层的出口渲染;
'/children1' => '/parent/children1'
'/children2' => '/parent/children2'
  • 1
  • 2
  • 使用重定向将虚拟的一级菜单路由重定向到某个真实子路由上;
{
  path: '/parent',
  redirect: '/parent/children1'
}
  • 1
  • 2
  • 3
  • 4
  • 在一级菜单的链接中使用虚拟的一级菜单路由;
<router-link to="/parent">一级菜单</router-link>
  • 1

以上!


JavaScript问题


setTimeout中的this

今天在项目开发过程中遇到大坑了,鼓搞了两小时发现是`setTimeout`中的`this`被自动指向了`window`的原因,还是基础没学好。。。 贴上部分代码:
// 因为setTimeout中的this指向window,所以得耍个trick,保存当前对象this
let that = this

setTimeout(function () {
  that.loadingDisplay = 'none'
}, 1000)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用classList改变elementclass

今天想做点击后使选中链接高亮,其他链接自动恢复默认的样式的功能。一开始直接修改通过`element.style` 实现效果, 在Chrome下测试通过,但是在Edge和IE中都会报错,经查证发现严格模式无法修改只读属性,于是在MDN上发现使用`classList`改变`element`的`class`的方法 上代码:
if (this.lastElement !== null) {
  this.lastElement.classList.remove('activate')
}
this.lastElement = event.target
event.target.classList.add('activate')
  • 1
  • 2
  • 3
  • 4
  • 5

SVG绘制圆环图

参考文章: 
小tip: 使用SVG寥寥数行实现圆环loading进度效果

使用 `stroke-dasharray` 属性实现如下效果:

SVG图

图中的小圆点使用是用 `` 画的小实心圆:
<circle cx="240" cy="94" r="3" fill="#9e9e9e"></circle>
  • 1
虚线使用 `` :
<line x1="240" y1="88" x2="240" y2="55" stroke="#9e9e9e" stroke-width="2" stroke-dasharray="2 2" />
  • 1

页面滚动添加动画

  • 为scroll事件添加监听器
  • 使用scrollTop获取当前视口顶部距离页面顶部的高度:
let scrollTop = document.getElementById('scroll').scrollTop
  • 1
  • 将scrollTop与window.innerHeight相加获得当前视口底部距离页面顶部的高度:
let scrollBottom = scrollTop + window.innerHeight
  • 1
  • 根据特定div的高度为其设置相应的动画:
if (scrollTop > 20 && scrollBottom < (ribbonHeight + servicesHeight / 2)) {
  intro1.classList.add('vertical-anim')
  device1.classList.add('vertical-anim')
  device2.classList.add('vertical-anim')
}
  • 1
  • 2
  • 3
  • 4
  • 5
大功告成!

CSS问题

overflow属性

参考链接: 
overflow - CSS | MDN

overflow 属性规定当内容溢出元素框时发生的事情。 语法
/* 默认值。内容不会被修剪,会呈现在元素框之外 */
overflow: visible;

/* 内容会被修剪,并且其余内容不可见 */
overflow: hidden;

/* 内容会被修剪,浏览器会显示滚动条以便查看其余内容 */
overflow: scroll;

/* 由浏览器定夺,如果内容被修剪,就会显示滚动条 */
overflow: auto;

/* 规定从父元素继承overflow属性的值 */
overflow: inherit;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
当我在设计登录界面的卡片框的时候,我想在基本的卡片框上方露出一小截白边,这个技术使用`:before`伪类可以坐到,但也需要在改容器中设置`overflow`属性的值。 **`overflow: hidden;`效果:**

overflow: hidden

**`overflow: visible;`效果:**

这里写图片描述

::before伪类

参考链接: 
::before (:before) - CSS | MDN

::before 会创建一个作为当前元素子元素的伪元素。常通过 content 属性来为一个元素添加修饰性的内容。 此元素默认为行内元素。
/* CSS3 语法 */
element::before { 样式 }  

/* (单冒号)CSS2 过时语法 (仅用来支持 IE8) */
element:before  { 样式 }  

/* 在每一个p元素前插入内容 */
p::before { content: "Hello world!"; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

::after伪类

参考链接: 
::after (:after) - CSS | MDN

::after伪元素匹配一个作为当前元素最后一个子元素的伪元素。常通过 content 属性来为一个元素添加修饰性的内容。 此元素默认为行内元素。 我使用::after伪类为当前激活链接添加一个标记,效果如图:

::after

box-shadow 属性

参考链接: 
CSS3 box-shadow 属性

使用下面这个box-shadow属性:
box-shadow: #666 0px 0px 10px;
  • 1
为载入进度圆环加上如下阴影效果:

进度圆环

绝对定位的水平居中

最近遇到一个需求,需要把用户头像嵌入到父级div的兄弟div上,完成的效果图如下:

头像

一开始采用方式是` `使用相对布局,父元素加上属性`text-align: center;`,但是无效,而且相对布局中的元素就算被改变位置之后,依旧会占据原来的位置,造成大面积留白,非常丑,故弃之。 后来尝试使用绝对布局,因为给` `设定的宽度和高度是固定的,于是就可以结合left属性进行水平居中。
left: 50%;
margin-left: -50px;
  • 1
  • 2
这两行代码的意思是,首先设置` `的最左边距离左边框50%,然后因为半径是50px,所以通过设置margin-left将元素整体左移50px,使圆心水平居中。

Flex 布局

参考文章: 
Flex 布局教程:语法篇

我使用下面的代码:
justify-content: center;
  • 1
对齐我的TapBar:

TapBar

两端对齐,项目之间的间隔都相等,并且在交叉轴上居中对齐:
justify-content: space-between;
align-items: center;
  • 1
  • 2

这里写图片描述

部署

双十一的时候阿里云9.9元买云服务器,可惜没抢到,但是后来发现有个学生优惠49包半年也还还挺便宜于是就购买之。 服务器的操作系统:CentOS 6.5 64位,所以下面从0开始讲解Vue.js 2.0工程部署在操作系统为CentOS 6.5服务器的步骤。 首先,你当然得有台服务器……躲过了双十一还是得挨一刀啊=.=

Linux中创建用户

由于到手的是一台裸机,所以一切都得自己配,不过也好,温习一下以前学习的Linux基础知识~ *众所周知,生产环境中的Linux系统不推荐直接使用root 帐号,这是因为root权限最大,你的任何误操作就可能使数据找不回来,而普通用户对系统的操作是有限的。* 对于一个刚到手的新服务器,你的第一次SSH连接应该是以root的身份登录的,你需要手动添加一个普通用户。 下面讲解添加一个普通用户的基本步骤:
  • 在Linux系统中,只有root用户才能够创建一个新用户,如下的命令将新建一个登录名 ‘xxx’的用户。
sudo useradd xxx
  • 1
  • 完成了这一操作后,你还应该使用passwd命令为其设置一个初始密码。输入该命令后,会系统会请求输入密码。
sudo passwd xxx
  • 1
  • 在生产环境中,我们经常需要提升普通用户的权限以完成某种操作,这时就要用到sudo命令,如果你按照上述的步骤,你应该会遇到下面这个错误:
XXX is not in the sudoers file
  • 1
这是因为 ‘xxx’用户不在`sudoers`组中。 我参考这篇文章解决了这个问题:

Linux有问必答:怎样解决“XXX is not in the sudoers file”错误

现在,一个具有sudo权限的普通用户已经创建好了。

安装Node.js

众所周知,Linux的各种发行版的包管理器中的Node.js版本都相当之老,这也给新手带来了不少麻烦。 我尝试过以下几种安装Node.js的方法:
  1. yum install, 版本太老。
  2. nvm, 安装的都在本地,不能加 sudo的,sudo 回去/usr/bin 或/usr/local/bin下面去找的,遇到权限问题很蛋疼!
  3. 直接编译最新版的Node.js源代码,同时也要安装好多依赖包,相当麻烦。
  4. 直接下载使用最新的编译好的Node.js,方便快捷。

我参考了这篇文章:

在centOS 6下部署node

安装Nginx

vue-cli生成的项目可以使用npm run dev命令直接让程序跑起来,但是生产环境中还使用开发环境的服务器是不行的,我们需要的服务器性能要高,占用内存要小,并发性要好,于是我的目光投向了服务器界大名鼎鼎的Nginx.

在安装Nginx的工程中遇到的问题和安装Node.js类似,我参考下面这篇文章成功的安装的Nginx:

CENTOS 6.5 配置YUM安装NGINX

配置Nginx访问应用

Beginner’s Guide

在工程目录下使用如下代码生成dist目录

npm run build
  • 1

参考官方教程添加一个server节点,其中的root参数绑定dist文件夹的绝对路径即可。

其中一开始遇到一个bug,

nginx 403 forbidden
  • 1

查证后发现是权限问题,参考下面这篇文章,把nginx的启动用户改成目录的所属用户即可。

nginx 403 forbidden 二种原因

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值