universal-router icon indicating copy to clipboard operation
universal-router copied to clipboard

TypeError: Cannot read property 'substr' of undefined

Open pfftdammitchris opened this issue 6 years ago • 1 comments

I just updated all of my dependencies and now I am getting this error.

Server boots up just fine. However when I try to load the page this error occurs:

1

After calling src/server.js at line 147:1 it seems to be passing in an undefined route path or something is glitching. How is that so? Clearly my paths are defined as shown in this post.

Inside server.js. Line 147:1 is the line starting with: const route = await router.resolve

    const context = {
      // Enables critical path CSS rendering
      // https://github.com/kriasoft/isomorphic-style-loader
      insertCss: (...styles) => {
        // eslint-disable-next-line no-underscore-dangle
        styles.forEach(style => css.add(style._getCss()));
      },
      fetch,
      // You can access redux through react-redux connect
      store,
      storeSubscription: null,
    };

    const route = await router.resolve({
      ...context,
      path: req.path,
      query: req.query,
    });

    if (route.redirect) {
      res.redirect(route.status || 302, route.redirect);
      return;
    }

And here is the class func in universal-router (copied straightly from node_modules) that cannot proceed because it is catching an undefined value route:

class UniversalRouter {
  constructor(routes, options = {}) {
    if (Object(routes) !== routes) {
      throw new TypeError('Invalid routes');
    }

    this.baseUrl = options.baseUrl || '';
    this.resolveRoute = options.resolveRoute || resolveRoute;
    this.context = Object.assign({ router: this }, options.context);
    this.root = Array.isArray(routes) ? { path: '', children: routes, parent: null } : routes;
    this.root.parent = null;
  }

  resolve(pathnameOrContext) {
    const context = Object.assign(
      {},
      this.context,
      typeof pathnameOrContext === 'string' ? { pathname: pathnameOrContext } : pathnameOrContext,
    );
    const match = matchRoute(
      this.root,
      this.baseUrl,
      context.pathname.substr(this.baseUrl.length),
      [],
      null,
    );
    const resolve = this.resolveRoute;
    let matches = null;
    let nextMatches = null;

    function next(resume, parent = matches.value.route) {
      matches = nextMatches || match.next();
      nextMatches = null;

      if (!resume) {
        if (matches.done || !isChildRoute(parent, matches.value.route)) {
          nextMatches = matches;
          return Promise.resolve(null);
        }
      }

      if (matches.done) {
        return Promise.reject(Object.assign(
          new Error('Page not found'),
          { context, status: 404, statusCode: 404 },
        ));
      }

      return Promise.resolve(resolve(
        Object.assign({}, context, matches.value),
        matches.value.params,
      )).then((result) => {
        if (result !== null && result !== undefined) {
          return result;
        }

        return next(resume, parent);
      });
    }

    context.next = next;

    return next(true, this.root);
  }
}

So, in node_modules/src/UniversalRouter.js, how is it catching an undefined value when it is being executed after the context declaration?

  resolve(pathnameOrContext) {
    const context = Object.assign(
      {},
      this.context,
      typeof pathnameOrContext === 'string' ? { pathname: pathnameOrContext } : pathnameOrContext,
    );
    const match = matchRoute(
      this.root,
      this.baseUrl,
      context.pathname.substr(this.baseUrl.length),
      [],
      null,
    );

Here are my routes.js:

const routes = {

  path: '/',

  // Keep in mind, routes are evaluated in order
  children: [
    {
      path: '/',
      load: () => import(/* webpackChunkName: 'home' */ './home'),
    },
    {
      path: '/contact',
      load: () => import(/* webpackChunkName: 'contact' */ './contact'),
    },
    /*{
      path: '/login',
      load: () => import('./login'),
    },
    {
      path: '/register',
      load: () => import('./register'),
    },
    */{
      path: '/about',
      load: () => import(/* webpackChunkName: 'about' */ './about'),
    },
    /*{
      path: '/privacy',
      load: () => import('./privacy'),
    },
    {
      path: '/admin',
      load: () => import('./admin'),
    },*/
    {
      path: '/rnews',
      load: () => import('./rnews'),
    },
    {
      path: '/cp',
      load: () => import('./cp'),
    },
    // Wildcard routes, e.g. { path: '*', ... } (must go last)
    {
      path: '*',
      load: () => import(/* webpackChunkName: 'not-found' */ './not-found'),
    },
  ],

  async action({ next }) {
    console.log(next);
    // Execute each child route until one of them return the result
    const route = await next();

    // Provide default values for title, description etc.
    route.title = `${route.title || 'ForbiddenGrounds'}`;
    route.description = route.description || '';

    return route;
  },

};

// The error page is available by permanent url for development mode
if (__DEV__) {
  routes.children.unshift({
    path: '/error',
    action: require('./error').default,
  });
}

export default routes;

pfftdammitchris avatar Oct 08 '17 21:10 pfftdammitchris

Please see Migration from v3 to v4 section in changelog.

Also, changes from this PR can be useful to you: https://github.com/kriasoft/react-starter-kit/pull/1403

frenzzy avatar Oct 09 '17 06:10 frenzzy