前端開發碎碎念

深紅發表於2018-04-13

工作也有一段時間了,平時忙於業務程式碼的編寫中,發現身邊的一些人以及自己,對一些基本概念理解有所偏差,可能鬧出笑話,會問出下面這些常識性錯誤的奇怪問題:

  1. vuejs怎麼在伺服器部署?(我提交到伺服器之後執行了 npm run dev之後關閉了是可以開啟網頁的,但是關閉了ssh之後,服務馬上就不能用了,請問正確的部署方式是怎麼樣的?)
  2. vue開發的專案,前端寫的.vue檔案中的生命週期方法,線上還存在嗎?

2333,怎麼都是關於Vue的問題。。。我真沒黑Vue開發者,不過也可以看出,Vue的小白受眾的確比較多。

部落格文章原文

webpack和webpack-dev-server

現在基於Vue,React的SPA單頁應用開發,都傾向於採用webpack的模組化構建方案。可能大多數人,開發一個專案,會使用腳手架工具(vue-cli, create-react-app) 我們本地開發時,執行命令列npm run dev,然後就開始編寫業務邏輯了,對於其中發生了什麼,大多數人可能不太關心。其實執行了該命令,就是執行了webpack-dev-server

webpack-dev-server是webpack官方提供的一個小型Express伺服器,正是因為webpack-dev-server自己開啟了一個伺服器,我們才能夠前後端分離開發(我們不需要關心後端的程式碼)。前端啟動的這個伺服器,是用來構建和渲染頁面,並提供了自動重新整理和熱替換功能。

簡單來說: webpack只是構建(npm run build)

webpack-dev-server除了構建,還提供web服務(npm run dev)

路由

什麼是路由? 簡單來說:/about/deepred /home/ 這些就是路由

在web開發中,路由分為前端路由和後臺路由 其實在單頁應用還沒有流行前,路由基本指的是後臺路由。如果你熟悉傳統的後臺web開發,可能對下面的程式碼很熟悉:

app.get('/about', function (req, res) {
  res.render('about', { title: 'Hey', message: 'Hello there!'});
});
app.get('/', function (req, res) {
  res.render('index');
});
複製程式碼

傳統的web網站,所有的路由都是由後臺定義的。當我們想訪問一個頁面http://anata.me/about/,首先向後臺傳送一個請求,後臺根據定義好的路由,決定渲染哪個頁面。

然而單頁應用的出現,改變了這個模式。如果你是前端開發,應該對這段程式碼更加熟悉:

routes: [
    {
      path: '/user/:userId',
      name: 'user',
      component: User
    },
    {
      path: '/about/',
      name: 'about',
      component: About
    }
  ]
複製程式碼

前端路由是將頁面的渲染權交給了js控制,不通過請求伺服器來判斷渲染頁面。前端一般利用histroy和hash來控制,達到不重新整理頁面可以使顯示內容發生變化,這樣速度更快,使用者體驗更好。前端路由解放了服務端,專心提供介面資料服務。

打包部署

腳手架生成的專案,一般執行npm run build之後,會在專案根目錄生成一個dist目錄,這就是我們打包好後的靜態資原始檔。 注意的是

  1. 我們線上執行的單頁應用,就是打包好後的dist檔案,並不是src目錄下的原始檔
  2. 線上部署更不是執行npm run dev啟動專案。npm run dev啟動的伺服器只是為了開發而使用的,真正線上的伺服器,是由後臺提供的(比如PHP,Java, python, Node...)

部署的方式有很多,比如可以把dist檔案和後臺程式碼放在一起,後臺把dist檔案當做靜態資源讀取即可。不過因為採用了前端路由的方案,後臺還需要配置一下,以Express舉例:

// 訪問靜態資原始檔 這裡是訪問所有dist目錄下的靜態資原始檔
app.use(express.static(path.resolve(__dirname, '../dist')))
// 因為是單頁應用 所有請求都走/dist/index.html
// 這一句要放在所有其他路由的後面
app.get('*', function(req, res) {
    const html = fs.readFileSync(path.resolve(__dirname, '../dist/index.html'), 'utf-8')
    res.send(html)
})
複製程式碼

