mergeWithConfig(routes, routesConfig = [], rewriteRules = [], parentPath = '') {
        /**
         * In dev mode, we need to add timestamp to every route's hash as prefix.
         * otherwise when we change the code in page.vue, route's hash remains the same,
         * webpack hot middleware will throw a "Duplicate declaration" error.
         */
        let timestamp = this.isDev ? (new Date()).getTime() : '';
        let errorIndex;

        routes.forEach((route, index) => {
            // add to set
            this.flatRoutes.add(route);

            // rewrite route path with rules
            route.rewritePath = this.rewriteRoutePath(rewriteRules, route.path);
            route.fullPath = parentPath ? `${parentPath}/${route.path}` : route.path;

            // find error route
            if (route.fullPath === this.config.errorHandler.errorPath) {
                this.errorRoute = route;
                // add default error route alias
                this.errorRoute.alias = '*';
                errorIndex = index;
            }

            // find route in config
            let routeConfigArr = routesConfig.filter(function ({pattern}) {
                return pattern instanceof RegExp
                    ? pattern.test(route.fullPath) : pattern === route.fullPath;
            });

            // mixin with config, rewrites path, add lazyLoading, meta
            let routeConfig;
            if (routeConfigArr.length !== 0) {
                if (routeConfigArr.length === 1) {
                    routeConfig = routeConfigArr[0];
                }
                else {
                    routeConfig = {};
                    routeConfigArr.forEach(tmpRouteConfig => Object.assign(routeConfig, tmpRouteConfig));
                }
            }

            if (routeConfig) {
                let {
                    path: routePath,
                    lazyLoading,
                    chunkname
                } = routeConfig;

                Object.assign(route, routeConfig, {
                    rewritePath: routePath || route.rewritePath,
                    lazyLoading: lazyLoading || !!chunkname
                });
            }

            /**
             * generate hash for each route which will be used in routes.js template,
             * an underscore "_" will be added in front of each hash, because JS variables can't
             * start with numbers
             */
            route.hash = timestamp + createHash('md5').update(route.component).digest('hex');

            /**
             * turn route fullPath into regexp
             * eg. /detail/:id => /^\/detail\/[^\/]+\/?$/
             */
            route.pathRegExp = route.rewritePath === '*'
                ? /^.*$/
                : routes2Reg(route.rewritePath);

            // merge recursively
            if (route.children && route.children.length) {
                this.mergeWithConfig(route.children, routesConfig, rewriteRules, route.fullPath);
            }
        });

        // remove errorRoute and add it to the end
        if (errorIndex !== undefined) {
            routes.splice(errorIndex, 1);
        }
    }
merge routes with config recursively

@param {Array} routes routes
@param {Array} routesConfig config
@param {Array} rewriteRules rewriteRules
@param {Array} parentPath parentPath