How do we migrate from ng1 to vue

Posted by alexander.s on Wed, 15 May 2019 10:08:14 +0200

The original technology stack ng1 + gulp + slim+
A backend management project for vue *2 + iframe

This is a back-end management project created by back-end students because of the shortage of manpower itself. At first, gulp + ng1 is used to develop the project. At the same time, after the front-end takes over, in order to facilitate the development and keep up with the trend, the new opening subdirectory is developed by vue, nginx and iframe are integrated. The last project has become three projects. In fact, the first project is developed. When you start, you don't even know how to start it.

Problems to be solved

Hierarchical structure of projects

The original structure

Top-level directories only contain multiple subfolders and build.sh, each subproject needs to be compiled and developed independently.

New structure

Using signle-spa as the solution of entry file, the entry file of all projects can be managed uniformly, and all projects can be developed and compiled together at the same time, thus eliminating switching back and forth and port conflict.

The Chaos of Language Construction

The original structure

The original app uses ng1 to write the JS part, slim to write the page template, and gulp to complete the traversal of all JS files, and packaged into a js. Later, some new pages use iframe to introduce another vue-cli project, and the two share login data through cookie.

Updated architecture

Because of the problem of template files, gulp is still the main method. webpack is responsible for js packaging of vue and original app and compiling of resource files. It is agreed that the original ng part should not be updated as much as possible, and new vue will be used for compiling.

Gradual transition

The original plan

Regardless of it, the old ones need to be updated, and the new ones need to be written in the vue project.

Current solutions

single-spa for page splitting, will need to update the old ng part as a new sub-app, splitting out and then update, to ensure that local updates do not affect the overall.

Solving process

Compiler tool

After defining the overall migration plan, the first step is to change the compiling tool. The first step is to replace gulp with webpack (because webpack is customarily configured, and webpack 4 + Babel 7 really compiles much faster).

But because slim can't find the right relationship with the web pack plug-in, it finally decided to keep the relevant html files for gulp compiling ng ng

A minor question

gulp support for web pack

The web pack version supported by the gulp-webpack plug-in is 2, but the goal is to use 4 (for speed). Fortunately, the web pack support uses node to invoke, as long as a callback is given to gulp after compilation.


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)
      }

      // output
      process.stdout.write(stats.toString({
        // Various messages during compilation are stored in the stats object
        colors: true, // Increase console color switch
        modules: false, // Do not add built-in module information
        children: false, // No additional sublevel information
        chunks: false, // Allow less output
        chunkModules: false // Do not add information from built-in modules to package information
      }) + '\n\n')
    })

    compiler.hooks.afterEmit.tap('gulp', function() {
      resolve()
    })
  })
}

Similarly, devServer uses custom scripts, and of course, for company reasons, api switching is directly placed in devServer's before.

/**
 * webpack devserver
 */
const webpack = require("webpack");
const WebpackDevServer = require("webpack-dev-server");
const proxy = require("http-proxy-middleware");

let env = "dev"; // Environmental Science

module.exports = function(config) {
  return new Promise((resolve, reject) => {
    // Need to be configured in node mode
    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();
    });
  });
};


Unified Construction and Development

Because the language used is different, the pages responsible are different, Store and Route are different, if you want to be unified, you must solve these problems.

single-spa

SINGLE-SPA is a JavaScript meta-framework that allows us to build micro-front-ends using different frameworks that can coexist in a single application.


microservice style has been popular for some time, so can the front end use the same micro service? single-spa is a meta-framework that supports almost all front-end development frameworks. Our migration goal is to split the original ng part into a small app and gradually migrate to vue.

Unified Store

Ultimately decided to use vuex as the Store of the whole project, but how to integrate with the rootScope of NG itself is another problem. Fortunately, the scope of the js file introduced through import is common. Just mount the rootScope of ng on vuex, and then vuex triggers the updating of ng in the form of plug-ins.

import store from '../store'

Object.assign(store.state, {
    _ng: {
      $rootScope: $rootScope,
      $state: $state
    }
  })
/**
 * Synchronize these data into ng's Cope
 * @param store
 */
export const ngPlugin = store => {
  // Called when store is initialized
  store.subscribe(({ type, payload }, state) => {
    if (state._ng) {
      state._ng.$rootScope[type] = payload
      state._ng.$rootScope.$apply()
    }
  })
}

Unified routing

At present, the routing jump mode is still separate, but the vue and ng jump mode is changed to the single-spa route jump mode by instructions. Of course, because the previous routing of NG is to continue hash instead of history, there are still some compatible operations.

import { navigateToUrl } from 'single-spa'

directives: {
      // spa links
      spaLink (element, {value}) {
        element.style.display = 'inline-block'
        element.style.width = '100%'
        // Automatically judge hash type
        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)
          }
        })
      }
    },

Unification of directory structure

One of the benefits of using web pack is that you can use alias to introduce the relevant components of vue. After moving the original level directories into src, you can achieve seamless migration by modifying alias.

Split app

There's nothing to say, split by business relevance and priority, and manage with single-spa

Current progress

Of course, migration is not a matter of overnight. In fact, the sidebar navigation bar of the whole project has been replaced, which supports the search box that has been noisy to do. There are many problems in the process of replacement. However, because the app is split, it does not affect the normal operation of the whole project. It seems that migration is promising. At least now, starting the project does not need all kinds of branches. At the same time, there are many problems in the process of replacement. Because of laziness, I also wrote seed system to quickly generate project pages by defining data structure. This is what I will say later.

Topics: Webpack Vue Javascript Nginx