也可以把dist靜態檔案和後臺程式碼分開,通過Nginx部署

server {
        listen 80;
        server_name 127.0.0.1;
        location / {
            root   /data/deered/dist; #前端打包後的dist檔案位置
            try_files $uri $uri/ /index.html; #防止頁面重新整理404
            index  index.html;
        }
    }
複製程式碼

跨域

因為webpack-dev-server啟動了一個伺服器,所以在開發時,前端去請求真正的後臺介面,是存在跨域問題的。webpack提供了跨域的解決方案,原理就是讓伺服器反向代理請求真正的介面

vue-cli配置跨域

proxyTable: {
      '/api': {
        target: 'http://localhost:8089/api/',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    },
複製程式碼

前端請求/api/xxxx時,webpack-dev-server啟動的伺服器會幫我們請求http://localhost:8089/api/xxxx,同時返回資料。

有些人就會有疑惑,那打包後的檔案,是不是也能跨域。前面我們說了,線上部署就不是執行npm run dev,所以,前端是不是跨域要看你怎麼部署了。

如果你把打包後的dist檔案和後端程式碼放在一起,那麼根本就不存在跨域問題! 如果前端靜態檔案和後端不在一起,那麼可以用Nginx做轉發

server {
        listen 80;
        server_name 127.0.0.1;
        location / {
            root   /data/deered/dist; #前端打包後的dist檔案位置
            index  index.html;
            try_files $uri $uri/ /index.html;
        }
        location /api {
            proxy_pass http://127.0.0.1:8089 #後臺地址
        }
    }
複製程式碼

Vue和React

Vue的指令和模板語言讓開發者可以很簡潔的完成一個複雜的功能,而React的JSX語法,則讓開發者擁有更多的自主權。 從Vue轉向React的開發者,一開始可能會非常不適應,畢竟v-for v-if v-model這些最基本的功能,React竟然全都要我們自己去實現。

我們其實可以從本質上來看:

一個Vue的元件:

<template>
  <div class="hello" @click="say">
    <h1>{{ msg }}</h1>
    <h2 v-if="show">show me</h2>
  </div>
</template>

<script>
export default {
  name: 'Hello World',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App',
      show: false
    }
  }
  methods: {
    say() {
      console.log('hi')
    }
  }
}
</script>

<style scoped>
h1, h2 {
  font-weight: normal;
}
</style>

複製程式碼

一個React的元件

const styles = {
  fontWeight: 'normal'
}
export default class Hello extends Component {
  constructor(props) {
        super(props);
        this.state = {
            msg: 'Welcome to Your React App',
            show: false
        };
    }

  say() {
    console.log('hi')
  }

  render() {
    return (
      <div class="hello" onClick={this.say}>
        <h1 className={styles}>{this.state.msg}</h1>
        {this.state.show ? <h2>show me</h2> : null}
      </div>
    )
  }
}
複製程式碼

從兩個元件對比就能看見: React元件完全就是一個Class類,你一直在寫各種類方法,甚至你的css也是個物件,所以React要求開發者有較好的ES6基礎,因為你無時無刻不在寫JS

而Vue就不一樣了,Vue元件其實就是個普通的物件,你只是在修改這個物件的屬性:name data methods components,說的通俗點,你根本就是在配置物件,例如:你配置了這個物件的components屬性,於是就可以在模板中使用自定義元件

因此,React本質上是不可能給你提供類似v-for的API,因為JS已經有了for迴圈,陣列也有map方法,你寫React就是在寫JS,為啥還需要額外的遍歷方法呢?而Vue就不同了,它提供的指令,其實就是在內部幫你寫JS,所以從React轉向Vue的開發者,一開始會覺得,Vue的程式碼更簡潔了。不過,這是靠犧牲自由度換來的,畢竟在React裡,怎麼實現遍歷,完全由你自己決定

相關文章