部門最近的一個新項目啟動,很幸運由我來主導整個前端部分的技術選型和整體架構,項目工作量很大,但是卻沒有足夠的人手,只有三個連CSS都不太會的實習生跟着我一起做,壓力山大。兩個月以來,雖然遇見了很多問題,但是最終順利的解決了,項目基本完成,果斷寫一篇總結,畢竟是第一個真正意義上全權自己負責的大項目 。
一、技術選型。
如果沒有接觸過新的知識,我可能會像之前的部門的所有項目一樣,按部就班的使用Jquery + bootstrap + sea.js/require.js 進行開發,但是我說了NO。
首先,這次項目初步估計有近百個功能點和幾十個頁面,如果仍用jquery的方法,光是臃腫的dom操作代碼就把人寫的筋疲力盡了,而且我自己本人也是在是厭倦了重復而乏味DOM操作。所以我選擇了Vue, 至於為什么不是react和anglar, 相對於他們Vue我覺得對於新手來說是很容易上手的,相對於react一些相關的技術棧,Vue對於實習生更容易掌握。使用Vue我只需要把項目共用的模塊封裝成共用組件,讓他們去調用就可以了,這一點保證了他們很少去寫CSS樣式,也為項目快速的開發完成起到了一定的決定因素。
最終使用的技術如下:
基礎JS框架: Vue, 基礎樣式和組件框架: iView ,國際化插件: vue-i18n,表單驗證插件:vee-validate
項目打包工具:webpack + babel
代碼規范性檢查: eslint
二、項目過程中遇見的問題。
這部分其實是我寫這篇博客的主要目的,好多問題,畢竟總結更多的是去記錄過去遇見的問題和走過的彎路。
1、舊的JS代碼的兼容。
由於項目中有一部分的代碼是之前的項目組使用的seajs封裝的模塊,而且這部分代碼內部的邏輯比較復雜,重寫基本是不可能的,沒時間何精力去研究,只有通過引入到我們的webpak工程中,如何把這部分代碼挪過來並且很少改動就成了一個大問題。很幸運,webpack直接支持AMD或CMD的代碼,我用的vue-cli初始化的項目,所以更改了一些webpack.base.config里的一些配置,但是忍讓需要修改一些配置讓原來js里的require能夠找到原來的模塊並執行。
新建了一個oldModuleConfig.js,
const path = require('path') function resolve (dir) { return path.join(__dirname, '..', dir) } const oldModuleConfig = { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), /* Switch EWeb */ 'oldModule1': resolve('src/oldModule1'), 'oldModule2': resolve('src/oldModule2'), 'oldModule3': resolve('src/oldModule3'), 'oldModule4': resolve('src/oldModule4'), } module.exports = oldModuleConfig
然后修改了webpack.base.config.js
resolve: { extensions: ['.js', '.vue', '.json', '.less'], /** alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src') } **/ // 將原來的這部分改成這樣 alias: oldModuleConfig }
這樣原來的module1里面如果寫了require就可以直接使用了
var module2 = require('module2') //這行代碼如果沒有配置直接引入就找不到module2這個模塊,而配置alias之后就可以運行了
這是本人自己想到的略low的方法,如果有高人指出可以在webpack里引入舊的seajs/requirejs代碼其他方法,歡迎指出。
2、原有代碼無法通過eslint語法檢查
原來的代碼雖然引進來了,但是卻無法通過eslint的檢查,這個問題我是直接選擇忽視原有文件的檢查,如果你是用了vue-cli構建的項目,可以修改.eslintignore
build/*.js config/*.js src/oldCodeFolder //舊代碼的文件夾
3、Vue-router 頁面刷新
如果用過vue-router的應該知道,如果點擊的鏈接就是現在的頁面,那么當前頁面組件是不會刷新的,實際過程中可能希望再次點擊頁面是刷新一下。解決辦法是使用一個中轉頁面bus,所有的頁面跳轉到這個bus.vue,然后由這個頁面再調回原來的頁面,這樣就達到了刷新的效果。
<!-- 這是一個中轉的頁面,本身不具有任何內容,為什么要設置這個中轉頁面呢? 因為vue-router點擊當前頁面的鏈接時並不會刷新組件,為了保持再次點擊刷新, 通過設置這個bus中轉頁面即可實現 --> <template> <div> </div> </template> <script> export default { data () { return {} }, methods: { jumpToPage () { let path = this.$route.params.path if (path) { this.$router.replace(path) } } }, mounted: function () { this.jumpToPage() } } </script>
然后router-view里傳入下一個即將跳轉的頁面路徑即可
<router-link :to="{ name: 'bus', params: { path: nextPath }}":key="link.en"> {{ link.en }} </router-link>
4、iView封裝帶分頁的表格組件
iView提供了Table和Page兩個組件,但是很蛋疼,沒有提供帶分頁的表格組件,所以需要自己進行組合實現。這里提供示例代碼,
<template> <div class="clear"> <Table :columns='columns' :data='showData' :ref="refLabel" :loading="loading" stripe :no-data-text="'<span class=\'no-data-text \' > <i class=\'icon-no-data\'></i> ' + $t('message.nodata')+ '</span>'"></Table> <Page :total='dataCount' :page-size='pageSize' :show-total='isShowTotal' :current.sync="current" class='paging' @on-change='changepage'></Page> </div> </template> <style scoped> .paging{ float:right; margin-top:20px; } </style> <script> export default { data () { return { ajaxHistoryData: [], // 初始化信息總條數 dataCount: 0, // 每頁顯示多少條 showData: [], current: 1 } }, props: { pageSize: { type: Number, default: 10 }, columns: { type: Array }, isShowTotal: { type: Boolean, default: true }, tableData: { type: Array }, refLabel: { type: String }, loading: { type: Boolean, default: false } }, methods: { // 獲取歷史記錄信息 handleShowData () { if (this.tableData && this.tableData.length) { // 保存取到的所有數據 this.dataCount = this.tableData.length // 初始化顯示,小於每頁顯示條數,全顯,大於每頁顯示條數,取前每頁條數顯示 if (this.tableData.length < this.pageSize) { this.showData = this.tableData } else { this.showData = this.tableData.slice(0, this.pageSize) } } else { this.showData = [] this.dataCount = 0 } this.current = 1 }, currentChange (value) { }, changepage (index) { var _start = (index - 1) * this.pageSize var _end = index * this.pageSize this.showData = this.tableData.slice(_start, _end) } }, created () { this.handleShowData() }, watch: { tableData (oldVal, newVal) { this.handleShowData()
// 表格刷新了,當前頁標識需要回到第一頁的位置 this.current = 1 } } } </script>
這里沒有寫異步獲取數據的方法,所以具體使用時需要解渴自己的業務邏輯進行修改。
5、webpack打包體積過大,減少打包體積
說出來你們可能不信,我們的代碼最終放在的服務器智能放下60M左右的文件,我也是很無奈,所以減少webpack打包體積就成了一個必須的問題。解決方法如下:
a、首先最直觀的,將生產環境的sourceMap設為false ,這里設置完之后,打包后的文件就沒有了.map文件,這一步基本減少了一大半的代碼體積。
b、使用webpack-bundle-analyzer 優化你的代碼
如果vue-cli構建的項目,只需要在package.json的scripts里加入:
"analyz": "set NODE_ENV=production && set npm_config_report=true && npm run build"
然后運行npm run analyz, 打包成功后瀏覽器會自動打開類似下面的頁面,找出其中共用寫入Vendors, 然后使用webpack.optimize.CommonsChunkPlugin 進行優化
c、如果你們有CDN的話,盡量把基礎代碼如: vue , vue-router 放在CDN上面
d、tree shaking 去除無用的代碼
6、其他
其實還有許多大大小小的問題,比如Vue的路由攔截,webpack多頁面,DDL優化打包速度,覆蓋iVIew組件,nginx代理,組件scoped樣式覆蓋不了iView默認樣式等等許多,每一個解決完了都有滿滿的成就感。
三、項目構建問題回顧
1、代碼初期沒有架構合理,導致后期存在一些維護上的問題。
比如,代碼引入了SASS,開始沒有設置一個主題的公共文件,導致后面設計變動整體主題跟着發生了一些改變,雖然iView支持更改主題,但是自己寫的一些組件由於沒有共用的主題文件,導致后期修改比較麻煩。
2、代碼沒有review
雖然代碼整體風格使用了eslint去規范了,但是其實真正開發的時候發現三個兄弟的代碼很不規范,畢竟工作經驗不足,包括變量的大小寫,css類命名,甚至在頁面里使用了Jquery等問題,一開始沒有review, 后期仔細閱讀他們的代碼的時候才發現這些問題,然后才進行修改。其實這些問題在項目開始我就應該說明的。
3、其他
后續補充。。。
四、項目收獲
整個項目在代碼架構上還是獲得了其他同事的認可,至少推動了部門前端向前走了一步,我算是部門第一個吃螃蟹的人,敢於把新技術果斷使用到新的項目里,第一次將webpack + vue的技術棧整體運用了一遍,雖然不能說精通,但是應該也是熟練掌握了,總覺得自己平日所學沒有白費,實踐應用了一遍滿滿的收獲。
2018 繼續前行。
喜歡的話可以點個推薦或者關注哦!
注:本文出自博客園 https://home.cnblogs.com/u/mdengcc/ ,轉載請注明出處。