Vue3(四)從jQuery 轉到 Vue工程化 的捷徑

金色海洋(jyk)發表於2021-02-15

不會 webpack 還想學 vue 工程化開發 的福音

熟悉jQuery開發的,學習vue的簡單使用是沒用啥問題的,但是學習vue的工程化開發方式,往往會遇到各種問題,比如:

webpack、node、npm、cnpm、yarn、腳手架、開發環境、測試環境、生產環境、各種安裝、各種建立。
好在 vue3 不容易報錯了,想當初 vue2.x 的時候各種報錯,看到錯誤就只能乾瞪眼,這都是啥?好像是webpack的報錯。
當初學 vue2 就卡在了建立專案上,各種嘗試居然一個專案都沒跑起來。

如果能像jQuery那樣,直接開魯那多好呀!

各種陰差陽錯+機緣巧合的情況下,弄出來了這種在 CND 模式下仿工程化開發的方式。一開始只是想方便我做線上演示,後來各種完善,發現還是應該有點搞頭了。再加上大神在弄vite,似乎也是對webpack比較頭疼。。。

好了不墨跡了,開始說我的做法。

vue全家桶和UI庫的載入方式

這個很傳統了,官方也支援。

  <script src="https://unpkg.com/vue@3.0.5/dist/vue.global.js"></script>
  <script src="https://unpkg.com/vue-router@4.0.3/dist/vue-router.global.js"></script>
  <script src="https://unpkg.com/vuex@4.0.0-rc.2/dist/vuex.global.js"></script>
  <link href="https://unpkg.com/element-plus@1.0.2-beta.30/lib/theme-chalk/index.css" rel="stylesheet">
  <script src="https://unpkg.com/element-plus@1.0.2-beta.30/lib/index.full.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

瀏覽器會對js檔案做快取,第一次有點慢,後快取後就快了。
001下載js.png

某網站有時候會卡一下,不卡的話還是很快的。

js程式碼的載入方式

<script type="module" src="src/main.js?v=4"></script>

聽說vite也是這麼載入的。好吧就是從vite建立的專案裡copy來的。
要加上 type="module" 否則載入不了。

資料夾結構和程式碼編寫風格

資料夾當然是把工程化的拿過來之間用了,挺簡潔明瞭的。
因為瀏覽器也支援 import 的方式載入js,那麼也就是說,CDN方式下也可以用import載入。那麼js程式碼方面也不會有太大的差別。
我們來對比一下:
002資料夾對比.png

左面是CND的專案,右面是工程化的專案。

  • 資料夾結構完全一致,
  • js檔案都能對應上
  • vue檔案拆分成 html + js 兩個檔案(app.vue除外)

main.js

/*
import store from './store/index.js?v=1'
import router from './router/index.js?v=1'
import App from './app.js?v=1'

// 建立vue3的例項
const app = Vue.createApp(App)
  .use(store) 
  .use(router)
  .use(ElementPlus)
  .mount('#app')
*/

const ver = window.__ver || ''
Promise.all([
  import('./store/index.js' + ver),
  import('./router/index.js' + ver),
  import('./app.js' + ver),
]).then((res) => {
  // 建立vue3的例項
  const app = Vue.createApp(res[2].default)
    .use(res[0].default) // 掛載vuex
    .use(res[1].default) // 掛載路由
    .use(ElementPlus) // 載入ElementPlus
    .mount('#app') // 掛載Vue的app例項
})

註釋掉的程式碼,和工程化裡的程式碼是一致的,只是這種方式只支援常量,所以想把版本加在url地址上面就比較麻煩。
所以改為了這種非同步的方式,這樣可以把版本號給拼接上去。這樣更新瀏覽器的js快取就方便多了。

app.js

export default {
  name: 'app',
  setup() {
    do something...
  
    return {
    }
  }
}

工程化專案裡面是App.vue,對應的是網頁裡 id=“app” 的div。
這裡改成純js檔案的形式,因為模板就是index.html的div。
好吧,其實是main.js裡面的載入方式不知道要怎麼改。。。

router


const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => myImport('views/home')
  },
  {
    path: '/About',
    name: 'About',
    component: () => myImport('views/About')
  },
  {
    path: '/component',
    name: 'component',
    component: () => myImport('views/component')
  },
  {
    path: '/store',
    name: 'store',
    component: () => myImport('views/store')
  }
]

