vue-router: Loading asynchronously a non .vue component fails

Version

2.5.2

Reproduction link

https://github.com/fpoliquin/vue-bug-async.git

Steps to reproduce

Create a simple JavaScript or TypeScript component:

Async.ts

import Vue from 'vue'
import Component from 'vue-class-component'

@Component({
    template: '<p>Hello {{msg}}</p>'
})
export default class Async extends Vue {
    msg: 'world'
}

Try to load async:

Router.ts

const Async = resolve => require(['Async'], resolve)

export default new Router({
    mode: 'history',
    routes: [
        {
            path: '/async',
            component: Async
        }
    ...

What is expected?

The component should be mounted and operational after loading the webpack chunk

What is actually happening?

The console shows this error:

Failed to mount component: template or render function not defined.


I found a workaround by replacing a little piece of code : From src/history/base.js line 341

          // save resolved on async factory in case it's used elsewhere
          def.resolved = typeof resolvedDef === 'function'
            ? resolvedDef
            : _Vue.extend(resolvedDef)
          match.components[key] = resolvedDef

To

          if (resolvedDef.default) {
            def.resolved = resolvedDef.default;
            match.components[key] = resolvedDef.default;
          } else {
            // save resolved on async factory in case it's used elsewhere
            def.resolved = typeof resolvedDef === 'function'
              ? resolvedDef
              : _Vue.extend(resolvedDef);
            match.components[key] = resolvedDef;
          }

This works for me but I am not sure if it is a good fix for everyone else…

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 19 (3 by maintainers)

Most upvoted comments

What versions of vue-loader and vue-router are you using? vue-loader 13.0 introduced changes that required an upgrade of vue-router for this to work. With older versions of the router, you now have to do

{ path: '/forum', component: () => import('./components/Forum.vue').then(m => m.default) } /

set module to esnext in tsconfig.json, now you can use

component: () => import('. /async.js').then(m => m)

Amazing @fpoliquin 💃💃if someone has problems I was exporting my modules without default:

app.router.ts

const ModelExplorerComponent = resolve => (require as any)(['./model-explorer/model-explorer.component'], module => resolve(module.default));

./model-explorer/model-explorer.component

export default class ModelExplorerComponent extends ToolComponent { }

And if you’te using webpack don’t forget

output: {
  publicPath: 'js/'
},

(your path could be other)

Hi @yyx990803, thank you for your answer.

Typescript doesn’t support this synthax yet so I had to change it a little bit like this :

component: = (resolve) => (require as any)(['./async'], function (module) {
    resolve(module.default)
})

And now it is working.

I don’t know if it would be a good idea do update the documentation with this. I know I lost a lot of time figuring this out.

Thanks for your help.