咱們是如何從ng1遷移ing到vue的

本來的技術棧 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的問題

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

SINGLE-SPA是一個 JavaScript 元框架,它容許咱們使用不一樣的框架構建微前端,而這些框架能夠共存於單個應用中。

後端微服務架構(microservice style)已經流行了一段時間了,那麼前端能不能一樣使用微服務呢?頁面拆分紅不一樣的部分,互相之間互不干擾又緊密相連,single-spa正是爲此而出現的,並且更好的事,single-spa支持幾乎全部的前端開發框架,是一個框架的元框架,而咱們的遷移目標正好就是將本來的ng部分拆分紅一個個小的app而後逐步遷移到vue上麼

統一Store

最終決定使用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,就能作到無縫遷移了

拆分app

沒什麼好說的,按照業務相關性和優先級拆分,使用single-spa進行管理

目前進度

固然啦,遷移也不是一朝一夕的事,其實主要把整個項目的側邊欄導航欄給換了,支持了一直吵着要作的搜索框,更換的過程當中還出過很多問題,不過由於拆分了app,卻是沒有影響整個項目的正常運行,看來遷移有望,起碼如今啓動項目不用各類切分支了😂,同時由於偷懶,還專門寫了seed系統,經過定義數據結構快速生成項目頁面,這也是後話了

相關文章
相關標籤/搜索