本来的技术栈 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也不同,想要统一的话,就必须解决这些问题
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系统,经过定义数据结构快速生成项目页面,这也是后话了