const router = VueRouter.createRouter({
  history: VueRouter.createWebHistory(),
  routes
})

export default router
  • 動態路由
    這裡採用動態路由的方式,另外換成了我自己封裝的函式,可以載入html和js檔案,然後變成動態元件的方式,這樣元件就可以被路由載入了。

  • 路徑設定問題
    本來想把html和js檔案放在一個資料夾裡面,就可以用同一個url載入了,結果和我想的不一樣。
    由於載入 html 和載入 js 的路徑規則不太一樣,再加上路由導航的原因,
    所以只好用 src 作為分隔標識,統一從src開始計算路徑。

myImport

// 直接放在Window裡面好了。。。
window.myImport = (url) => {
  return new Promise((resolve, reject) => {
    const ver = window.__ver || ''
    const baseUrl = window.__basrUrl || '/src/'
    // 先載入js
    import(baseUrl + url + '.js' + ver).then((resjs) => {
      const js = resjs.default
      if (js.template === '') {
        // 如果模板是空的,表示需要載入html作為模板
        axios.get(baseUrl + url + '.html' + ver).then((resHTML) => {
          js.template = resHTML.data
          resolve(js)
        })
      } else {
        // 否則直接使用js註冊元件
        resolve(js)
      }
    })
  })
}

一開始還想做個外掛掛到vue上面,後來試了半天沒成功。
然後覺得自己挺傻的,cnd環境,一個靜態函式,直接掛在Window上面不就行了嗎。

  • 載入 js 和 html
    先用 import 非同步載入 js,目的是便於拼接url,然後判斷是否有template。
    如果有的話,就不載入html了。
    如果沒有的話,在用axios載入html,然後設定給template,這樣就變成了一個標準的js元件。

  • 是否會重複載入?
    元件自帶快取機制,第一次會載入,以後就不會重複載入了。

store

import { Set_Count } from './mutation-types.js'

export default Vuex.createStore({
  state: {
    count: 0,
    myObject: {
      time: '現在的時間:'
    },
    myArray: [1,2,2,3,4]
  },
  getters: {
    getAddCount: (state) => {
      return state.count + 1
    } 
  },
  mutations: {
    // 計數器
    setCount(state, num = 1) {
      state.count += num
    },
    [Set_Count](state, num = 1) {
      state.count += num
    }
  },
  actions: {
  },
  modules: {
  }
})

基本上沒啥區別。

如何方便的寫模板

直接看圖,更清晰一些。
003元件.png
一邊寫js程式碼,另一邊寫模板。這樣也是很方便的。

一開始想在瀏覽器裡面直接載入vue檔案,然後處理成js元件。
想了半天,理論上應該可以,但是我這水平估計夠嗆,所以採用了這種折中的方式。

元件裡面載入元件

004元件加元件.png

  • defineAsyncComponent
    這個是Vue提供的非同步元件,如果在工程化裡面,可以直接載入vue檔案。
    我在cnd裡面試了一下,沒成功。所以只好用純js元件的方式。

動態路由不需要套這個,但是非同步元件就要套上,否則沒有效果。

搭一個梯子

這樣做專案和 jQuery 的風格挺像的,檔案copy過來,建立個網站就可以開魯了。

同時程式碼編寫方式又採用工程化的方式,熟悉之後可以方便的切換的工程化的開發方式。

就好像在 jQuery 與 vue 的工程化直接搭了一個梯子,應該大概可以方便我們翻過去吧。

便於除錯

  • 設定斷點看狀態。
    005斷點.png

  • 看成員
    006看看都有啥.png

  • 進到內部了,好吧其實我都看不懂。。。
    007內部.png

js檔案的快取問題

快取是個好東東,避免我們重複載入js檔案,加快頁面顯示速度,但是如果我們的js改了,瀏覽器卻還是在用快取怎麼辦?

我們可以設定一個版本號,載入檔案後面就可以。當更新的時候,改一下版本號,就可以重新載入了。

原始碼

https://github.com/naturefwvue/nf-vue-cnd/tree/main/cnd/project-template

線上演示

https://naturefwvue.github.io/nf-vue-cnd/cnd/project-template/
一開始可能會有的卡,第一次點導航會載入檔案,所以會慢一點,以後就好了。好像應該加一個載入中的狀態。

相關文章