本來的技術棧 ng1 + gulp + slim + vue *2 + iframe 的一個後端管理項目javascript
這是一個自己由於人手不足,一開始由後端同窗建立的後端管理項目,基本採用了gulp + ng1來進行開發,同時前端接手以後爲了方便開發以及跟上潮流,採用了新開子目錄使用vue開發,nginx和iframe進行整合的方式,最後一個項目變成了三個項目,其實最開始進行開發的時候,連怎麼啓動都不知道😂html
頂級目錄只包含多個子文件夾以及build.sh,每一個子項目須要獨立進行編譯以及開發前端
採用signle-spa做爲入口文件解決方案,統一管理全部項目的入口文件,實現一次啓動,全部項目都能一塊兒開發以及編譯,省去了來回切換以及端口衝突vue
本來的app是使用ng1來進行編寫js部分,slim來編寫頁面模版,同時使用gulp來完成遍歷全部的js文件,並打包到一個js中,後來一些新的頁面部分採用iframe引入另外一個vue-cli項目,二者之間經過cookie來進行登陸數據的共享。java
由於模版文件的問題,仍然以gulp爲主,webpack負責vue和本來app的js打包和資源文件的編譯工做,你們約定好,本來的ng部分儘可能不更新,新的採用vue進行編寫node
老的無論它,須要更新就回去更新,新的需求去vue的項目中編寫webpack
single-spa進行頁面的拆分,將須要更新的老的ng部分做爲一個新的子app,拆分出來以後再進行更新,保證局部更新,不影響總體nginx
肯定了總體的遷移方案以後,就是首先對編譯工具的改造了,最開始是想把gulp先替換成webpack的(由於習慣配置webpack了,以及webpack4 + babel7真的編譯速度快了不少)web
可是由於slim始終找不到適合使用的webpack插件的關係,最終決定仍是保留gulp進行編譯ng的相關的html文件vuex
gulp-webpack插件支持的webpack版本是2,可是目標是使用4(爲了快),好在webpack支持使用node來進行調用,只要在編譯結束以後給gulp一個回調就能夠了
const webpack = require('webpack')
const fs = require('fs')
module.exports = function (webpackConfig) {
return new Promise((resolve, reject) => {
const compiler = webpack(webpackConfig);
compiler.run((err, stats) => {
if (err) {
console.error(err)
reject(err)
}
// 輸出
process.stdout.write(stats.toString({
// stats對象中保存着編譯過程當中的各類消息
colors: true, // 增長控制檯顏色開關
modules: false, // 不增長內置模塊信息
children: false, // 不增長子級信息
chunks: false, // 容許較少的輸出
chunkModules: false // 不將內置模塊的信息加到包信息
}) + '\n\n')
})
compiler.hooks.afterEmit.tap('gulp', function() {
resolve()
})
})
}
複製代碼
同理,devServer也使用自定義的腳本, 固然由於公司緣由,其中的api切換也直接放在devServer的before中
/**
* webpack的devserver
*/
const webpack = require("webpack");
const WebpackDevServer = require("webpack-dev-server");
const proxy = require("http-proxy-middleware");
let env = "dev"; // 環境
module.exports = function(config) {
return new Promise((resolve, reject) => {
// node模式下須要進行配置
let devServerConfig = config.devServer;
let devPath = `http://${devServerConfig.host}:${devServerConfig.port}/`;
config.entry.app.unshift("webpack/hot/dev-server");
config.entry.app.unshift(`webpack-dev-server/client?${devPath}`);
const server = new WebpackDevServer(webpack(config), {
open: devServerConfig.open,
contentBase: config.output.path,
publicPath: config.output.publicPath,
hot: true,
disableHostCheck: devServerConfig.disableHostCheck,
historyApiFallback: true,
inline: devServerConfig.inline,
watchContentBase: devServerConfig.watchContentBase,
before: function(app) {
},
stats: {
colors: true
}
});
server.listen(devServerConfig.port, devServerConfig.host, function(err) {
if (err) {
console.log(err);
reject(err);
}
console.log(`Listening at ${devPath}`);
resolve();
});
});
};
複製代碼
由於使用的語言不同,負責的頁面不同,Store和Route也不同,想要統一的話,就必須解決這些問題
後端微服務架構(microservice style)已經流行了一段時間了,那麼前端能不能一樣使用微服務呢?頁面拆分紅不一樣的部分,互相之間互不干擾又緊密相連,single-spa正是爲此而出現的,並且更好的事,single-spa支持幾乎全部的前端開發框架,是一個框架的元框架,而咱們的遷移目標正好就是將本來的ng部分拆分紅一個個小的app而後逐步遷移到vue上麼SINGLE-SPA是一個 JavaScript 元框架,它容許咱們使用不一樣的框架構建微前端,而這些框架能夠共存於單個應用中。
最終決定使用vuex做爲整個項目的Store,可是如何與ng自己的rootScope進行整合就又是一個問題了,好在經過import引入的js文件的做用域是共同的,只須要將ng的rootScope掛載上vuex,而後vuex使用插件的形式反過來觸發更新ng就好了.
import store from '../store'
Object.assign(store.state, {
_ng: {
$rootScope: $rootScope,
$state: $state
}
})
複製代碼
/** * 同步這些數據到ng的Scope裏 * @param store */
export const ngPlugin = store => {
// 當 store 初始化後調用
store.subscribe(({ type, payload }, state) => {
if (state._ng) {
state._ng.$rootScope[type] = payload
state._ng.$rootScope.$apply()
}
})
}
複製代碼
目前仍然各自爲政,只不過路由跳轉方式經過指令的方式,將vue和ng的跳轉修改成使用single-spa的路由跳轉方式. 固然,由於以前ng的路由是繼續hash而不是history,因此還有一部分兼容操做
import { navigateToUrl } from 'single-spa'
directives: {
// spa連接
spaLink (element, {value}) {
element.style.display = 'inline-block'
element.style.width = '100%'
// 自動判斷hash類型
let hash = (value || '').includes('#') ? value.replace('/#', '#') : `#/${value}`
element.setAttribute('href', value ? hash : 'javascript:void(0)')
element.addEventListener('click', (e) => {
e.preventDefault()
if (value) {
navigateToUrl(hash)
}
})
}
},
複製代碼
使用webpack的一個好處就是可使用alias的方式 引入vue的相關組件,將原先平級的目錄都移入src以後,只要修改alias,就能作到無縫遷移了
沒什麼好說的,按照業務相關性和優先級拆分,使用single-spa進行管理
固然啦,遷移也不是一朝一夕的事,其實主要把整個項目的側邊欄導航欄給換了,支持了一直吵着要作的搜索框,更換的過程當中還出過很多問題,不過由於拆分了app,卻是沒有影響整個項目的正常運行,看來遷移有望,起碼如今啓動項目不用各類切分支了😂,同時由於偷懶,還專門寫了seed系統,經過定義數據結構快速生成項目頁面,這也是後話了